diff --git a/llvm/docs/SPIRVUsage.rst b/llvm/docs/SPIRVUsage.rst index f58587314e6b5..6e4c49e21d109 100644 --- a/llvm/docs/SPIRVUsage.rst +++ b/llvm/docs/SPIRVUsage.rst @@ -153,6 +153,8 @@ list of supported SPIR-V extensions, sorted alphabetically by their extension na - Adds atomic add instruction on floating-point numbers. * - ``SPV_EXT_shader_atomic_float_min_max`` - Adds atomic min and max instruction on floating-point numbers. + * - ``SPV_INTEL_2d_block_io`` + - Adds additional subgroup block prefetch, load, load transposed, load transformed and store instructions to read two-dimensional blocks of data from a two-dimensional region of memory, or to write two-dimensional blocks of data to a two dimensional region of memory. * - ``SPV_INTEL_arbitrary_precision_integers`` - Allows generating arbitrary width integer types. * - ``SPV_INTEL_bindless_images`` diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp index e3ba0fb80979f..47a1968f6cd63 100644 --- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp @@ -1058,6 +1058,24 @@ static bool buildBindlessImageINTELInst(const SPIRV::IncomingCall *Call, return true; } +/// Helper function for building Intel's 2d block io instructions. +static bool build2DBlockIOINTELInst(const SPIRV::IncomingCall *Call, + unsigned Opcode, + MachineIRBuilder &MIRBuilder, + SPIRVGlobalRegistry *GR) { + // Generate SPIRV instruction accordingly. + if (Call->isSpirvOp()) + return buildOpFromWrapper(MIRBuilder, Opcode, Call, Register(0)); + + auto MIB = MIRBuilder.buildInstr(Opcode) + .addDef(Call->ReturnRegister) + .addUse(GR->getSPIRVTypeID(Call->ReturnType)); + for (unsigned i = 0; i < Call->Arguments.size(); ++i) + MIB.addUse(Call->Arguments[i]); + + return true; +} + static unsigned getNumComponentsForDim(SPIRV::Dim::Dim dim) { switch (dim) { case SPIRV::Dim::DIM_1D: @@ -2264,6 +2282,17 @@ static bool generateBindlessImageINTELInst(const SPIRV::IncomingCall *Call, return buildBindlessImageINTELInst(Call, Opcode, MIRBuilder, GR); } +static bool generate2DBlockIOINTELInst(const SPIRV::IncomingCall *Call, + MachineIRBuilder &MIRBuilder, + SPIRVGlobalRegistry *GR) { + // Lookup the instruction opcode in the TableGen records. + const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; + unsigned Opcode = + SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode; + + return build2DBlockIOINTELInst(Call, Opcode, MIRBuilder, GR); +} + static bool buildNDRange(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR) { @@ -2845,6 +2874,8 @@ std::optional lowerBuiltin(const StringRef DemangledCall, return generateExtendedBitOpsInst(Call.get(), MIRBuilder, GR); case SPIRV::BindlessINTEL: return generateBindlessImageINTELInst(Call.get(), MIRBuilder, GR); + case SPIRV::Block2DLoadStore: + return generate2DBlockIOINTELInst(Call.get(), MIRBuilder, GR); } return false; } diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.td b/llvm/lib/Target/SPIRV/SPIRVBuiltins.td index c9a5c92ee3a66..c5246235adff6 100644 --- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.td +++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.td @@ -67,6 +67,7 @@ def CoopMatr : BuiltinGroup; def ICarryBorrow : BuiltinGroup; def ExtendedBitOps : BuiltinGroup; def BindlessINTEL : BuiltinGroup; +def Block2DLoadStore : BuiltinGroup; //===----------------------------------------------------------------------===// // Class defining a demangled builtin record. The information in the record @@ -714,6 +715,13 @@ defm : DemangledNativeBuiltin<"__spirv_ConvertHandleToImageINTEL", OpenCL_std, B defm : DemangledNativeBuiltin<"__spirv_ConvertHandleToSamplerINTEL", OpenCL_std, BindlessINTEL, 1, 1, OpConvertHandleToSamplerINTEL>; defm : DemangledNativeBuiltin<"__spirv_ConvertHandleToSampledImageINTEL", OpenCL_std, BindlessINTEL, 1, 1, OpConvertHandleToSampledImageINTEL>; +// SPV_INTEL_2d_block_io builtin records +defm : DemangledNativeBuiltin<"__spirv_Subgroup2DBlockLoadINTEL", OpenCL_std, Block2DLoadStore, 10, 10, OpSubgroup2DBlockLoadINTEL>; +defm : DemangledNativeBuiltin<"__spirv_Subgroup2DBlockLoadTransposeINTEL", OpenCL_std, Block2DLoadStore, 10, 10, OpSubgroup2DBlockLoadTransposeINTEL>; +defm : DemangledNativeBuiltin<"__spirv_Subgroup2DBlockLoadTransformINTEL", OpenCL_std, Block2DLoadStore, 10, 10, OpSubgroup2DBlockLoadTransformINTEL>; +defm : DemangledNativeBuiltin<"__spirv_Subgroup2DBlockPrefetchINTEL", OpenCL_std, Block2DLoadStore, 9, 9, OpSubgroup2DBlockPrefetchINTEL>; +defm : DemangledNativeBuiltin<"__spirv_Subgroup2DBlockStoreINTEL", OpenCL_std, Block2DLoadStore, 10, 10, OpSubgroup2DBlockStoreINTEL>; + //===----------------------------------------------------------------------===// // Class defining a work/sub group builtin that should be translated into a // SPIR-V instruction using the defined properties. diff --git a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp index 8b9201ee7dae3..a7308fe9ba741 100644 --- a/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp @@ -92,7 +92,9 @@ static const std::map> {"SPV_INTEL_long_composites", SPIRV::Extension::Extension::SPV_INTEL_long_composites}, {"SPV_INTEL_fp_max_error", - SPIRV::Extension::Extension::SPV_INTEL_fp_max_error}}; + SPIRV::Extension::Extension::SPV_INTEL_fp_max_error}, + {"SPV_INTEL_2d_block_io", + SPIRV::Extension::Extension::SPV_INTEL_2d_block_io}}; bool SPIRVExtensionsParser::parse(cl::Option &O, StringRef ArgName, StringRef ArgValue, diff --git a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td index 14f4f53c4cca3..e7fe6980e7c0e 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td +++ b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.td @@ -928,3 +928,20 @@ def OpAliasScopeDeclINTEL: Op<5912, (outs ID:$res), (ins ID:$AliasDomain, variab "$res = OpAliasScopeDeclINTEL $AliasDomain">; def OpAliasScopeListDeclINTEL: Op<5913, (outs ID:$res), (ins variable_ops), "$res = OpAliasScopeListDeclINTEL">; + +// SPV_INTEL_2d_block_io +def OpSubgroup2DBlockLoadINTEL: Op<6231, (outs), (ins ID:$element_size, ID:$block_width, ID:$block_height, + ID:$block_count, ID:$src_base_ptr, ID:$memory_width, ID:$memory_height, ID:$memory_pitch, ID:$coord, ID:$dst_ptr), + "OpSubgroup2DBlockLoadINTEL $element_size $block_width $block_height $block_count $src_base_ptr $memory_width $memory_height $memory_pitch $coord $dst_ptr">; +def OpSubgroup2DBlockLoadTransposeINTEL: Op<6233, (outs), (ins ID:$element_size, ID:$block_width, ID:$block_height, + ID:$block_count, ID:$src_base_ptr, ID:$memory_width, ID:$memory_height, ID:$memory_pitch, ID:$coord, ID:$dst_ptr), + "OpSubgroup2DBlockLoadTransposeINTEL $element_size $block_width $block_height $block_count $src_base_ptr $memory_width $memory_height $memory_pitch $coord $dst_ptr">; +def OpSubgroup2DBlockLoadTransformINTEL: Op<6232, (outs), (ins ID:$element_size, ID:$block_width, ID:$block_height, + ID:$block_count, ID:$src_base_ptr, ID:$memory_width, ID:$memory_height, ID:$memory_pitch, ID:$coord, ID:$dst_ptr), + "OpSubgroup2DBlockLoadTransformINTEL $element_size $block_width $block_height $block_count $src_base_ptr $memory_width $memory_height $memory_pitch $coord $dst_ptr">; +def OpSubgroup2DBlockPrefetchINTEL: Op<6234, (outs), (ins ID:$element_size, ID:$block_width, ID:$block_height, + ID:$block_count, ID:$src_base_ptr, ID:$memory_width, ID:$memory_height, ID:$memory_pitch, ID:$coord), + "OpSubgroup2DBlockPrefetchINTEL $element_size $block_width $block_height $block_count $src_base_ptr $memory_width $memory_height $memory_pitch $coord">; +def OpSubgroup2DBlockStoreINTEL: Op<6235, (outs), (ins ID:$element_size, ID:$block_width, ID:$block_height, + ID:$block_count, ID:$src_ptr, ID:$dst_base_ptr, ID:$memory_width, ID:$memory_height, ID:$memory_pitch, ID:$coord), + "OpSubgroup2DBlockStoreINTEL $element_size $block_width $block_height $block_count $src_ptr $dst_base_ptr $memory_width $memory_height $memory_pitch $coord">; diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp index 8ba163ed57ed2..568086aada960 100644 --- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp @@ -1739,6 +1739,30 @@ void addInstrRequirements(const MachineInstr &MI, Reqs.addExtension(SPIRV::Extension::SPV_INTEL_bindless_images); Reqs.addCapability(SPIRV::Capability::BindlessImagesINTEL); break; + case SPIRV::OpSubgroup2DBlockLoadINTEL: + case SPIRV::OpSubgroup2DBlockLoadTransposeINTEL: + case SPIRV::OpSubgroup2DBlockLoadTransformINTEL: + case SPIRV::OpSubgroup2DBlockPrefetchINTEL: + case SPIRV::OpSubgroup2DBlockStoreINTEL: { + if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_2d_block_io)) + report_fatal_error("OpSubgroup2DBlock[Load/LoadTranspose/LoadTransform/" + "Prefetch/Store]INTEL instructions require the " + "following SPIR-V extension: SPV_INTEL_2d_block_io", + false); + Reqs.addExtension(SPIRV::Extension::SPV_INTEL_2d_block_io); + Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockIOINTEL); + + const auto OpCode = MI.getOpcode(); + if (OpCode == SPIRV::OpSubgroup2DBlockLoadTransposeINTEL) { + Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockTransposeINTEL); + break; + } + if (OpCode == SPIRV::OpSubgroup2DBlockLoadTransformINTEL) { + Reqs.addCapability(SPIRV::Capability::Subgroup2DBlockTransformINTEL); + break; + } + break; + } case SPIRV::OpKill: { Reqs.addCapability(SPIRV::Capability::Shader); } break; diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td index caee778eddbc4..1fe06885119f7 100644 --- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td +++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td @@ -313,6 +313,7 @@ defm SPV_INTEL_bindless_images : ExtensionOperand<116>; defm SPV_INTEL_long_composites : ExtensionOperand<117>; defm SPV_INTEL_memory_access_aliasing : ExtensionOperand<118>; defm SPV_INTEL_fp_max_error : ExtensionOperand<119>; +defm SPV_INTEL_2d_block_io : ExtensionOperand<120>; //===----------------------------------------------------------------------===// // Multiclass used to define Capabilities enum values and at the same time @@ -513,6 +514,9 @@ defm LongCompositesINTEL : CapabilityOperand<6089, 0, 0, [SPV_INTEL_long_composi defm BindlessImagesINTEL : CapabilityOperand<6528, 0, 0, [SPV_INTEL_bindless_images], []>; defm MemoryAccessAliasingINTEL : CapabilityOperand<5910, 0, 0, [SPV_INTEL_memory_access_aliasing], []>; defm FPMaxErrorINTEL : CapabilityOperand<6169, 0, 0, [SPV_INTEL_fp_max_error], []>; +defm Subgroup2DBlockIOINTEL : CapabilityOperand<6228, 0, 0, [SPV_INTEL_2d_block_io], []>; +defm Subgroup2DBlockTransformINTEL : CapabilityOperand<6229, 0, 0, [SPV_INTEL_2d_block_io], [Subgroup2DBlockIOINTEL]>; +defm Subgroup2DBlockTransposeINTEL : CapabilityOperand<6230, 0, 0, [SPV_INTEL_2d_block_io], [Subgroup2DBlockIOINTEL]>; //===----------------------------------------------------------------------===// // Multiclass used to define SourceLanguage enum values and at the same time diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_2d_block_io/2d_block_io_generic.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_2d_block_io/2d_block_io_generic.ll new file mode 100644 index 0000000000000..960c4e6fb9902 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_INTEL_2d_block_io/2d_block_io_generic.ll @@ -0,0 +1,47 @@ +; RUN: not llc -O0 -mtriple=spirv64-unknown-unknown %s -o %t.spvt 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR +; RUN: llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_2d_block_io %s -o - | FileCheck %s + +; CHECK-ERROR: LLVM ERROR: OpSubgroup2DBlock[Load/LoadTranspose/LoadTransform/Prefetch/Store]INTEL +; CHECK-ERROR-SAME: instructions require the following SPIR-V extension: SPV_INTEL_2d_block_io + +; CHECK: OpCapability Subgroup2DBlockIOINTEL +; CHECK: OpCapability Subgroup2DBlockTransformINTEL +; CHECK: OpCapability Subgroup2DBlockTransposeINTEL +; CHECK: OpExtension "SPV_INTEL_2d_block_io" + +; CHECK-DAG: %[[Int8Ty:[0-9]+]] = OpTypeInt 8 0 +; CHECK-DAG: %[[Int32Ty:[0-9]+]] = OpTypeInt 32 0 +; CHECK-DAG: %[[Const42:[0-9]+]] = OpConstant %[[Int32Ty]] 42 +; CHECK-DAG: %[[VoidTy:[0-9]+]] = OpTypeVoid +; CHECK-DAG: %[[GlbPtrTy:[0-9]+]] = OpTypePointer CrossWorkgroup %[[Int8Ty]] +; CHECK-DAG: %[[VectorTy:[0-9]+]] = OpTypeVector %[[Int32Ty]] 2 +; CHECK-DAG: %[[PrvPtrTy:[0-9]+]] = OpTypePointer Function %[[Int8Ty]] +; CHECK: %[[BaseSrc:[0-9]+]] = OpFunctionParameter %[[GlbPtrTy]] +; CHECK: %[[BaseDst:[0-9]+]] = OpFunctionParameter %[[GlbPtrTy]] +; CHECK: %[[Width:[0-9]+]] = OpFunctionParameter %[[Int32Ty]] +; CHECK: %[[Height:[0-9]+]] = OpFunctionParameter %[[Int32Ty]] +; CHECK: %[[Pitch:[0-9]+]] = OpFunctionParameter %[[Int32Ty]] +; CHECK: %[[Coord:[0-9]+]] = OpFunctionParameter %[[VectorTy]] +; CHECK: %[[Dst:[0-9]+]] = OpFunctionParameter %[[PrvPtrTy]] +; CHECK: %[[Src:[0-9]+]] = OpFunctionParameter %[[PrvPtrTy]] +; CHECK: OpSubgroup2DBlockLoadINTEL %[[Const42]] %[[Const42]] %[[Const42]] %[[Const42]] %[[BaseSrc]] %[[Width]] %[[Height]] %[[Pitch]] %[[Coord]] %[[Dst]] +; CHECK: OpSubgroup2DBlockLoadTransformINTEL %[[Const42]] %[[Const42]] %[[Const42]] %[[Const42]] %[[BaseSrc]] %[[Width]] %[[Height]] %[[Pitch]] %[[Coord]] %[[Dst]] +; CHECK: OpSubgroup2DBlockLoadTransposeINTEL %[[Const42]] %[[Const42]] %[[Const42]] %[[Const42]] %[[BaseSrc]] %[[Width]] %[[Height]] %[[Pitch]] %[[Coord]] %[[Dst]] +; CHECK: OpSubgroup2DBlockPrefetchINTEL %[[Const42]] %[[Const42]] %[[Const42]] %[[Const42]] %[[BaseSrc]] %[[Width]] %[[Height]] %[[Pitch]] %[[Coord]] +; CHECK: OpSubgroup2DBlockStoreINTEL %[[Const42]] %[[Const42]] %[[Const42]] %[[Const42]] %[[Src]] %[[BaseDst]] %[[Width]] %[[Height]] %[[Pitch]] %[[Coord]] + +define spir_func void @foo(ptr addrspace(1) %base_address, ptr addrspace(1) %dst_base_pointer, i32 %width, i32 %height, i32 %pitch, <2 x i32> %coord, ptr %dst_pointer, ptr %src_pointer) { +entry: + call spir_func void @_Z32__spirv_Subgroup2DBlockLoadINTELiiiiPU3AS1KviiiDv2_iPv(i32 42, i32 42, i32 42, i32 42, ptr addrspace(1) %base_address, i32 %width, i32 %height, i32 %pitch, <2 x i32> %coord, ptr %dst_pointer) + call spir_func void @_Z41__spirv_Subgroup2DBlockLoadTransformINTELiiiiPU3AS1KviiiDv2_iPv(i32 42, i32 42, i32 42, i32 42, ptr addrspace(1) %base_address, i32 %width, i32 %height, i32 %pitch, <2 x i32> %coord, ptr %dst_pointer) + call spir_func void @_Z41__spirv_Subgroup2DBlockLoadTransposeINTELiiiiPU3AS1KviiiDv2_iPv(i32 42, i32 42, i32 42, i32 42, ptr addrspace(1) %base_address, i32 %width, i32 %height, i32 %pitch, <2 x i32> %coord, ptr %dst_pointer) + call spir_func void @_Z36__spirv_Subgroup2DBlockPrefetchINTELiiiiPU3AS1KviiiDv2_i(i32 42, i32 42, i32 42, i32 42, ptr addrspace(1) %base_address, i32 %width, i32 %height, i32 %pitch, <2 x i32> %coord) + call spir_func void @_Z33__spirv_Subgroup2DBlockStoreINTELiiiiPKvPU3AS1viiiDv2_i(i32 42, i32 42, i32 42, i32 42, ptr %src_pointer, ptr addrspace(1) %dst_base_pointer, i32 %width, i32 %height, i32 %pitch, <2 x i32> %coord) + ret void +} + +declare spir_func void @_Z32__spirv_Subgroup2DBlockLoadINTELiiiiPU3AS1KviiiDv2_iPv(i32, i32, i32, i32, ptr addrspace(1), i32, i32, i32, <2 x i32>, ptr) +declare spir_func void @_Z41__spirv_Subgroup2DBlockLoadTransformINTELiiiiPU3AS1KviiiDv2_iPv(i32, i32, i32, i32, ptr addrspace(1), i32, i32, i32, <2 x i32>, ptr) +declare spir_func void @_Z41__spirv_Subgroup2DBlockLoadTransposeINTELiiiiPU3AS1KviiiDv2_iPv(i32, i32, i32, i32, ptr addrspace(1), i32, i32, i32, <2 x i32>, ptr) +declare spir_func void @_Z36__spirv_Subgroup2DBlockPrefetchINTELiiiiPU3AS1KviiiDv2_i(i32, i32, i32, i32, ptr addrspace(1), i32, i32, i32, <2 x i32>) +declare spir_func void @_Z33__spirv_Subgroup2DBlockStoreINTELiiiiPKvPU3AS1viiiDv2_i(i32, i32, i32, i32, ptr, ptr addrspace(1), i32, i32, i32, <2 x i32>)