[Flint] moving ir gen specific code to separate file
This commit is contained in:
@@ -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 }));
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user