[llvm] 5ac6967 - [SPIR-V] Support TargetExtType for SPIR-V builtin types

Michal Paszkowski via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 27 12:40:13 PST 2023


Author: Michal Paszkowski
Date: 2023-02-27T21:39:25+01:00
New Revision: 5ac69674bf4fbe4adaca4170a2ad60c8a32613ed

URL: https://github.com/llvm/llvm-project/commit/5ac69674bf4fbe4adaca4170a2ad60c8a32613ed
DIFF: https://github.com/llvm/llvm-project/commit/5ac69674bf4fbe4adaca4170a2ad60c8a32613ed.diff

LOG: [SPIR-V] Support TargetExtType for SPIR-V builtin types

This patch adds support for TargetExtType/target(...) representing
SPIR-V builtin types. After D135202, target(...) is the preferred way
for representing SPIR-V builtin types in LLVM IR and the only working
in the opaque pointer mode.

In order to maintain compatibility with LLVM IR generated by older
versions of Clang and LLVM/SPIR-V Translator, pointers-to-opaque-structs
denoting SPIR-V/OpenCL builtin types will be translated to equivalent
SPIR-V target extension types. This translation is only available in the
typed pointer mode (-opaque-pointers=0).

The relevant LIT tests with SPIR-V builtins were converted to use the
new target(...) notation.

Differential Revision: https://reviews.llvm.org/D144494

Added: 
    

Modified: 
    llvm/lib/CodeGen/ValueTypes.cpp
    llvm/lib/IR/Type.cpp
    llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
    llvm/lib/Target/SPIRV/SPIRVBuiltins.h
    llvm/lib/Target/SPIRV/SPIRVBuiltins.td
    llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
    llvm/lib/Target/SPIRV/SPIRVUtils.cpp
    llvm/test/CodeGen/SPIRV/image_store.ll
    llvm/test/CodeGen/SPIRV/spirv.Queue.ll
    llvm/test/CodeGen/SPIRV/transcoding/spirv-types.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/CodeGen/ValueTypes.cpp b/llvm/lib/CodeGen/ValueTypes.cpp
index 99590d99ddb8d..753650dc3eb0c 100644
--- a/llvm/lib/CodeGen/ValueTypes.cpp
+++ b/llvm/lib/CodeGen/ValueTypes.cpp
@@ -590,6 +590,8 @@ MVT MVT::getVT(Type *Ty, bool HandleUnknown){
       getVT(VTy->getElementType(), /*HandleUnknown=*/ false),
             VTy->getElementCount());
   }
+  case Type::TargetExtTyID:
+    return MVT(MVT::Other);
   }
 }
 

