Skip to content

Commit 89c23f7

Browse files
authored
[SPIR-V] Add cl_khr_kernel_clock / SPV_KHR_shader_clock extension (#92771)
Recognize `cl_khr_kernel_clock` builtins and translate them to `OpReadClockKHR` instructions. The `Scope` operand is deduced from the builtin function name. spirv-val does not pass yet due to OpReadClockKHR only supporting the valid scopes for Vulkan (Device and Subgroup, but not Workgroup), so leave validation disabled with a TODO.
1 parent 235465e commit 89c23f7

File tree

7 files changed

+119
-0
lines changed

7 files changed

+119
-0
lines changed

llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,39 @@ static bool generateGroupUniformInst(const SPIRV::IncomingCall *Call,
11181118
return true;
11191119
}
11201120

1121+
static bool generateKernelClockInst(const SPIRV::IncomingCall *Call,
1122+
MachineIRBuilder &MIRBuilder,
1123+
SPIRVGlobalRegistry *GR) {
1124+
const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
1125+
MachineFunction &MF = MIRBuilder.getMF();
1126+
const auto *ST = static_cast<const SPIRVSubtarget *>(&MF.getSubtarget());
1127+
if (!ST->canUseExtension(SPIRV::Extension::SPV_KHR_shader_clock)) {
1128+
std::string DiagMsg = std::string(Builtin->Name) +
1129+
": the builtin requires the following SPIR-V "
1130+
"extension: SPV_KHR_shader_clock";
1131+
report_fatal_error(DiagMsg.c_str(), false);
1132+
}
1133+
1134+
MachineRegisterInfo *MRI = MIRBuilder.getMRI();
1135+
Register ResultReg = Call->ReturnRegister;
1136+
MRI->setRegClass(ResultReg, &SPIRV::IDRegClass);
1137+
1138+
// Deduce the `Scope` operand from the builtin function name.
1139+
SPIRV::Scope::Scope ScopeArg =
1140+
StringSwitch<SPIRV::Scope::Scope>(Builtin->Name)
1141+
.EndsWith("device", SPIRV::Scope::Scope::Device)
1142+
.EndsWith("work_group", SPIRV::Scope::Scope::Workgroup)
1143+
.EndsWith("sub_group", SPIRV::Scope::Scope::Subgroup);
1144+
Register ScopeReg = buildConstantIntReg(ScopeArg, MIRBuilder, GR);
1145+
1146+
MIRBuilder.buildInstr(SPIRV::OpReadClockKHR)
1147+
.addDef(ResultReg)
1148+
.addUse(GR->getSPIRVTypeID(Call->ReturnType))
1149+
.addUse(ScopeReg);
1150+
1151+
return true;
1152+
}
1153+
11211154
// These queries ask for a single size_t result for a given dimension index, e.g
11221155
// size_t get_global_id(uint dimindex). In SPIR-V, the builtins corresonding to
11231156
// these values are all vec3 types, so we need to extract the correct index or
@@ -2290,6 +2323,8 @@ std::optional<bool> lowerBuiltin(const StringRef DemangledCall,
22902323
return generateIntelSubgroupsInst(Call.get(), MIRBuilder, GR);
22912324
case SPIRV::GroupUniform:
22922325
return generateGroupUniformInst(Call.get(), MIRBuilder, GR);
2326+
case SPIRV::KernelClock:
2327+
return generateKernelClockInst(Call.get(), MIRBuilder, GR);
22932328
}
22942329
return false;
22952330
}

llvm/lib/Target/SPIRV/SPIRVBuiltins.td

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ def LoadStore : BuiltinGroup;
5858
def IntelSubgroups : BuiltinGroup;
5959
def AtomicFloating : BuiltinGroup;
6060
def GroupUniform : BuiltinGroup;
61+
def KernelClock : BuiltinGroup;
6162

6263
//===----------------------------------------------------------------------===//
6364
// Class defining a demangled builtin record. The information in the record
@@ -952,6 +953,14 @@ defm : DemangledGroupBuiltin<"group_scan_exclusive_logical_xor", OnlyWork, OpGro
952953
defm : DemangledGroupBuiltin<"group_scan_inclusive_logical_xor", OnlyWork, OpGroupLogicalXorKHR>;
953954
defm : DemangledGroupBuiltin<"group_reduce_logical_xor", OnlyWork, OpGroupLogicalXorKHR>;
954955

