Skip to documentation
SLOP

tiny.choir.ir.traits

Reference tiny.choir ir traits

Defined in ir.

API (26)

Actions

Public operations.

Types and contracts

Public types and contracts.

No direct callersNo direct callsirtraits
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallsNo direct callersprivate sourcelib.choir.src.core.traitsverifySingleBlockRegionsir.traitsSingleBlockImplicitTerminator
Static calls · unresolved targets: 0 · external targets: 3.
Called byCallsprivate sourcelib.choir.src.core.traitsverifyOperationOperandsWithinprivate sourcelib.choir.src.core.traitsisValueWithinir.traitsverifyOperandsWithin
Static calls · unresolved targets: 0 · external targets: 0.

Source: lib/choir/src/core/root.zig:36

zig
pub const traits = @import("traits.zig");

Source: lib/choir/src/core/traits.zig

zig
const std = @import("std");const Operation = @import("operation/root.zig").Operation;const Block = @import("block.zig").Block;const Value = @import("value.zig").Value;const Context = @import("context/root.zig").Context;const interfaces = @import("interfaces/root.zig");pub const TraitError = error{    OperandCountMismatch,    ResultCountMismatch,    RegionCountMismatch,    SingleBlockRegionMismatch,    ImplicitTerminatorMismatch,    TerminatorNotLast,    IsolatedFromAbove,    SameOperandsAndResultTypeMismatch,    SameTypeOperandsMismatch,    TypesMatchWithMismatch,};fn isValueWithin(root: *const Operation, value: *const Value) bool {    return switch (value.kind) {        .block_argument => |info| blk: {            const block: *const Block = @ptrCast(@alignCast(info.owner));            const parent_op = block.getParentOperation() orelse break :blk false;            break :blk root.isAncestor(parent_op);        },        .op_result => |info| root.isProperAncestor(@ptrCast(@alignCast(info.owner))),    };}pub fn verifyOperandsWithin(root: *const Operation, candidate: *const Operation) TraitError!void {    for (candidate.operands.items) |operand| {        if (!isValueWithin(root, operand.value)) {            return TraitError.IsolatedFromAbove;        }    }}fn verifyOperationOperandsWithin(root: *const Operation, candidate: *const Operation, check_candidate: bool) TraitError!void {    if (check_candidate) {        try verifyOperandsWithin(root, candidate);    }    for (candidate.regions.items) |*region| {        var block = region.blocks.head;        while (block) |current_block| {            var op_node = current_block.operations.head;            while (op_node) |node| {                const nested_op: *const Operation = @ptrCast(@alignCast(node));                try verifyOperationOperandsWithin(root, nested_op, true);                op_node = nested_op.next_op;            }            block = current_block.next;        }    }}fn verifySingleBlockRegions(op: *const Operation) TraitError!void {    for (op.regions.items) |region| {        if (!region.hasOneBlock()) return TraitError.SingleBlockRegionMismatch;    }}pub fn registerOperationTrait(ctx: *Context, op_name: []const u8, comptime Trait: type) anyerror!void {    if (@hasDecl(Trait, "traits")) {        _ = try ctx.registerOperation(op_name, Trait.traits);    }    ctx.registerTraitDefinition(Trait.entry()) catch |err| switch (err) {        error.DuplicateTrait => {},        else => return err,    };    try ctx.registerOperationTraitId(op_name, Trait.id);}pub fn NOperands(comptime count: usize) type {    return struct {        pub const trait_name = std.fmt.comptimePrint("ir.trait.n_operands.{d}", .{count});        pub const id: interfaces.TraitId = interfaces.traitId(trait_name);        fn verify(op_ptr: *const anyopaque) anyerror!void {            const op: *const Operation = @ptrCast(@alignCast(op_ptr));            if (op.operands.items.len != count) return TraitError.OperandCountMismatch;        }        pub const vtable: interfaces.TraitVTable = .{ .verify = verify };        pub fn entry() interfaces.TraitEntry {            return .{ .id = id, .vtable = &vtable };        }    };}pub fn NResults(comptime count: usize) type {    return struct {        pub const trait_name = std.fmt.comptimePrint("ir.trait.n_results.{d}", .{count});        pub const id: interfaces.TraitId = interfaces.traitId(trait_name);        fn verify(op_ptr: *const anyopaque) anyerror!void {            const op: *const Operation = @ptrCast(@alignCast(op_ptr));            if (op.results.items.len != count) return TraitError.ResultCountMismatch;        }        pub const vtable: interfaces.TraitVTable = .{ .verify = verify };        pub fn entry() interfaces.TraitEntry {            return .{ .id = id, .vtable = &vtable };        }    };}pub const ZeroOperands = NOperands(0);pub const OneOperand = NOperands(1);pub const ZeroResults = NResults(0);pub const OneResult = NResults(1);pub fn NRegions(comptime count: usize) type {    return struct {        pub const trait_name = std.fmt.comptimePrint("ir.trait.n_regions.{d}", .{count});        pub const id: interfaces.TraitId = interfaces.traitId(trait_name);        fn verify(op_ptr: *const anyopaque) anyerror!void {            const op: *const Operation = @ptrCast(@alignCast(op_ptr));            if (op.regions.items.len != count) return TraitError.RegionCountMismatch;        }        pub const vtable: interfaces.TraitVTable = .{ .verify = verify };        pub fn entry() interfaces.TraitEntry {            return .{ .id = id, .vtable = &vtable };        }    };}pub fn AtLeastNRegions(comptime count: usize) type {    return struct {        pub const trait_name = std.fmt.comptimePrint("ir.trait.at_least_n_regions.{d}", .{count});        pub const id: interfaces.TraitId = interfaces.traitId(trait_name);        fn verify(op_ptr: *const anyopaque) anyerror!void {            const op: *const Operation = @ptrCast(@alignCast(op_ptr));            if (op.regions.items.len < count) return TraitError.RegionCountMismatch;        }        pub const vtable: interfaces.TraitVTable = .{ .verify = verify };        pub fn entry() interfaces.TraitEntry {            return .{ .id = id, .vtable = &vtable };        }    };}pub fn AtMostNRegions(comptime count: usize) type {    return struct {        pub const trait_name = std.fmt.comptimePrint("ir.trait.at_most_n_regions.{d}", .{count});        pub const id: interfaces.TraitId = interfaces.traitId(trait_name);        fn verify(op_ptr: *const anyopaque) anyerror!void {            const op: *const Operation = @ptrCast(@alignCast(op_ptr));            if (op.regions.items.len > count) return TraitError.RegionCountMismatch;        }        pub const vtable: interfaces.TraitVTable = .{ .verify = verify };        pub fn entry() interfaces.TraitEntry {            return .{ .id = id, .vtable = &vtable };        }    };}pub const ZeroRegions = NRegions(0);pub const OneRegion = NRegions(1);pub const SingleBlock = struct {    pub const trait_name = "ir.trait.single_block";    pub const id: interfaces.TraitId = interfaces.traitId(trait_name);    fn verify(op_ptr: *const anyopaque) anyerror!void {        const op: *const Operation = @ptrCast(@alignCast(op_ptr));        try verifySingleBlockRegions(op);    }    pub const vtable: interfaces.TraitVTable = .{ .verify_regions = verify };    pub fn entry() interfaces.TraitEntry {        return .{ .id = id, .vtable = &vtable };    }};pub fn SingleBlockImplicitTerminator(comptime terminator_name: []const u8) type {    return struct {        pub const trait_name = std.fmt.comptimePrint(            "ir.trait.single_block_implicit_terminator.{s}",            .{terminator_name},        );        pub const id: interfaces.TraitId = interfaces.traitId(trait_name);        fn verify(op_ptr: *const anyopaque) anyerror!void {            const op: *const Operation = @ptrCast(@alignCast(op_ptr));            try verifySingleBlockRegions(op);            for (op.regions.items) |region| {                const block = region.getEntryBlock() orelse return TraitError.SingleBlockRegionMismatch;                const term_any = block.getTerminator() orelse return TraitError.ImplicitTerminatorMismatch;                const term: *const Operation = @ptrCast(@alignCast(term_any));                if (!std.mem.eql(u8, term.name.name, terminator_name)) {                    return TraitError.ImplicitTerminatorMismatch;                }            }        }        pub const vtable: interfaces.TraitVTable = .{ .verify_regions = verify };        pub fn entry() interfaces.TraitEntry {            return .{ .id = id, .vtable = &vtable };        }    };}pub const Terminator = struct {    pub const trait_name = "ir.trait.terminator";    pub const id: interfaces.TraitId = interfaces.traitId(trait_name);    pub const traits = interfaces.OperationTraits{ .is_terminator = true };    fn verify(op_ptr: *const anyopaque) anyerror!void {        const op: *const Operation = @ptrCast(@alignCast(op_ptr));        if (op.getBlock() == null) return;        if (op.next_op != null) return TraitError.TerminatorNotLast;    }    pub const vtable: interfaces.TraitVTable = .{ .verify = verify };    pub fn entry() interfaces.TraitEntry {        return .{ .id = id, .vtable = &vtable };    }};pub const NoTerminator = struct {    pub const trait_name = "ir.trait.no_terminator";    pub const id: interfaces.TraitId = interfaces.traitId(trait_name);    pub const traits = interfaces.OperationTraits{ .has_no_terminator = true };    fn verify(op_ptr: *const anyopaque) anyerror!void {        const op: *const Operation = @ptrCast(@alignCast(op_ptr));        try verifySingleBlockRegions(op);    }    pub const vtable: interfaces.TraitVTable = .{ .verify_regions = verify };    pub fn entry() interfaces.TraitEntry {        return .{ .id = id, .vtable = &vtable };    }};pub const HasOnlyGraphRegion = struct {    pub const trait_name = "ir.trait.has_only_graph_region";    pub const id: interfaces.TraitId = interfaces.traitId(trait_name);    pub const traits = interfaces.OperationTraits{ .has_only_graph_regions = true };    pub const vtable: interfaces.TraitVTable = .{};    pub fn entry() interfaces.TraitEntry {        return .{ .id = id, .vtable = &vtable };    }};pub const SameOperandsAndResultType = struct {    pub const trait_name = "ir.trait.same_operands_and_result_type";    pub const id: interfaces.TraitId = interfaces.traitId(trait_name);    fn verify(op_ptr: *const anyopaque) anyerror!void {        const op: *const Operation = @ptrCast(@alignCast(op_ptr));        if (op.results.items.len == 0) return TraitError.SameOperandsAndResultTypeMismatch;        if (op.operands.items.len == 0) return TraitError.SameOperandsAndResultTypeMismatch;        const ref_type = op.results.items[0].type;        for (op.results.items) |result| {            if (!result.type.eql(ref_type)) return TraitError.SameOperandsAndResultTypeMismatch;        }        for (op.operands.items) |operand| {            if (!operand.value.type.eql(ref_type)) return TraitError.SameOperandsAndResultTypeMismatch;        }    }    pub const vtable: interfaces.TraitVTable = .{ .verify = verify };    pub fn entry() interfaces.TraitEntry {        return .{ .id = id, .vtable = &vtable };    }};pub const SameTypeOperands = struct {    pub const trait_name = "ir.trait.same_type_operands";    pub const id: interfaces.TraitId = interfaces.traitId(trait_name);    fn verify(op_ptr: *const anyopaque) anyerror!void {        const op: *const Operation = @ptrCast(@alignCast(op_ptr));        if (op.operands.items.len < 2) return;        const ref_type = op.operands.items[0].value.type;        for (op.operands.items[1..]) |operand| {            if (!operand.value.type.eql(ref_type)) {                return TraitError.SameTypeOperandsMismatch;            }        }    }    pub const vtable: interfaces.TraitVTable = .{ .verify = verify };    pub fn entry() interfaces.TraitEntry {        return .{ .id = id, .vtable = &vtable };    }};pub const TypeRef = union(enum) {    operand: usize,    result: usize,};pub const TypesMatchWithConfig = struct {    label: []const u8,    target: TypeRef,    source: TypeRef,};pub fn TypesMatchWith(comptime config: TypesMatchWithConfig) type {    return struct {        pub const trait_name = std.fmt.comptimePrint(            "ir.trait.types_match_with.{s}.{s}{d}_{s}{d}",            .{                config.label,                @tagName(config.target),                switch (config.target) {                    inline else => |idx| idx,                },                @tagName(config.source),                switch (config.source) {                    inline else => |idx| idx,                },            },        );        pub const id: interfaces.TraitId = interfaces.traitId(trait_name);        fn typeAt(op: *const Operation, ref: TypeRef) ?@import("type.zig").Type {            return switch (ref) {                .operand => |idx| if (idx < op.operands.items.len)                    op.operands.items[idx].value.type                else                    null,                .result => |idx| if (idx < op.results.items.len)                    op.results.items[idx].type                else                    null,            };        }        fn verify(op_ptr: *const anyopaque) anyerror!void {            const op: *const Operation = @ptrCast(@alignCast(op_ptr));            const target_type = typeAt(op, config.target) orelse                return TraitError.TypesMatchWithMismatch;            const source_type = typeAt(op, config.source) orelse                return TraitError.TypesMatchWithMismatch;            if (!target_type.eql(source_type)) {                return TraitError.TypesMatchWithMismatch;            }        }        pub const vtable: interfaces.TraitVTable = .{ .verify = verify };        pub fn entry() interfaces.TraitEntry {            return .{ .id = id, .vtable = &vtable };        }    };}pub const IsolatedFromAbove = struct {    pub const trait_name = "ir.trait.isolated_from_above";    pub const id: interfaces.TraitId = interfaces.traitId(trait_name);    fn verify(op_ptr: *const anyopaque) anyerror!void {        const op: *const Operation = @ptrCast(@alignCast(op_ptr));        try verifyOperationOperandsWithin(op, op, false);    }    pub const vtable: interfaces.TraitVTable = .{ .verify_regions = verify };    pub fn entry() interfaces.TraitEntry {        return .{ .id = id, .vtable = &vtable };    }};pub const SymbolTable = struct {    pub const trait_name = "ir.trait.symbol_table";    pub const id: interfaces.TraitId = interfaces.traitId(trait_name);    pub const traits = interfaces.OperationTraits{ .is_symbol_table = true };    fn verify(op_ptr: *const anyopaque) anyerror!void {        const op: *Operation = @ptrCast(@alignCast(@constCast(op_ptr)));        try @import("symbols.zig").SymbolTable.verifyOperation(op);    }    pub const vtable: interfaces.TraitVTable = .{ .verify_regions = verify };    pub fn entry() interfaces.TraitEntry {        return .{ .id = id, .vtable = &vtable };    }};

Also reachable as

backends.wasm.emission.module_encoding.common.ir.traits.

Audit

Definitions19
Public names38
Members15
Version26.7.0
Revisiondaab053ee433