128 lines
5.3 KiB
Zig
128 lines
5.3 KiB
Zig
const instruction = @import("../../../ir/instruction.zig");
|
|
const program_ir = @import("../../../ir/program.zig");
|
|
const validator = @import("../../../ir/validator.zig");
|
|
const resource_layout = @import("resource_layout.zig");
|
|
|
|
pub const Error = error{
|
|
InvalidProgram,
|
|
InvalidResourceLayout,
|
|
};
|
|
|
|
pub fn run(program: *program_ir.Program, layout: *const resource_layout.Layout) Error!void {
|
|
validator.validate(program) catch return Error.InvalidProgram;
|
|
if (program.properties.resources_lowered)
|
|
return;
|
|
if (layout.resource_indices.len != program.storage_buffers.entries.items.len)
|
|
return Error.InvalidResourceLayout;
|
|
|
|
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.InvalidProgram;
|
|
const reference = bufferReference(inst.operation) orelse continue;
|
|
const resource = switch (reference) {
|
|
.logical => |value| value,
|
|
.binding_table => return Error.InvalidProgram,
|
|
};
|
|
const binding_table_index = layout.bindingTableIndex(resource) orelse return Error.InvalidResourceLayout;
|
|
if (binding_table_index >= layout.bindings.len)
|
|
return Error.InvalidResourceLayout;
|
|
const buffer = program.storage_buffers.get(resource) orelse return Error.InvalidProgram;
|
|
const binding = layout.bindings[binding_table_index];
|
|
if (binding.binding_table_index != binding_table_index or binding.set != buffer.set or binding.binding != buffer.binding)
|
|
return Error.InvalidResourceLayout;
|
|
}
|
|
}
|
|
|
|
for (program.blocks.entries.items) |block_entry| {
|
|
const block = block_entry orelse continue;
|
|
for (block.instructions.items) |instruction_id| {
|
|
const inst = program.instructions.getMut(instruction_id) orelse unreachable;
|
|
const reference = bufferReferenceMut(&inst.operation) orelse continue;
|
|
const resource = reference.logical;
|
|
const binding_table_index = layout.bindingTableIndex(resource).?;
|
|
reference.* = .{ .binding_table = binding_table_index };
|
|
}
|
|
}
|
|
|
|
program.properties.resources_lowered = true;
|
|
validator.validate(program) catch return Error.InvalidProgram;
|
|
}
|
|
|
|
fn bufferReference(operation: instruction.Operation) ?instruction.BufferReference {
|
|
return switch (operation) {
|
|
.load_buffer => |op| op.buffer,
|
|
.store_buffer => |op| op.buffer,
|
|
else => null,
|
|
};
|
|
}
|
|
|
|
fn bufferReferenceMut(operation: *instruction.Operation) ?*instruction.BufferReference {
|
|
return switch (operation.*) {
|
|
.load_buffer => |*op| &op.buffer,
|
|
.store_buffer => |*op| &op.buffer,
|
|
else => null,
|
|
};
|
|
}
|
|
|
|
test "[gen9] compute resource lowering: resolve logical buffers" {
|
|
const std = @import("std");
|
|
const Builder = @import("../../../ir/Builder.zig");
|
|
const device = @import("../../../device.zig");
|
|
const operand = @import("../../../ir/operand.zig");
|
|
const printer = @import("../../../ir/printer.zig");
|
|
|
|
const device_info: device.DeviceInfo = .{
|
|
.generation = .gen9,
|
|
.platform = .skylake,
|
|
.pci_device_id = 0x1912,
|
|
.grf_count = 128,
|
|
};
|
|
var program = program_ir.Program.init(std.testing.allocator, .{ 1, 1, 1 }, device_info, .simd8);
|
|
defer program.deinit();
|
|
var builder = Builder.init(&program);
|
|
|
|
const value = try builder.addVirtualRegister(.{
|
|
.size_bytes = 32,
|
|
.alignment_bytes = 32,
|
|
.element_type = .u32,
|
|
.lane_count = 8,
|
|
.class = .temporary,
|
|
});
|
|
const buffer = try builder.addStorageBuffer(.{ .set = 1, .binding = 3, .name = "storage" });
|
|
const entry = try builder.addBlock("entry");
|
|
const store_id = try builder.appendInstruction(entry, .simd8, null, .{
|
|
.store_buffer = .{
|
|
.buffer = .{ .logical = buffer },
|
|
.byte_offset = .{
|
|
.register = .{ .immediate = .{ .u32 = 0 } },
|
|
.type = .u32,
|
|
.region = operand.Region.broadcast(),
|
|
},
|
|
.source = .{
|
|
.register = .{ .virtual = value },
|
|
.type = .u32,
|
|
.region = operand.Region.contiguous(.simd8),
|
|
},
|
|
},
|
|
});
|
|
try builder.setTerminator(entry, .end_thread);
|
|
|
|
var layout = try resource_layout.Layout.init(std.testing.allocator, &program);
|
|
defer layout.deinit(std.testing.allocator);
|
|
layout.bindings[0].binding = 4;
|
|
try std.testing.expectError(Error.InvalidResourceLayout, run(&program, &layout));
|
|
try std.testing.expect(!program.properties.resources_lowered);
|
|
try std.testing.expect(program.instructions.get(store_id).?.operation.store_buffer.buffer == .logical);
|
|
layout.bindings[0].binding = 3;
|
|
|
|
try run(&program, &layout);
|
|
try validator.validate(&program);
|
|
|
|
try std.testing.expect(program.properties.resources_lowered);
|
|
try std.testing.expectEqual(@as(u8, 0), program.instructions.get(store_id).?.operation.store_buffer.buffer.binding_table);
|
|
const text = try printer.allocPrint(std.testing.allocator, &program);
|
|
defer std.testing.allocator.free(text);
|
|
try std.testing.expect(std.mem.indexOf(u8, text, "store_buffer bti(0), 0:u32") != null);
|
|
}
|