mirror of
https://github.com/ziglang/zig.git
synced 2025-12-24 07:03:11 +00:00
Merge pull request #23815 from alichraghi/master
spirv: unroll all vector operations
This commit is contained in:
commit
dc6ffc28b5
@ -2014,7 +2014,7 @@ pub const Cpu = struct {
|
||||
.global, .local, .shared => is_gpu,
|
||||
.constant => is_gpu and (context == null or context == .constant),
|
||||
.param => is_nvptx,
|
||||
.input, .output, .uniform, .push_constant, .storage_buffer => is_spirv,
|
||||
.input, .output, .uniform, .push_constant, .storage_buffer, .physical_storage_buffer => is_spirv,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,8 +1,21 @@
|
||||
//! This file is auto-generated by tools/update_cpu_features.zig.
|
||||
|
||||
const std = @import("../std.zig");
|
||||
const CpuFeature = std.Target.Cpu.Feature;
|
||||
const CpuModel = std.Target.Cpu.Model;
|
||||
|
||||
pub const Feature = enum {
|
||||
addresses,
|
||||
arbitrary_precision_integers,
|
||||
float16,
|
||||
float64,
|
||||
generic_pointer,
|
||||
int64,
|
||||
kernel,
|
||||
matrix,
|
||||
physical_storage_buffer,
|
||||
shader,
|
||||
storage_push_constant16,
|
||||
v1_0,
|
||||
v1_1,
|
||||
v1_2,
|
||||
@ -10,18 +23,8 @@ pub const Feature = enum {
|
||||
v1_4,
|
||||
v1_5,
|
||||
v1_6,
|
||||
int64,
|
||||
float16,
|
||||
float64,
|
||||
matrix,
|
||||
storage_push_constant16,
|
||||
arbitrary_precision_integers,
|
||||
kernel,
|
||||
addresses,
|
||||
generic_pointer,
|
||||
variable_pointers,
|
||||
vector16,
|
||||
shader,
|
||||
physical_storage_buffer,
|
||||
};
|
||||
|
||||
pub const featureSet = CpuFeature.FeatureSetFns(Feature).featureSet;
|
||||
@ -34,6 +37,83 @@ pub const all_features = blk: {
|
||||
const len = @typeInfo(Feature).@"enum".fields.len;
|
||||
std.debug.assert(len <= CpuFeature.Set.needed_bit_count);
|
||||
var result: [len]CpuFeature = undefined;
|
||||
result[@intFromEnum(Feature.addresses)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable Addresses capability",
|
||||
.dependencies = featureSet(&[_]Feature{
|
||||
.v1_0,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.arbitrary_precision_integers)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable SPV_INTEL_arbitrary_precision_integers extension and the ArbitraryPrecisionIntegersINTEL capability",
|
||||
.dependencies = featureSet(&[_]Feature{
|
||||
.v1_5,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.float16)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable Float16 capability",
|
||||
.dependencies = featureSet(&[_]Feature{
|
||||
.v1_0,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.float64)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable Float64 capability",
|
||||
.dependencies = featureSet(&[_]Feature{
|
||||
.v1_0,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.generic_pointer)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable GenericPointer capability",
|
||||
.dependencies = featureSet(&[_]Feature{
|
||||
.addresses,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.int64)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable Int64 capability",
|
||||
.dependencies = featureSet(&[_]Feature{
|
||||
.v1_0,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.kernel)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable Kernel capability",
|
||||
.dependencies = featureSet(&[_]Feature{
|
||||
.v1_0,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.matrix)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable Matrix capability",
|
||||
.dependencies = featureSet(&[_]Feature{
|
||||
.v1_0,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.physical_storage_buffer)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable SPV_KHR_variable_pointers extension and the (VariablePointers, VariablePointersStorageBuffer) capabilities",
|
||||
.dependencies = featureSet(&[_]Feature{
|
||||
.v1_0,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.shader)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable Shader capability",
|
||||
.dependencies = featureSet(&[_]Feature{
|
||||
.matrix,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.storage_push_constant16)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable SPV_KHR_16bit_storage extension and the StoragePushConstant16 capability",
|
||||
.dependencies = featureSet(&[_]Feature{
|
||||
.v1_3,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.v1_0)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable version 1.0",
|
||||
@ -42,92 +122,58 @@ pub const all_features = blk: {
|
||||
result[@intFromEnum(Feature.v1_1)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable version 1.1",
|
||||
.dependencies = featureSet(&[_]Feature{.v1_0}),
|
||||
.dependencies = featureSet(&[_]Feature{
|
||||
.v1_0,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.v1_2)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable version 1.2",
|
||||
.dependencies = featureSet(&[_]Feature{.v1_1}),
|
||||
.dependencies = featureSet(&[_]Feature{
|
||||
.v1_1,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.v1_3)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable version 1.3",
|
||||
.dependencies = featureSet(&[_]Feature{.v1_2}),
|
||||
.dependencies = featureSet(&[_]Feature{
|
||||
.v1_2,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.v1_4)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable version 1.4",
|
||||
.dependencies = featureSet(&[_]Feature{.v1_3}),
|
||||
.dependencies = featureSet(&[_]Feature{
|
||||
.v1_3,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.v1_5)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable version 1.5",
|
||||
.dependencies = featureSet(&[_]Feature{.v1_4}),
|
||||
.dependencies = featureSet(&[_]Feature{
|
||||
.v1_4,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.v1_6)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable version 1.6",
|
||||
.dependencies = featureSet(&[_]Feature{.v1_5}),
|
||||
.dependencies = featureSet(&[_]Feature{
|
||||
.v1_5,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.int64)] = .{
|
||||
result[@intFromEnum(Feature.variable_pointers)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable Int64 capability",
|
||||
.dependencies = featureSet(&[_]Feature{.v1_0}),
|
||||
};
|
||||
result[@intFromEnum(Feature.float16)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable Float16 capability",
|
||||
.dependencies = featureSet(&[_]Feature{.v1_0}),
|
||||
};
|
||||
result[@intFromEnum(Feature.float64)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable Float64 capability",
|
||||
.dependencies = featureSet(&[_]Feature{.v1_0}),
|
||||
};
|
||||
result[@intFromEnum(Feature.matrix)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable Matrix capability",
|
||||
.dependencies = featureSet(&[_]Feature{.v1_0}),
|
||||
};
|
||||
result[@intFromEnum(Feature.storage_push_constant16)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable SPV_KHR_16bit_storage extension and the StoragePushConstant16 capability",
|
||||
.dependencies = featureSet(&[_]Feature{.v1_3}),
|
||||
};
|
||||
result[@intFromEnum(Feature.arbitrary_precision_integers)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable SPV_INTEL_arbitrary_precision_integers extension and the ArbitraryPrecisionIntegersINTEL capability",
|
||||
.dependencies = featureSet(&[_]Feature{.v1_5}),
|
||||
};
|
||||
result[@intFromEnum(Feature.kernel)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable Kernel capability",
|
||||
.dependencies = featureSet(&[_]Feature{.v1_0}),
|
||||
};
|
||||
result[@intFromEnum(Feature.addresses)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable Addresses capability",
|
||||
.dependencies = featureSet(&[_]Feature{.v1_0}),
|
||||
};
|
||||
result[@intFromEnum(Feature.generic_pointer)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable GenericPointer capability",
|
||||
.dependencies = featureSet(&[_]Feature{ .v1_0, .addresses }),
|
||||
.description = "Enable SPV_KHR_physical_storage_buffer extension and the PhysicalStorageBufferAddresses capability",
|
||||
.dependencies = featureSet(&[_]Feature{
|
||||
.v1_0,
|
||||
}),
|
||||
};
|
||||
result[@intFromEnum(Feature.vector16)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable Vector16 capability",
|
||||
.dependencies = featureSet(&[_]Feature{ .v1_0, .kernel }),
|
||||
};
|
||||
result[@intFromEnum(Feature.shader)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable Shader capability",
|
||||
.dependencies = featureSet(&[_]Feature{ .v1_0, .matrix }),
|
||||
};
|
||||
result[@intFromEnum(Feature.physical_storage_buffer)] = .{
|
||||
.llvm_name = null,
|
||||
.description = "Enable SPV_KHR_physical_storage_buffer extension and the PhysicalStorageBufferAddresses capability",
|
||||
.dependencies = featureSet(&[_]Feature{.v1_0}),
|
||||
.dependencies = featureSet(&[_]Feature{
|
||||
.kernel,
|
||||
}),
|
||||
};
|
||||
const ti = @typeInfo(Feature);
|
||||
for (&result, 0..) |*elem, i| {
|
||||
@ -141,18 +187,23 @@ pub const cpu = struct {
|
||||
pub const generic: CpuModel = .{
|
||||
.name = "generic",
|
||||
.llvm_name = "generic",
|
||||
.features = featureSet(&[_]Feature{.v1_0}),
|
||||
.features = featureSet(&[_]Feature{}),
|
||||
};
|
||||
|
||||
pub const vulkan_v1_2: CpuModel = .{
|
||||
.name = "vulkan_v1_2",
|
||||
.llvm_name = null,
|
||||
.features = featureSet(&[_]Feature{ .v1_5, .shader, .physical_storage_buffer }),
|
||||
};
|
||||
|
||||
pub const opencl_v2: CpuModel = .{
|
||||
.name = "opencl_v2",
|
||||
.llvm_name = null,
|
||||
.features = featureSet(&[_]Feature{ .v1_2, .kernel, .addresses, .generic_pointer }),
|
||||
.features = featureSet(&[_]Feature{
|
||||
.generic_pointer,
|
||||
.kernel,
|
||||
.v1_2,
|
||||
}),
|
||||
};
|
||||
pub const vulkan_v1_2: CpuModel = .{
|
||||
.name = "vulkan_v1_2",
|
||||
.llvm_name = null,
|
||||
.features = featureSet(&[_]Feature{
|
||||
.shader,
|
||||
.v1_5,
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
@ -531,6 +531,7 @@ pub const AddressSpace = enum(u5) {
|
||||
uniform,
|
||||
push_constant,
|
||||
storage_buffer,
|
||||
physical_storage_buffer,
|
||||
|
||||
// AVR address spaces.
|
||||
flash,
|
||||
|
||||
230
lib/std/gpu.zig
230
lib/std/gpu.zig
@ -1,81 +1,24 @@
|
||||
const std = @import("std.zig");
|
||||
|
||||
/// Will make `ptr` contain the location of the current invocation within the
|
||||
/// global workgroup. Each component is equal to the index of the local workgroup
|
||||
/// multiplied by the size of the local workgroup plus `localInvocationId`.
|
||||
/// `ptr` must be a reference to variable or struct field.
|
||||
pub fn globalInvocationId(comptime ptr: *addrspace(.input) @Vector(3, u32)) void {
|
||||
asm volatile (
|
||||
\\OpDecorate %ptr BuiltIn GlobalInvocationId
|
||||
:
|
||||
: [ptr] "" (ptr),
|
||||
);
|
||||
}
|
||||
|
||||
/// Will make that variable contain the location of the current cluster
|
||||
/// culling, task, mesh, or compute shader invocation within the local
|
||||
/// workgroup. Each component ranges from zero through to the size of the
|
||||
/// workgroup in that dimension minus one.
|
||||
/// `ptr` must be a reference to variable or struct field.
|
||||
pub fn localInvocationId(comptime ptr: *addrspace(.input) @Vector(3, u32)) void {
|
||||
asm volatile (
|
||||
\\OpDecorate %ptr BuiltIn LocalInvocationId
|
||||
:
|
||||
: [ptr] "" (ptr),
|
||||
);
|
||||
}
|
||||
|
||||
/// Output vertex position from a `Vertex` entrypoint
|
||||
/// `ptr` must be a reference to variable or struct field.
|
||||
pub fn position(comptime ptr: *addrspace(.output) @Vector(4, f32)) void {
|
||||
asm volatile (
|
||||
\\OpDecorate %ptr BuiltIn Position
|
||||
:
|
||||
: [ptr] "" (ptr),
|
||||
);
|
||||
}
|
||||
|
||||
/// Will make `ptr` contain the index of the vertex that is
|
||||
/// being processed by the current vertex shader invocation.
|
||||
/// `ptr` must be a reference to variable or struct field.
|
||||
pub fn vertexIndex(comptime ptr: *addrspace(.input) u32) void {
|
||||
asm volatile (
|
||||
\\OpDecorate %ptr BuiltIn VertexIndex
|
||||
:
|
||||
: [ptr] "" (ptr),
|
||||
);
|
||||
}
|
||||
|
||||
/// Will make `ptr` contain the index of the instance that is
|
||||
/// being processed by the current vertex shader invocation.
|
||||
/// `ptr` must be a reference to variable or struct field.
|
||||
pub fn instanceIndex(comptime ptr: *addrspace(.input) u32) void {
|
||||
asm volatile (
|
||||
\\OpDecorate %ptr BuiltIn InstanceIndex
|
||||
:
|
||||
: [ptr] "" (ptr),
|
||||
);
|
||||
}
|
||||
|
||||
/// Output fragment depth from a `Fragment` entrypoint
|
||||
/// `ptr` must be a reference to variable or struct field.
|
||||
pub fn fragmentCoord(comptime ptr: *addrspace(.input) @Vector(4, f32)) void {
|
||||
asm volatile (
|
||||
\\OpDecorate %ptr BuiltIn FragCoord
|
||||
:
|
||||
: [ptr] "" (ptr),
|
||||
);
|
||||
}
|
||||
|
||||
/// Output fragment depth from a `Fragment` entrypoint
|
||||
/// `ptr` must be a reference to variable or struct field.
|
||||
pub fn fragmentDepth(comptime ptr: *addrspace(.output) f32) void {
|
||||
asm volatile (
|
||||
\\OpDecorate %ptr BuiltIn FragDepth
|
||||
:
|
||||
: [ptr] "" (ptr),
|
||||
);
|
||||
}
|
||||
pub const position_in = @extern(*addrspace(.input) @Vector(4, f32), .{ .name = "position" });
|
||||
pub const position_out = @extern(*addrspace(.output) @Vector(4, f32), .{ .name = "position" });
|
||||
pub const point_size_in = @extern(*addrspace(.input) f32, .{ .name = "point_size" });
|
||||
pub const point_size_out = @extern(*addrspace(.output) f32, .{ .name = "point_size" });
|
||||
pub extern const invocation_id: u32 addrspace(.input);
|
||||
pub extern const frag_coord: @Vector(4, f32) addrspace(.input);
|
||||
pub extern const point_coord: @Vector(2, f32) addrspace(.input);
|
||||
// TODO: direct/indirect values
|
||||
// pub extern const front_facing: bool addrspace(.input);
|
||||
// TODO: runtime array
|
||||
// pub extern const sample_mask;
|
||||
pub extern var frag_depth: f32 addrspace(.output);
|
||||
pub extern const num_workgroups: @Vector(3, u32) addrspace(.input);
|
||||
pub extern const workgroup_size: @Vector(3, u32) addrspace(.input);
|
||||
pub extern const workgroup_id: @Vector(3, u32) addrspace(.input);
|
||||
pub extern const local_invocation_id: @Vector(3, u32) addrspace(.input);
|
||||
pub extern const global_invocation_id: @Vector(3, u32) addrspace(.input);
|
||||
pub extern const vertex_index: u32 addrspace(.input);
|
||||
pub extern const instance_index: u32 addrspace(.input);
|
||||
|
||||
/// Forms the main linkage for `input` and `output` address spaces.
|
||||
/// `ptr` must be a reference to variable or struct field.
|
||||
@ -101,74 +44,85 @@ pub fn binding(comptime ptr: anytype, comptime set: u32, comptime bind: u32) voi
|
||||
);
|
||||
}
|
||||
|
||||
pub const Origin = enum(u32) {
|
||||
/// Increase toward the right and downward
|
||||
upper_left = 7,
|
||||
/// Increase toward the right and upward
|
||||
lower_left = 8,
|
||||
};
|
||||
|
||||
/// The coordinates appear to originate in the specified `origin`.
|
||||
/// Only valid with the `Fragment` calling convention.
|
||||
pub fn fragmentOrigin(comptime entry_point: anytype, comptime origin: Origin) void {
|
||||
asm volatile (
|
||||
\\OpExecutionMode %entry_point $origin
|
||||
:
|
||||
: [entry_point] "" (entry_point),
|
||||
[origin] "c" (@intFromEnum(origin)),
|
||||
);
|
||||
}
|
||||
|
||||
pub const DepthMode = enum(u32) {
|
||||
/// Declares that this entry point dynamically writes the
|
||||
/// `fragmentDepth` built in-decorated variable.
|
||||
replacing = 12,
|
||||
pub const ExecutionMode = union(Tag) {
|
||||
/// Sets origin of the framebuffer to the upper-left corner
|
||||
origin_upper_left,
|
||||
/// Sets origin of the framebuffer to the lower-left corner
|
||||
origin_lower_left,
|
||||
/// Indicates that the fragment shader writes to `frag_depth`,
|
||||
/// replacing the fixed-function depth value.
|
||||
depth_replacing,
|
||||
/// Indicates that per-fragment tests may assume that
|
||||
/// any `fragmentDepth` built in-decorated value written by the shader is
|
||||
/// any `frag_depth` built in-decorated value written by the shader is
|
||||
/// greater-than-or-equal to the fragment’s interpolated depth value
|
||||
greater = 14,
|
||||
depth_greater,
|
||||
/// Indicates that per-fragment tests may assume that
|
||||
/// any `fragmentDepth` built in-decorated value written by the shader is
|
||||
/// any `frag_depth` built in-decorated value written by the shader is
|
||||
/// less-than-or-equal to the fragment’s interpolated depth value
|
||||
less = 15,
|
||||
depth_less,
|
||||
/// Indicates that per-fragment tests may assume that
|
||||
/// any `fragmentDepth` built in-decorated value written by the shader is
|
||||
/// any `frag_depth` built in-decorated value written by the shader is
|
||||
/// the same as the fragment’s interpolated depth value
|
||||
unchanged = 16,
|
||||
depth_unchanged,
|
||||
/// Indicates the workgroup size in the x, y, and z dimensions.
|
||||
local_size: LocalSize,
|
||||
|
||||
pub const Tag = enum(u32) {
|
||||
origin_upper_left = 7,
|
||||
origin_lower_left = 8,
|
||||
depth_replacing = 12,
|
||||
depth_greater = 14,
|
||||
depth_less = 15,
|
||||
depth_unchanged = 16,
|
||||
local_size = 17,
|
||||
};
|
||||
|
||||
pub const LocalSize = struct { x: u32, y: u32, z: u32 };
|
||||
};
|
||||
|
||||
/// Only valid with the `Fragment` calling convention.
|
||||
pub fn depthMode(comptime entry_point: anytype, comptime mode: DepthMode) void {
|
||||
asm volatile (
|
||||
\\OpExecutionMode %entry_point $mode
|
||||
:
|
||||
: [entry_point] "" (entry_point),
|
||||
[mode] "c" (mode),
|
||||
);
|
||||
}
|
||||
|
||||
/// Indicates the workgroup size in the `x`, `y`, and `z` dimensions.
|
||||
/// Only valid with the `GLCompute` or `Kernel` calling conventions.
|
||||
pub fn workgroupSize(comptime entry_point: anytype, comptime size: @Vector(3, u32)) void {
|
||||
asm volatile (
|
||||
\\OpExecutionMode %entry_point LocalSize %x %y %z
|
||||
:
|
||||
: [entry_point] "" (entry_point),
|
||||
[x] "c" (size[0]),
|
||||
[y] "c" (size[1]),
|
||||
[z] "c" (size[2]),
|
||||
);
|
||||
}
|
||||
|
||||
/// A hint to the client, which indicates the workgroup size in the `x`, `y`, and `z` dimensions.
|
||||
/// Only valid with the `GLCompute` or `Kernel` calling conventions.
|
||||
pub fn workgroupSizeHint(comptime entry_point: anytype, comptime size: @Vector(3, u32)) void {
|
||||
asm volatile (
|
||||
\\OpExecutionMode %entry_point LocalSizeHint %x %y %z
|
||||
:
|
||||
: [entry_point] "" (entry_point),
|
||||
[x] "c" (size[0]),
|
||||
[y] "c" (size[1]),
|
||||
[z] "c" (size[2]),
|
||||
);
|
||||
/// Declare the mode entry point executes in.
|
||||
pub fn executionMode(comptime entry_point: anytype, comptime mode: ExecutionMode) void {
|
||||
const cc = @typeInfo(@TypeOf(entry_point)).@"fn".calling_convention;
|
||||
switch (mode) {
|
||||
.origin_upper_left,
|
||||
.origin_lower_left,
|
||||
.depth_replacing,
|
||||
.depth_greater,
|
||||
.depth_less,
|
||||
.depth_unchanged,
|
||||
=> {
|
||||
if (cc != .spirv_fragment) {
|
||||
@compileError(
|
||||
\\invalid execution mode '
|
||||
++ @tagName(mode) ++
|
||||
\\' for function with '
|
||||
++ @tagName(cc) ++
|
||||
\\' calling convention
|
||||
);
|
||||
}
|
||||
asm volatile (
|
||||
\\OpExecutionMode %entry_point $mode
|
||||
:
|
||||
: [entry_point] "" (entry_point),
|
||||
[mode] "c" (@intFromEnum(mode)),
|
||||
);
|
||||
},
|
||||
.local_size => |size| {
|
||||
if (cc != .spirv_kernel) {
|
||||
@compileError(
|
||||
\\invalid execution mode 'local_size' for function with '
|
||||
++ @tagName(cc) ++
|
||||
\\' calling convention
|
||||
);
|
||||
}
|
||||
asm volatile (
|
||||
\\OpExecutionMode %entry_point LocalSize $x $y $z
|
||||
:
|
||||
: [entry_point] "" (entry_point),
|
||||
[x] "c" (size.x),
|
||||
[y] "c" (size.y),
|
||||
[z] "c" (size.z),
|
||||
);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -3693,7 +3693,7 @@ pub fn errorSetBits(zcu: *const Zcu) u16 {
|
||||
const target = zcu.getTarget();
|
||||
|
||||
if (zcu.error_limit == 0) return 0;
|
||||
if (target.cpu.arch == .spirv64) {
|
||||
if (target.cpu.arch.isSpirV()) {
|
||||
if (!std.Target.spirv.featureSetHas(target.cpu.features, .storage_push_constant16)) {
|
||||
return 32;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -296,12 +296,26 @@ fn processInstruction(self: *Assembler) !void {
|
||||
};
|
||||
break :blk .{ .value = try self.spv.importInstructionSet(set_tag) };
|
||||
},
|
||||
.OpExecutionMode, .OpExecutionModeId => {
|
||||
assert(try self.processGenericInstruction() == null);
|
||||
const entry_point_id = try self.resolveRefId(self.inst.operands.items[0].ref_id);
|
||||
const exec_mode: spec.ExecutionMode = @enumFromInt(self.inst.operands.items[1].value);
|
||||
const gop = try self.spv.entry_points.getOrPut(self.gpa, entry_point_id);
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = .{};
|
||||
} else if (gop.value_ptr.exec_mode != null) {
|
||||
return self.fail(
|
||||
self.currentToken().start,
|
||||
"cannot set execution mode more than once to any entry point",
|
||||
.{},
|
||||
);
|
||||
}
|
||||
gop.value_ptr.exec_mode = exec_mode;
|
||||
return;
|
||||
},
|
||||
else => switch (self.inst.opcode.class()) {
|
||||
.TypeDeclaration => try self.processTypeInstruction(),
|
||||
else => if (try self.processGenericInstruction()) |result|
|
||||
result
|
||||
else
|
||||
return,
|
||||
else => (try self.processGenericInstruction()) orelse return,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -92,11 +92,12 @@ pub const Decl = struct {
|
||||
/// This models a kernel entry point.
|
||||
pub const EntryPoint = struct {
|
||||
/// The declaration that should be exported.
|
||||
decl_index: Decl.Index,
|
||||
decl_index: ?Decl.Index = null,
|
||||
/// The name of the kernel to be exported.
|
||||
name: []const u8,
|
||||
name: ?[]const u8 = null,
|
||||
/// Calling Convention
|
||||
execution_model: spec.ExecutionModel,
|
||||
exec_model: ?spec.ExecutionModel = null,
|
||||
exec_mode: ?spec.ExecutionMode = null,
|
||||
};
|
||||
|
||||
/// A general-purpose allocator which may be used to allocate resources for this module
|
||||
@ -164,8 +165,6 @@ cache: struct {
|
||||
void_type: ?IdRef = null,
|
||||
int_types: std.AutoHashMapUnmanaged(std.builtin.Type.Int, IdRef) = .empty,
|
||||
float_types: std.AutoHashMapUnmanaged(std.builtin.Type.Float, IdRef) = .empty,
|
||||
// This cache is required so that @Vector(X, u1) in direct representation has the
|
||||
// same ID as @Vector(X, bool) in indirect representation.
|
||||
vector_types: std.AutoHashMapUnmanaged(struct { IdRef, u32 }, IdRef) = .empty,
|
||||
array_types: std.AutoHashMapUnmanaged(struct { IdRef, IdRef }, IdRef) = .empty,
|
||||
|
||||
@ -186,7 +185,7 @@ decls: std.ArrayListUnmanaged(Decl) = .empty,
|
||||
decl_deps: std.ArrayListUnmanaged(Decl.Index) = .empty,
|
||||
|
||||
/// The list of entry points that should be exported from this module.
|
||||
entry_points: std.ArrayListUnmanaged(EntryPoint) = .empty,
|
||||
entry_points: std.AutoArrayHashMapUnmanaged(IdRef, EntryPoint) = .empty,
|
||||
|
||||
pub fn init(gpa: Allocator, target: std.Target) Module {
|
||||
const version_minor: u8 = blk: {
|
||||
@ -306,19 +305,30 @@ fn entryPoints(self: *Module) !Section {
|
||||
var seen = try std.DynamicBitSetUnmanaged.initEmpty(self.gpa, self.decls.items.len);
|
||||
defer seen.deinit(self.gpa);
|
||||
|
||||
for (self.entry_points.items) |entry_point| {
|
||||
for (self.entry_points.keys(), self.entry_points.values()) |entry_point_id, entry_point| {
|
||||
interface.items.len = 0;
|
||||
seen.setRangeValue(.{ .start = 0, .end = self.decls.items.len }, false);
|
||||
|
||||
try self.addEntryPointDeps(entry_point.decl_index, &seen, &interface);
|
||||
|
||||
const entry_point_id = self.declPtr(entry_point.decl_index).result_id;
|
||||
try self.addEntryPointDeps(entry_point.decl_index.?, &seen, &interface);
|
||||
try entry_points.emit(self.gpa, .OpEntryPoint, .{
|
||||
.execution_model = entry_point.execution_model,
|
||||
.execution_model = entry_point.exec_model.?,
|
||||
.entry_point = entry_point_id,
|
||||
.name = entry_point.name,
|
||||
.name = entry_point.name.?,
|
||||
.interface = interface.items,
|
||||
});
|
||||
|
||||
if (entry_point.exec_mode == null and entry_point.exec_model == .Fragment) {
|
||||
switch (self.target.os.tag) {
|
||||
.vulkan, .opengl => |tag| {
|
||||
try self.sections.execution_modes.emit(self.gpa, .OpExecutionMode, .{
|
||||
.entry_point = entry_point_id,
|
||||
.mode = if (tag == .vulkan) .OriginUpperLeft else .OriginLowerLeft,
|
||||
});
|
||||
},
|
||||
.opencl => {},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return entry_points;
|
||||
@ -352,6 +362,11 @@ pub fn finalize(self: *Module, a: Allocator) ![]Word {
|
||||
.vector16 => try self.addCapability(.Vector16),
|
||||
// Shader
|
||||
.shader => try self.addCapability(.Shader),
|
||||
.variable_pointers => {
|
||||
try self.addExtension("SPV_KHR_variable_pointers");
|
||||
try self.addCapability(.VariablePointersStorageBuffer);
|
||||
try self.addCapability(.VariablePointers);
|
||||
},
|
||||
.physical_storage_buffer => {
|
||||
try self.addExtension("SPV_KHR_physical_storage_buffer");
|
||||
try self.addCapability(.PhysicalStorageBufferAddresses);
|
||||
@ -366,20 +381,20 @@ pub fn finalize(self: *Module, a: Allocator) ![]Word {
|
||||
// Emit memory model
|
||||
const addressing_model: spec.AddressingModel = blk: {
|
||||
if (self.hasFeature(.shader)) {
|
||||
break :blk switch (self.target.cpu.arch) {
|
||||
.spirv32 => .Logical, // TODO: I don't think this will ever be implemented.
|
||||
.spirv64 => .PhysicalStorageBuffer64,
|
||||
else => unreachable,
|
||||
};
|
||||
} else if (self.hasFeature(.kernel)) {
|
||||
break :blk switch (self.target.cpu.arch) {
|
||||
.spirv32 => .Physical32,
|
||||
.spirv64 => .Physical64,
|
||||
else => unreachable,
|
||||
};
|
||||
if (self.hasFeature(.physical_storage_buffer)) {
|
||||
assert(self.target.cpu.arch == .spirv64);
|
||||
break :blk .PhysicalStorageBuffer64;
|
||||
}
|
||||
assert(self.target.cpu.arch == .spirv);
|
||||
break :blk .Logical;
|
||||
}
|
||||
|
||||
unreachable;
|
||||
assert(self.hasFeature(.kernel));
|
||||
break :blk switch (self.target.cpu.arch) {
|
||||
.spirv32 => .Physical32,
|
||||
.spirv64 => .Physical64,
|
||||
else => unreachable,
|
||||
};
|
||||
};
|
||||
try self.sections.memory_model.emit(self.gpa, .OpMemoryModel, .{
|
||||
.addressing_model = addressing_model,
|
||||
@ -746,13 +761,15 @@ pub fn declareEntryPoint(
|
||||
self: *Module,
|
||||
decl_index: Decl.Index,
|
||||
name: []const u8,
|
||||
execution_model: spec.ExecutionModel,
|
||||
exec_model: spec.ExecutionModel,
|
||||
exec_mode: ?spec.ExecutionMode,
|
||||
) !void {
|
||||
try self.entry_points.append(self.gpa, .{
|
||||
.decl_index = decl_index,
|
||||
.name = try self.arena.allocator().dupe(u8, name),
|
||||
.execution_model = execution_model,
|
||||
});
|
||||
const gop = try self.entry_points.getOrPut(self.gpa, self.declPtr(decl_index).result_id);
|
||||
gop.value_ptr.decl_index = decl_index;
|
||||
gop.value_ptr.name = try self.arena.allocator().dupe(u8, name);
|
||||
gop.value_ptr.exec_model = exec_model;
|
||||
// Might've been set by assembler
|
||||
if (!gop.found_existing) gop.value_ptr.exec_mode = exec_mode;
|
||||
}
|
||||
|
||||
pub fn debugName(self: *Module, target: IdResult, name: []const u8) !void {
|
||||
|
||||
@ -162,7 +162,7 @@ pub fn updateExports(
|
||||
if (ip.isFunctionType(nav_ty)) {
|
||||
const spv_decl_index = try self.object.resolveNav(zcu, nav_index);
|
||||
const cc = Type.fromInterned(nav_ty).fnCallingConvention(zcu);
|
||||
const execution_model: spec.ExecutionModel = switch (target.os.tag) {
|
||||
const exec_model: spec.ExecutionModel = switch (target.os.tag) {
|
||||
.vulkan, .opengl => switch (cc) {
|
||||
.spirv_vertex => .Vertex,
|
||||
.spirv_fragment => .Fragment,
|
||||
@ -185,7 +185,8 @@ pub fn updateExports(
|
||||
try self.object.spv.declareEntryPoint(
|
||||
spv_decl_index,
|
||||
exp.opts.name.toSlice(ip),
|
||||
execution_model,
|
||||
exec_model,
|
||||
null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -501,21 +501,26 @@ pub fn addrSpaceCastIsValid(
|
||||
/// part of a merge (result of a branch) and may not be stored in memory at all. This function returns
|
||||
/// for a particular architecture and address space wether such pointers are logical.
|
||||
pub fn arePointersLogical(target: std.Target, as: AddressSpace) bool {
|
||||
if (target.os.tag != .vulkan) {
|
||||
return false;
|
||||
}
|
||||
if (target.os.tag != .vulkan) return false;
|
||||
|
||||
return switch (as) {
|
||||
// TODO: Vulkan doesn't support pointers in the generic address space, we
|
||||
// should remove this case but this requires a change in defaultAddressSpace().
|
||||
// For now, at least disable them from being regarded as physical.
|
||||
.generic => true,
|
||||
// For now, all global pointers are represented using PhysicalStorageBuffer, so these are real
|
||||
// pointers.
|
||||
// For now, all global pointers are represented using StorageBuffer or CrossWorkgroup,
|
||||
// so these are real pointers.
|
||||
.global => false,
|
||||
// TODO: Allowed with VK_KHR_variable_pointers.
|
||||
.shared => true,
|
||||
.constant, .local, .input, .output, .uniform, .push_constant, .storage_buffer => true,
|
||||
.physical_storage_buffer => false,
|
||||
.shared => !target.cpu.features.isEnabled(@intFromEnum(std.Target.spirv.Feature.variable_pointers)),
|
||||
.constant,
|
||||
.local,
|
||||
.input,
|
||||
.output,
|
||||
.uniform,
|
||||
.push_constant,
|
||||
.storage_buffer,
|
||||
=> true,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
@ -802,7 +807,8 @@ pub fn zigBackend(target: std.Target, use_llvm: bool) std.builtin.CompilerBacken
|
||||
.powerpc, .powerpcle, .powerpc64, .powerpc64le => .stage2_powerpc,
|
||||
.riscv64 => .stage2_riscv64,
|
||||
.sparc64 => .stage2_sparc64,
|
||||
.spirv64 => .stage2_spirv64,
|
||||
.spirv32 => if (target.os.tag == .opencl) .stage2_spirv64 else .other,
|
||||
.spirv, .spirv64 => .stage2_spirv64,
|
||||
.wasm32, .wasm64 => .stage2_wasm,
|
||||
.x86 => .stage2_x86,
|
||||
.x86_64 => .stage2_x86_64,
|
||||
|
||||
@ -117,9 +117,9 @@ export fn testMutablePointer() void {
|
||||
// tmp.zig:37:38: note: imported here
|
||||
// neg_inf.zon:1:1: error: expected type '?u8'
|
||||
// tmp.zig:57:28: note: imported here
|
||||
// neg_inf.zon:1:1: error: expected type 'tmp.testNonExhaustiveEnum__enum_499'
|
||||
// neg_inf.zon:1:1: error: expected type 'tmp.testNonExhaustiveEnum__enum_501'
|
||||
// tmp.zig:62:39: note: imported here
|
||||
// neg_inf.zon:1:1: error: expected type 'tmp.testUntaggedUnion__union_501'
|
||||
// neg_inf.zon:1:1: error: expected type 'tmp.testUntaggedUnion__union_503'
|
||||
// tmp.zig:67:44: note: imported here
|
||||
// neg_inf.zon:1:1: error: expected type 'tmp.testTaggedUnionVoid__union_504'
|
||||
// neg_inf.zon:1:1: error: expected type 'tmp.testTaggedUnionVoid__union_506'
|
||||
// tmp.zig:72:50: note: imported here
|
||||
|
||||
@ -15,6 +15,6 @@ pub export fn entry() void {
|
||||
// error
|
||||
//
|
||||
// :7:25: error: unable to resolve comptime value
|
||||
// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_473.C' must be comptime-known
|
||||
// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_475.C' must be comptime-known
|
||||
// :4:16: note: struct requires comptime because of this field
|
||||
// :4:16: note: types are not available at runtime
|
||||
|
||||
@ -16,5 +16,5 @@ pub export fn entry2() void {
|
||||
//
|
||||
// :3:6: error: no field or member function named 'copy' in '[]const u8'
|
||||
// :9:8: error: no field or member function named 'bar' in '@TypeOf(.{})'
|
||||
// :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_477'
|
||||
// :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_479'
|
||||
// :12:6: note: struct declared here
|
||||
|
||||
@ -6,6 +6,6 @@ export fn foo() void {
|
||||
|
||||
// error
|
||||
//
|
||||
// :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_466'
|
||||
// :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_468'
|
||||
// :3:16: note: struct declared here
|
||||
// :1:11: note: struct declared here
|
||||
|
||||
@ -44,9 +44,9 @@ comptime {
|
||||
//
|
||||
// :5:23: error: expected error union type, found 'comptime_int'
|
||||
// :10:23: error: expected error union type, found '@TypeOf(.{})'
|
||||
// :15:23: error: expected error union type, found 'tmp.test2__struct_503'
|
||||
// :15:23: error: expected error union type, found 'tmp.test2__struct_505'
|
||||
// :15:23: note: struct declared here
|
||||
// :20:27: error: expected error union type, found 'tmp.test3__struct_505'
|
||||
// :20:27: error: expected error union type, found 'tmp.test3__struct_507'
|
||||
// :20:27: note: struct declared here
|
||||
// :25:23: error: expected error union type, found 'struct { comptime *const [5:0]u8 = "hello" }'
|
||||
// :31:13: error: expected error union type, found 'u32'
|
||||
|
||||
@ -145,7 +145,7 @@ const test_targets = blk: {
|
||||
.{
|
||||
.target = std.Target.Query.parse(.{
|
||||
.arch_os_abi = "spirv64-vulkan",
|
||||
.cpu_features = "vulkan_v1_2+int64+float16+float64",
|
||||
.cpu_features = "vulkan_v1_2+physical_storage_buffer+int64+float16+float64",
|
||||
}) catch unreachable,
|
||||
.use_llvm = false,
|
||||
.use_lld = false,
|
||||
|
||||
@ -1047,6 +1047,128 @@ const targets = [_]ArchTarget{
|
||||
},
|
||||
},
|
||||
},
|
||||
.{
|
||||
.zig_name = "spirv",
|
||||
.llvm = .{
|
||||
.name = "SPIRV",
|
||||
.td_name = "SPIRV",
|
||||
},
|
||||
.branch_quota = 2000,
|
||||
.extra_features = &.{
|
||||
.{
|
||||
.zig_name = "v1_0",
|
||||
.desc = "Enable version 1.0",
|
||||
.deps = &.{},
|
||||
},
|
||||
.{
|
||||
.zig_name = "v1_1",
|
||||
.desc = "Enable version 1.1",
|
||||
.deps = &.{"v1_0"},
|
||||
},
|
||||
.{
|
||||
.zig_name = "v1_2",
|
||||
.desc = "Enable version 1.2",
|
||||
.deps = &.{"v1_1"},
|
||||
},
|
||||
.{
|
||||
.zig_name = "v1_3",
|
||||
.desc = "Enable version 1.3",
|
||||
.deps = &.{"v1_2"},
|
||||
},
|
||||
.{
|
||||
.zig_name = "v1_4",
|
||||
.desc = "Enable version 1.4",
|
||||
.deps = &.{"v1_3"},
|
||||
},
|
||||
.{
|
||||
.zig_name = "v1_5",
|
||||
.desc = "Enable version 1.5",
|
||||
.deps = &.{"v1_4"},
|
||||
},
|
||||
.{
|
||||
.zig_name = "v1_6",
|
||||
.desc = "Enable version 1.6",
|
||||
.deps = &.{"v1_5"},
|
||||
},
|
||||
.{
|
||||
.zig_name = "int64",
|
||||
.desc = "Enable Int64 capability",
|
||||
.deps = &.{"v1_0"},
|
||||
},
|
||||
.{
|
||||
.zig_name = "float16",
|
||||
.desc = "Enable Float16 capability",
|
||||
.deps = &.{"v1_0"},
|
||||
},
|
||||
.{
|
||||
.zig_name = "float64",
|
||||
.desc = "Enable Float64 capability",
|
||||
.deps = &.{"v1_0"},
|
||||
},
|
||||
.{
|
||||
.zig_name = "matrix",
|
||||
.desc = "Enable Matrix capability",
|
||||
.deps = &.{"v1_0"},
|
||||
},
|
||||
.{
|
||||
.zig_name = "storage_push_constant16",
|
||||
.desc = "Enable SPV_KHR_16bit_storage extension and the StoragePushConstant16 capability",
|
||||
.deps = &.{"v1_3"},
|
||||
},
|
||||
.{
|
||||
.zig_name = "arbitrary_precision_integers",
|
||||
.desc = "Enable SPV_INTEL_arbitrary_precision_integers extension and the ArbitraryPrecisionIntegersINTEL capability",
|
||||
.deps = &.{"v1_5"},
|
||||
},
|
||||
.{
|
||||
.zig_name = "kernel",
|
||||
.desc = "Enable Kernel capability",
|
||||
.deps = &.{"v1_0"},
|
||||
},
|
||||
.{
|
||||
.zig_name = "addresses",
|
||||
.desc = "Enable Addresses capability",
|
||||
.deps = &.{"v1_0"},
|
||||
},
|
||||
.{
|
||||
.zig_name = "generic_pointer",
|
||||
.desc = "Enable GenericPointer capability",
|
||||
.deps = &.{ "v1_0", "addresses" },
|
||||
},
|
||||
.{
|
||||
.zig_name = "vector16",
|
||||
.desc = "Enable Vector16 capability",
|
||||
.deps = &.{ "v1_0", "kernel" },
|
||||
},
|
||||
.{
|
||||
.zig_name = "shader",
|
||||
.desc = "Enable Shader capability",
|
||||
.deps = &.{ "v1_0", "matrix" },
|
||||
},
|
||||
.{
|
||||
.zig_name = "variable_pointers",
|
||||
.desc = "Enable SPV_KHR_physical_storage_buffer extension and the PhysicalStorageBufferAddresses capability",
|
||||
.deps = &.{"v1_0"},
|
||||
},
|
||||
.{
|
||||
.zig_name = "physical_storage_buffer",
|
||||
.desc = "Enable SPV_KHR_variable_pointers extension and the (VariablePointers, VariablePointersStorageBuffer) capabilities",
|
||||
.deps = &.{"v1_0"},
|
||||
},
|
||||
},
|
||||
.extra_cpus = &.{
|
||||
.{
|
||||
.llvm_name = null,
|
||||
.zig_name = "vulkan_v1_2",
|
||||
.features = &.{ "v1_5", "shader" },
|
||||
},
|
||||
.{
|
||||
.llvm_name = null,
|
||||
.zig_name = "opencl_v2",
|
||||
.features = &.{ "v1_2", "kernel", "addresses", "generic_pointer" },
|
||||
},
|
||||
},
|
||||
},
|
||||
.{
|
||||
.zig_name = "riscv",
|
||||
.llvm = .{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user