diff --git a/llvm/docs/SPIRVUsage.rst b/llvm/docs/SPIRVUsage.rst index 6ff8034cac00c..bbc95d43c3eb8 100644 --- a/llvm/docs/SPIRVUsage.rst +++ b/llvm/docs/SPIRVUsage.rst @@ -213,6 +213,8 @@ list of supported SPIR-V extensions, sorted alphabetically by their extension na - Adds a bitwise instruction on three operands and a look-up table index for specifying the bitwise operation to perform. * - ``SPV_INTEL_subgroup_matrix_multiply_accumulate`` - Adds an instruction to compute the matrix product of an M x K matrix with a K x N matrix and then add an M x N matrix. + * - ``SPV_INTEL_fpga_buffer_location`` + - Adds a pointer decoration for FPGA targets, indicating that a global memory pointer accesses only a specific physical memory location. To enable multiple extensions, list them separated by comma. For example, to enable support for atomic operations on floating-point numbers and arbitrary precision integers, use: diff --git a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp index 5991a9af6364d..f22d735310f77 100644 --- a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp @@ -363,6 +363,15 @@ bool SPIRVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder, buildOpDecorate(VRegs[i][0], MIRBuilder, Decoration, {}); } + if (MDNode *Node = F.getMetadata("kernel_arg_buffer_location")) { + int64_t BufferLoc = + processKernelArgBufferLocation(F, Node, i, VRegs, -1); + if (BufferLoc != -1) + buildOpDecorate(VRegs[i][0], MIRBuilder, + SPIRV::Decoration::BufferLocationINTEL, + {static_cast(BufferLoc)}); + } + MDNode *Node = F.getMetadata("spirv.ParameterDecorations"); if (Node && i < Node->getNumOperands() && isa(Node->getOperand(i))) { diff --git a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp index 56cbd9414c9ee..02dc1083838b0 100644 --- a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp @@ -97,7 +97,9 @@ static const std::map> SPIRV::Extension::Extension:: SPV_INTEL_subgroup_matrix_multiply_accumulate}, {"SPV_INTEL_ternary_bitwise_function", - SPIRV::Extension::Extension::SPV_INTEL_ternary_bitwise_function}}; + SPIRV::Extension::Extension::SPV_INTEL_ternary_bitwise_function}, + {"SPV_INTEL_fpga_buffer_location", + SPIRV::Extension::Extension::SPV_INTEL_fpga_buffer_location}}; bool SPIRVExtensionsParser::parse(cl::Option &O, StringRef ArgName, StringRef ArgValue, diff --git a/llvm/lib/Target/SPIRV/SPIRVMetadata.cpp b/llvm/lib/Target/SPIRV/SPIRVMetadata.cpp index 3800aac70df32..75523626b7878 100644 --- a/llvm/lib/Target/SPIRV/SPIRVMetadata.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVMetadata.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "SPIRVMetadata.h" +#include "llvm/IR/Constants.h" using namespace llvm; @@ -82,4 +83,15 @@ MDString *getOCLKernelArgTypeQual(const Function &F, unsigned ArgIdx) { return getOCLKernelArgAttribute(F, ArgIdx, "kernel_arg_type_qual"); } +int64_t processKernelArgBufferLocation( + const Function &F, MDNode *Node, int i, + llvm::ArrayRef> VRegs, int64_t BufferLoc) { + if (Node && static_cast(i) < Node->getNumOperands()) + if (auto *CI = dyn_cast( + cast(Node->getOperand(i))->getValue())) + if (F.getFunctionType()->getParamType(i)->isPointerTy()) + return CI->getSExtValue(); + return BufferLoc; +} + } // namespace llvm diff --git a/llvm/lib/Target/SPIRV/SPIRVMetadata.h b/llvm/lib/Target/SPIRV/SPIRVMetadata.h index fb4269457d6dd..22f8cacc062c7 100644 --- a/llvm/lib/Target/SPIRV/SPIRVMetadata.h +++ b/llvm/lib/Target/SPIRV/SPIRVMetadata.h @@ -14,6 +14,7 @@ #ifndef LLVM_LIB_TARGET_SPIRV_SPIRVMETADATA_H #define LLVM_LIB_TARGET_SPIRV_SPIRVMETADATA_H +#include "llvm/CodeGen/Register.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" @@ -25,6 +26,8 @@ namespace llvm { MDString *getOCLKernelArgAccessQual(const Function &F, unsigned ArgIdx); MDString *getOCLKernelArgTypeQual(const Function &F, unsigned ArgIdx); - +int64_t processKernelArgBufferLocation( + const Function &F, MDNode *Node, int i, + llvm::ArrayRef> VRegs, int64_t BufferLoc); } // namespace llvm #endif // LLVM_LIB_TARGET_SPIRV_METADATA_H diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp index 6d2ecd563d200..f03fb66ce7a64 100644 --- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp @@ -920,6 +920,9 @@ static void addOpDecorateReqs(const MachineInstr &MI, unsigned DecIndex, } else if (Dec == SPIRV::Decoration::FPMaxErrorDecorationINTEL) { Reqs.addRequirements(SPIRV::Capability::FPMaxErrorINTEL); Reqs.addExtension(SPIRV::Extension::SPV_INTEL_fp_max_error); + } else if (Dec == SPIRV::Decoration::BufferLocationINTEL) { + Reqs.addRequirements(SPIRV::Capability::FPGABufferLocationINTEL); + Reqs.addExtension(SPIRV::Extension::SPV_INTEL_fpga_buffer_location); } } diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td index cc32200a0a261..a151061e50f5e 100644 --- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td +++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td @@ -315,6 +315,7 @@ defm SPV_INTEL_memory_access_aliasing : ExtensionOperand<118>; defm SPV_INTEL_fp_max_error : ExtensionOperand<119>; defm SPV_INTEL_ternary_bitwise_function : ExtensionOperand<120>; defm SPV_INTEL_subgroup_matrix_multiply_accumulate : ExtensionOperand<121>; +defm SPV_INTEL_fpga_buffer_location : ExtensionOperand<122>; //===----------------------------------------------------------------------===// // Multiclass used to define Capabilities enum values and at the same time @@ -517,6 +518,7 @@ defm MemoryAccessAliasingINTEL : CapabilityOperand<5910, 0, 0, [SPV_INTEL_memory defm FPMaxErrorINTEL : CapabilityOperand<6169, 0, 0, [SPV_INTEL_fp_max_error], []>; defm TernaryBitwiseFunctionINTEL : CapabilityOperand<6241, 0, 0, [SPV_INTEL_ternary_bitwise_function], []>; defm SubgroupMatrixMultiplyAccumulateINTEL : CapabilityOperand<6236, 0, 0, [SPV_INTEL_subgroup_matrix_multiply_accumulate], []>; +defm FPGABufferLocationINTEL : CapabilityOperand<5920, 0, 0, [SPV_INTEL_fpga_buffer_location], []>; //===----------------------------------------------------------------------===// // Multiclass used to define SourceLanguage enum values and at the same time @@ -1268,6 +1270,7 @@ defm FunctionFloatingPointModeINTEL : DecorationOperand<6080, 0, 0, [], [Functio defm AliasScopeINTEL : DecorationOperand<5914, 0, 0, [], [MemoryAccessAliasingINTEL]>; defm NoAliasINTEL : DecorationOperand<5915, 0, 0, [], [MemoryAccessAliasingINTEL]>; defm FPMaxErrorDecorationINTEL : DecorationOperand<6170, 0, 0, [], [FPMaxErrorINTEL]>; +defm BufferLocationINTEL : DecorationOperand<5921, 0, 0, [SPV_INTEL_fpga_buffer_location], [FPGABufferLocationINTEL]>; //===----------------------------------------------------------------------===// // Multiclass used to define BuiltIn enum values and at the same time diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_fpga_buffer_location/FPGABufferLocation.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_fpga_buffer_location/FPGABufferLocation.ll new file mode 100644 index 0000000000000..8fe5174e9a74f --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_fpga_buffer_location/FPGABufferLocation.ll @@ -0,0 +1,115 @@ +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_INTEL_fpga_buffer_location %s -o %t.spt +; RUN: FileCheck %s --input-file=%t.spt +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_INTEL_fpga_buffer_location %s -o - -filetype=obj | spirv-val %} + +; CHECK-DAG: OpCapability FPGABufferLocationINTEL +; CHECK-DAG: OpExtension "SPV_INTEL_fpga_buffer_location" +; CHECK-DAG: OpName %[[#ARGA:]] "a" +; CHECK-DAG: OpName %[[#ARGB:]] "b" +; CHECK-DAG: OpName %[[#ARGC:]] "c" +; CHECK-DAG: OpName %[[#ARGD:]] "d" +; CHECK-DAG: OpName %[[#ARGE:]] "e" +; CHECK-NOT: OpDecorate %[[#ARGC]] BufferLocationINTEL -1 +; CHECK-NOT: OpDecorate %[[#ARGC]] BufferLocationINTEL -1 +; CHECK-DAG: OpDecorate %[[#ARGA]] BufferLocationINTEL 1 +; CHECK-DAG: OpDecorate %[[#ARGB]] BufferLocationINTEL 2 +; CHECK-NOT: OpDecorate %[[#ARGD]] BufferLocationINTEL -1 +; CHECK-NOT: OpDecorate %[[#ARGE]] BufferLocationINTEL 3 +; CHECK-DAG: OpDecorate %[[#]] BufferLocationINTEL 123456789 + +; CHECK-DAG: %[[#]] = OpFunction +; CHECK-DAG: %[[#ARGA]] = OpFunctionParameter %[[#]] +; CHECK-DAG: %[[#ARGB]] = OpFunctionParameter %[[#]] +; CHECK-DAG: %[[#ARGC]] = OpFunctionParameter %[[#]] + + + + +%struct.MyIP = type { ptr addrspace(4) } + +@.str.4 = internal unnamed_addr addrspace(1) constant [19 x i8] c"{5921:\22123456789\22}\00" +@.str.1 = internal unnamed_addr addrspace(1) constant [9 x i8] c"main.cpp\00" + +; Function Attrs: nounwind +define spir_kernel void @test(ptr addrspace(1) %a, ptr addrspace(1) %b, ptr addrspace(1) %c, i32 %d, i32 %e) local_unnamed_addr !kernel_arg_addr_space !3 !kernel_arg_access_qual !4 !kernel_arg_type !5 !kernel_arg_base_type !5 !kernel_arg_buffer_location !6 +{ +entry: + ret void +} + +; test1 : direct on kernel argument +; Function Attrs: norecurse nounwind readnone +define spir_kernel void @test.1(ptr addrspace(4) %a) #0 +{ +entry: + %0 = call ptr addrspace(4) @llvm.ptr.annotation.p4.p1(ptr addrspace(4) %a, ptr addrspace(1) getelementptr inbounds ([19 x i8], ptr addrspace(1) @.str.4, i32 0, i32 0), ptr addrspace(1) getelementptr inbounds ([9 x i8], ptr addrspace(1) @.str.1, i32 0, i32 0), i32 7, ptr addrspace(1) null) + store i8 0, ptr addrspace(4) %0, align 8 + ret void +} + +$test.2 = comdat any +; test2 : general +; Function Attrs: convergent mustprogress norecurse +define weak_odr dso_local spir_kernel void @test.2(ptr addrspace(1) align 4 %arg_a) #0 comdat !kernel_arg_buffer_location !7 { +entry: + %this.addr.i = alloca ptr addrspace(4), align 8 + %arg_a.addr = alloca ptr addrspace(1), align 8 + %MyIP = alloca %struct.MyIP, align 8 + %arg_a.addr.ascast = addrspacecast ptr %arg_a.addr to ptr addrspace(4) + %MyIP.ascast = addrspacecast ptr %MyIP to ptr addrspace(4) + store ptr addrspace(1) %arg_a, ptr addrspace(4) %arg_a.addr.ascast, align 8 + %a = getelementptr inbounds %struct.MyIP, ptr addrspace(4) %MyIP.ascast, i32 0, i32 0 + %0 = call ptr addrspace(4) @llvm.ptr.annotation.p4.p1(ptr addrspace(4) %a, ptr addrspace(1) getelementptr inbounds ([33 x i8], ptr addrspace(1) @.str.4, i32 0, i32 0), ptr addrspace(1) getelementptr inbounds ([9 x i8], ptr addrspace(1) @.str.1, i32 0, i32 0), i32 7, ptr addrspace(1) null) + %b = load ptr addrspace(1), ptr addrspace(4) %arg_a.addr.ascast, align 8 + %1 = addrspacecast ptr addrspace(1) %b to ptr addrspace(4) + store ptr addrspace(4) %1, ptr addrspace(4) %0, align 8 + %this.addr.ascast.i = addrspacecast ptr %this.addr.i to ptr addrspace(4) + store ptr addrspace(4) %MyIP.ascast, ptr addrspace(4) %this.addr.ascast.i, align 8 + %this1.i = load ptr addrspace(4), ptr addrspace(4) %this.addr.ascast.i, align 8 + %a.i = getelementptr inbounds %struct.MyIP, ptr addrspace(4) %this1.i, i32 0, i32 0 + %2 = call ptr addrspace(4) @llvm.ptr.annotation.p4.p1(ptr addrspace(4) %a.i, ptr addrspace(1) getelementptr inbounds ([19 x i8], ptr addrspace(1) @.str.4, i32 0, i32 0), ptr addrspace(1) getelementptr inbounds ([9 x i8], ptr addrspace(1) @.str.1, i32 0, i32 0), i32 7, ptr addrspace(1) null) + %3 = load ptr addrspace(4), ptr addrspace(4) %2, align 8 + %4 = load i32, ptr addrspace(4) %3, align 4 + %inc.i = add nsw i32 %4, 1 + store i32 %inc.i, ptr addrspace(4) %3, align 4 + ret void +} + +; test3 : memcpy +; Function Attrs: convergent mustprogress norecurse +define spir_kernel void @test.3(ptr addrspace(1) align 4 %arg_a, ptr %arg_b) { +entry: + %this.addr.i = alloca ptr addrspace(4), align 8 + %arg_a.addr = alloca ptr addrspace(1), align 8 + %MyIP = alloca %struct.MyIP, align 8 + %arg_a.addr.ascast = addrspacecast ptr %arg_a.addr to ptr addrspace(4) + %MyIP.ascast = addrspacecast ptr %MyIP to ptr addrspace(4) + store ptr addrspace(1) %arg_a, ptr addrspace(4) %arg_a.addr.ascast, align 8 + %a = getelementptr inbounds %struct.MyIP, ptr addrspace(4) %MyIP.ascast, i32 0, i32 0 + %0 = call ptr addrspace(4) @llvm.ptr.annotation.p4.p1(ptr addrspace(4) %a, ptr addrspace(1) getelementptr inbounds ([19 x i8], ptr addrspace(1) @.str.4, i32 0, i32 0), ptr addrspace(1) getelementptr inbounds ([9 x i8], ptr addrspace(1) @.str.1, i32 0, i32 0), i32 7, ptr addrspace(1) null) + call void @llvm.memcpy.p4.p0(ptr addrspace(4) %0, ptr %arg_b, i64 4, i1 false) + ret void +} + +; Function Attrs: nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite) +declare ptr addrspace(4) @llvm.ptr.annotation.p4.p1(ptr addrspace(4), ptr addrspace(1), ptr addrspace(1), i32, ptr addrspace(1)) #1 + +; Function Attrs: argmemonly nofree nounwind willreturn +declare void @llvm.memcpy.p4.p0(ptr addrspace(4) noalias captures(none) writeonly, ptr noalias captures(none) readonly, i64, i1 immarg) #2 + +!opencl.enable.FP_CONTRACT = !{} +!opencl.ocl.version = !{!0} +!opencl.spir.version = !{!0} +!opencl.used.extensions = !{!1} +!opencl.used.optional.core.features = !{!1} +!opencl.compiler.options = !{!1} +!llvm.ident = !{!2} + +!0 = !{i32 2, i32 0} +!1 = !{} +!2 = !{!""} +!3 = !{i32 1, i32 1, i32 1} +!4 = !{!"none", !"none", !"none"} +!5 = !{!"int*", !"float*", !"int*"} +!6 = !{i32 1, i32 2, i32 -1, i32 -1, i32 3} +!7 = !{i32 -1} diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_fpga_buffer_location/sycl-buffer-location-with-ptr-annotation.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_fpga_buffer_location/sycl-buffer-location-with-ptr-annotation.ll new file mode 100644 index 0000000000000..6a00047b47d66 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_fpga_buffer_location/sycl-buffer-location-with-ptr-annotation.ll @@ -0,0 +1,83 @@ +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_INTEL_fpga_buffer_location %s -o %t.spt +; RUN: FileCheck %s --input-file=%t.spt +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-ext=+SPV_INTEL_fpga_buffer_location %s -o - -filetype=obj | spirv-val %} + +; CHECK-DAG: OpDecorate %[[#Ptr1:]] BufferLocationINTEL 0 +; CHECK-DAG: OpDecorate %[[#Ptr2:]] BufferLocationINTEL 0 + +; CHECK-DAG: %[[#Ptr1]] = OpLoad %[[#]] +; CHECK-DAG: OpReturnValue %[[#Ptr1]] + +; CHECK-DAG: %[[#Bitcast:]] = OpBitcast %[[#]] %[[#]] +; CHECK-DAG: %[[#Ptr2]] = OpInBoundsPtrAccessChain %[[#]] %[[#Bitcast]] %[[#]] %[[#]] +; CHECK-DAG: OpReturnValue %[[#Ptr2]] + + +%struct.MyIP = type <{ ptr addrspace(4), i32, [4 x i8] }> + +$_ZNK4MyIPclEv = comdat any + +$_Z8annotateIiEPT_S1_ = comdat any + +$_Z9annotate2IiEPT_S1_ = comdat any + +@.str = private unnamed_addr addrspace(1) constant [16 x i8] c"sycl-properties\00", section "llvm.metadata" +@.str.1 = private unnamed_addr addrspace(1) constant [9 x i8] c"test.cpp\00", section "llvm.metadata" +@.str.2 = private unnamed_addr addrspace(1) constant [21 x i8] c"sycl-buffer-location\00", section "llvm.metadata" +@.str.3 = private unnamed_addr addrspace(1) constant [2 x i8] c"0\00", section "llvm.metadata" +@.args = private unnamed_addr addrspace(1) constant { ptr addrspace(1), ptr addrspace(1) } { ptr addrspace(1) @.str.2, ptr addrspace(1) @.str.3 }, section "llvm.metadata" +@.str.4 = private unnamed_addr addrspace(1) constant [11 x i8] c"{5921:\220\22}\00", section "llvm.metadata" + +; Function Attrs: convergent mustprogress noinline norecurse nounwind optnone +define linkonce_odr dso_local spir_func void @_ZNK4MyIPclEv(ptr addrspace(4) %this) comdat align 2 !srcloc !8 { +entry: + %call1 = call spir_func noundef ptr addrspace(4) @_Z8annotateIiEPT_S1_(ptr addrspace(4) noundef %this) + %call2 = call spir_func noundef ptr addrspace(4) @_Z9annotate2IiEPT_S1_(ptr addrspace(4) noundef %this) + ret void +} + +; Function Attrs: convergent mustprogress noinline norecurse nounwind optnone +define linkonce_odr dso_local spir_func noundef ptr addrspace(4) @_Z8annotateIiEPT_S1_(ptr addrspace(4) noundef %ptr) comdat !srcloc !9 { +entry: + %retval = alloca ptr addrspace(4), align 8 + %ptr.addr = alloca ptr addrspace(4), align 8 + %retval.ascast = addrspacecast ptr %retval to ptr addrspace(4) + %ptr.addr.ascast = addrspacecast ptr %ptr.addr to ptr addrspace(4) + store ptr addrspace(4) %ptr, ptr addrspace(4) %ptr.addr.ascast, align 8 + %0 = load ptr addrspace(4), ptr addrspace(4) %ptr.addr.ascast, align 8 + %1 = call ptr addrspace(4) @llvm.ptr.annotation.p4.p1(ptr addrspace(4) %0, ptr addrspace(1) @.str.4, ptr addrspace(1) @.str.1, i32 25, ptr addrspace(1) null) + ret ptr addrspace(4) %1 +} + +; Function Attrs: convergent mustprogress noinline norecurse nounwind optnone +define linkonce_odr dso_local spir_func noundef ptr addrspace(4) @_Z9annotate2IiEPT_S1_(ptr addrspace(4) noundef %ptr) comdat !srcloc !9 { +entry: + %retval = alloca ptr addrspace(4), align 8 + %ptr.addr = alloca ptr addrspace(4), align 8 + %retval.ascast = addrspacecast ptr %retval to ptr addrspace(4) + %ptr.addr.ascast = addrspacecast ptr %ptr.addr to ptr addrspace(4) + store ptr addrspace(4) %ptr, ptr addrspace(4) %ptr.addr.ascast, align 8 + %0 = load ptr addrspace(4), ptr addrspace(4) %ptr.addr.ascast, align 8 + %1 = getelementptr inbounds %struct.MyIP, ptr addrspace(4) %0, i32 0, i32 0 + %2 = call ptr addrspace(4) @llvm.ptr.annotation.p4.p1(ptr addrspace(4) %1, ptr addrspace(1) @.str.4, ptr addrspace(1) @.str.1, i32 25, ptr addrspace(1) null) + ret ptr addrspace(4) %2 +} + +; Function Attrs: nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: readwrite) +declare ptr addrspace(4) @llvm.ptr.annotation.p4.p1(ptr addrspace(4), ptr addrspace(1), ptr addrspace(1), i32, ptr addrspace(1)) + +!llvm.module.flags = !{!0, !1} +!opencl.spir.version = !{!2} +!spirv.Source = !{!3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 7, !"frame-pointer", i32 2} +!2 = !{i32 1, i32 2} +!3 = !{i32 4, i32 100000} +!4 = !{!"Intel(R) oneAPI DPC++/C++ Compiler 2024.2.0 (2024.x.0.YYYYMMDD)"} +!5 = !{i32 717} +!6 = !{i32 -1, i32 -1} +!7 = !{} +!8 = !{i32 1004} +!9 = !{i32 563}