SPIR-V 1.4 fixes (#755)

Fixes #753
Fixes #754

* Ensure opaque structs are not considered to have a layout
* Add all literal samplers to all entry points
diff --git a/lib/SPIRVProducerPass.cpp b/lib/SPIRVProducerPass.cpp
index dff843e..c735616 100644
--- a/lib/SPIRVProducerPass.cpp
+++ b/lib/SPIRVProducerPass.cpp
@@ -630,9 +630,6 @@
   using FunctionToResourceVarsMapType =
       DenseMap<Function *, SmallVector<ResourceVarInfo *, 8>>;
   FunctionToResourceVarsMapType FunctionToResourceVarsMap;
-  // Map of functions and the literal samplers they use.  Built during sampler
-  // generation and used to create entry point interfaces.
-  DenseMap<Function *, SmallVector<SPIRVID, 8>> FunctionToLiteralSamplersMap;
 
   // What LLVM types map to SPIR-V types needing layout?  These are the
   // arrays and structures supporting storage buffers and uniform buffers.
@@ -1471,9 +1468,14 @@
 }
 
 SPIRVID SPIRVProducerPass::getSPIRVType(Type *Ty, bool needs_layout) {
-  // Only pointers, structs and arrays should have layout decorations.
+  // Only pointers, non-opaque structs and arrays should have layout
+  // decorations.
   if (!(isa<PointerType>(Ty) || isa<ArrayType>(Ty) || isa<StructType>(Ty))) {
     needs_layout = false;
+  } else if (auto StructTy = dyn_cast<StructType>(Ty)) {
+    if (StructTy->isOpaque()) {
+      needs_layout = false;
+    }
   }
   // |layout| is the index used for |Ty|'s entry in the type map. Each type
   // stores a laid out and non-laid out version of the type.
@@ -2156,16 +2158,14 @@
       sampler_value = (*getSamplerMap())[third_param].first;
     }
 
+    // Add literal samplers to each entry point interface as an
+    // over-approximation.
     auto sampler_var_id = addSPIRVGlobalVariable(
-        getSPIRVType(SamplerTy), spv::StorageClassUniformConstant);
+        getSPIRVType(SamplerTy), spv::StorageClassUniformConstant,
+        /* InitId = */ SPIRVID(0), /* add_interface = */ true);
 
     SamplerLiteralToIDMap[sampler_value] = sampler_var_id;
 
-    // Record mapping between the parent function and the sampler variables it
-    // uses so we can add it to its interface list
-    auto F = call->getParent()->getParent();
-    FunctionToLiteralSamplersMap[F].push_back(sampler_var_id);
-
     unsigned descriptor_set;
     unsigned binding;
     if (SamplerLiteralToBindingMap.find(sampler_value) ==
@@ -2797,10 +2797,6 @@
         }
       }
 