956+
// cl_khr_kernel_clock / SPV_KHR_shader_clock
957+
defm : DemangledNativeBuiltin<"clock_read_device", OpenCL_std, KernelClock, 0, 0, OpReadClockKHR>;
958+
defm : DemangledNativeBuiltin<"clock_read_work_group", OpenCL_std, KernelClock, 0, 0, OpReadClockKHR>;
959+
defm : DemangledNativeBuiltin<"clock_read_sub_group", OpenCL_std, KernelClock, 0, 0, OpReadClockKHR>;
960+
defm : DemangledNativeBuiltin<"clock_read_hilo_device", OpenCL_std, KernelClock, 0, 0, OpReadClockKHR>;
961+
defm : DemangledNativeBuiltin<"clock_read_hilo_work_group", OpenCL_std, KernelClock, 0, 0, OpReadClockKHR>;
962+
defm : DemangledNativeBuiltin<"clock_read_hilo_sub_group", OpenCL_std, KernelClock, 0, 0, OpReadClockKHR>;
963+
955964
//===----------------------------------------------------------------------===//
956965
// Class defining an atomic instruction on floating-point numbers.
957966
//

llvm/lib/Target/SPIRV/SPIRVCommandLine.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ static const std::map<std::string, SPIRV::Extension::Extension>
5555
SPIRV::Extension::Extension::SPV_INTEL_variable_length_array},
5656
{"SPV_INTEL_function_pointers",
5757
SPIRV::Extension::Extension::SPV_INTEL_function_pointers},
58+
{"SPV_KHR_shader_clock",
59+
SPIRV::Extension::Extension::SPV_KHR_shader_clock},
5860
};
5961

