-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
spirv: miscellaneous stuff #22889
base: master
Are you sure you want to change the base?
spirv: miscellaneous stuff #22889
Conversation
lib/std/Target/spirv.zig
Outdated
SPV_AMD_shader_fragment_mask, | ||
SPV_AMD_gpu_shader_int16, | ||
v1_6, | ||
SPV_AMDX_shader_enqueue, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's totally fine if you don't feel like doing this, but bonus points for making the script fix these names, i.e. amdx_shader_enqueue
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah i was actually going to ask is it okay to add helper functions like featureToExtension
to Target/spirv.zig
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you elaborate? What would that function do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
returns the actual extension name of a feature. currently we basically do @tagName(feature)
but that would no longer work if we turn features name to snake_case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
never mind. im removing all those unknown features. if someone wants to emit a random capability/extension they can do it through inline assembly. all cpu features must be recognizable by the compiler
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be clear, I'm not actually opposed to having all these features if there's at least a conceivable world where some compiler-adjacent tooling might be interested in representing/querying them - even if that's not the Zig compiler specifically. For example, I consider it a design goal of std.Target
to be usable for tools like dis/assemblers, decompilers, emulators, compilers for other languages, etc...
Good point re: mapping Ziggified names to SPIR-V names; I hadn't thought about that aspect. Ordinarily, we don't add helper functions of this nature in std.Target.<arch>
, but that's mostly an artifact of the feature bits not necessarily corresponding to some official set of features. Since the data is readily available when generating the feature list, I don't see any harm in adding a method along the lines of extensionName(feature: Feature) [:0]const u8
for SPIR-V. Obviously only relevant if we decide to go back to that approach rather than the new one you proposed here.
Definitely interested in @Snektron's perspective on all this.
a3f7b49
to
b7782ce
Compare
`OpCapability` and `OpExtension` now can also be emitted from inline assembly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks pretty good imo. I'm not completely convinced yet about the target features, but I guess this is better than what it was.
pub fn binding(comptime ptr: anytype, comptime descriptor_set: u32, comptime bind: u32) void { | ||
asm volatile ("OpDecorate %ptr DescriptorSet " ++ &[_]u8{'0' + descriptor_set} ++ | ||
"OpDecorate %ptr Binding " ++ &[_]u8{'0' + bind} | ||
: | ||
: [ptr] "" (ptr), | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that this should work
pub fn binding(comptime ptr: anytype, comptime descriptor_set: u32, comptime bind: u32) void { | |
asm volatile ("OpDecorate %ptr DescriptorSet " ++ &[_]u8{'0' + descriptor_set} ++ | |
"OpDecorate %ptr Binding " ++ &[_]u8{'0' + bind} | |
: | |
: [ptr] "" (ptr), | |
); | |
pub fn binding(comptime ptr: anytype, comptime descriptor_set: u32, comptime bind: u32) void { | |
asm volatile ( | |
\\OpDecorate %ptr DescriptorSet $set | |
\\OpDecorate %ptr Binding $bind | |
: | |
: [ptr] "" (ptr), | |
[set] "c" (set), | |
[bind] "c" (bind), | |
); |
this $constant syntax was added a while ago I think
ShaderStereoViewNV, | ||
PerViewAttributesNV, | ||
FragmentFullyCoveredEXT, | ||
MeshShadingNV, | ||
ImageFootprintNV, | ||
FragmentBarycentricNV, | ||
ComputeDerivativeGroupQuadsNV, | ||
FragmentDensityEXT, | ||
ShadingRateNV, | ||
GroupNonUniformPartitionedNV, | ||
ShaderNonUniform, | ||
ShaderNonUniformEXT, | ||
RuntimeDescriptorArray, | ||
RuntimeDescriptorArrayEXT, | ||
InputAttachmentArrayDynamicIndexing, | ||
InputAttachmentArrayDynamicIndexingEXT, | ||
UniformTexelBufferArrayDynamicIndexing, | ||
UniformTexelBufferArrayDynamicIndexingEXT, | ||
StorageTexelBufferArrayDynamicIndexing, | ||
StorageTexelBufferArrayDynamicIndexingEXT, | ||
UniformBufferArrayNonUniformIndexing, | ||
UniformBufferArrayNonUniformIndexingEXT, | ||
SampledImageArrayNonUniformIndexing, | ||
SampledImageArrayNonUniformIndexingEXT, | ||
StorageBufferArrayNonUniformIndexing, | ||
StorageBufferArrayNonUniformIndexingEXT, | ||
StorageImageArrayNonUniformIndexing, | ||
StorageImageArrayNonUniformIndexingEXT, | ||
InputAttachmentArrayNonUniformIndexing, | ||
InputAttachmentArrayNonUniformIndexingEXT, | ||
UniformTexelBufferArrayNonUniformIndexing, | ||
UniformTexelBufferArrayNonUniformIndexingEXT, | ||
StorageTexelBufferArrayNonUniformIndexing, | ||
StorageTexelBufferArrayNonUniformIndexingEXT, | ||
RayTracingNV, | ||
VulkanMemoryModel, | ||
VulkanMemoryModelKHR, | ||
VulkanMemoryModelDeviceScope, | ||
VulkanMemoryModelDeviceScopeKHR, | ||
PhysicalStorageBufferAddresses, | ||
PhysicalStorageBufferAddressesEXT, | ||
ComputeDerivativeGroupLinearNV, | ||
RayTracingProvisionalKHR, | ||
CooperativeMatrixNV, | ||
FragmentShaderSampleInterlockEXT, | ||
FragmentShaderShadingRateInterlockEXT, | ||
ShaderSMBuiltinsNV, | ||
FragmentShaderPixelInterlockEXT, | ||
DemoteToHelperInvocationEXT, | ||
SubgroupShuffleINTEL, | ||
SubgroupBufferBlockIOINTEL, | ||
SubgroupImageBlockIOINTEL, | ||
SubgroupImageMediaBlockIOINTEL, | ||
RoundToInfinityINTEL, | ||
FloatingPointModeINTEL, | ||
IntegerFunctions2INTEL, | ||
FunctionPointersINTEL, | ||
IndirectReferencesINTEL, | ||
AsmINTEL, | ||
AtomicFloat32MinMaxEXT, | ||
AtomicFloat64MinMaxEXT, | ||
AtomicFloat16MinMaxEXT, | ||
VectorComputeINTEL, | ||
VectorAnyINTEL, | ||
ExpectAssumeKHR, | ||
SubgroupAvcMotionEstimationINTEL, | ||
SubgroupAvcMotionEstimationIntraINTEL, | ||
SubgroupAvcMotionEstimationChromaINTEL, | ||
VariableLengthArrayINTEL, | ||
FunctionFloatControlINTEL, | ||
FPGAMemoryAttributesINTEL, | ||
FPFastMathModeINTEL, | ||
ArbitraryPrecisionIntegersINTEL, | ||
UnstructuredLoopControlsINTEL, | ||
FPGALoopControlsINTEL, | ||
KernelAttributesINTEL, | ||
FPGAKernelAttributesINTEL, | ||
FPGAMemoryAccessesINTEL, | ||
FPGAClusterAttributesINTEL, | ||
LoopFuseINTEL, | ||
FPGABufferLocationINTEL, | ||
USMStorageClassesINTEL, | ||
IOPipesINTEL, | ||
BlockingPipesINTEL, | ||
FPGARegINTEL, | ||
AtomicFloat32AddEXT, | ||
AtomicFloat64AddEXT, | ||
LongConstantCompositeINTEL, | ||
v1_6, | ||
int8, | ||
int16, | ||
int64, | ||
float16, | ||
float64, | ||
addresses, | ||
matrix, | ||
kernel, | ||
generic_pointer, | ||
vector16, | ||
shader, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these the same features as LLVM?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LLVM doesn't define any features (yet?).
https://github.com/llvm/llvm-project/blob/5c93eb56dc9bc0c0210483cdd5d31e6b6580454f/llvm/lib/Target/SPIRV/SPIRV.td
// TODO: merge tools/update_spirv_features.zig into this script | ||
//.{ | ||
// .zig_name = "spirv", | ||
// .llvm_name = "SPIRV", | ||
// .td_name = "SPIRV.td", | ||
//}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we need something equivalent to this again with LLVM 20? Since SPIR-V is enabled by default in LLVM 20?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we actually want to enable using LLVM's SPIR-V backend with Zig? I'd brought that up a while back (I think around the time of the LLVM 19 upgrade?) and there seemed to be some resistance to the idea.
Right now, we explicitly prevent it:
Lines 13019 to 13023 in 8a3aeba
// We don't currently support using these backends. | |
.spirv, | |
.spirv32, | |
.spirv64, | |
=> {}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't do that yet because they define no features
if (std.Target.spirv.featureSetHas(target.cpu.features, .v1_0)) break :blk 0; | ||
// TODO: always assume a version set? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we can always assume to have SPIR-V 1.0
const key = .{ child_ty.toIntern(), storage_class, child_repr }; | ||
const entry = try self.ptr_types.getOrPut(self.gpa, key); | ||
if (entry.found_existing) { | ||
const fwd_id = entry.value_ptr.ty_id; | ||
if (!entry.value_ptr.fwd_emitted) { | ||
try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpTypeForwardPointer, .{ | ||
.pointer_type = fwd_id, | ||
.storage_class = storage_class, | ||
}); | ||
entry.value_ptr.fwd_emitted = true; | ||
} | ||
return fwd_id; | ||
} | ||
|
||
const result_id = self.spv.allocId(); | ||
entry.value_ptr.* = .{ | ||
.ty_id = result_id, | ||
.fwd_emitted = false, | ||
}; | ||
|
||
fn ptrType(self: *NavGen, child_ty: Type, storage_class: StorageClass, child_repr: Repr) !IdRef { | ||
const child_ty_id = try self.resolveType(child_ty, child_repr); | ||
|
||
try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpTypePointer, .{ | ||
.id_result = result_id, | ||
.storage_class = storage_class, | ||
.type = child_ty_id, | ||
}); | ||
|
||
const result_id = try self.spv.ptrType(child_ty_id, storage_class); | ||
if (storage_class == .Uniform or storage_class == .PushConstant) try self.spv.decorate(child_ty_id, .Block); | ||
try self.spv.decorate(result_id, .{ .ArrayStride = .{ .array_stride = @intCast(child_ty.abiSize(self.pt.zcu)) } }); | ||
return result_id; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not the right way to handle things because it doesn't correctly handle recursive pointers. The call to self.resolveType()
would enter an infinite loop, thats why the ptr_types
map is handled especially. For example, this kernel fails:
const Node = struct { node: *Node };
export fn oef() callconv(.spirv_kernel) void {
var a: Node = undefined;
_ = &a;
}
~/programming/zig/build/spirv-zig/bin/zig build-obj ./test.zig -fno-compiler-rt -target spirv64-ope
ncl-gnu -mcpu generic+int64+int16+int8+float64+float16+generic_pointer+v1_6+kernel -fno-llvm -freference-trace
fish: Job 1, '~/programming/zig/build/spirv-z…' terminated by signal SIGSEGV (Address boundary error)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the future we might be able to remove this ugly piece of code by relying on SPV_KHR_untyped_pointers
. Some projects are already adding support for this, so hopefully we will be able to use this in the not too far away future.
cc @Snektron @alexrp