authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2026-06-21 08:49:15+03:30
committergravatar for alichraghi@noreply.codeberg.orgAli Cheraghi <alichraghi@noreply.codeberg.org> 2026-06-25 15:47:10+02:00
log14d5da916447f10bb812c3c6a199ab4ab76f61ec
tree404d52bd50144909e0123097bb118bf2410a868e
parent6e8a83282f10bcce7f80c9f213d2ae6407651163

spirv: don't put dummy `OpVariable` for non-Function pointers

This would raise a validation error when the parameter type is a non-Function opaque pointer. e.g. an `@extern(*addrspace(.constant) const SampledImage, ...)`

2 files changed, 44 insertions(+), 1 deletions(-)

src/codegen/spirv/CodeGen.zig+2-1
...@@ -8112,7 +8112,8 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)...@@ -8112,7 +8112,8 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)
8112 if (!arg_ty.hasRuntimeBits(zcu)) continue;8112 if (!arg_ty.hasRuntimeBits(zcu)) continue;
81138113
8114 if (arg_ty.zigTypeTag(zcu) == .pointer and !arg_ty.isSlice(zcu) and8114 if (arg_ty.zigTypeTag(zcu) == .pointer and !arg_ty.isSlice(zcu) and
8115 !arg_ty.childType(zcu).hasRuntimeBits(zcu))8115 !arg_ty.childType(zcu).hasRuntimeBits(zcu) and
8116 cg.module.storageClass(arg_ty.ptrAddressSpace(zcu)) == .function)
8116 {8117 {
8117 // in logical addressing, pointer arguments to function calls8118 // in logical addressing, pointer arguments to function calls
8118 // must be memory object declarations (OpVariable). for pointers to8119 // must be memory object declarations (OpVariable). for pointers to
test/cases/image_sampling_spirv.zig created+42
...@@ -0,0 +1,42 @@
1pub const Image = @SpirvType(.{ .image = .{
2 .usage = .{ .sampled = f32 },
3 .format = .unknown,
4 .dim = .@"2d",
5 .depth = .not_depth,
6 .arrayed = false,
7 .multisampled = false,
8 .access = .unknown,
9} });
10pub const SampledImage = @SpirvType(.{ .sampled_image = Image });
11
12const image_in = @extern(*addrspace(.constant) const SampledImage, .{
13 .name = "image_in",
14 .decoration = .{ .descriptor = .{ .set = 2, .binding = 0 } },
15});
16const uv_in = @extern(*addrspace(.input) @Vector(2, f32), .{ .name = "uv", .decoration = .{ .location = 0 } });
17const color_out = @extern(*addrspace(.output) @Vector(4, f32), .{ .name = "color", .decoration = .{ .location = 0 } });
18
19export fn main() callconv(.{ .spirv_fragment = .{} }) void {
20 color_out.* = imageSample(image_in, uv_in.*);
21}
22
23fn imageSample(
24 sampled_image: *addrspace(.constant) const SampledImage,
25 uv: @Vector(2, f32),
26) @Vector(4, f32) {
27 return asm volatile (
28 \\%loaded_sampler = OpLoad %SampledImage %sampled_image
29 \\%ret = OpImageSampleImplicitLod %Result %loaded_sampler %uv
30 : [ret] "" (-> @Vector(4, f32)),
31 : [SampledImage] "t" (SampledImage),
32 [sampled_image] "" (sampled_image),
33 [Result] "t" (@Vector(4, f32)),
34 [uv] "" (uv),
35 );
36}
37
38// compile
39// output_mode=Exe
40// backend=selfhosted
41// target=spirv32-vulkan
42// emit_bin=true