adding backend agnostic IR
Test / build_and_test (push) Successful in 5m16s
Build / build (push) Successful in 6m50s

This commit is contained in:
2026-07-20 22:07:41 +02:00
parent 2375abf688
commit 9b1b223186
70 changed files with 7358 additions and 250 deletions
+93
View File
@@ -0,0 +1,93 @@
const std = @import("std");
const cfg = @import("../cfg.zig");
const ids = @import("../id.zig");
const module_ir = @import("../module.zig");
pub const Error = std.mem.Allocator.Error || error{
InvalidBlock,
DefinitionDoesNotDominateUse,
};
const DominanceUseContext = struct {
module: *const module_ir.Module,
analysis: *const cfg,
function_id: ids.FunctionId,
use_block: ids.BlockId,
use_index: usize,
valid: bool = true,
};
pub fn validate(module: *const module_ir.Module, function_id: ids.FunctionId) Error!void {
var analysis = cfg.init(module.backingAllocator(), module, function_id) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
else => return error.InvalidBlock,
};
defer analysis.deinit();
const function = module.functions.get(function_id).?;
for (function.blocks.items) |block_id| {
const block = module.blocks.get(block_id).?;
for (block.instructions.items, 0..) |instruction_id, instruction_index| {
const instruction = module.instructions.get(instruction_id).?;
var context: DominanceUseContext = .{
.module = module,
.analysis = &analysis,
.function_id = function_id,
.use_block = block_id,
.use_index = instruction_index,
};
instruction.operation.visitValueUses(&context, checkDominanceUse);
if (!context.valid)
return error.DefinitionDoesNotDominateUse;
}
var context: DominanceUseContext = .{
.module = module,
.analysis = &analysis,
.function_id = function_id,
.use_block = block_id,
.use_index = block.instructions.items.len,
};
module_ir.visitTerminatorValueUses(block.terminator.?, &context, checkDominanceUse);
if (!context.valid)
return error.DefinitionDoesNotDominateUse;
}
}
fn checkDominanceUse(context: *DominanceUseContext, value_id: ids.ValueId) void {
if (!context.valid)
return;
const value = context.module.values.get(value_id) orelse {
context.valid = false;
return;
};
context.valid = switch (value.definition) {
.constant, .undef => true,
.function_parameter => |definition| definition.function == context.function_id,
.block_parameter => |definition| context.analysis.dominates(definition.block, context.use_block),
.instruction => |instruction_id| blk: {
const definition = context.module.instructions.get(instruction_id) orelse break :blk false;
if (!context.analysis.dominates(definition.parent_block, context.use_block))
break :blk false;
if (definition.parent_block != context.use_block)
break :blk true;
const block = context.module.blocks.get(context.use_block) orelse break :blk false;
for (block.instructions.items, 0..) |candidate, definition_index| {
if (candidate == instruction_id)
break :blk definition_index < context.use_index;
}
break :blk false;
},
};
}