6062
bool SPIRVExtensionsParser::parse(cl::Option &O, llvm::StringRef ArgName,

llvm/lib/Target/SPIRV/SPIRVInstrInfo.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,11 @@ def OpGroupNonUniformRotateKHR: Op<4431, (outs ID:$res),
802802
(ins TYPE:$type, ID:$scope, ID:$value, ID:$delta, variable_ops),
803803
"$res = OpGroupNonUniformRotateKHR $type $scope $value $delta">;
804804

805+
// SPV_KHR_shader_clock
806+
def OpReadClockKHR: Op<5056, (outs ID:$res),
807+
(ins TYPE:$type, ID:$scope),
808+
"$res = OpReadClockKHR $type $scope">;
809+
805810
// 3.49.7, Constant-Creation Instructions
806811

807812
// - SPV_INTEL_function_pointers

llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,14 @@ void addInstrRequirements(const MachineInstr &MI,
11171117
Reqs.addCapability(SPIRV::Capability::GroupUniformArithmeticKHR);
11181118
}
11191119
break;
1120+
case SPIRV::OpReadClockKHR:
1121+
if (!ST.canUseExtension(SPIRV::Extension::SPV_KHR_shader_clock))
1122+
report_fatal_error("OpReadClockKHR instruction requires the "
1123+
"following SPIR-V extension: SPV_KHR_shader_clock",
1124+
false);
1125+
Reqs.addExtension(SPIRV::Extension::SPV_KHR_shader_clock);
1126+
Reqs.addCapability(SPIRV::Capability::ShaderClockKHR);
1127+
break;
11201128
case SPIRV::OpFunctionPointerCallINTEL:
11211129
if (ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)) {
11221130
Reqs.addExtension(SPIRV::Extension::SPV_INTEL_function_pointers);

llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,7 @@ defm ImageGatherBiasLodAMD : CapabilityOperand<5009, 0, 0, [], [Shader]>;
413413
defm FragmentMaskAMD : CapabilityOperand<5010, 0, 0, [], [Shader]>;
414414
defm StencilExportEXT : CapabilityOperand<5013, 0, 0, [], [Shader]>;
415415
defm ImageReadWriteLodAMD : CapabilityOperand<5015, 0, 0, [], [Shader]>;
416+
defm ShaderClockKHR : CapabilityOperand<5055, 0, 0, [SPV_KHR_shader_clock], []>;
416417
defm SampleMaskOverrideCoverageNV : CapabilityOperand<5249, 0, 0, [], [SampleRateShading]>;
417418
defm GeometryShaderPassthroughNV : CapabilityOperand<5251, 0, 0, [], [Geometry]>;
418419
defm ShaderViewportIndexLayerEXT : CapabilityOperand<5254, 0, 0, [], [MultiViewport]>;
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
; RUN: not llc -O0 -mtriple=spirv64-unknown-unknown %s -o %t.spvt 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
2+
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_shader_clock %s -o - | FileCheck %s
3+
; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_shader_clock %s -o - -filetype=obj | spirv-val %}
4+
5+
; CHECK-ERROR: LLVM ERROR: clock_read_device: the builtin requires the following SPIR-V extension: SPV_KHR_shader_clock
6+
7+
; CHECK: OpCapability ShaderClockKHR
8+
; CHECK: OpExtension "SPV_KHR_shader_clock"
9+
; CHECK-DAG: [[uint:%[a-z0-9_]+]] = OpTypeInt 32
10+
; CHECK-DAG: [[ulong:%[a-z0-9_]+]] = OpTypeInt 64
11+
; CHECK-DAG: [[v2uint:%[a-z0-9_]+]] = OpTypeVector [[uint]] 2
12+
; CHECK-DAG: [[uint_1:%[a-z0-9_]+]] = OpConstant [[uint]] 1
13+
; CHECK-DAG: [[uint_2:%[a-z0-9_]+]] = OpConstant [[uint]] 2
14+
; CHECK-DAG: [[uint_3:%[a-z0-9_]+]] = OpConstant [[uint]] 3
15+
; CHECK: OpReadClockKHR [[ulong]] [[uint_1]]
16+
; CHECK: OpReadClockKHR [[ulong]] [[uint_2]]
17+
; CHECK: OpReadClockKHR [[ulong]] [[uint_3]]
18+
; CHECK: OpReadClockKHR [[v2uint]] [[uint_1]]
19+
; CHECK: OpReadClockKHR [[v2uint]] [[uint_2]]
20+
; CHECK: OpReadClockKHR [[v2uint]] [[uint_3]]
21+
22+
define dso_local spir_kernel void @test_clocks(ptr addrspace(1) nocapture noundef writeonly align 8 %out64, ptr addrspace(1) nocapture noundef writeonly align 8 %outv2) {
23+
entry:
24+
%call = tail call spir_func i64 @_Z17clock_read_devicev()
25+
store i64 %call, ptr addrspace(1) %out64, align 8
26+
%call1 = tail call spir_func i64 @_Z21clock_read_work_groupv()
27+
%arrayidx2 = getelementptr inbounds i8, ptr addrspace(1) %out64, i32 8
28+
store i64 %call1, ptr addrspace(1) %arrayidx2, align 8
29+
%call3 = tail call spir_func i64 @_Z20clock_read_sub_groupv()
30+
%arrayidx4 = getelementptr inbounds i8, ptr addrspace(1) %out64, i32 16
31+
store i64 %call3, ptr addrspace(1) %arrayidx4, align 8
32+
%call5 = tail call spir_func <2 x i32> @_Z22clock_read_hilo_devicev()
33+
store <2 x i32> %call5, ptr addrspace(1) %outv2, align 8
34+
%call7 = tail call spir_func <2 x i32> @_Z26clock_read_hilo_work_groupv()
35+
%arrayidx8 = getelementptr inbounds i8, ptr addrspace(1) %outv2, i32 8
36+
store <2 x i32> %call7, ptr addrspace(1) %arrayidx8, align 8
37+
%call9 = tail call spir_func <2 x i32> @_Z25clock_read_hilo_sub_groupv()
38+
%arrayidx10 = getelementptr inbounds i8, ptr addrspace(1) %outv2, i32 16
39+
store <2 x i32> %call9, ptr addrspace(1) %arrayidx10, align 8
40+
ret void
41+
}
42+
43+
; Function Attrs: convergent nounwind
44+
declare spir_func i64 @_Z17clock_read_devicev() local_unnamed_addr
45+
46+
; Function Attrs: convergent nounwind
47+
declare spir_func i64 @_Z21clock_read_work_groupv() local_unnamed_addr
48+
49+
; Function Attrs: convergent nounwind
50+
declare spir_func i64 @_Z20clock_read_sub_groupv() local_unnamed_addr
51+
52+
; Function Attrs: convergent nounwind
53+
declare spir_func <2 x i32> @_Z22clock_read_hilo_devicev() local_unnamed_addr
54+
55+
; Function Attrs: convergent nounwind
56+
declare spir_func <2 x i32> @_Z26clock_read_hilo_work_groupv() local_unnamed_addr
57+
58+
; Function Attrs: convergent nounwind
59+
declare spir_func <2 x i32> @_Z25clock_read_hilo_sub_groupv() local_unnamed_addr

0 commit comments

Comments
 (0)