No error report for variable image offset when before-legal-hlsl is on (#4316)

PR #4118 (d71ac38b8e) let spirv-val report a validation error when we
use offset for an OpImage* instruction instead of ConstantOffset. Since
some compilers like DXC rely on spirv-opt for function inlining or loop
unrolling, the spirv-val change broke some working shaders when the
shader developers disable the optimization (spirv-opt).

For example, DXC recently got this issue from a few users e.g.,
https://github.com/microsoft/DirectXShaderCompiler/issues/3807

Since this error is reported only when the spirv-opt is disabled, it
looks like the exact case that we have to skip spirv-val when
`--before-legalize-hlsl` is given. Moreover, avoiding the error using
`--before-legalize-hlsl` on DXC is exactly what FXC and DXC's DXIL
do (they do not report the error if the offset becomes a constant after
function inlining or loop unrolling).
diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp
index bdb2516..2ece572 100644
--- a/source/val/validate_image.cpp
+++ b/source/val/validate_image.cpp
@@ -442,7 +442,8 @@
              << " components, but given " << offset_size;
     }
 
-    if (spvIsVulkanEnv(_.context()->target_env)) {
+    if (!_.options()->before_hlsl_legalization &&
+        spvIsVulkanEnv(_.context()->target_env)) {
       if (opcode != SpvOpImageGather && opcode != SpvOpImageDrefGather &&
           opcode != SpvOpImageSparseGather &&
           opcode != SpvOpImageSparseDrefGather) {
diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp
index 1d3b1a7..4d57b26 100644
--- a/test/val/val_image_test.cpp
+++ b/test/val/val_image_test.cpp
@@ -1791,6 +1791,20 @@
                         "OpImage*Gather operations"));
 }
 
+TEST_F(ValidateImage, SampleImplicitLodVulkanOffsetWrongBeforeLegalization) {
+  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
+%res4 = OpImageSampleImplicitLod %f32vec4 %simg %f32vec4_0000 Offset %s32vec2_01
+)";
+
+  CompileSuccessfully(
+      GenerateShaderCode(body, "", "Fragment", "", SPV_ENV_VULKAN_1_0).c_str());
+  getValidatorOptions()->before_hlsl_legalization = true;
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+}
+
 TEST_F(ValidateImage, SampleImplicitLodMoreThanOneOffset) {
   const std::string body = R"(
 %img = OpLoad %type_image_f32_2d_0001 %uniform_image_f32_2d_0001