[Flint] moving ir gen specific code to separate file
Mirror Gitea refs to GitHub / mirror (push) Successful in 17s
Test / build_and_test (push) Successful in 3m52s
Build / build (push) Canceled after 4m13s

This commit is contained in:
2026-08-14 03:19:36 +02:00
parent a4ee2a8bd2
commit b4954da909
23 changed files with 2076 additions and 2394 deletions
@@ -0,0 +1,20 @@
const std = @import("std");
pub const Error = error{UnsupportedWorkgroupSize};
pub fn validateWorkgroupSize(size: [3]u32) Error!void {
if (size[0] == 0 or size[1] == 0 or size[2] == 0 or size[0] > 128 or size[1] > 128 or size[2] > 64)
return Error.UnsupportedWorkgroupSize;
const xy = std.math.mul(u32, size[0], size[1]) catch return Error.UnsupportedWorkgroupSize;
const invocations = std.math.mul(u32, xy, size[2]) catch return Error.UnsupportedWorkgroupSize;
if (invocations > 128)
return Error.UnsupportedWorkgroupSize;
}
test "[gen9] compute: validate workgroup limits" {
try validateWorkgroupSize(.{ 1, 1, 1 });
try validateWorkgroupSize(.{ 128, 1, 1 });
try std.testing.expectError(Error.UnsupportedWorkgroupSize, validateWorkgroupSize(.{ 0, 1, 1 }));
try std.testing.expectError(Error.UnsupportedWorkgroupSize, validateWorkgroupSize(.{ 129, 1, 1 }));
try std.testing.expectError(Error.UnsupportedWorkgroupSize, validateWorkgroupSize(.{ 64, 3, 1 }));
}
+73
View File
@@ -0,0 +1,73 @@
const std = @import("std");
const shader_ir = @import("shader_ir").ir;
const device = @import("../../device.zig");
const program_ir = @import("../../ir/program.zig");
const common_ir = @import("../../lower/common_ir.zig");
pub const compute = @import("compute/compute.zig");
pub const validator = @import("validator.zig");
pub const Options = common_ir.Options;
pub const Error = common_ir.Error || compute.Error || error{
UnsupportedGeneration,
UnsupportedStage,
UnsupportedDispatchWidth,
UnsupportedGrfSize,
};
pub fn lower(
allocator: std.mem.Allocator,
module: *shader_ir.module.Module,
device_info: device.DeviceInfo,
options: Options,
) Error!program_ir.Program {
if (device_info.generation != .gen9)
return Error.UnsupportedGeneration;
if (module.stage != .compute)
return Error.UnsupportedStage;
if (options.dispatch_width != .simd8 or !device_info.supportsDispatch(.simd8))
return Error.UnsupportedDispatchWidth;
if (device_info.grf_size_bytes != 32)
return Error.UnsupportedGrfSize;
if (module.execution_modes.workgroup_size) |workgroup_size|
try compute.validateWorkgroupSize(workgroup_size);
var program = try common_ir.lower(allocator, module, device_info, options);
errdefer program.deinit();
validator.validate(&program) catch return Error.InvalidLoweredProgram;
return program;
}
test "[gen9] target: reject unsupported target configurations" {
var module = try shader_ir.parser.parseString(std.testing.allocator,
\\shader compute @main
\\{
\\ fn @main() -> void
\\ {
\\ .entry():
\\ return
\\ }
\\}
);
defer module.deinit();
const gen9_device: device.DeviceInfo = .{
.generation = .gen9,
.platform = .skylake,
.pci_device_id = 0x1912,
.grf_count = 128,
};
var other_generation = gen9_device;
other_generation.generation = .gen11;
try std.testing.expectError(Error.UnsupportedGeneration, lower(std.testing.allocator, &module, other_generation, .{}));
module.stage = .fragment;
try std.testing.expectError(Error.UnsupportedStage, lower(std.testing.allocator, &module, gen9_device, .{}));
module.stage = .compute;
try std.testing.expectError(Error.UnsupportedDispatchWidth, lower(std.testing.allocator, &module, gen9_device, .{ .dispatch_width = .simd16 }));
var wide_grf = gen9_device;
wide_grf.grf_size_bytes = 64;
try std.testing.expectError(Error.UnsupportedGrfSize, lower(std.testing.allocator, &module, wide_grf, .{}));
}
@@ -0,0 +1,173 @@
const std = @import("std");
const compute = @import("compute/compute.zig");
const shared = @import("../../ir/validator.zig");
const instruction = @import("../../ir/instruction.zig");
const operand = @import("../../ir/operand.zig");
const program_ir = @import("../../ir/program.zig");
pub const Error = shared.Error || compute.Error || error{
UnsupportedGeneration,
UnsupportedDispatchWidth,
UnsupportedGrfSize,
UnsupportedExecutionSize,
UnsupportedDataType,
InvalidPhysicalFlag,
InvalidPayloadLayout,
};
pub fn validate(program: *const program_ir.Program) Error!void {
try shared.validate(program);
if (program.device_info.generation != .gen9)
return Error.UnsupportedGeneration;
try compute.validateWorkgroupSize(program.workgroup_size);
if (program.dispatch_width != .simd8 or !program.device_info.supportsDispatch(.simd8))
return Error.UnsupportedDispatchWidth;
if (program.device_info.grf_size_bytes != 32)
return Error.UnsupportedGrfSize;
for (program.blocks.entries.items) |block_entry| {
const block = block_entry orelse continue;
for (block.instructions.items) |instruction_id| {
const inst = program.instructions.get(instruction_id) orelse return Error.InvalidInstruction;
switch (inst.execution_size) {
.simd1, .simd8 => {},
else => return Error.UnsupportedExecutionSize,
}
try validateInstruction(inst.*);
}
try validateTerminator(block.terminator.?);
}
for (program.virtual_registers.entries.items) |entry| {
const register = entry orelse continue;
if (!register.element_type.isInitialTargetType())
return Error.UnsupportedDataType;
}
try validatePayload(program);
}
fn validateInstruction(inst: instruction.Instruction) Error!void {
if (inst.predicate) |predicate|
try validateFlag(predicate.flag);
switch (inst.operation) {
.load_global_invocation_id => |op| try validateDestination(op.destination),
.load_buffer => |op| {
try validateDestination(op.destination);
try validateSource(op.byte_offset);
},
.store_buffer => |op| {
try validateSource(op.byte_offset);
try validateSource(op.source);
},
.move => |op| {
try validateDestination(op.destination);
try validateSource(op.source);
},
.binary => |op| {
try validateDestination(op.destination);
try validateSource(op.lhs);
try validateSource(op.rhs);
},
.compare => |op| {
try validateFlag(op.destination);
try validateSource(op.lhs);
try validateSource(op.rhs);
},
.parallel_copy => |copy| {
for (copy.register_copies) |item| {
try validateDestination(item.destination);
try validateSource(item.source);
}
for (copy.flag_copies) |item| switch (item.source) {
.constant => {},
.dynamic => |predicate| try validateFlag(predicate.flag),
};
},
}
}
fn validateSource(source: operand.Source) Error!void {
try validateType(source.type);
switch (source.register) {
.immediate => |immediate| try validateImmediate(immediate),
else => {},
}
}
fn validateDestination(destination: operand.Destination) Error!void {
try validateType(destination.type);
}
fn validateType(data_type: operand.DataType) Error!void {
if (!data_type.isInitialTargetType())
return Error.UnsupportedDataType;
}
fn validateImmediate(immediate: operand.Immediate) Error!void {
switch (immediate) {
.u32, .i32, .f32 => {},
}
}
fn validateTerminator(terminator: instruction.Terminator) Error!void {
switch (terminator) {
.conditional_branch => |branch| {
try validateFlag(branch.predicate.flag);
try validateEdge(branch.true_edge);
try validateEdge(branch.false_edge);
},
.jump => |edge| try validateEdge(edge),
else => {},
}
}
fn validateEdge(edge: instruction.Edge) Error!void {
for (edge.arguments) |argument| switch (argument) {
.source => {},
.predicate => |predicate_value| switch (predicate_value) {
.constant => {},
.dynamic => |predicate| try validateFlag(predicate.flag),
},
};
}
fn validateFlag(flag: operand.FlagRef) Error!void {
switch (flag) {
.virtual => {},
.physical => |physical| if (physical.register != 0 or physical.subregister > 1)
return Error.InvalidPhysicalFlag,
}
}
fn validatePayload(program: *const program_ir.Program) Error!void {
if (program.payload.header_grf) |header| {
if (header.number != 0 or header.byte_offset != 0)
return Error.InvalidPayloadLayout;
}
}
test "[gen9] validator: layer target legality over shared structural validation" {
const Builder = @import("../../ir/Builder.zig");
const device = @import("../../device.zig");
const gen11_device: device.DeviceInfo = .{
.generation = .gen11,
.platform = .ice_lake,
.pci_device_id = 0x8a52,
.grf_count = 128,
.supports_simd16 = true,
};
var program = program_ir.Program.init(std.testing.allocator, .{ 1, 1, 1 }, gen11_device, .simd16);
defer program.deinit();
var builder = Builder.init(&program);
const entry = try builder.addBlock("entry");
try builder.setTerminator(entry, .end_thread);
try shared.validate(&program);
try std.testing.expectError(Error.UnsupportedGeneration, validate(&program));
program.device_info.generation = .gen9;
try std.testing.expectError(Error.UnsupportedDispatchWidth, validate(&program));
}
+29
View File
@@ -0,0 +1,29 @@
const std = @import("std");
const shader_ir = @import("shader_ir").ir;
const device = @import("../device.zig");
const program_ir = @import("../ir/program.zig");
const common_ir = @import("../lower/common_ir.zig");
pub const gen9 = @import("gen9/gen9.zig");
pub const Error = gen9.Error || error{UnsupportedGeneration};
pub const ValidationError = gen9.validator.Error || error{UnsupportedGeneration};
pub fn lower(
allocator: std.mem.Allocator,
module: *shader_ir.module.Module,
device_info: device.DeviceInfo,
options: common_ir.Options,
) Error!program_ir.Program {
return switch (device_info.generation) {
.gen9 => gen9.lower(allocator, module, device_info, options),
.gen10, .gen11 => Error.UnsupportedGeneration,
};
}
pub fn validate(program: *const program_ir.Program) ValidationError!void {
return switch (program.device_info.generation) {
.gen9 => gen9.validator.validate(program),
.gen10, .gen11 => ValidationError.UnsupportedGeneration,
};
}