spirv-llvm-translator/Support-SPV_INTEL_maximum_registers-extension.patch
Stefan Dirsch b3e81e17d6 Accepting request 1156749 from home:aaronpuchert:llvm-next
- Update to version 18.1.0.
  * Compatibility with LLVM 18.
- Add rpmlintrc: following the LLVM's new versioning scheme, this
  package not only has versions X.1.Y now, but the SO name is X.1.
  However, the minor version is always going to be 1, and there is
  no need to distinguish between minor versions, so we don't add it
  to the package name.
- Drop ca3ae0cc.patch that landed upstream.
- Add Support-SPV_INTEL_maximum_registers-extension.patch to revert
  change temporarily because the corresponding change in spirv-
  headers is not released yet.

OBS-URL: https://build.opensuse.org/request/show/1156749
OBS-URL: https://build.opensuse.org/package/show/X11:XOrg/spirv-llvm-translator?expand=0&rev=12
2024-03-14 04:36:44 +00:00

394 lines
16 KiB
Diff

From d970c9126c033ebcbb7187bc705eae2e54726b74 Mon Sep 17 00:00:00 2001
From: Vlad Korovin <vladislav.korovin@intel.com>
Date: Wed, 6 Mar 2024 12:17:00 +0100
Subject: [PATCH] [Backport to 18] Support SPV_INTEL_maximum_registers
extension (#2344) (#2388)
Spec:
KhronosGroup/SPIRV-Registry#235
Co-authored-by: Viktoria Maximova <viktoria.maksimova@intel.com>
---
include/LLVMSPIRVExtensions.inc | 1 +
lib/SPIRV/SPIRVReader.cpp | 42 +++++++++
lib/SPIRV/SPIRVWriter.cpp | 37 +++++++-
lib/SPIRV/SPIRVWriter.h | 1 +
lib/SPIRV/libSPIRV/SPIRVEntry.cpp | 3 +
lib/SPIRV/libSPIRV/SPIRVEntry.h | 19 ++++-
lib/SPIRV/libSPIRV/SPIRVEnum.h | 6 ++
lib/SPIRV/libSPIRV/SPIRVIsValidEnum.h | 3 +
lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h | 8 ++
lib/SPIRV/libSPIRV/SPIRVStream.cpp | 1 +
lib/SPIRV/libSPIRV/SPIRVStream.h | 1 +
spirv-headers-tag.conf | 2 +-
.../registerallocmode_maxreg_extension.ll | 85 +++++++++++++++++++
13 files changed, 206 insertions(+), 3 deletions(-)
create mode 100644 test/extensions/INTEL/SPV_INTEL_maximum_registers/registerallocmode_maxreg_extension.ll
diff --git a/include/LLVMSPIRVExtensions.inc b/include/LLVMSPIRVExtensions.inc
index 780faec576..b884e37230 100644
--- a/include/LLVMSPIRVExtensions.inc
+++ b/include/LLVMSPIRVExtensions.inc
@@ -69,3 +69,4 @@ EXT(SPV_INTEL_fpga_argument_interfaces)
EXT(SPV_INTEL_fpga_latency_control)
EXT(SPV_INTEL_fp_max_error)
EXT(SPV_INTEL_cache_controls)
+EXT(SPV_INTEL_maximum_registers)
diff --git a/lib/SPIRV/SPIRVReader.cpp b/lib/SPIRV/SPIRVReader.cpp
index 0502d4e613..daf9fb6a21 100644
--- a/lib/SPIRV/SPIRVReader.cpp
+++ b/lib/SPIRV/SPIRVReader.cpp
@@ -4306,6 +4306,48 @@ bool SPIRVToLLVM::transMetadata() {
F->setMetadata(kSPIR2MD::IntelFPGAIPInterface,
MDNode::get(*Context, InterfaceMDVec));
}
+ if (auto *EM = BF->getExecutionMode(ExecutionModeMaximumRegistersINTEL)) {
+ NamedMDNode *ExecModeMD =
+ M->getOrInsertNamedMetadata(kSPIRVMD::ExecutionMode);
+
+ SmallVector<Metadata *, 4> ValueVec;
+ ValueVec.push_back(ConstantAsMetadata::get(F));
+ ValueVec.push_back(
+ ConstantAsMetadata::get(getUInt32(M, EM->getExecutionMode())));
+ ValueVec.push_back(
+ ConstantAsMetadata::get(getUInt32(M, EM->getLiterals()[0])));
+ ExecModeMD->addOperand(MDNode::get(*Context, ValueVec));
+ }
+ if (auto *EM = BF->getExecutionMode(ExecutionModeMaximumRegistersIdINTEL)) {
+ NamedMDNode *ExecModeMD =
+ M->getOrInsertNamedMetadata(kSPIRVMD::ExecutionMode);
+
+ SmallVector<Metadata *, 4> ValueVec;
+ ValueVec.push_back(ConstantAsMetadata::get(F));
+ ValueVec.push_back(
+ ConstantAsMetadata::get(getUInt32(M, EM->getExecutionMode())));
+
+ auto *ExecOp = BF->getModule()->getValue(EM->getLiterals()[0]);
+ ValueVec.push_back(
+ MDNode::get(*Context, ConstantAsMetadata::get(cast<ConstantInt>(
+ transValue(ExecOp, nullptr, nullptr)))));
+ ExecModeMD->addOperand(MDNode::get(*Context, ValueVec));
+ }
+ if (auto *EM =
+ BF->getExecutionMode(ExecutionModeNamedMaximumRegistersINTEL)) {
+ NamedMDNode *ExecModeMD =
+ M->getOrInsertNamedMetadata(kSPIRVMD::ExecutionMode);
+
+ SmallVector<Metadata *, 4> ValueVec;
+ ValueVec.push_back(ConstantAsMetadata::get(F));
+ ValueVec.push_back(
+ ConstantAsMetadata::get(getUInt32(M, EM->getExecutionMode())));
+
+ assert(EM->getLiterals()[0] == 0 &&
+ "Invalid named maximum number of registers");
+ ValueVec.push_back(MDString::get(*Context, "AutoINTEL"));
+ ExecModeMD->addOperand(MDNode::get(*Context, ValueVec));
+ }
}
NamedMDNode *MemoryModelMD =
M->getOrInsertNamedMetadata(kSPIRVMD::MemoryModel);
diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp
index ba25f210f6..55a66c1e64 100644
--- a/lib/SPIRV/SPIRVWriter.cpp
+++ b/lib/SPIRV/SPIRVWriter.cpp
@@ -977,7 +977,10 @@ SPIRVFunction *LLVMToSPIRVBase::transFunctionDecl(Function *F) {
transFPGAFunctionMetadata(BF, F);
- transFunctionMetadataAsUserSemanticDecoration(BF, F);
+ if (BM->isAllowedToUseExtension(ExtensionID::SPV_INTEL_maximum_registers))
+ transFunctionMetadataAsExecutionMode(BF, F);
+ else
+ transFunctionMetadataAsUserSemanticDecoration(BF, F);
transAuxDataInst(BF, F);
@@ -1118,6 +1121,38 @@ void LLVMToSPIRVBase::transFPGAFunctionMetadata(SPIRVFunction *BF,
transMetadataDecorations(FDecoMD, BF);
}
+void LLVMToSPIRVBase::transFunctionMetadataAsExecutionMode(SPIRVFunction *BF,
+ Function *F) {
+ SmallVector<MDNode *, 1> RegisterAllocModeMDs;
+ F->getMetadata("RegisterAllocMode", RegisterAllocModeMDs);
+
+ for (unsigned I = 0; I < RegisterAllocModeMDs.size(); I++) {
+ auto *RegisterAllocMode = RegisterAllocModeMDs[I]->getOperand(0).get();
+ if (isa<MDString>(RegisterAllocMode)) {
+ StringRef Str = getMDOperandAsString(RegisterAllocModeMDs[I], 0);
+ NamedMaximumNumberOfRegisters NamedValue =
+ SPIRVNamedMaximumNumberOfRegistersNameMap::rmap(Str.str());
+ BF->addExecutionMode(BM->add(new SPIRVExecutionMode(
+ OpExecutionMode, BF, ExecutionModeNamedMaximumRegistersINTEL,
+ NamedValue)));
+ } else if (isa<MDNode>(RegisterAllocMode)) {
+ auto *RegisterAllocNodeMDOp =
+ getMDOperandAsMDNode(RegisterAllocModeMDs[I], 0);
+ int Num = getMDOperandAsInt(RegisterAllocNodeMDOp, 0);
+ auto *Const =
+ BM->addConstant(transType(Type::getInt32Ty(F->getContext())), Num);
+ BF->addExecutionMode(BM->add(new SPIRVExecutionModeId(
+ BF, ExecutionModeMaximumRegistersIdINTEL, Const->getId())));
+ } else {
+ int64_t RegisterAllocVal =
+ mdconst::dyn_extract<ConstantInt>(RegisterAllocMode)->getZExtValue();
+ BF->addExecutionMode(BM->add(new SPIRVExecutionMode(
+ OpExecutionMode, BF, ExecutionModeMaximumRegistersINTEL,
+ RegisterAllocVal)));
+ }
+ }
+}
+
void LLVMToSPIRVBase::transFunctionMetadataAsUserSemanticDecoration(
SPIRVFunction *BF, Function *F) {
if (auto *RegisterAllocModeMD = F->getMetadata("RegisterAllocMode")) {
diff --git a/lib/SPIRV/SPIRVWriter.h b/lib/SPIRV/SPIRVWriter.h
index cafff7f2c8..344a77f8fc 100644
--- a/lib/SPIRV/SPIRVWriter.h
+++ b/lib/SPIRV/SPIRVWriter.h
@@ -131,6 +131,7 @@ class LLVMToSPIRVBase : protected BuiltinCallHelper {
SPIRVFunction *transFunctionDecl(Function *F);
void transVectorComputeMetadata(Function *F);
void transFPGAFunctionMetadata(SPIRVFunction *BF, Function *F);
+ void transFunctionMetadataAsExecutionMode(SPIRVFunction *BF, Function *F);
void transFunctionMetadataAsUserSemanticDecoration(SPIRVFunction *BF,
Function *F);
void transAuxDataInst(SPIRVFunction *BF, Function *F);
diff --git a/lib/SPIRV/libSPIRV/SPIRVEntry.cpp b/lib/SPIRV/libSPIRV/SPIRVEntry.cpp
index a522d71943..b7ea5ff715 100644
--- a/lib/SPIRV/libSPIRV/SPIRVEntry.cpp
+++ b/lib/SPIRV/libSPIRV/SPIRVEntry.cpp
@@ -660,6 +660,9 @@ void SPIRVExecutionMode::decode(std::istream &I) {
case ExecutionModeSchedulerTargetFmaxMhzINTEL:
case ExecutionModeRegisterMapInterfaceINTEL:
case ExecutionModeStreamingInterfaceINTEL:
+ case ExecutionModeMaximumRegistersINTEL:
+ case ExecutionModeMaximumRegistersIdINTEL:
+ case ExecutionModeNamedMaximumRegistersINTEL:
WordLiterals.resize(1);
break;
default:
diff --git a/lib/SPIRV/libSPIRV/SPIRVEntry.h b/lib/SPIRV/libSPIRV/SPIRVEntry.h
index 7218e4ac32..7c0afc903b 100644
--- a/lib/SPIRV/libSPIRV/SPIRVEntry.h
+++ b/lib/SPIRV/libSPIRV/SPIRVEntry.h
@@ -696,6 +696,17 @@ class SPIRVExecutionMode : public SPIRVAnnotation {
}
}
+ std::optional<ExtensionID> getRequiredExtension() const override {
+ switch (static_cast<unsigned>(ExecMode)) {
+ case ExecutionModeMaximumRegistersINTEL:
+ case ExecutionModeMaximumRegistersIdINTEL:
+ case ExecutionModeNamedMaximumRegistersINTEL:
+ return ExtensionID::SPV_INTEL_maximum_registers;
+ default:
+ return {};
+ }
+ }
+
protected:
_SPIRV_DCL_ENCDEC
SPIRVExecutionModeKind ExecMode;
@@ -757,6 +768,11 @@ class SPIRVComponentExecutionModes {
return IsDenorm(EMK) || IsRoundingMode(EMK) || IsFPMode(EMK) ||
IsOtherFP(EMK);
};
+ auto IsMaxRegisters = [&](auto EMK) {
+ return EMK == ExecutionModeMaximumRegistersINTEL ||
+ EMK == ExecutionModeMaximumRegistersIdINTEL ||
+ EMK == ExecutionModeNamedMaximumRegistersINTEL;
+ };
auto IsCompatible = [&](SPIRVExecutionMode *EM0, SPIRVExecutionMode *EM1) {
if (EM0->getTargetId() != EM1->getTargetId())
return true;
@@ -770,7 +786,8 @@ class SPIRVComponentExecutionModes {
return true;
return !(IsDenorm(EMK0) && IsDenorm(EMK1)) &&
!(IsRoundingMode(EMK0) && IsRoundingMode(EMK1)) &&
- !(IsFPMode(EMK0) && IsFPMode(EMK1));
+ !(IsFPMode(EMK0) && IsFPMode(EMK1)) &&
+ !(IsMaxRegisters(EMK0) && IsMaxRegisters(EMK1));
};
for (auto I = ExecModes.begin(); I != ExecModes.end(); ++I) {
assert(IsCompatible(ExecMode, (*I).second) &&
diff --git a/lib/SPIRV/libSPIRV/SPIRVEnum.h b/lib/SPIRV/libSPIRV/SPIRVEnum.h
index d1bbc83626..ccabddb597 100644
--- a/lib/SPIRV/libSPIRV/SPIRVEnum.h
+++ b/lib/SPIRV/libSPIRV/SPIRVEnum.h
@@ -291,6 +291,12 @@ template <> inline void SPIRVMap<SPIRVExecutionModeKind, SPIRVCapVec>::init() {
{CapabilityFPGAKernelAttributesINTEL});
ADD_VEC_INIT(ExecutionModeNamedBarrierCountINTEL,
{CapabilityVectorComputeINTEL});
+ ADD_VEC_INIT(ExecutionModeMaximumRegistersINTEL,
+ {CapabilityRegisterLimitsINTEL});
+ ADD_VEC_INIT(ExecutionModeMaximumRegistersIdINTEL,
+ {CapabilityRegisterLimitsINTEL});
+ ADD_VEC_INIT(ExecutionModeNamedMaximumRegistersINTEL,
+ {CapabilityRegisterLimitsINTEL});
}
template <> inline void SPIRVMap<SPIRVMemoryModelKind, SPIRVCapVec>::init() {
diff --git a/lib/SPIRV/libSPIRV/SPIRVIsValidEnum.h b/lib/SPIRV/libSPIRV/SPIRVIsValidEnum.h
index 080b8bcd86..9930349dbd 100644
--- a/lib/SPIRV/libSPIRV/SPIRVIsValidEnum.h
+++ b/lib/SPIRV/libSPIRV/SPIRVIsValidEnum.h
@@ -73,6 +73,9 @@ inline bool isValid(spv::ExecutionModel V) {
case ExecutionModelCallableKHR:
case ExecutionModeRegisterMapInterfaceINTEL:
case ExecutionModeStreamingInterfaceINTEL:
+ case ExecutionModeMaximumRegistersINTEL:
+ case ExecutionModeMaximumRegistersIdINTEL:
+ case ExecutionModeNamedMaximumRegistersINTEL:
return true;
default:
return false;
diff --git a/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h b/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h
index 2635c974be..53fc2e192a 100644
--- a/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h
+++ b/lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h
@@ -637,6 +637,7 @@ template <> inline void SPIRVMap<Capability, std::string>::init() {
add(CapabilityFPGAArgumentInterfacesINTEL, "FPGAArgumentInterfacesINTEL");
add(CapabilityFPGALatencyControlINTEL, "FPGALatencyControlINTEL");
add(CapabilityFPMaxErrorINTEL, "FPMaxErrorINTEL");
+ add(CapabilityRegisterLimitsINTEL, "RegisterLimitsINTEL");
// From spirv_internal.hpp
add(internal::CapabilityFastCompositeINTEL, "FastCompositeINTEL");
add(internal::CapabilityOptNoneINTEL, "OptNoneINTEL");
@@ -691,6 +692,13 @@ template <> inline void SPIRVMap<HostAccessQualifier, std::string>::init() {
}
SPIRV_DEF_NAMEMAP(HostAccessQualifier, SPIRVHostAccessQualifierNameMap)
+template <>
+inline void SPIRVMap<NamedMaximumNumberOfRegisters, std::string>::init() {
+ add(NamedMaximumNumberOfRegistersAutoINTEL, "AutoINTEL");
+}
+SPIRV_DEF_NAMEMAP(NamedMaximumNumberOfRegisters,
+ SPIRVNamedMaximumNumberOfRegistersNameMap);
+
} /* namespace SPIRV */
#endif // SPIRV_LIBSPIRV_SPIRVNAMEMAPENUM_H
diff --git a/lib/SPIRV/libSPIRV/SPIRVStream.cpp b/lib/SPIRV/libSPIRV/SPIRVStream.cpp
index 7b785b5b55..7dfbdddbfa 100644
--- a/lib/SPIRV/libSPIRV/SPIRVStream.cpp
+++ b/lib/SPIRV/libSPIRV/SPIRVStream.cpp
@@ -147,6 +147,7 @@ SPIRV_DEF_ENCDEC(SPIRVDebugExtOpKind)
SPIRV_DEF_ENCDEC(NonSemanticAuxDataOpKind)
SPIRV_DEF_ENCDEC(InitializationModeQualifier)
SPIRV_DEF_ENCDEC(HostAccessQualifier)
+SPIRV_DEF_ENCDEC(NamedMaximumNumberOfRegisters)
SPIRV_DEF_ENCDEC(LinkageType)
// Read a string with padded 0's at the end so that they form a stream of
diff --git a/lib/SPIRV/libSPIRV/SPIRVStream.h b/lib/SPIRV/libSPIRV/SPIRVStream.h
index 0a788044a6..21cb51a3a0 100644
--- a/lib/SPIRV/libSPIRV/SPIRVStream.h
+++ b/lib/SPIRV/libSPIRV/SPIRVStream.h
@@ -231,6 +231,7 @@ SPIRV_DEC_ENCDEC(SPIRVDebugExtOpKind)
SPIRV_DEC_ENCDEC(NonSemanticAuxDataOpKind)
SPIRV_DEC_ENCDEC(InitializationModeQualifier)
SPIRV_DEC_ENCDEC(HostAccessQualifier)
+SPIRV_DEC_ENCDEC(NamedMaximumNumberOfRegisters)
SPIRV_DEC_ENCDEC(LinkageType)
const SPIRVEncoder &operator<<(const SPIRVEncoder &O, const std::string &Str);
diff --git a/spirv-headers-tag.conf b/spirv-headers-tag.conf
index 7fae55f32b..3c34bf8933 100644
--- a/spirv-headers-tag.conf
+++ b/spirv-headers-tag.conf
@@ -1 +1 @@
-1c6bb2743599e6eb6f37b2969acc0aef812e32e3
+b73e168ca5e123dcf3dea8a34b19a5130f421ae1
diff --git a/test/extensions/INTEL/SPV_INTEL_maximum_registers/registerallocmode_maxreg_extension.ll b/test/extensions/INTEL/SPV_INTEL_maximum_registers/registerallocmode_maxreg_extension.ll
new file mode 100644
index 0000000000..1dfc768ffe
--- /dev/null
+++ b/test/extensions/INTEL/SPV_INTEL_maximum_registers/registerallocmode_maxreg_extension.ll
@@ -0,0 +1,85 @@
+; RUN: llvm-as %s -o %t.bc
+; RUN: llvm-spirv -spirv-text --spirv-ext=+SPV_INTEL_maximum_registers %t.bc
+; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
+; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_maximum_registers -o %t.spv
+; RUN: llvm-spirv -r %t.spv -spirv-target-env=SPV-IR -o - | llvm-dis -o %t.rev.ll
+; RUN: FileCheck < %t.rev.ll %s --check-prefix=CHECK-LLVM
+
+; CHECK-SPIRV: EntryPoint [[#]] [[#FUNC0:]] "main_l3"
+; CHECK-SPIRV: EntryPoint [[#]] [[#FUNC1:]] "main_l6"
+; CHECK-SPIRV: EntryPoint [[#]] [[#FUNC2:]] "main_l9"
+; CHECK-SPIRV: EntryPoint [[#]] [[#FUNC3:]] "main_l13"
+; CHECK-SPIRV: EntryPoint [[#]] [[#FUNC4:]] "main_l19"
+
+; CHECK-SPIRV: ExecutionMode [[#FUNC0]] 6461 2
+; CHECK-SPIRV: ExecutionMode [[#FUNC1]] 6461 1
+; CHECK-SPIRV: ExecutionMode [[#FUNC2]] 6463 0
+; CHECK-SPIRV: ExecutionModeId [[#FUNC3]] 6462 [[#Const3:]]
+; CHECK-SPIRV: TypeInt [[#TypeInt:]] 32 0
+; CHECK-SPIRV: Constant [[#TypeInt]] [[#Const3]] 3
+
+; CHECK-SPIRV-NOT: ExecutionMode [[#FUNC4]]
+
+; CHECK-LLVM: !spirv.ExecutionMode = !{![[#FLAG0:]], ![[#FLAG1:]], ![[#FLAG2:]], ![[#FLAG3:]]}
+; CHECK-LLVM: ![[#FLAG0]] = !{ptr @main_l3, i32 6461, i32 2}
+; CHECK-LLVM: ![[#FLAG1]] = !{ptr @main_l6, i32 6461, i32 1}
+; CHECK-LLVM: ![[#FLAG2]] = !{ptr @main_l9, i32 6463, !"AutoINTEL"}
+; CHECK-LLVM: ![[#FLAG3]] = !{ptr @main_l13, i32 6462, ![[#VAL:]]}
+; CHECK-LLVM: ![[#VAL]] = !{i32 3}
+
+target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
+target triple = "spir64"
+
+; Function Attrs: noinline nounwind optnone
+define weak dso_local spir_kernel void @main_l3() #0 !RegisterAllocMode !10 {
+newFuncRoot:
+ ret void
+}
+
+; Function Attrs: noinline nounwind optnone
+define weak dso_local spir_kernel void @main_l6() #0 !RegisterAllocMode !11 {
+newFuncRoot:
+ ret void
+}
+
+; Function Attrs: noinline nounwind optnone
+define weak dso_local spir_kernel void @main_l9() #0 !RegisterAllocMode !12 {
+newFuncRoot:
+ ret void
+}
+
+; Function Attrs: noinline nounwind optnone
+define weak dso_local spir_kernel void @main_l13() #0 !RegisterAllocMode !13 {
+newFuncRoot:
+ ret void
+}
+
+; Function Attrs: noinline nounwind optnone
+define weak dso_local spir_kernel void @main_l19() #0 {
+newFuncRoot:
+ ret void
+}
+
+attributes #0 = { noinline nounwind optnone }
+
+
+!opencl.compiler.options = !{!0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0}
+!spirv.Source = !{!2, !3, !3, !3, !3, !3, !2, !3, !2, !2, !2, !2, !2, !2, !2, !2, !2, !2, !2, !2, !2, !2}
+!llvm.module.flags = !{!4, !5, !6, !7, !8}
+!spirv.MemoryModel = !{!9, !9, !9, !9, !9, !9}
+!spirv.ExecutionMode = !{}
+
+!0 = !{}
+!2 = !{i32 4, i32 200000}
+!3 = !{i32 3, i32 200000}
+!4 = !{i32 1, !"wchar_size", i32 4}
+!5 = !{i32 7, !"openmp", i32 50}
+!6 = !{i32 7, !"openmp-device", i32 50}
+!7 = !{i32 8, !"PIC Level", i32 2}
+!8 = !{i32 7, !"frame-pointer", i32 2}
+!9 = !{i32 2, i32 2}
+!10 = !{i32 2}
+!11 = !{i32 1}
+!12 = !{!"AutoINTEL"}
+!13 = !{!14}
+!14 = !{i32 3}