diff  --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp
index 3d02ad2bba720..8c77e9862df07 100644
--- a/llvm/lib/IR/Type.cpp
+++ b/llvm/lib/IR/Type.cpp
@@ -862,7 +862,7 @@ struct TargetTypeInfo {
 static TargetTypeInfo getTargetTypeInfo(const TargetExtType *Ty) {
   LLVMContext &C = Ty->getContext();
   StringRef Name = Ty->getName();
-  if (Name.startswith("spirv.")) {
+  if (Name.startswith("spirv.") || Name.startswith("opencl.")) {
     return TargetTypeInfo(Type::getInt8PtrTy(C, 0), TargetExtType::HasZeroInit,
                           TargetExtType::CanBeGlobal);
   }

diff  --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
index d3876f4ba7469..1e0f8ca87a20c 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
@@ -1913,135 +1913,106 @@ std::optional<bool> lowerBuiltin(const StringRef DemangledCall,
   return false;
 }
 
-struct DemangledType {
+struct BuiltinType {
   StringRef Name;
   uint32_t Opcode;
 };
 
-#define GET_DemangledTypes_DECL
-#define GET_DemangledTypes_IMPL
+#define GET_BuiltinTypes_DECL
+#define GET_BuiltinTypes_IMPL
 
-struct ImageType {
+struct OpenCLType {
   StringRef Name;
-  StringRef SampledType;
-  AccessQualifier::AccessQualifier Qualifier;
-  Dim::Dim Dimensionality;
-  bool Arrayed;
-  bool Depth;
-  bool Multisampled;
-  bool Sampled;
-  ImageFormat::ImageFormat Format;
+  StringRef SpirvTypeLiteral;
 };
 
-struct PipeType {
-  StringRef Name;
-  AccessQualifier::AccessQualifier Qualifier;
-};
+#define GET_OpenCLTypes_DECL
+#define GET_OpenCLTypes_IMPL
 
-using namespace AccessQualifier;
-using namespace Dim;
-using namespace ImageFormat;
-#define GET_ImageTypes_DECL
-#define GET_ImageTypes_IMPL
-#define GET_PipeTypes_DECL
-#define GET_PipeTypes_IMPL
 #include "SPIRVGenTables.inc"
 } // namespace SPIRV
 
 //===----------------------------------------------------------------------===//
-// Misc functions for parsing builtin types and looking up implementation
-// details in TableGenerated tables.
+// Misc functions for parsing builtin types.
 //===----------------------------------------------------------------------===//
 
-static const SPIRV::DemangledType *findBuiltinType(StringRef Name) {
-  if (Name.startswith("opencl."))
-    return SPIRV::lookupBuiltinType(Name);
-  if (!Name.startswith("spirv."))
-    return nullptr;
-  // Some SPIR-V builtin types have a complex list of parameters as part of
-  // their name (e.g. spirv.Image._void_1_0_0_0_0_0_0). Those parameters often
-  // are numeric literals which cannot be easily represented by TableGen
-  // records and should be parsed instead.
-  unsigned BaseTypeNameLength =
-      Name.contains('_') ? Name.find('_') - 1 : Name.size();
-  return SPIRV::lookupBuiltinType(Name.substr(0, BaseTypeNameLength).str());
+static Type *parseTypeString(const StringRef Name, LLVMContext &Context) {
+  if (Name.startswith("void"))
+    return Type::getVoidTy(Context);
+  else if (Name.startswith("int") || Name.startswith("uint"))
+    return Type::getInt32Ty(Context);
+  else if (Name.startswith("float"))
+    return Type::getFloatTy(Context);
+  else if (Name.startswith("half"))
+    return Type::getHalfTy(Context);
+  llvm_unreachable("Unable to recognize type!");
 }
 
-static std::unique_ptr<const SPIRV::ImageType>
-lookupOrParseBuiltinImageType(StringRef Name) {
-  if (Name.startswith("opencl.")) {
-    // Lookup OpenCL builtin image type lowering details in TableGen records.
-    const SPIRV::ImageType *Record = SPIRV::lookupImageType(Name);
-    return std::unique_ptr<SPIRV::ImageType>(new SPIRV::ImageType(*Record));
+static const TargetExtType *parseToTargetExtType(const Type *OpaqueType,
+                                                 MachineIRBuilder &MIRBuilder) {
+  assert(isSpecialOpaqueType(OpaqueType) &&
+         "Not a SPIR-V/OpenCL special opaque type!");
+  assert(!OpaqueType->isTargetExtTy() &&
+         "This already is SPIR-V/OpenCL TargetExtType!");
+
+  StringRef NameWithParameters = OpaqueType->getStructName();
+
+  // Pointers-to-opaque-structs representing OpenCL types are first translated
+  // to equivalent SPIR-V types. OpenCL builtin type names should have the
+  // following format: e.g. %opencl.event_t
+  if (NameWithParameters.startswith("opencl.")) {
+    const SPIRV::OpenCLType *OCLTypeRecord =
+        SPIRV::lookupOpenCLType(NameWithParameters);
+    if (!OCLTypeRecord)
+      report_fatal_error("Missing TableGen record for OpenCL type: " +
+                         NameWithParameters);
+    NameWithParameters = OCLTypeRecord->SpirvTypeLiteral;
+    // Continue with the SPIR-V builtin type...
   }
-  if (!Name.startswith("spirv."))
-    llvm_unreachable("Unknown builtin image type name/literal");
-  // Parse the literals of SPIR-V image builtin parameters. The name should
-  // have the following format:
-  // spirv.Image._Type_Dim_Depth_Arrayed_MS_Sampled_ImageFormat_AccessQualifier
-  // e.g. %spirv.Image._void_1_0_0_0_0_0_0
-  StringRef TypeParametersString = Name.substr(strlen("spirv.Image."));
-  SmallVector<StringRef> TypeParameters;
-  SplitString(TypeParametersString, TypeParameters, "_");
-  assert(TypeParameters.size() == 8 &&
-         "Wrong number of literals in SPIR-V builtin image type");
-
-  StringRef SampledType = TypeParameters[0];
-  unsigned Dim, Depth, Arrayed, Multisampled, Sampled, Format, AccessQual;
-  bool AreParameterLiteralsValid =
-      !(TypeParameters[1].getAsInteger(10, Dim) ||
-        TypeParameters[2].getAsInteger(10, Depth) ||
-        TypeParameters[3].getAsInteger(10, Arrayed) ||
-        TypeParameters[4].getAsInteger(10, Multisampled) ||
-        TypeParameters[5].getAsInteger(10, Sampled) ||
-        TypeParameters[6].getAsInteger(10, Format) ||
-        TypeParameters[7].getAsInteger(10, AccessQual));
-  assert(AreParameterLiteralsValid &&
-         "Invalid format of SPIR-V image type parameter literals.");
-
-  return std::unique_ptr<SPIRV::ImageType>(new SPIRV::ImageType{
-      Name, SampledType, SPIRV::AccessQualifier::AccessQualifier(AccessQual),
-      SPIRV::Dim::Dim(Dim), static_cast<bool>(Arrayed),
-      static_cast<bool>(Depth), static_cast<bool>(Multisampled),
-      static_cast<bool>(Sampled), SPIRV::ImageFormat::ImageFormat(Format)});
-}
 
-static std::unique_ptr<const SPIRV::PipeType>
-lookupOrParseBuiltinPipeType(StringRef Name) {
-  if (Name.startswith("opencl.")) {
-    // Lookup OpenCL builtin pipe type lowering details in TableGen records.
-    const SPIRV::PipeType *Record = SPIRV::lookupPipeType(Name);
-    return std::unique_ptr<SPIRV::PipeType>(new SPIRV::PipeType(*Record));
+  // Names of the opaque structs representing a SPIR-V builtins without
+  // parameters should have the following format: e.g. %spirv.Event
+  assert(NameWithParameters.startswith("spirv.") &&
+         "Unknown builtin opaque type!");
+
+  // Parametrized SPIR-V builtins names follow this format:
+  // e.g. %spirv.Image._void_1_0_0_0_0_0_0, %spirv.Pipe._0
+  if (NameWithParameters.find('_') == std::string::npos)
+    return TargetExtType::get(OpaqueType->getContext(), NameWithParameters);
+
+  SmallVector<StringRef> Parameters;
+  unsigned BaseNameLength = NameWithParameters.find('_') - 1;
+  SplitString(NameWithParameters.substr(BaseNameLength + 1), Parameters, "_");
+
+  SmallVector<Type *, 1> TypeParameters;
+  bool HasTypeParamter = !isDigit(Parameters[0][0]);
+  if (HasTypeParamter)
+    TypeParameters.push_back(parseTypeString(
+        Parameters[0], MIRBuilder.getMF().getFunction().getContext()));
+  SmallVector<unsigned> IntParameters;
+  for (unsigned i = HasTypeParamter ? 1 : 0; i < Parameters.size(); i++) {
+    unsigned IntParameter = 0;
+    bool ValidLiteral = !Parameters[i].getAsInteger(10, IntParameter);
+    assert(ValidLiteral &&
+           "Invalid format of SPIR-V builtin parameter literal!");
+    IntParameters.push_back(IntParameter);
   }
-  if (!Name.startswith("spirv."))
-    llvm_unreachable("Unknown builtin pipe type name/literal");
-  // Parse the access qualifier literal in the name of the SPIR-V pipe type.
-  // The name should have the following format:
-  // spirv.Pipe._AccessQualifier
-  // e.g. %spirv.Pipe._1
-  if (Name.endswith("_0"))
-    return std::unique_ptr<SPIRV::PipeType>(
-        new SPIRV::PipeType{Name, SPIRV::AccessQualifier::ReadOnly});
-  if (Name.endswith("_1"))
-    return std::unique_ptr<SPIRV::PipeType>(
-        new SPIRV::PipeType{Name, SPIRV::AccessQualifier::WriteOnly});
-  if (Name.endswith("_2"))
-    return std::unique_ptr<SPIRV::PipeType>(
-        new SPIRV::PipeType{Name, SPIRV::AccessQualifier::ReadWrite});
-  llvm_unreachable("Unknown pipe type access qualifier literal");
+  return TargetExtType::get(OpaqueType->getContext(),
+                            NameWithParameters.substr(0, BaseNameLength),
+                            TypeParameters, IntParameters);
 }
 
 //===----------------------------------------------------------------------===//
 // Implementation functions for builtin types.
 //===----------------------------------------------------------------------===//
 
-static SPIRVType *getNonParametrizedType(const StructType *OpaqueType,
-                                         const SPIRV::DemangledType *TypeRecord,
+static SPIRVType *getNonParametrizedType(const TargetExtType *ExtensionType,
+                                         const SPIRV::BuiltinType *TypeRecord,
                                          MachineIRBuilder &MIRBuilder,
                                          SPIRVGlobalRegistry *GR) {
   unsigned Opcode = TypeRecord->Opcode;
   // Create or get an existing type from GlobalRegistry.
-  return GR->getOrCreateOpTypeByOpcode(OpaqueType, MIRBuilder, Opcode);
+  return GR->getOrCreateOpTypeByOpcode(ExtensionType, MIRBuilder, Opcode);
 }
 
 static SPIRVType *getSamplerType(MachineIRBuilder &MIRBuilder,
@@ -2050,78 +2021,87 @@ static SPIRVType *getSamplerType(MachineIRBuilder &MIRBuilder,
   return GR->getOrCreateOpTypeSampler(MIRBuilder);
 }
 
-static SPIRVType *getPipeType(const StructType *OpaqueType,
+static SPIRVType *getPipeType(const TargetExtType *ExtensionType,
                               MachineIRBuilder &MIRBuilder,
                               SPIRVGlobalRegistry *GR) {
-  // Lookup pipe type lowering details in TableGen records or parse the
-  // name/literal for details.
-  std::unique_ptr<const SPIRV::PipeType> Record =
-      lookupOrParseBuiltinPipeType(OpaqueType->getName());
+  assert(ExtensionType->getNumIntParameters() == 1 &&
+         "Invalid number of parameters for SPIR-V pipe builtin!");
   // Create or get an existing type from GlobalRegistry.
-  return GR->getOrCreateOpTypePipe(MIRBuilder, Record.get()->Qualifier);
+  return GR->getOrCreateOpTypePipe(MIRBuilder,
+                                   SPIRV::AccessQualifier::AccessQualifier(
+                                       ExtensionType->getIntParameter(0)));
 }
 
 static SPIRVType *
-getImageType(const StructType *OpaqueType,
-             SPIRV::AccessQualifier::AccessQualifier AccessQual,
+getImageType(const TargetExtType *ExtensionType,
+             const SPIRV::AccessQualifier::AccessQualifier Qualifier,
              MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR) {
-  // Lookup image type lowering details in TableGen records or parse the
-  // name/literal for details.
-  std::unique_ptr<const SPIRV::ImageType> Record =
-      lookupOrParseBuiltinImageType(OpaqueType->getName());
-
-  SPIRVType *SampledType =
-      GR->getOrCreateSPIRVTypeByName(Record.get()->SampledType, MIRBuilder);
+  assert(ExtensionType->getNumTypeParameters() == 1 &&
+         "SPIR-V image builtin type must have sampled type parameter!");
+  const SPIRVType *SampledType =
+      GR->getOrCreateSPIRVType(ExtensionType->getTypeParameter(0), MIRBuilder);
+  assert(ExtensionType->getNumIntParameters() == 7 &&
+         "Invalid number of parameters for SPIR-V image builtin!");
+  // Create or get an existing type from GlobalRegistry.
   return GR->getOrCreateOpTypeImage(
-      MIRBuilder, SampledType, Record.get()->Dimensionality,
-      Record.get()->Depth, Record.get()->Arrayed, Record.get()->Multisampled,
-      Record.get()->Sampled, Record.get()->Format,
-      AccessQual == SPIRV::AccessQualifier::WriteOnly
+      MIRBuilder, SampledType,
+      SPIRV::Dim::Dim(ExtensionType->getIntParameter(0)),
+      ExtensionType->getIntParameter(1), ExtensionType->getIntParameter(2),
+      ExtensionType->getIntParameter(3), ExtensionType->getIntParameter(4),
+      SPIRV::ImageFormat::ImageFormat(ExtensionType->getIntParameter(5)),
+      Qualifier == SPIRV::AccessQualifier::WriteOnly
           ? SPIRV::AccessQualifier::WriteOnly
-          : Record.get()->Qualifier);
+          : SPIRV::AccessQualifier::AccessQualifier(
+                ExtensionType->getIntParameter(6)));
 }
 
-static SPIRVType *getSampledImageType(const StructType *OpaqueType,
+static SPIRVType *getSampledImageType(const TargetExtType *OpaqueType,
                                       MachineIRBuilder &MIRBuilder,
                                       SPIRVGlobalRegistry *GR) {
-  StringRef TypeParametersString =
-      OpaqueType->getName().substr(strlen("spirv.SampledImage."));
-  LLVMContext &Context = MIRBuilder.getMF().getFunction().getContext();
-  Type *ImageOpaqueType = StructType::getTypeByName(
-      Context, "spirv.Image." + TypeParametersString.str());
-  SPIRVType *TargetImageType =
-      GR->getOrCreateSPIRVType(ImageOpaqueType, MIRBuilder);
-  return GR->getOrCreateOpTypeSampledImage(TargetImageType, MIRBuilder);
+  SPIRVType *OpaqueImageType = getImageType(
+      OpaqueType, SPIRV::AccessQualifier::ReadOnly, MIRBuilder, GR);
+  // Create or get an existing type from GlobalRegistry.
+  return GR->getOrCreateOpTypeSampledImage(OpaqueImageType, MIRBuilder);
 }
 
 namespace SPIRV {
-SPIRVType *lowerBuiltinType(const StructType *OpaqueType,
+SPIRVType *lowerBuiltinType(const Type *OpaqueType,
                             SPIRV::AccessQualifier::AccessQualifier AccessQual,
                             MachineIRBuilder &MIRBuilder,
                             SPIRVGlobalRegistry *GR) {
-  assert(OpaqueType->hasName() &&
-         "Structs representing builtin types must have a parsable name");
+  // In LLVM IR, SPIR-V and OpenCL builtin types are represented as either
+  // target(...) target extension types or pointers-to-opaque-structs. The
+  // approach relying on structs is deprecated and works only in the non-opaque
+  // pointer mode (-opaque-pointers=0).
+  // In order to maintain compatibility with LLVM IR generated by older versions
+  // of Clang and LLVM/SPIR-V Translator, the pointers-to-opaque-structs are
+  // "translated" to target extension types. This translation is temporary and
+  // will be removed in the future release of LLVM.
+  const TargetExtType *BuiltinType = dyn_cast<TargetExtType>(OpaqueType);
+  if (!BuiltinType)
+    BuiltinType = parseToTargetExtType(OpaqueType, MIRBuilder);
+
   unsigned NumStartingVRegs = MIRBuilder.getMRI()->getNumVirtRegs();
 
-  const StringRef Name = OpaqueType->getName();
+  const StringRef Name = BuiltinType->getName();
   LLVM_DEBUG(dbgs() << "Lowering builtin type: " << Name << "\n");
 
   // Lookup the demangled builtin type in the TableGen records.
-  const SPIRV::DemangledType *TypeRecord = findBuiltinType(Name);
+  const SPIRV::BuiltinType *TypeRecord = SPIRV::lookupBuiltinType(Name);
   if (!TypeRecord)
     report_fatal_error("Missing TableGen record for builtin type: " + Name);
 
   // "Lower" the BuiltinType into TargetType. The following get<...>Type methods
-  // use the implementation details from TableGen records to either create a new
-  // OpType<...> machine instruction or get an existing equivalent SPIRVType
-  // from GlobalRegistry.
+  // use the implementation details from TableGen records or TargetExtType
+  // parameters to either create a new OpType<...> machine instruction or get an
+  // existing equivalent SPIRVType from GlobalRegistry.
   SPIRVType *TargetType;
   switch (TypeRecord->Opcode) {
   case SPIRV::OpTypeImage:
-    TargetType = getImageType(OpaqueType, AccessQual, MIRBuilder, GR);
+    TargetType = getImageType(BuiltinType, AccessQual, MIRBuilder, GR);
     break;
   case SPIRV::OpTypePipe:
-    TargetType = getPipeType(OpaqueType, MIRBuilder, GR);
+    TargetType = getPipeType(BuiltinType, MIRBuilder, GR);
     break;
   case SPIRV::OpTypeDeviceEvent:
     TargetType = GR->getOrCreateOpTypeDeviceEvent(MIRBuilder);
@@ -2130,18 +2110,18 @@ SPIRVType *lowerBuiltinType(const StructType *OpaqueType,
     TargetType = getSamplerType(MIRBuilder, GR);
     break;
   case SPIRV::OpTypeSampledImage:
-    TargetType = getSampledImageType(OpaqueType, MIRBuilder, GR);
+    TargetType = getSampledImageType(BuiltinType, MIRBuilder, GR);
     break;
   default:
-    TargetType = getNonParametrizedType(OpaqueType, TypeRecord, MIRBuilder, GR);
+    TargetType =
+        getNonParametrizedType(BuiltinType, TypeRecord, MIRBuilder, GR);
     break;
   }
 
   // Emit OpName instruction if a new OpType<...> instruction was added
   // (equivalent type was not found in GlobalRegistry).
   if (NumStartingVRegs < MIRBuilder.getMRI()->getNumVirtRegs())
-    buildOpName(GR->getSPIRVTypeID(TargetType), OpaqueType->getName(),
-                MIRBuilder);
+    buildOpName(GR->getSPIRVTypeID(TargetType), Name, MIRBuilder);
 
   return TargetType;
 }

diff  --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.h b/llvm/lib/Target/SPIRV/SPIRVBuiltins.h
index 26d2e8ab0fd6b..7ee5c49dc5b32 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.h
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.h
@@ -45,7 +45,7 @@ std::optional<bool> lowerBuiltin(const StringRef DemangledCall,
 /// \return A machine instruction representing the OpType<...> SPIR-V type.
 ///
 /// \p Type is the special opaque/builtin type to be lowered.
-SPIRVType *lowerBuiltinType(const StructType *Type,
+SPIRVType *lowerBuiltinType(const Type *Type,
                             AccessQualifier::AccessQualifier AccessQual,
                             MachineIRBuilder &MIRBuilder,
                             SPIRVGlobalRegistry *GR);

diff  --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.td b/llvm/lib/Target/SPIRV/SPIRVBuiltins.td
index 635c6451ea04a..8acd4691787e4 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.td
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.td
@@ -1101,141 +1101,105 @@ foreach i = ["", "2", "3", "4", "8", "16"] in {
 }
 
 //===----------------------------------------------------------------------===//
-// Class defining implementation details of demangled builtin types. The info
+// Class defining implementation details of SPIR-V builtin types. The info
 // in the record is used for lowering into OpType.
 //
-// name is the demangled name of the given builtin.
+// name is the name of the given SPIR-V builtin type.
 // operation specifies the SPIR-V opcode the StructType should be lowered to.
 //===----------------------------------------------------------------------===//
-class DemangledType<string name, Op operation> {
+class BuiltinType<string name, Op operation> {
   string Name = name;
   Op Opcode = operation;
 }
 
-// Table gathering all the demangled type records.
-def DemangledTypes : GenericTable {
-  let FilterClass = "DemangledType";
+// Table gathering all the builtin type records.
+def BuiltinTypes : GenericTable {
+  let FilterClass = "BuiltinType";
   let Fields = ["Name", "Opcode"];
 }
 
 // Function to lookup builtin types by their demangled name.
 def lookupBuiltinType : SearchIndex {
-  let Table = DemangledTypes;
+  let Table = BuiltinTypes;
   let Key = ["Name"];
 }
 
-def : DemangledType<"opencl.reserve_id_t", OpTypeReserveId>;
-def : DemangledType<"opencl.event_t", OpTypeEvent>;
-def : DemangledType<"opencl.queue_t", OpTypeQueue>;
-def : DemangledType<"opencl.sampler_t", OpTypeSampler>;
-def : DemangledType<"opencl.clk_event_t", OpTypeDeviceEvent>;
-
-def : DemangledType<"spirv.ReserveId", OpTypeReserveId>;
-def : DemangledType<"spirv.PipeStorage", OpTypePipeStorage>;
-def : DemangledType<"spirv.Queue", OpTypeQueue>;
-def : DemangledType<"spirv.Event", OpTypeEvent>;
-def : DemangledType<"spirv.Sampler", OpTypeSampler>;
-def : DemangledType<"spirv.DeviceEvent", OpTypeDeviceEvent>;
-
-// Some SPIR-V builtin types (e.g. spirv.Image) have a complex list of
-// parameters as part of their name. Some of those parameters should be treated
-// as numeric literals and therefore they cannot be represented in TableGen and
-// should be parsed instead.
-def : DemangledType<"spirv.Image", OpTypeImage>;
-def : DemangledType<"spirv.SampledImage", OpTypeSampledImage>;
-def : DemangledType<"spirv.Pipe", OpTypePipe>;
-
-// Class definining lowering details for various variants of image type indentifiers.
-class ImageType<string name> {
+def : BuiltinType<"spirv.ReserveId", OpTypeReserveId>;
+def : BuiltinType<"spirv.PipeStorage", OpTypePipeStorage>;
+def : BuiltinType<"spirv.Queue", OpTypeQueue>;
+def : BuiltinType<"spirv.Event", OpTypeEvent>;
+def : BuiltinType<"spirv.Sampler", OpTypeSampler>;
+def : BuiltinType<"spirv.DeviceEvent", OpTypeDeviceEvent>;
+def : BuiltinType<"spirv.Image", OpTypeImage>;
+def : BuiltinType<"spirv.SampledImage", OpTypeSampledImage>;
+def : BuiltinType<"spirv.Pipe", OpTypePipe>;
+
+
+//===----------------------------------------------------------------------===//
+// Class matching an OpenCL builtin type name to an equivalent SPIR-V
+// builtin type literal.
+//
+// name is the name of the given OpenCL builtin type.
+// spirvTypeLiteral is the literal of an equivalent SPIR-V builtin type.
+//===----------------------------------------------------------------------===//
+class OpenCLType<string name, string spirvTypeLiteral> {
   string Name = name;
-  string Type = "void";
-  AccessQualifier Qualifier = !cond(!not(!eq(!find(name, "_ro_t"), -1)) : ReadOnly,
-                                  !not(!eq(!find(name, "_wo_t"), -1)) : WriteOnly,
-                                  !not(!eq(!find(name, "_rw_t"), -1)) : ReadWrite,
-                                  true : ReadOnly);
-  Dim Dimensionality = !cond(!not(!eq(!find(name, "buffer"), -1)) : DIM_Buffer,
-                                  !not(!eq(!find(name, "image1"), -1)) : DIM_1D,
-                                  !not(!eq(!find(name, "image2"), -1)) : DIM_2D,
-                                  !not(!eq(!find(name, "image3"), -1)) : DIM_3D);
-  bit Arrayed = !not(!eq(!find(name, "array"), -1));
-  bit Depth = !not(!eq(!find(name, "depth"), -1));
-  bit Multisampled = false;
-  bit Sampled = false;
-  ImageFormat Format = Unknown;
+  string SpirvTypeLiteral = spirvTypeLiteral;
 }
 
-// Table gathering all the image type records.
-def ImageTypes : GenericTable {
-  let FilterClass = "ImageType";
-  let Fields = ["Name", "Type", "Qualifier", "Dimensionality", "Arrayed",
-                "Depth", "Multisampled", "Sampled", "Format"];
-  string TypeOf_Qualifier = "AccessQualifier";
-  string TypeOf_Dimensionality = "Dim";
-  string TypeOf_Format = "ImageFormat";
+// Table gathering all the OpenCL type records.
+def OpenCLTypes : GenericTable {
+  let FilterClass = "OpenCLType";
+  let Fields = ["Name", "SpirvTypeLiteral"];
 }
 
-// Function to lookup builtin image types by their demangled name.
-def lookupImageType : SearchIndex {
-  let Table = ImageTypes;
+// Function to lookup OpenCL types by their name.
+def lookupOpenCLType : SearchIndex {
+  let Table = OpenCLTypes;
   let Key = ["Name"];
 }
 
-// Multiclass used to define at the same time a DemangledType record used
-// for matching an incoming demangled string to the OpTypeImage opcode and
-// ImageType conatining the lowering details.
-multiclass DemangledImageType<string name> {
-  def : DemangledType<name, OpTypeImage>;
-  def : ImageType<name>;
+def : OpenCLType<"opencl.reserve_id_t", "spirv.ReserveId">;
+def : OpenCLType<"opencl.event_t", "spirv.Event">;
+def : OpenCLType<"opencl.queue_t", "spirv.Queue">;
+def : OpenCLType<"opencl.sampler_t", "spirv.Sampler">;
+def : OpenCLType<"opencl.clk_event_t", "spirv.DeviceEvent">;
+
+foreach aq = ["_t", "_ro_t", "_wo_t", "_rw_t"] in {
+  defvar p = !cond(!not(!eq(!find(aq, "_rw_t"), -1)) : "2",
+                   !not(!eq(!find(aq, "_wo_t"), -1)) : "1",
+                                                true : "0");
+  def : OpenCLType<!strconcat("opencl.pipe", aq), 
+                   !strconcat("spirv.Pipe._", p)>;
 }
 
 foreach aq = ["_t", "_ro_t", "_wo_t", "_rw_t"] in {
-  defm : DemangledImageType<!strconcat("opencl.image1d", aq)>;
-  defm : DemangledImageType<!strconcat("opencl.image1d_array", aq)>;
-  defm : DemangledImageType<!strconcat("opencl.image1d_buffer", aq)>;
+  defvar p7 = !cond(!not(!eq(!find(aq, "_rw_t"), -1)) : "2",
+                    !not(!eq(!find(aq, "_wo_t"), -1)) : "1",
+                                                 true : "0");
+
+  def : OpenCLType<!strconcat("opencl.image1d", aq), 
+                   !strconcat("spirv.Image._void_0_0_0_0_0_0_", p7)>;
+  def : OpenCLType<!strconcat("opencl.image1d_array", aq), 
+                   !strconcat("spirv.Image._void_0_0_1_0_0_0_", p7)>;
+  def : OpenCLType<!strconcat("opencl.image1d_buffer", aq), 
+                   !strconcat("spirv.Image._void_5_0_0_0_0_0_", p7)>;
 
   foreach a1 = ["", "_array"] in {
     foreach a2 = ["", "_msaa"] in {
       foreach a3 = ["", "_depth"] in {
-        defm : DemangledImageType<!strconcat("opencl.image2d", a1, a2, a3, aq)>;
+        defvar p2 = !cond(!not(!eq(!find(a3, "_depth"), -1)) : "1", true : "0");
+        defvar p3 = !cond(!not(!eq(!find(a1, "_array"), -1))  : "1", true : "0");
+        defvar p4 = !cond(!not(!eq(!find(a2, "msaa"), -1))  : "1", true : "0");
+
+        def : OpenCLType<!strconcat("opencl.image2d", a1, a2, a3, aq), 
+                         !strconcat("spirv.Image._void_1_", p2 , "_", p3, "_", p4, "_0_0_", p7)>;
       }
     }
   }
-
-  defm : DemangledImageType<!strconcat("opencl.image3d", aq)>;
-}
-
-// Class definining lowering details for various variants of pipe type indentifiers.
-class PipeType<string name> {
-  string Name = name;
-  AccessQualifier Qualifier = !cond(!not(!eq(!find(name, "_ro_t"), -1)) : ReadOnly,
-                                  !not(!eq(!find(name, "_wo_t"), -1)) : WriteOnly,
-                                  !not(!eq(!find(name, "_rw_t"), -1)) : ReadWrite,
-                                  true : ReadOnly);
-}
-
-// Table gathering all the pipe type records.
-def PipeTypes : GenericTable {
-  let FilterClass = "PipeType";
-  let Fields = ["Name", "Qualifier"];
-  string TypeOf_Qualifier = "AccessQualifier";
-}
-
-// Function to lookup builtin pipe types by their demangled name.
-def lookupPipeType : SearchIndex {
-  let Table = PipeTypes;
-  let Key = ["Name"];
-}
-
-// Multiclass used to define at the same time a DemangledType record used
-// for matching an incoming demangled string to the OpTypePipe opcode and
-// PipeType conatining the lowering details.
-multiclass DemangledPipeType<string name> {
-  def : DemangledType<name, OpTypePipe>;
-  def : PipeType<name>;
-}
-
-foreach aq = ["_t", "_ro_t", "_wo_t", "_rw_t"] in {
-  defm : DemangledPipeType<!strconcat("opencl.pipe", aq)>;
+  
+  def : OpenCLType<!strconcat("opencl.image3d", aq), 
+                   !strconcat("spirv.Image._void_2_0_0_0_0_0_", p7)>;
 }
 
 //===----------------------------------------------------------------------===//

diff  --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index 0f85c4839e107..7da239cd31ff7 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -573,9 +573,8 @@ SPIRVType *SPIRVGlobalRegistry::getOrCreateSpecialType(
     assert(!PType->isOpaque());
     Ty = PType->getNonOpaquePointerElementType();
   }
-  auto SType = cast<StructType>(Ty);
-  assert(isSpecialOpaqueType(SType) && "Not a special opaque builtin type");
-  return SPIRV::lowerBuiltinType(SType, AccQual, MIRBuilder, this);
+  assert(isSpecialOpaqueType(Ty) && "Not a special opaque builtin type");
+  return SPIRV::lowerBuiltinType(Ty, AccQual, MIRBuilder, this);
 }
 
 SPIRVType *SPIRVGlobalRegistry::getOpTypePointer(

diff  --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index df1817f91cf87..b6353ec2fb6b4 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -332,16 +332,6 @@ std::string getOclOrSpirvBuiltinDemangledName(StringRef Name) {
   return Name.substr(Start, Len).str();
 }
 
-static bool isOpenCLBuiltinType(const StructType *SType) {
-  return SType->isOpaque() && SType->hasName() &&
-         SType->getName().startswith("opencl.");
-}
-
-static bool isSPIRVBuiltinType(const StructType *SType) {
-  return SType->isOpaque() && SType->hasName() &&
-         SType->getName().startswith("spirv.");
-}
-
 const Type *getTypedPtrEltType(const Type *Ty) {
   auto PType = dyn_cast<PointerType>(Ty);
   if (!PType || PType->isOpaque())
@@ -349,9 +339,21 @@ const Type *getTypedPtrEltType(const Type *Ty) {
   return PType->getNonOpaquePointerElementType();
 }
 
+static bool hasBuiltinTypePrefix(StringRef Name) {
+  if (Name.starts_with("opencl.") || Name.starts_with("spirv."))
+    return true;
+  return false;
+}
+
 bool isSpecialOpaqueType(const Type *Ty) {
-  if (auto SType = dyn_cast<StructType>(getTypedPtrEltType(Ty)))
-    return isOpenCLBuiltinType(SType) || isSPIRVBuiltinType(SType);
+  const StructType *SType = dyn_cast<StructType>(getTypedPtrEltType(Ty));
+  if (SType && SType->hasName())
+    return hasBuiltinTypePrefix(SType->getName());
+
+  if (const TargetExtType *EType =
+          dyn_cast<TargetExtType>(getTypedPtrEltType(Ty)))
+    return hasBuiltinTypePrefix(EType->getName());
+
   return false;
 }
 } // namespace llvm

diff  --git a/llvm/test/CodeGen/SPIRV/image_store.ll b/llvm/test/CodeGen/SPIRV/image_store.ll
index e66d1821142b3..3542cc2e8e9b3 100644
--- a/llvm/test/CodeGen/SPIRV/image_store.ll
+++ b/llvm/test/CodeGen/SPIRV/image_store.ll
@@ -1,8 +1,8 @@
 ; RUN: llc -O0 -opaque-pointers=0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
 
 ;; Image types may be represented in two ways while translating to SPIR-V:
-;; - OpenCL form, for example, '%opencl.image2d_ro_t',
-;; - SPIR-V form, for example, '%spirv.Image._void_1_0_0_0_0_0_0',
+;; - OpenCL form based on pointers-to-opaque-structs, e.g. '%opencl.image2d_ro_t',
+;; - SPIR-V form based on TargetExtType, e.g. 'target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 0)',
 ;; but it is still one type which should be translated to one SPIR-V type.
 ;;
 ;; The test checks that the code below is successfully translated and only one
@@ -12,12 +12,11 @@
 ; CHECK-NOT: OpTypeImage
 
 %opencl.image2d_ro_t = type opaque
-%spirv.Image._void_1_0_0_0_0_0_0 = type opaque
 
 define spir_kernel void @read_image(%opencl.image2d_ro_t addrspace(1)* %srcimg) {
 entry:
   %srcimg.addr = alloca %opencl.image2d_ro_t addrspace(1)*, align 8
-  %spirvimg.addr = alloca %spirv.Image._void_1_0_0_0_0_0_0 addrspace(1)*, align 8
+  %spirvimg.addr = alloca target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 0), align 8
   store %opencl.image2d_ro_t addrspace(1)* %srcimg, %opencl.image2d_ro_t addrspace(1)** %srcimg.addr, align 8
   ret void
 }

diff  --git a/llvm/test/CodeGen/SPIRV/spirv.Queue.ll b/llvm/test/CodeGen/SPIRV/spirv.Queue.ll
index 6c0e11998f6f5..d8175a6dda8c0 100644
--- a/llvm/test/CodeGen/SPIRV/spirv.Queue.ll
+++ b/llvm/test/CodeGen/SPIRV/spirv.Queue.ll
@@ -1,11 +1,9 @@
-; RUN: llc -O0 -opaque-pointers=0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
 
 ; CHECK-SPIRV: OpCapability DeviceEnqueue
 ; CHECK-SPIRV: OpTypeQueue
 
-%spirv.Queue = type opaque
-
-define spir_func void @enqueue_simple_block(%spirv.Queue* addrspace(3)* nocapture %q) {
+define spir_func void @enqueue_simple_block(target("spirv.Queue") %q) {
 entry:
   ret void
 }

diff  --git a/llvm/test/CodeGen/SPIRV/transcoding/spirv-types.ll b/llvm/test/CodeGen/SPIRV/transcoding/spirv-types.ll
index 25ecb4f6d94f1..f8db0ba2c1cd4 100644
--- a/llvm/test/CodeGen/SPIRV/transcoding/spirv-types.ll
+++ b/llvm/test/CodeGen/SPIRV/transcoding/spirv-types.ll
@@ -1,6 +1,6 @@
 ;; Test SPIR-V opaque types
 
-; RUN: llc -O0 -opaque-pointers=0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
 
 ; CHECK-SPIRV-DAG: OpCapability Float16
 ; CHECK-SPIRV-DAG: OpCapability ImageReadWrite
@@ -28,23 +28,6 @@
 ; CHECK-SPIRV-DAG: %[[#SAMP:]] = OpTypeSampler
 ; CHECK-SPIRV-DAG: %[[#SAMPIMG:]] = OpTypeSampledImage %[[#IMG2DD_RD]]
 
-%spirv.Pipe._0 = type opaque ; read_only pipe
-%spirv.Pipe._1 = type opaque ; write_only pipe
-%spirv.Image._void_0_0_0_0_0_0_0 = type opaque ; read_only image1d_ro_t
-%spirv.Image._int_1_0_0_0_0_0_0 = type opaque ; read_only image2d_ro_t
-%spirv.Image._uint_2_0_0_0_0_0_0 = type opaque ; read_only image3d_ro_t
-%spirv.Image._float_1_1_0_0_0_0_0 = type opaque; read_only image2d_depth_ro_t
-%spirv.Image._half_1_0_1_0_0_0_0 = type opaque ; read_only image2d_array_ro_t
-%spirv.Image._float_5_0_0_0_0_0_0 = type opaque ; read_only image1d_buffer_ro_t
-%spirv.Image._void_0_0_0_0_0_0_1 = type opaque ; write_only image1d_wo_t
-%spirv.Image._void_1_0_0_0_0_0_2 = type opaque ; read_write image2d_rw_t
-%spirv.DeviceEvent          = type opaque ; clk_event_t
-%spirv.Event                = type opaque ; event_t
-%spirv.Queue                = type opaque ; queue_t
-%spirv.ReserveId            = type opaque ; reserve_id_t
-%spirv.Sampler              = type opaque ; sampler_t
-%spirv.SampledImage._float_1_1_0_0_0_0_0 = type opaque
-
 ; CHECK-SPIRV: OpFunction
 ; CHECK-SPIRV: %[[#]] = OpFunctionParameter %[[#PIPE_RD]]
 ; CHECK-SPIRV: %[[#]] = OpFunctionParameter %[[#PIPE_WR]]
@@ -57,15 +40,15 @@
 ; CHECK-SPIRV: %[[#]] = OpFunctionParameter %[[#IMG2D_RW]]
 
 define spir_kernel void @foo(
-  %spirv.Pipe._0 addrspace(1)* nocapture %a,
-  %spirv.Pipe._1 addrspace(1)* nocapture %b,
-  %spirv.Image._void_0_0_0_0_0_0_0 addrspace(1)* nocapture %c1,
-  %spirv.Image._int_1_0_0_0_0_0_0 addrspace(1)* nocapture %d1,
-  %spirv.Image._uint_2_0_0_0_0_0_0 addrspace(1)* nocapture %e1,
-  %spirv.Image._half_1_0_1_0_0_0_0 addrspace(1)* nocapture %f1,
-  %spirv.Image._float_5_0_0_0_0_0_0 addrspace(1)* nocapture %g1,
-  %spirv.Image._void_0_0_0_0_0_0_1 addrspace(1)* nocapture %c2,
-  %spirv.Image._void_1_0_0_0_0_0_2 addrspace(1)* nocapture %d3) {
+  target("spirv.Pipe", 0) %a,
+  target("spirv.Pipe", 1) %b,
+  target("spirv.Image", void, 0, 0, 0, 0, 0, 0, 0) %c1,
+  target("spirv.Image", i32, 1, 0, 0, 0, 0, 0, 0) %d1,
+  target("spirv.Image", i32, 2, 0, 0, 0, 0, 0, 0) %e1,
+  target("spirv.Image", half, 1, 0, 1, 0, 0, 0, 0) %f1,
+  target("spirv.Image", float, 5, 0, 0, 0, 0, 0, 0) %g1,
+  target("spirv.Image", void, 0, 0, 0, 0, 0, 0, 1) %c2,
+  target("spirv.Image", void, 1, 0, 0, 0, 0, 0, 2) %d3) {
 entry:
   ret void
 }
@@ -77,10 +60,10 @@ entry:
 ; CHECK-SPIRV: %[[#]] = OpFunctionParameter %[[#RESID]]
 
 define spir_func void @bar(
-  %spirv.DeviceEvent * %a,
-  %spirv.Event * %b,
-  %spirv.Queue * %c,
-  %spirv.ReserveId * %d) {
+  target("spirv.DeviceEvent") %a,
+  target("spirv.Event") %b,
+  target("spirv.Queue") %c,
+  target("spirv.ReserveId") %d) {
   ret void
 }
 
@@ -90,13 +73,13 @@ define spir_func void @bar(
 ; CHECK-SPIRV: %[[#SAMPIMG_VAR:]] = OpSampledImage %[[#SAMPIMG]] %[[#IMG_ARG]] %[[#SAMP_ARG]]
 ; CHECK-SPIRV: %[[#]] = OpImageSampleExplicitLod %[[#]] %[[#SAMPIMG_VAR]]
 
-define spir_func void @test_sampler(%spirv.Image._float_1_1_0_0_0_0_0 addrspace(1)* %srcimg.coerce,
-                                    %spirv.Sampler addrspace(1)* %s.coerce) {
-  %1 = tail call spir_func %spirv.SampledImage._float_1_1_0_0_0_0_0 addrspace(1)* @_Z20__spirv_SampledImagePU3AS1K34__spirv_Image__float_1_1_0_0_0_0_0PU3AS1K15__spirv_Sampler(%spirv.Image._float_1_1_0_0_0_0_0 addrspace(1)* %srcimg.coerce, %spirv.Sampler addrspace(1)* %s.coerce)
-  %2 = tail call spir_func <4 x float> @_Z38__spirv_ImageSampleExplicitLod_Rfloat4PU3AS120__spirv_SampledImageDv4_iif(%spirv.SampledImage._float_1_1_0_0_0_0_0 addrspace(1)* %1, <4 x i32> zeroinitializer, i32 2, float 1.000000e+00)
+define spir_func void @test_sampler(target("spirv.Image", float, 1, 1, 0, 0, 0, 0, 0) %srcimg.coerce,
+                                    target("spirv.Sampler") %s.coerce) {
+  %1 = tail call spir_func target("spirv.Image", float, 1, 1, 0, 0, 0, 0, 0) @_Z20__spirv_SampledImagePU3AS1K34__spirv_Image__float_1_1_0_0_0_0_0PU3AS1K15__spirv_Sampler(target("spirv.Image", float, 1, 1, 0, 0, 0, 0, 0) %srcimg.coerce, target("spirv.Sampler") %s.coerce)
+  %2 = tail call spir_func <4 x float> @_Z38__spirv_ImageSampleExplicitLod_Rfloat4PU3AS120__spirv_SampledImageDv4_iif(target("spirv.Image", float, 1, 1, 0, 0, 0, 0, 0) %1, <4 x i32> zeroinitializer, i32 2, float 1.000000e+00)
   ret void
 }
 
-declare spir_func %spirv.SampledImage._float_1_1_0_0_0_0_0 addrspace(1)* @_Z20__spirv_SampledImagePU3AS1K34__spirv_Image__float_1_1_0_0_0_0_0PU3AS1K15__spirv_Sampler(%spirv.Image._float_1_1_0_0_0_0_0 addrspace(1)*, %spirv.Sampler addrspace(1)*)
+declare spir_func target("spirv.Image", float, 1, 1, 0, 0, 0, 0, 0) @_Z20__spirv_SampledImagePU3AS1K34__spirv_Image__float_1_1_0_0_0_0_0PU3AS1K15__spirv_Sampler(target("spirv.Image", float, 1, 1, 0, 0, 0, 0, 0), target("spirv.Sampler"))
 
-declare spir_func <4 x float> @_Z38__spirv_ImageSampleExplicitLod_Rfloat4PU3AS120__spirv_SampledImageDv4_iif(%spirv.SampledImage._float_1_1_0_0_0_0_0 addrspace(1)*, <4 x i32>, i32, float)
+declare spir_func <4 x float> @_Z38__spirv_ImageSampleExplicitLod_Rfloat4PU3AS120__spirv_SampledImageDv4_iif(target("spirv.Image", float, 1, 1, 0, 0, 0, 0, 0), <4 x i32>, i32, float)


        


More information about the llvm-commits mailing list