99 lines
4.1 KiB
Zig
99 lines
4.1 KiB
Zig
const ids = @import("id.zig");
|
|
const instruction_ir = @import("instruction.zig");
|
|
const module_ir = @import("module.zig");
|
|
|
|
pub const Visitor = struct {
|
|
context: ?*anyopaque = null,
|
|
visitInterfaceVariable: ?*const fn (?*anyopaque, ids.InterfaceVariableId, *const module_ir.InterfaceVariable) anyerror!void = null,
|
|
visitResource: ?*const fn (?*anyopaque, ids.ResourceId, *const module_ir.Resource) anyerror!void = null,
|
|
visitFunction: ?*const fn (?*anyopaque, ids.FunctionId, *const module_ir.Function) anyerror!void = null,
|
|
visitBlock: ?*const fn (?*anyopaque, ids.BlockId, *const module_ir.Block) anyerror!void = null,
|
|
visitInstruction: ?*const fn (?*anyopaque, ids.InstructionId, *const instruction_ir.Instruction) anyerror!void = null,
|
|
visitTerminator: ?*const fn (?*anyopaque, ids.BlockId, module_ir.Terminator) anyerror!void = null,
|
|
visitValueUse: ?*const fn (?*anyopaque, ids.BlockId, ?ids.InstructionId, ids.ValueId) anyerror!void = null,
|
|
};
|
|
|
|
const UseContext = struct {
|
|
visitor_context: ?*anyopaque,
|
|
callback: *const fn (?*anyopaque, ids.BlockId, ?ids.InstructionId, ids.ValueId) anyerror!void,
|
|
block: ids.BlockId,
|
|
instruction: ?ids.InstructionId,
|
|
failure: ?anyerror = null,
|
|
};
|
|
|
|
pub fn walk(module: *const module_ir.Module, visitor: Visitor) !void {
|
|
for (module.interface_variables.entries.items, 0..) |entry, index| {
|
|
const variable = entry orelse continue;
|
|
if (visitor.visitInterfaceVariable) |callback|
|
|
try callback(visitor.context, ids.InterfaceVariableId.fromIndex(index), &variable);
|
|
}
|
|
|
|
for (module.resources.entries.items, 0..) |entry, index| {
|
|
const resource = entry orelse continue;
|
|
if (visitor.visitResource) |callback|
|
|
try callback(visitor.context, ids.ResourceId.fromIndex(index), &resource);
|
|
}
|
|
|
|
for (module.functions.entries.items, 0..) |entry, function_index| {
|
|
const function = entry orelse continue;
|
|
const function_id = ids.FunctionId.fromIndex(function_index);
|
|
|
|
if (visitor.visitFunction) |callback|
|
|
try callback(visitor.context, function_id, &function);
|
|
|
|
for (function.blocks.items) |block_id| {
|
|
const block = module.blocks.get(block_id) orelse continue;
|
|
|
|
if (visitor.visitBlock) |callback|
|
|
try callback(visitor.context, block_id, block);
|
|
|
|
for (block.instructions.items) |instruction_id| {
|
|
const instruction = module.instructions.get(instruction_id) orelse continue;
|
|
|
|
if (visitor.visitInstruction) |callback|
|
|
try callback(visitor.context, instruction_id, instruction);
|
|
|
|
if (visitor.visitValueUse) |callback| {
|
|
var context: UseContext = .{
|
|
.visitor_context = visitor.context,
|
|
.callback = callback,
|
|
.block = block_id,
|
|
.instruction = instruction_id,
|
|
};
|
|
instruction.operation.visitValueUses(&context, visitUse);
|
|
|
|
if (context.failure) |failure|
|
|
return failure;
|
|
}
|
|
}
|
|
|
|
if (block.terminator) |terminator| {
|
|
if (visitor.visitTerminator) |callback|
|
|
try callback(visitor.context, block_id, terminator);
|
|
|
|
if (visitor.visitValueUse) |callback| {
|
|
var context: UseContext = .{
|
|
.visitor_context = visitor.context,
|
|
.callback = callback,
|
|
.block = block_id,
|
|
.instruction = null,
|
|
};
|
|
module_ir.visitTerminatorValueUses(terminator, &context, visitUse);
|
|
|
|
if (context.failure) |failure|
|
|
return failure;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn visitUse(context: *UseContext, value: ids.ValueId) void {
|
|
if (context.failure != null)
|
|
return;
|
|
|
|
context.callback(context.visitor_context, context.block, context.instruction, value) catch |err| {
|
|
context.failure = err;
|
|
};
|
|
}
|