[SPIR-V] Add SPV_INTEL_predicated_io extension (#161591)
This PR introduces the support for the SPIR-V extension `SPV_INTEL_predicated_io`. This extension adds predicated load and store instructions. Predicated load performs load from memory if predicate is true; otherwise, it uses default_value as a result. Predicated store performs store of value to memory if predicate is true; otherwise, it does nothing. Reference Specification: https://github.com/intel/llvm/blob/sycl/sycl/doc/design/spirv-extensions/SPV_INTEL_predicated_io.asciidoc
This commit is contained in:
parent
86ad98c37a
commit
f802acf32d
@ -233,6 +233,8 @@ Below is a list of supported SPIR-V extensions, sorted alphabetically by their e
|
||||
- Adds support for 4-bit integer type, and allow this type to be used in cooperative matrices.
|
||||
* - ``SPV_KHR_float_controls2``
|
||||
- Adds execution modes and decorations to control floating-point computations in both kernels and shaders. It can be used on whole modules and individual instructions.
|
||||
* - ``SPV_INTEL_predicated_io``
|
||||
- Adds predicated load and store instructions that conditionally read from or write to memory based on a boolean predicate.
|
||||
|
||||
SPIR-V representation in LLVM IR
|
||||
================================
|
||||
|
||||
@ -284,6 +284,17 @@ void SPIRVInstPrinter::printInst(const MCInst *MI, uint64_t Address,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SPIRV::OpPredicatedLoadINTEL:
|
||||
case SPIRV::OpPredicatedStoreINTEL: {
|
||||
const unsigned NumOps = MI->getNumOperands();
|
||||
if (NumOps > NumFixedOps) {
|
||||
OS << ' ';
|
||||
printSymbolicOperand<OperandCategory::MemoryOperandOperand>(
|
||||
MI, NumOps - 1, OS);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printRemainingVariableOps(MI, NumFixedOps, OS);
|
||||
break;
|
||||
|
||||
@ -2419,6 +2419,27 @@ static bool generatePipeInst(const SPIRV::IncomingCall *Call,
|
||||
return buildPipeInst(Call, Opcode, Scope, MIRBuilder, GR);
|
||||
}
|
||||
|
||||
static bool generatePredicatedLoadStoreInst(const SPIRV::IncomingCall *Call,
|
||||
MachineIRBuilder &MIRBuilder,
|
||||
SPIRVGlobalRegistry *GR) {
|
||||
const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
|
||||
unsigned Opcode =
|
||||
SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
|
||||
|
||||
bool IsSet = Opcode != SPIRV::OpPredicatedStoreINTEL;
|
||||
unsigned ArgSz = Call->Arguments.size();
|
||||
SmallVector<uint32_t, 1> ImmArgs;
|
||||
MachineRegisterInfo *MRI = MIRBuilder.getMRI();
|
||||
// Memory operand is optional and is literal.
|
||||
if (ArgSz > 3)
|
||||
ImmArgs.push_back(
|
||||
getConstFromIntrinsic(Call->Arguments[/*Literal index*/ 3], MRI));
|
||||
|
||||
Register TypeReg = GR->getSPIRVTypeID(Call->ReturnType);
|
||||
return buildOpFromWrapper(MIRBuilder, Opcode, Call,
|
||||
IsSet ? TypeReg : Register(0), ImmArgs);
|
||||
}
|
||||
|
||||
static bool buildNDRange(const SPIRV::IncomingCall *Call,
|
||||
MachineIRBuilder &MIRBuilder,
|
||||
SPIRVGlobalRegistry *GR) {
|
||||
@ -3019,6 +3040,8 @@ std::optional<bool> lowerBuiltin(const StringRef DemangledCall,
|
||||
return generate2DBlockIOINTELInst(Call.get(), MIRBuilder, GR);
|
||||
case SPIRV::Pipe:
|
||||
return generatePipeInst(Call.get(), MIRBuilder, GR);
|
||||
case SPIRV::PredicatedLoadStore:
|
||||
return generatePredicatedLoadStoreInst(Call.get(), MIRBuilder, GR);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -70,6 +70,7 @@ def BindlessINTEL : BuiltinGroup;
|
||||
def TernaryBitwiseINTEL : BuiltinGroup;
|
||||
def Block2DLoadStore : BuiltinGroup;
|
||||
def Pipe : BuiltinGroup;
|
||||
def PredicatedLoadStore : BuiltinGroup;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Class defining a demangled builtin record. The information in the record
|
||||
@ -752,6 +753,10 @@ defm : DemangledNativeBuiltin<"__spirv_Subgroup2DBlockLoadTransformINTEL", OpenC
|
||||
defm : DemangledNativeBuiltin<"__spirv_Subgroup2DBlockPrefetchINTEL", OpenCL_std, Block2DLoadStore, 9, 9, OpSubgroup2DBlockPrefetchINTEL>;
|
||||
defm : DemangledNativeBuiltin<"__spirv_Subgroup2DBlockStoreINTEL", OpenCL_std, Block2DLoadStore, 10, 10, OpSubgroup2DBlockStoreINTEL>;
|
||||
|
||||
// SPV_INTEL_predicated_io builtin records
|
||||
defm : DemangledNativeBuiltin<"__spirv_PredicatedLoadINTEL", OpenCL_std, PredicatedLoadStore, 3, 4, OpPredicatedLoadINTEL>;
|
||||
defm : DemangledNativeBuiltin<"__spirv_PredicatedStoreINTEL", OpenCL_std, PredicatedLoadStore, 3, 4, OpPredicatedStoreINTEL>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Class defining a work/sub group builtin that should be translated into a
|
||||
// SPIR-V instruction using the defined properties.
|
||||
|
||||
@ -151,7 +151,9 @@ static const std::map<std::string, SPIRV::Extension::Extension, std::less<>>
|
||||
{"SPV_KHR_bfloat16", SPIRV::Extension::Extension::SPV_KHR_bfloat16},
|
||||
{"SPV_EXT_relaxed_printf_string_address_space",
|
||||
SPIRV::Extension::Extension::
|
||||
SPV_EXT_relaxed_printf_string_address_space}};
|
||||
SPV_EXT_relaxed_printf_string_address_space},
|
||||
{"SPV_INTEL_predicated_io",
|
||||
SPIRV::Extension::Extension::SPV_INTEL_predicated_io}};
|
||||
|
||||
bool SPIRVExtensionsParser::parse(cl::Option &O, StringRef ArgName,
|
||||
StringRef ArgValue,
|
||||
|
||||
@ -987,3 +987,9 @@ def OpSubgroup2DBlockPrefetchINTEL: Op<6234, (outs), (ins ID:$element_size, ID:$
|
||||
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">;
|
||||
|
||||
// SPV_INTEL_predicated_io
|
||||
def OpPredicatedLoadINTEL: Op<6528, (outs ID:$res), (ins TYPE:$resType, ID:$ptr, ID:$predicate, ID:$default_value, variable_ops),
|
||||
"$res = OpPredicatedLoadINTEL $resType $ptr $predicate $default_value">;
|
||||
def OpPredicatedStoreINTEL: Op<6529, (outs), (ins ID:$ptr, ID:$object, ID:$predicate, variable_ops),
|
||||
"OpPredicatedStoreINTEL $ptr $object $predicate">;
|
||||
|
||||
@ -2035,6 +2035,17 @@ void addInstrRequirements(const MachineInstr &MI,
|
||||
// TODO: Add UntypedPointersKHR when implemented.
|
||||
break;
|
||||
}
|
||||
case SPIRV::OpPredicatedLoadINTEL:
|
||||
case SPIRV::OpPredicatedStoreINTEL: {
|
||||
if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_predicated_io))
|
||||
report_fatal_error(
|
||||
"OpPredicated[Load/Store]INTEL instructions require "
|
||||
"the following SPIR-V extension: SPV_INTEL_predicated_io",
|
||||
false);
|
||||
Reqs.addExtension(SPIRV::Extension::SPV_INTEL_predicated_io);
|
||||
Reqs.addCapability(SPIRV::Capability::PredicatedIOINTEL);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
@ -385,6 +385,7 @@ defm SPV_INTEL_int4 : ExtensionOperand<123, [EnvOpenCL]>;
|
||||
defm SPV_KHR_float_controls2 : ExtensionOperand<124, [EnvVulkan, EnvOpenCL]>;
|
||||
defm SPV_INTEL_tensor_float32_conversion : ExtensionOperand<125, [EnvOpenCL]>;
|
||||
defm SPV_KHR_bfloat16 : ExtensionOperand<126, [EnvVulkan, EnvOpenCL]>;
|
||||
defm SPV_INTEL_predicated_io : ExtensionOperand<127, [EnvOpenCL]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Multiclass used to define Capabilities enum values and at the same time
|
||||
@ -594,6 +595,7 @@ defm SubgroupMatrixMultiplyAccumulateINTEL : CapabilityOperand<6236, 0, 0, [SPV_
|
||||
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]>;
|
||||
defm PredicatedIOINTEL : CapabilityOperand<6257, 0, 0, [SPV_INTEL_predicated_io], []>;
|
||||
defm Int4TypeINTEL : CapabilityOperand<5112, 0, 0, [SPV_INTEL_int4], []>;
|
||||
defm Int4CooperativeMatrixINTEL : CapabilityOperand<5114, 0, 0, [SPV_INTEL_int4], [Int4TypeINTEL, CooperativeMatrixKHR]>;
|
||||
defm TensorFloat32RoundingINTEL : CapabilityOperand<6425, 0, 0, [SPV_INTEL_tensor_float32_conversion], []>;
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
; RUN: not llc -O0 -mtriple=spirv64-unknown-unknown %s -o %t.spvt 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
|
||||
; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_INTEL_predicated_io %s -o - | FileCheck %s
|
||||
|
||||
; CHECK-ERROR: LLVM ERROR: OpPredicated[Load/Store]INTEL
|
||||
; CHECK-ERROR-SAME: instructions require the following SPIR-V extension: SPV_INTEL_predicated_io
|
||||
|
||||
; CHECK-DAG: Capability PredicatedIOINTEL
|
||||
; CHECK-DAG: Extension "SPV_INTEL_predicated_io"
|
||||
|
||||
; CHECK-DAG: %[[Int32Ty:[0-9]+]] = OpTypeInt 32 0
|
||||
; CHECK-DAG: %[[IntPtrTy:[0-9]+]] = OpTypePointer CrossWorkgroup %[[Int32Ty]]
|
||||
; CHECK-DAG: %[[BoolTy:[0-9]+]] = OpTypeBool
|
||||
; CHECK-DAG: %[[VoidTy:[0-9]+]] = OpTypeVoid
|
||||
; CHECK: %[[LoadPtr:[0-9]+]] = OpFunctionParameter %[[IntPtrTy]]
|
||||
; CHECK: %[[StorePtr:[0-9]+]] = OpFunctionParameter %[[IntPtrTy]]
|
||||
; CHECK: %[[DefaultVal:[0-9]+]] = OpFunctionParameter %[[Int32Ty]]
|
||||
; CHECK: %[[StoreObj:[0-9]+]] = OpFunctionParameter %[[Int32Ty]]
|
||||
; CHECK: %[[Predicate:[0-9]+]] = OpFunctionParameter %[[BoolTy]]
|
||||
; CHECK: PredicatedLoadINTEL %[[Int32Ty]] %[[LoadPtr]] %[[Predicate]] %[[DefaultVal]]
|
||||
; CHECK: PredicatedLoadINTEL %[[Int32Ty]] %[[LoadPtr]] %[[Predicate]] %[[DefaultVal]] None
|
||||
; CHECK: PredicatedStoreINTEL %[[StorePtr]] %[[StoreObj]] %[[Predicate]]
|
||||
; CHECK: PredicatedStoreINTEL %[[StorePtr]] %[[StoreObj]] %[[Predicate]] None
|
||||
|
||||
define spir_func void @foo(ptr addrspace(1) %load_pointer, ptr addrspace(1) %store_pointer, i32 %default_value, i32 %store_object, i1 zeroext %predicate) {
|
||||
entry:
|
||||
%1 = call spir_func i32 @_Z27__spirv_PredicatedLoadINTELPU3AS1Kibi(ptr addrspace(1) %load_pointer, i1 %predicate, i32 %default_value)
|
||||
%2 = call spir_func i32 @_Z27__spirv_PredicatedLoadINTELPU3AS1Kibii(ptr addrspace(1) %load_pointer, i1 %predicate, i32 %default_value, i32 0)
|
||||
call spir_func void @_Z28__spirv_PredicatedStoreINTELPU3AS1Kiib(ptr addrspace(1) %store_pointer, i32 %store_object, i1 %predicate)
|
||||
call spir_func void @_Z28__spirv_PredicatedStoreINTELPU3AS1Kiibi(ptr addrspace(1) %store_pointer, i32 %store_object, i1 %predicate, i32 0)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare spir_func i32 @_Z27__spirv_PredicatedLoadINTELPU3AS1Kibi(ptr addrspace(1), i1, i32)
|
||||
declare spir_func i32 @_Z27__spirv_PredicatedLoadINTELPU3AS1Kibii(ptr addrspace(1), i1, i32, i32)
|
||||
declare spir_func void @_Z28__spirv_PredicatedStoreINTELPU3AS1Kiib(ptr addrspace(1), i32, i1)
|
||||
declare spir_func void @_Z28__spirv_PredicatedStoreINTELPU3AS1Kiibi(ptr addrspace(1), i32, i1, i32)
|
||||
Loading…
x
Reference in New Issue
Block a user