-      for (auto sampler_id : FunctionToLiteralSamplersMap[F]) {
-        Ops << sampler_id;
-      }
-
       if (clspv::Option::ModuleConstantsInStorageBuffer()) {
         auto *V = module->getGlobalVariable(
             clspv::ClusteredConstantsVariableName(), true);
diff --git a/test/Spv1p4/interface_literal_sampler_in_helper.ll b/test/Spv1p4/interface_literal_sampler_in_helper.ll
new file mode 100644
index 0000000..5f44cab
--- /dev/null
+++ b/test/Spv1p4/interface_literal_sampler_in_helper.ll
@@ -0,0 +1,41 @@
+; RUN: clspv-opt -SPIRVProducerPass %s -o %t.ll -producer-out-file %t.spv -spv-version=1.4
+; RUN: spirv-dis %t.spv -o %t.spvasm
+; RUN: FileCheck %s < %t.spvasm
+; RUN: spirv-val --target-env vulkan1.1spv1.4 %t.spv
+
+; CHECK: OpEntryPoint GLCompute %{{.*}} "foo" [[sampler_var:%[a-zA-Z0-9_]+]]
+; CHECK-DAG: [[sampler:%[a-zA-Z0-9_]+]] = OpTypeSampler
+; CHECK-DAG: [[float:%[a-zA-Z0-9_]+]] = OpTypeFloat 32
+; CHECK-DAG: [[sampler_ptr:%[a-zA-Z0-9_]+]] = OpTypePointer UniformConstant [[sampler]]
+; CHECK-DAG: [[sampler_var]] = OpVariable [[sampler_ptr]] UniformConstant
+
+target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
+target triple = "spir-unknown-unknown"
+
+%opencl.image2d_ro_t.float.sampled = type opaque
+%opencl.sampler_t = type opaque
+
+@__spirv_WorkgroupSize = local_unnamed_addr addrspace(8) global <3 x i32> zeroinitializer
+
+declare <4 x float> @_Z11read_imagef14ocl_image2d_ro11ocl_samplerDv2_f.opencl.image2d_ro_t.float.sampled(%opencl.image2d_ro_t.float.sampled addrspace(1)*, %opencl.sampler_t addrspace(2)*, <2 x float>)
+
+define void @bar(%opencl.image2d_ro_t.float.sampled addrspace(1)* %img) {
+entry:
+  %0 = call %opencl.sampler_t addrspace(2)* @_Z25clspv.sampler_var_literal(i32 0, i32 0, i32 18)
+  %1 = tail call <4 x float> @_Z11read_imagef14ocl_image2d_ro11ocl_samplerDv2_f.opencl.image2d_ro_t.float.sampled(%opencl.image2d_ro_t.float.sampled addrspace(1)* %img, %opencl.sampler_t addrspace(2)* %0, <2 x float> <float 1.000000e+00, float 2.000000e+00>)
+  ret void
+}
+
+define spir_kernel void @foo(%opencl.image2d_ro_t.float.sampled addrspace(1)* %img) !clspv.pod_args_impl !0 {
+entry:
+  %0 = call %opencl.image2d_ro_t.float.sampled addrspace(1)* @_Z14clspv.resource.0(i32 1, i32 0, i32 6, i32 0, i32 0, i32 0)
+  call void @bar(%opencl.image2d_ro_t.float.sampled addrspace(1)* %0)
+  ret void
+}
+
+declare %opencl.sampler_t addrspace(2)* @_Z25clspv.sampler_var_literal(i32, i32, i32)
+
+declare %opencl.image2d_ro_t.float.sampled addrspace(1)* @_Z14clspv.resource.0(i32, i32, i32, i32, i32, i32)
+
+!0 = !{i32 2}
+
diff --git a/test/Spv1p4/interface_sampler.ll b/test/Spv1p4/interface_sampler.ll
index e19320a..0029f49 100644
--- a/test/Spv1p4/interface_sampler.ll
+++ b/test/Spv1p4/interface_sampler.ll
@@ -3,7 +3,7 @@
 ; RUN: FileCheck %s < %t.spvasm
 ; RUN: spirv-val --target-env vulkan1.1spv1.4 %t.spv
 
-; CHECK: OpEntryPoint GLCompute %{{.*}} "test" {{.*}} [[sampler:%[a-zA-Z0-9_]+]]
+; CHECK: OpEntryPoint GLCompute %{{.*}} "test" [[sampler:%[a-zA-Z0-9_]+]]
 ; CHECK: [[sampler_type:%[a-zA-Z0-9_]+]] = OpTypeSampler
 ; CHECK: [[sampler_ptr:%[a-zA-Z0-9_]+]] = OpTypePointer UniformConstant [[sampler_type]]
 ; CHECK: [[sampler]] = OpVariable [[sampler_ptr]] UniformConstant
diff --git a/test/Spv1p4/opaque_structs.ll b/test/Spv1p4/opaque_structs.ll
new file mode 100644
index 0000000..aba9460
--- /dev/null
+++ b/test/Spv1p4/opaque_structs.ll
@@ -0,0 +1,35 @@
+; RUN: clspv-opt -SPIRVProducerPass %s -o %t.ll -producer-out-file %t.spv -spv-version=1.4
+; RUN: spirv-dis %t.spv -o %t.spvasm
+; RUN: FileCheck %s < %t.spvasm
+; RUN: spirv-val --target-env vulkan1.1spv1.4 %t.spv
+
+; CHECK: [[float:%[a-zA-Z0-9_]+]] = OpTypeFloat 32
+; CHECK-NOT: OpTypeImage
+; CHECK: OpTypeImage [[float]] 2D 0 0 0 1 Unknown
+; CHECK-NOT: OpTypeImage
+
+target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
+target triple = "spir-unknown-unknown"
+
+%opencl.image2d_ro_t.float.sampled = type opaque
+
+@__spirv_WorkgroupSize = local_unnamed_addr addrspace(8) global <3 x i32> zeroinitializer
+
+declare <4 x float> @_Z11read_imagef14ocl_image2d_roDv2_i.opencl.image2d_ro_t.float.sampled(%opencl.image2d_ro_t.float.sampled addrspace(1)*, <2 x i32>)
+
+define void @bar(%opencl.image2d_ro_t.float.sampled addrspace(1)* %img) {
+entry:
+  %0 = tail call <4 x float> @_Z11read_imagef14ocl_image2d_roDv2_i.opencl.image2d_ro_t.float.sampled(%opencl.image2d_ro_t.float.sampled addrspace(1)* %img, <2 x i32> zeroinitializer)
+  ret void
+}
+
+define spir_kernel void @foo(%opencl.image2d_ro_t.float.sampled addrspace(1)* %img) !clspv.pod_args_impl !0 {
+entry:
+  %0 = call %opencl.image2d_ro_t.float.sampled addrspace(1)* @_Z14clspv.resource.0(i32 1, i32 0, i32 6, i32 0, i32 0, i32 0)
+  call void @bar(%opencl.image2d_ro_t.float.sampled addrspace(1)* %0)
+  ret void
+}
+
+declare %opencl.image2d_ro_t.float.sampled addrspace(1)* @_Z14clspv.resource.0(i32, i32, i32, i32, i32, i32)
+
+!0 = !{i32 2}