[llvm] [SPIR-V] Add support for inline SPIR-V types (PR #125316)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 31 15:32:51 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-spir-v

Author: Cassandra Beckley (cassiebeckley)

<details>
<summary>Changes</summary>

Using HLSL's [Inline SPIR-V](https://microsoft.github.io/hlsl-specs/proposals/0011-inline-spirv.html) features, users have the ability to use [`SpirvType`](https://microsoft.github.io/hlsl-specs/proposals/0011-inline-spirv.html#types) to have fine-grained control over the SPIR-V representation of a type. As explained in the spec, this is useful because it enables vendors to author headers with types for their own extensions.

As discussed in [Target Extension Types for Inline SPIR-V and Decorated Types](https://github.com/llvm/wg-hlsl/pull/105), we would like to represent the HLSL SpirvType type using a 'spirv.Type' target extension type in LLVM IR. This pull request lowers that type to SPIR-V.

---
Full diff: https://github.com/llvm/llvm-project/pull/125316.diff


11 Files Affected:

- (modified) llvm/lib/IR/Type.cpp (+20) 
- (modified) llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp (+31) 
- (modified) llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.h (+1) 
- (modified) llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCCodeEmitter.cpp (+23) 
- (modified) llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp (+97-32) 
- (modified) llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp (+15) 
- (modified) llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h (+5) 
- (modified) llvm/lib/Target/SPIRV/SPIRVInstrFormats.td (+5) 
- (modified) llvm/lib/Target/SPIRV/SPIRVInstrInfo.td (+3) 
- (modified) llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp (+2-1) 
- (added) llvm/test/CodeGen/SPIRV/inline/type.ll (+32) 


``````````diff
diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp
index 277985b6b00a31..9a050bad1dfe26 100644
--- a/llvm/lib/IR/Type.cpp
+++ b/llvm/lib/IR/Type.cpp
@@ -968,6 +968,26 @@ static TargetTypeInfo getTargetTypeInfo(const TargetExtType *Ty) {
   if (Name == "spirv.Image")
     return TargetTypeInfo(PointerType::get(C, 0), TargetExtType::CanBeGlobal,
                           TargetExtType::CanBeLocal);
+  if (Name == "spirv.Type") {
+    assert(Ty->getNumIntParameters() == 3 &&
+           "Wrong number of parameters for spirv.Type");
+
+    auto Size = Ty->getIntParameter(1);
+    auto Alignment = Ty->getIntParameter(2);
+
+    // LLVM expects variables that can be allocated to have an alignment and
+    // size. Default to using a 32-bit int as the layout type if none are
+    // present.
+    llvm::Type *LayoutType = Type::getInt32Ty(C);
+    if (Size > 0 && Alignment > 0)
+      LayoutType =
+          ArrayType::get(Type::getIntNTy(C, Alignment), Size * 8 / Alignment);
+
+    return TargetTypeInfo(LayoutType, TargetExtType::CanBeGlobal,
+                          TargetExtType::CanBeLocal);
+  }
+  if (Name == "spirv.IntegralConstant" || Name == "spirv.Literal")
+    return TargetTypeInfo(Type::getVoidTy(C));
   if (Name.starts_with("spirv."))
     return TargetTypeInfo(PointerType::get(C, 0), TargetExtType::HasZeroInit,
                           TargetExtType::CanBeGlobal,
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
index 2ee0c79b8f7c12..136949d1116b22 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
@@ -116,6 +116,8 @@ void SPIRVInstPrinter::printInst(const MCInst *MI, uint64_t Address,
     recordOpExtInstImport(MI);
   } else if (OpCode == SPIRV::OpExtInst) {
     printOpExtInst(MI, OS);
+  } else if (OpCode == SPIRV::UNKNOWN_type) {
+    printUnknownType(MI, OS);
   } else {
     // Print any extra operands for variadic instructions.
     const MCInstrDesc &MCDesc = MII.get(OpCode);
@@ -314,6 +316,35 @@ void SPIRVInstPrinter::printOpDecorate(const MCInst *MI, raw_ostream &O) {
   }
 }
 
+void SPIRVInstPrinter::printUnknownType(const MCInst *MI, raw_ostream &O) {
+  const auto EnumOperand = MI->getOperand(1);
+  assert(EnumOperand.isImm() &&
+         "second operand of UNKNOWN_type must be opcode!");
+
+  const auto Enumerant = EnumOperand.getImm();
+  const auto NumOps = MI->getNumOperands();
+
+  // Encode the instruction enumerant and word count into the opcode
+  const auto OpCode = (0xFF & NumOps) << 16 | (0xFF & Enumerant);
+
+  // Print the opcode using the spirv-as arbitrary integer syntax
+  // https://github.com/KhronosGroup/SPIRV-Tools/blob/main/docs/syntax.md#arbitrary-integers
+  O << "!0x" << Twine::utohexstr(OpCode) << " ";
+
+  // The result ID must be printed after the opcode when using this syntax
+  printOperand(MI, 0, O);
+
+  O << " ";
+
+  const MCInstrDesc &MCDesc = MII.get(MI->getOpcode());
+  unsigned NumFixedOps = MCDesc.getNumOperands();
+  if (NumOps == NumFixedOps)
+    return;
+
+  // Print the rest of the operands
+  printRemainingVariableOps(MI, NumFixedOps, O, true);
+}
+
 static void printExpr(const MCExpr *Expr, raw_ostream &O) {
 #ifndef NDEBUG
   const MCSymbolRefExpr *SRE;
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.h b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.h
index 9b02524f50b81b..a7b38a6951c51e 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.h
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.h
@@ -35,6 +35,7 @@ class SPIRVInstPrinter : public MCInstPrinter {
 
   void printOpDecorate(const MCInst *MI, raw_ostream &O);
   void printOpExtInst(const MCInst *MI, raw_ostream &O);
+  void printUnknownType(const MCInst *MI, raw_ostream &O);
   void printRemainingVariableOps(const MCInst *MI, unsigned StartIndex,
                                  raw_ostream &O, bool SkipFirstSpace = false,
                                  bool SkipImmediates = false);
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCCodeEmitter.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCCodeEmitter.cpp
index 68cc6a3a7aac1b..9f2b74c29a93bc 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCCodeEmitter.cpp
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCCodeEmitter.cpp
@@ -46,6 +46,9 @@ class SPIRVMCCodeEmitter : public MCCodeEmitter {
   void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,
                          SmallVectorImpl<MCFixup> &Fixups,
                          const MCSubtargetInfo &STI) const override;
+  void encodeUnknownType(const MCInst &MI, SmallVectorImpl<char> &CB,
+                         SmallVectorImpl<MCFixup> &Fixups,
+                         const MCSubtargetInfo &STI) const;
 };
 
 } // end anonymous namespace
@@ -104,10 +107,30 @@ static void emitUntypedInstrOperands(const MCInst &MI,
     emitOperand(Op, CB);
 }
 
+void SPIRVMCCodeEmitter::encodeUnknownType(const MCInst &MI,
+                                           SmallVectorImpl<char> &CB,
+                                           SmallVectorImpl<MCFixup> &Fixups,
+                                           const MCSubtargetInfo &STI) const {
+  // Encode the first 32 SPIR-V bytes with the number of args and the opcode.
+  const uint64_t OpCode = MI.getOperand(1).getImm();
+  const uint32_t NumWords = MI.getNumOperands();
+  const uint32_t FirstWord = (NumWords << 16) | OpCode;
+  support::endian::write(CB, FirstWord, llvm::endianness::little);
+
+  emitOperand(MI.getOperand(0), CB);
+  for (unsigned i = 2; i < NumWords; ++i)
+    emitOperand(MI.getOperand(i), CB);
+}
+
 void SPIRVMCCodeEmitter::encodeInstruction(const MCInst &MI,
                                            SmallVectorImpl<char> &CB,
                                            SmallVectorImpl<MCFixup> &Fixups,
                                            const MCSubtargetInfo &STI) const {
+  if (MI.getOpcode() == SPIRV::UNKNOWN_type) {
+    encodeUnknownType(MI, CB, Fixups, STI);
+    return;
+  }
+
   // Encode the first 32 SPIR-V bytes with the number of args and the opcode.
   const uint64_t OpCode = getBinaryCodeForInstr(MI, Fixups, STI);
   const uint32_t NumWords = MI.getNumOperands() + 1;
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
index 95fa7bc3894fdc..518b83b880b6bb 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
@@ -2868,6 +2868,65 @@ static SPIRVType *getSampledImageType(const TargetExtType *OpaqueType,
   return GR->getOrCreateOpTypeSampledImage(OpaqueImageType, MIRBuilder);
 }
 
+static SPIRVType *getInlineSpirvType(const TargetExtType *ExtensionType,
+                                     MachineIRBuilder &MIRBuilder,
+                                     SPIRVGlobalRegistry *GR) {
+  assert(ExtensionType->getNumIntParameters() == 3 &&
+         "Inline SPIR-V type builtin takes an opcode, size, and alignment "
+         "parameter");
+  auto Opcode = ExtensionType->getIntParameter(0);
+
+  // auto Size = ExtensionType->getIntParameter(1);
+  // auto Alignment = ExtensionType->getIntParameter(2);
+
+  return GR->getOrCreateUnknownType(
+      ExtensionType, MIRBuilder, Opcode,
+      [&ExtensionType, &GR, &MIRBuilder](llvm::MachineInstrBuilder Instr) {
+        // TODO: probably pass in operands as array? idk
+        for (llvm::Type *Param : ExtensionType->type_params()) {
+          if (const TargetExtType *ParamEType =
+                  dyn_cast<TargetExtType>(Param)) {
+            if (ParamEType->getName() == "spirv.IntegralConstant") {
+              assert(ParamEType->getNumTypeParameters() == 1 &&
+                     "Inline SPIR-V integral constant builtin must have a type "
+                     "parameter");
+              assert(ParamEType->getNumIntParameters() == 1 &&
+                     "Inline SPIR-V integral constant builtin must have a "
+                     "value parameter");
+
+              auto OperandValue = ParamEType->getIntParameter(0);
+              auto *OperandType = ParamEType->getTypeParameter(0);
+
+              const SPIRVType *OperandSPIRVType =
+                  GR->getOrCreateSPIRVType(OperandType, MIRBuilder);
+
+              Instr = Instr.addUse(GR->buildConstantInt(
+                  OperandValue, MIRBuilder, OperandSPIRVType, true));
+              continue;
+            } else if (ParamEType->getName() == "spirv.Literal") {
+              assert(ParamEType->getNumTypeParameters() == 0 &&
+                     "Inline SPIR-V literal builtin does not take type "
+                     "parameters");
+              assert(ParamEType->getNumIntParameters() == 1 &&
+                     "Inline SPIR-V literal builtin must have an integer "
+                     "parameter");
+
+              auto OperandValue = ParamEType->getIntParameter(0);
+
+              Instr = Instr.addImm(OperandValue);
+              continue;
+            }
+          }
+          const SPIRVType *TypeOperand =
+              GR->getOrCreateSPIRVType(Param, MIRBuilder);
+          Instr = Instr.addUse(GR->getSPIRVTypeID(TypeOperand));
+        }
+        return Instr;
+      });
+
+  // GR->getOrCreateSPIRVArrayType();
+}
+
 namespace SPIRV {
 TargetExtType *parseBuiltinTypeNameToTargetExtType(std::string TypeName,
                                                    LLVMContext &Context) {
@@ -2940,39 +2999,45 @@ SPIRVType *lowerBuiltinType(const Type *OpaqueType,
   const StringRef Name = BuiltinType->getName();
   LLVM_DEBUG(dbgs() << "Lowering builtin type: " << Name << "\n");
 
-  // Lookup the demangled builtin type in the TableGen records.
-  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 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(BuiltinType, AccessQual, MIRBuilder, GR);
-    break;
-  case SPIRV::OpTypePipe:
-    TargetType = getPipeType(BuiltinType, MIRBuilder, GR);
-    break;
-  case SPIRV::OpTypeDeviceEvent:
-    TargetType = GR->getOrCreateOpTypeDeviceEvent(MIRBuilder);
-    break;
-  case SPIRV::OpTypeSampler:
-    TargetType = getSamplerType(MIRBuilder, GR);
-    break;
-  case SPIRV::OpTypeSampledImage:
-    TargetType = getSampledImageType(BuiltinType, MIRBuilder, GR);
-    break;
-  case SPIRV::OpTypeCooperativeMatrixKHR:
-    TargetType = getCoopMatrType(BuiltinType, MIRBuilder, GR);
-    break;
-  default:
-    TargetType =
-        getNonParameterizedType(BuiltinType, TypeRecord, MIRBuilder, GR);
-    break;
+  if (Name == "spirv.Type") {
+    TargetType = getInlineSpirvType(BuiltinType, MIRBuilder, GR);
+  } else {
+    // Lookup the demangled builtin type in the TableGen records.
+    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 or
+    // TargetExtType parameters to either create a new OpType<...> machine
+    // instruction or get an existing equivalent SPIRVType from
+    // GlobalRegistry.
+
+    switch (TypeRecord->Opcode) {
+    case SPIRV::OpTypeImage:
+      TargetType = getImageType(BuiltinType, AccessQual, MIRBuilder, GR);
+      break;
+    case SPIRV::OpTypePipe:
+      TargetType = getPipeType(BuiltinType, MIRBuilder, GR);
+      break;
+    case SPIRV::OpTypeDeviceEvent:
+      TargetType = GR->getOrCreateOpTypeDeviceEvent(MIRBuilder);
+      break;
+    case SPIRV::OpTypeSampler:
+      TargetType = getSamplerType(MIRBuilder, GR);
+      break;
+    case SPIRV::OpTypeSampledImage:
+      TargetType = getSampledImageType(BuiltinType, MIRBuilder, GR);
+      break;
+    case SPIRV::OpTypeCooperativeMatrixKHR:
+      TargetType = getCoopMatrType(BuiltinType, MIRBuilder, GR);
+      break;
+    default:
+      TargetType =
+          getNonParameterizedType(BuiltinType, TypeRecord, MIRBuilder, GR);
+      break;
+    }
   }
 
   // Emit OpName instruction if a new OpType<...> instruction was added
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index e2f1b211caa5c1..bb2e71e6870c12 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -1406,6 +1406,21 @@ SPIRVType *SPIRVGlobalRegistry::getOrCreateOpTypeByOpcode(
   return SpirvTy;
 }
 
+SPIRVType *SPIRVGlobalRegistry::getOrCreateUnknownType(
+    const Type *Ty, MachineIRBuilder &MIRBuilder, unsigned Opcode,
+    const std::function<llvm::MachineInstrBuilder(llvm::MachineInstrBuilder)>
+        &buildInstr) {
+  Register ResVReg = DT.find(Ty, &MIRBuilder.getMF());
+  if (ResVReg.isValid())
+    return MIRBuilder.getMF().getRegInfo().getUniqueVRegDef(ResVReg);
+  ResVReg = createTypeVReg(MIRBuilder);
+  SPIRVType *SpirvTy = buildInstr(MIRBuilder.buildInstr(SPIRV::UNKNOWN_type)
+                                      .addDef(ResVReg)
+                                      .addImm(Opcode));
+  DT.add(Ty, &MIRBuilder.getMF(), ResVReg);
+  return SpirvTy;
+}
+
 const MachineInstr *
 SPIRVGlobalRegistry::checkSpecialInstr(const SPIRV::SpecialTypeDescriptor &TD,
                                        MachineIRBuilder &MIRBuilder) {
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
index 0c94ec4df97f54..d1fd05c31d7e30 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
@@ -618,6 +618,11 @@ class SPIRVGlobalRegistry {
                                        MachineIRBuilder &MIRBuilder,
                                        unsigned Opcode);
 
+  SPIRVType *getOrCreateUnknownType(
+      const Type *Ty, MachineIRBuilder &MIRBuilder, unsigned Opcode,
+      const std::function<llvm::MachineInstrBuilder(llvm::MachineInstrBuilder)>
+          &buildInstr);
+
   const TargetRegisterClass *getRegClass(SPIRVType *SpvType) const;
   LLT getRegType(SPIRVType *SpvType) const;
 };
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstrFormats.td b/llvm/lib/Target/SPIRV/SPIRVInstrFormats.td
index 9451583a5fa858..2fde2b0bc0b1fb 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstrFormats.td
+++ b/llvm/lib/Target/SPIRV/SPIRVInstrFormats.td
@@ -25,6 +25,11 @@ class Op<bits<16> Opcode, dag outs, dag ins, string asmstr, list<dag> pattern =
   let Pattern = pattern;
 }
 
+class UnknownOp<dag outs, dag ins, string asmstr, list<dag> pattern = []>
+    : Op<0, outs, ins, asmstr, pattern> {
+  let isPseudo = 1;
+}
+
 // Pseudo instructions
 class Pseudo<dag outs, dag ins> : Op<0, outs, ins, ""> {
   let isPseudo = 1;
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td
index 1bc35c6e57a4f6..1fac9eec8d3bbb 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td
+++ b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td
@@ -25,6 +25,9 @@ let isCodeGenOnly=1 in {
   def GET_vpID: Pseudo<(outs vpID:$dst_id), (ins vpID:$src)>;
 }
 
+def UNKNOWN_type
+    : UnknownOp<(outs TYPE:$type), (ins i32imm:$opcode, variable_ops), " ">;
+
 def SPVTypeBin : SDTypeProfile<1, 2, []>;
 
 def assigntype : SDNode<"SPIRVISD::AssignType", SPVTypeBin>;
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index e7d8fe5bd8015b..01c0e0b24bfceb 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -495,7 +495,8 @@ bool SPIRVInstructionSelector::select(MachineInstr &I) {
   bool HasDefs = I.getNumDefs() > 0;
   Register ResVReg = HasDefs ? I.getOperand(0).getReg() : Register(0);
   SPIRVType *ResType = HasDefs ? GR.getSPIRVTypeForVReg(ResVReg) : nullptr;
-  assert(!HasDefs || ResType || I.getOpcode() == TargetOpcode::G_GLOBAL_VALUE);
+  assert(!HasDefs || ResType || I.getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||
+         I.getOpcode() == TargetOpcode::G_IMPLICIT_DEF);
   if (spvSelect(ResVReg, ResType, I)) {
     if (HasDefs) // Make all vregs 64 bits (for SPIR-V IDs).
       for (unsigned i = 0; i < I.getNumDefs(); ++i)
diff --git a/llvm/test/CodeGen/SPIRV/inline/type.ll b/llvm/test/CodeGen/SPIRV/inline/type.ll
new file mode 100644
index 00000000000000..c723b2902bec13
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/inline/type.ll
@@ -0,0 +1,32 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - | spirv-as - -o - | spirv-val %}
+
+; CHECK: [[uint32_t:%[0-9]+]] = OpTypeInt 32 0
+
+; CHECK: [[image_t:%[0-9]+]] = OpTypeImage %3 2D 2 0 0 1 Unknown
+%type_2d_image = type target("spirv.Image", float, 1, 2, 0, 0, 1, 0)
+
+%literal_false = type target("spirv.Literal", 0)
+%literal_8 = type target("spirv.Literal", 8)
+
+; CHECK: [[uint32_4:%[0-9]+]] = OpConstant [[uint32_t]] 4
+%integral_constant_4 = type target("spirv.IntegralConstant", i32, 4)
+
+; CHECK: !0x4001c [[array_t:%[0-9]+]] [[image_t]] [[uint32_4]]
+%ArrayTex2D = type target("spirv.Type", %type_2d_image, %integral_constant_4, 28, 0, 0)
+
+; CHECK: [[getTexArray_t:%[0-9]+]] = OpTypeFunction [[array_t]]
+
+; CHECK: [[getTexArray:%[0-9]+]] = OpFunction [[array_t]] None [[getTexArray_t]]
+declare %ArrayTex2D @getTexArray()
+
+define void @main() #1 {
+entry:
+  %images = alloca %ArrayTex2D
+
+; CHECK: {{%[0-9]+}} = OpFunctionCall [[array_t]] [[getTexArray]]
+  %retTex = call %ArrayTex2D @getTexArray()
+
+  ret void
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/125316


More information about the llvm-commits mailing list