[llvm] [SPIR-V] Add support for inline SPIR-V types (PR #125316)
Cassandra Beckley via llvm-commits
llvm-commits at lists.llvm.org
Fri Jan 31 15:31:05 PST 2025
https://github.com/cassiebeckley created https://github.com/llvm/llvm-project/pull/125316
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.
>From 3e15f7bf1fb58fed63bfc5484d010277e9a785ad Mon Sep 17 00:00:00 2001
From: Cassandra Beckley <cbeckley at google.com>
Date: Wed, 20 Nov 2024 15:05:49 -0800
Subject: [PATCH] [SPIR-V] Add support for inline SPIR-V types
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], 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.
---
llvm/lib/IR/Type.cpp | 20 +++
.../SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp | 31 +++++
.../SPIRV/MCTargetDesc/SPIRVInstPrinter.h | 1 +
.../SPIRV/MCTargetDesc/SPIRVMCCodeEmitter.cpp | 23 ++++
llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp | 129 +++++++++++++-----
llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp | 15 ++
llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h | 5 +
llvm/lib/Target/SPIRV/SPIRVInstrFormats.td | 5 +
llvm/lib/Target/SPIRV/SPIRVInstrInfo.td | 3 +
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 3 +-
llvm/test/CodeGen/SPIRV/inline/type.ll | 32 +++++
11 files changed, 234 insertions(+), 33 deletions(-)
create mode 100644 llvm/test/CodeGen/SPIRV/inline/type.ll
diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp
index 277985b6b00a31d..9a050bad1dfe26e 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 2ee0c79b8f7c125..136949d1116b22d 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 9b02524f50b81bd..a7b38a6951c51e4 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 68cc6a3a7aac1bc..9f2b74c29a93bc4 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 95fa7bc3894fdc5..518b83b880b6bb8 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 e2f1b211caa5c12..bb2e71e6870c12b 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 0c94ec4df97f541..d1fd05c31d7e305 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 9451583a5fa858a..2fde2b0bc0b1fb0 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 1bc35c6e57a4f65..1fac9eec8d3bbb1 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 e7d8fe5bd8015b1..01c0e0b24bfceb7 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 000000000000000..c723b2902bec134
--- /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
+}
More information about the llvm-commits
mailing list