Skip to documentation
SLOP

tiny.choir.ir.dialects.opSpec

Reference tiny.choir ir dialects opSpec

Defined in ir.dialects.

API (7)

Actions

Public operations.

Types and contracts

Public types and contracts.

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

Source

Source: lib/choir/src/core/dialects/spec.zig:926

zig
pub const opSpec = struct {    pub const Options = struct {        traits: interfaces.OperationTraits = .{},        attrs: []const []const u8 = &.{},        required_attrs: []const []const u8 = &.{},        attribute_specs: []const AttributeSpec = &.{},        operand_segments: ?interfaces.OperationSegmentSpec = null,        result_segments: ?interfaces.OperationSegmentSpec = null,        operand_types: []const interfaces.OperationTypeConstraint = &.{},        result_types: []const interfaces.OperationTypeConstraint = &.{},        properties: ?interfaces.OperationPropertiesModel = null,        interfaces: []const interfaces.InterfaceEntry = &.{},        dynamic_traits: []const OperationTraitSpec = &.{},    };    pub fn dialect(comptime Target: type) type {        const Names = namesFor(Target);        return struct {            pub fn name(comptime mnemonic: []const u8) []const u8 {                return Names.name(mnemonic);            }            pub fn state(comptime OpType: type, loc: Location) Operation.State {                return Names.state(OpType, loc);            }            pub fn define(comptime spec: anytype) OperationSpec {                comptime validateDecl(@TypeOf(spec), "mnemonic");                return shapedWithLayout(Names.name(@field(spec, "mnemonic")), shapeFromDecl(spec), layoutFromDecl(spec), optionsFromDecl(spec));            }            pub fn leaf(comptime spec: anytype) OperationSpec {                comptime validateDecl(@TypeOf(spec), "mnemonic");                return shapedWithLayout(Names.name(@field(spec, "mnemonic")), leafShapeFromDecl(spec), layoutFromDecl(spec), optionsFromDecl(spec));            }            pub fn terminator(comptime spec: anytype) OperationSpec {                comptime validateDecl(@TypeOf(spec), "mnemonic");                return shapedWithLayout(Names.name(@field(spec, "mnemonic")), terminatorShapeFromDecl(spec), layoutFromDecl(spec), terminatorOptionsFromDecl(spec));            }        };    }    pub fn define(comptime spec: anytype) OperationSpec {        comptime validateDecl(@TypeOf(spec), "name");        return shapedWithLayout(@field(spec, "name"), shapeFromDecl(spec), layoutFromDecl(spec), optionsFromDecl(spec));    }    pub fn terminator(comptime spec: anytype) OperationSpec {        comptime validateDecl(@TypeOf(spec), "name");        return shapedWithLayout(@field(spec, "name"), terminatorShapeFromDecl(spec), layoutFromDecl(spec), terminatorOptionsFromDecl(spec));    }    pub fn shaped(comptime full_name: []const u8, comptime op_shape: interfaces.OperationShape, comptime options: Options) OperationSpec {        return shapedWithLayout(full_name, op_shape, .{}, options);    }    pub fn dynamicTraits(comptime values: anytype) []const OperationTraitSpec {        return asSlice(OperationTraitSpec, values, "dynamic_traits");    }    pub fn verifier(comptime verify_fn: *const fn (op_ptr: *const anyopaque) anyerror!void) interfaces.InterfaceEntry {        return VerifyOpInterface.entryFor(verify_fn);    }    fn shapedWithLayout(comptime full_name: []const u8, comptime op_shape: interfaces.OperationShape, comptime op_layout: OperationLayout, comptime options: Options) OperationSpec {        if (full_name.len == 0) @compileError("operation name cannot be empty");        validateLayout(op_shape, op_layout);        return .{            .name = full_name,            .shape = op_shape,            .operand_names = op_layout.operands,            .result_names = op_layout.results,            .region_names = op_layout.regions,            .successor_names = op_layout.successors,            .traits = options.traits,            .inherent_attribute_names = attributeNamesWithRequired(options.attrs, options.required_attrs),            .required_attribute_names = options.required_attrs,            .attribute_specs = attributeSpecsWithNames(options.attribute_specs, attributeNamesWithRequired(options.attrs, options.required_attrs)),            .operand_segments = options.operand_segments,            .result_segments = options.result_segments,            .operand_type_constraints = options.operand_types,            .result_type_constraints = options.result_types,            .properties_model = options.properties,            .interfaces = options.interfaces,            .dynamic_traits = options.dynamic_traits,        };    }    fn layoutFromDecl(comptime spec: anytype) OperationLayout {        return .{            .operands = layoutField(spec, "operands", "operand_names"),            .results = layoutField(spec, "results", "result_names"),            .regions = layoutField(spec, "regions", "region_names"),            .successors = layoutField(spec, "successors", "successor_names"),        };    }    fn shapeFromDecl(comptime spec: anytype) interfaces.OperationShape {        const Spec = @TypeOf(spec);        if (comptime @hasField(Spec, "shape")) {            if (@hasField(Spec, "operands")) @compileError("operation declaration cannot specify both shape and operands");            if (@hasField(Spec, "results")) @compileError("operation declaration cannot specify both shape and results");            if (@hasField(Spec, "regions")) @compileError("operation declaration cannot specify both shape and regions");            if (@hasField(Spec, "successors")) @compileError("operation declaration cannot specify both shape and successors");            return shapeFromValue(@field(spec, "shape"));        }        return .{            .operands = shapeField(spec, "operands"),            .results = shapeField(spec, "results"),            .regions = shapeField(spec, "regions"),            .successors = shapeField(spec, "successors"),        };    }    fn terminatorShapeFromDecl(comptime spec: anytype) interfaces.OperationShape {        const Spec = @TypeOf(spec);        if (@hasField(Spec, "shape")) @compileError("terminator operation declaration cannot specify shape");        return .{            .operands = shapeField(spec, "operands"),            .results = shapeFieldOrExact(spec, "results", 0),            .regions = shapeFieldOrExact(spec, "regions", 0),            .successors = shapeFieldOrExact(spec, "successors", 0),        };    }    fn shapeFromValue(comptime value: anytype) interfaces.OperationShape {        const Value = @TypeOf(value);        if (Value == interfaces.OperationShape) return value;        return shape.of(value);    }    fn leafShapeFromDecl(comptime spec: anytype) interfaces.OperationShape {        const Spec = @TypeOf(spec);        if (@hasField(Spec, "shape")) @compileError("leaf operation declaration cannot specify shape");        if (@hasField(Spec, "regions")) @compileError("leaf operation declaration cannot specify regions");        if (@hasField(Spec, "successors")) @compileError("leaf operation declaration cannot specify successors");        return .{            .operands = shapeField(spec, "operands"),            .results = shapeField(spec, "results"),            .regions = interfaces.CountRange.exactly(0),            .successors = interfaces.CountRange.exactly(0),        };    }    fn shapeField(comptime spec: anytype, comptime name: []const u8) interfaces.CountRange {        if (comptime @hasField(@TypeOf(spec), name)) return shape.rangeFrom(@field(spec, name));        return .{};    }    fn layoutField(comptime spec: anytype, comptime shape_name: []const u8, comptime names_name: []const u8) []const []const u8 {        const inferred = if (comptime @hasField(@TypeOf(spec), shape_name))            componentNamesFromValue(@field(spec, shape_name), shape_name)        else            &.{};        if (comptime @hasField(@TypeOf(spec), names_name)) {            const explicit = componentNamesFromValue(@field(spec, names_name), names_name);            if (inferred.len != 0) {                @compileError("operation declaration cannot specify both named " ++ shape_name ++ " and " ++ names_name);            }            return explicit;        }        return inferred;    }    fn validateLayout(comptime op_shape: interfaces.OperationShape, comptime op_layout: OperationLayout) void {        validateLayoutRange(op_shape.operands, op_layout.operands, "operand");        validateLayoutRange(op_shape.results, op_layout.results, "result");        validateLayoutRange(op_shape.regions, op_layout.regions, "region");        validateLayoutRange(op_shape.successors, op_layout.successors, "successor");    }    fn validateLayoutRange(comptime range: interfaces.CountRange, comptime names: []const []const u8, comptime kind: []const u8) void {        if (range.max) |max| {            if (names.len > max) {                @compileError("operation " ++ kind ++ " names cannot exceed the operation shape maximum");            }        }    }    fn shapeFieldOrExact(comptime spec: anytype, comptime name: []const u8, comptime count: usize) interfaces.CountRange {        if (comptime @hasField(@TypeOf(spec), name)) return shape.rangeFrom(@field(spec, name));        return interfaces.CountRange.exactly(count);    }    fn optionsFromDecl(comptime spec: anytype) Options {        const attr_specs = attributeSpecsFromDecl(spec, "attrs");        const required_attr_specs = attributeSpecsFromDecl(spec, "required_attrs");        return .{            .traits = declField(spec, "traits", interfaces.OperationTraits{}),            .attrs = attributeNamesFromSpecs(attr_specs),            .required_attrs = attributeNamesFromSpecs(required_attr_specs),            .attribute_specs = attributeSpecsWithRequired(attr_specs, required_attr_specs),            .operand_segments = segmentDecl(spec, "operand_segments"),            .result_segments = segmentDecl(spec, "result_segments"),            .operand_types = declSlice(interfaces.OperationTypeConstraint, spec, "operand_types"),            .result_types = declSlice(interfaces.OperationTypeConstraint, spec, "result_types"),            .properties = declField(spec, "properties", @as(?interfaces.OperationPropertiesModel, null)),            .interfaces = declSlice(interfaces.InterfaceEntry, spec, "interfaces"),            .dynamic_traits = if (comptime @hasField(@TypeOf(spec), "dynamic_traits")) dynamicTraits(@field(spec, "dynamic_traits")) else &.{},        };    }    fn terminatorOptionsFromDecl(comptime spec: anytype) Options {        return optionsWithDynamicTrait(optionsFromDecl(spec), trait(core_traits.Terminator));    }    fn declField(comptime spec: anytype, comptime name: []const u8, comptime default: anytype) @TypeOf(default) {        if (comptime @hasField(@TypeOf(spec), name)) return @field(spec, name);        return default;    }    fn declSlice(comptime Element: type, comptime spec: anytype, comptime name: []const u8) []const Element {        if (comptime !@hasField(@TypeOf(spec), name)) return &.{};        return asSlice(Element, @field(spec, name), name);    }    fn segmentDecl(comptime spec: anytype, comptime name: []const u8) ?interfaces.OperationSegmentSpec {        if (comptime !@hasField(@TypeOf(spec), name)) return null;        const value = @field(spec, name);        if (@TypeOf(value) != interfaces.OperationSegmentSpec) {            @compileError("operation declaration field " ++ name ++ " must be an OperationSegmentSpec");        }        return value;    }    fn asSlice(comptime Element: type, comptime values: anytype, comptime name: []const u8) []const Element {        const Values = @TypeOf(values);        if (Values == []const Element) return values;        switch (@typeInfo(Values)) {            .pointer => |pointer_info| {                switch (pointer_info.size) {                    .one => switch (@typeInfo(pointer_info.child)) {                        .array => |array_info| {                            const typed = comptime blk: {                                var out: [array_info.len]Element = undefined;                                for (values.*, 0..) |value, index| {                                    out[index] = asElement(Element, value);                                }                                break :blk out;                            };                            return &typed;                        },                        .@"struct" => |struct_info| {                            if (!struct_info.is_tuple) @compileError("operation declaration field " ++ name ++ " must be a comptime slice, array, or tuple");                            const typed = comptime blk: {                                var out: [struct_info.field_names.len]Element = undefined;                                for (struct_info.field_names, 0..) |field_name, index| {                                    out[index] = asElement(Element, @field(values.*, field_name));                                }                                break :blk out;                            };                            return &typed;                        },                        else => @compileError("operation declaration field " ++ name ++ " must be a comptime slice or array pointer"),                    },                    .slice => {                        const typed = comptime blk: {                            var out: [values.len]Element = undefined;                            for (values, 0..) |value, index| {                                out[index] = asElement(Element, value);                            }                            break :blk out;                        };                        return &typed;                    },                    else => @compileError("operation declaration field " ++ name ++ " must be a comptime slice or array pointer"),                }            },            .array => |array_info| {                const typed = comptime blk: {                    var out: [array_info.len]Element = undefined;                    for (values, 0..) |value, index| {                        out[index] = asElement(Element, value);                    }                    break :blk out;                };                return &typed;            },            .@"struct" => |struct_info| {                if (!struct_info.is_tuple) @compileError("operation declaration field " ++ name ++ " must be a comptime slice, array, or tuple");                const typed = comptime blk: {                    var out: [struct_info.field_names.len]Element = undefined;                    for (struct_info.field_names, 0..) |field_name, index| {                        out[index] = asElement(Element, @field(values, field_name));                    }                    break :blk out;                };                return &typed;            },            else => @compileError("operation declaration field " ++ name ++ " must be a comptime slice or array pointer"),        }    }    fn asElement(comptime Element: type, comptime value: anytype) Element {        const Value = @TypeOf(value);        if (Element == OperationTraitSpec and Value == type) return trait(value);        if (Value == Element) return value;        return switch (@typeInfo(Element)) {            .@"struct" => |element_info| blk: {                var out: Element = undefined;                for (element_info.field_names) |field_name| {                    @field(out, field_name) = @field(value, field_name);                }                break :blk out;            },            else => value,        };    }    fn optionsWithDynamicTrait(comptime options: Options, comptime trait_spec: OperationTraitSpec) Options {        return .{            .traits = options.traits.merge(trait_spec.traits),            .attrs = options.attrs,            .required_attrs = options.required_attrs,            .attribute_specs = options.attribute_specs,            .operand_segments = options.operand_segments,            .result_segments = options.result_segments,            .operand_types = options.operand_types,            .result_types = options.result_types,            .properties = options.properties,            .interfaces = options.interfaces,            .dynamic_traits = dynamicTraitsWith(options.dynamic_traits, trait_spec),        };    }    fn dynamicTraitsWith(comptime dynamic_traits: []const OperationTraitSpec, comptime trait_spec: OperationTraitSpec) []const OperationTraitSpec {        for (dynamic_traits) |existing| {            if (existing.id == trait_spec.id) @compileError("operation dynamic trait is duplicated");        }        const values = comptime blk: {            var out: [dynamic_traits.len + 1]OperationTraitSpec = undefined;            for (dynamic_traits, 0..) |existing, index| {                out[index] = existing;            }            out[dynamic_traits.len] = trait_spec;            break :blk out;        };        return &values;    }    fn validateDecl(comptime Spec: type, comptime name_field: []const u8) void {        switch (@typeInfo(Spec)) {            .@"struct" => |struct_info| {                if (!@hasField(Spec, name_field)) @compileError("operation declaration must declare " ++ name_field);                inline for (struct_info.field_names) |field_name| {                    if (!isDeclField(field_name, name_field)) {                        @compileError("unknown operation declaration field: " ++ field_name);                    }                }            },            else => @compileError("operation declaration must be a struct literal"),        }    }    fn isDeclField(comptime field_name: []const u8, comptime name_field: []const u8) bool {        return std.mem.eql(u8, field_name, name_field) or            std.mem.eql(u8, field_name, "shape") or            std.mem.eql(u8, field_name, "operands") or            std.mem.eql(u8, field_name, "operand_names") or            std.mem.eql(u8, field_name, "results") or            std.mem.eql(u8, field_name, "result_names") or            std.mem.eql(u8, field_name, "regions") or            std.mem.eql(u8, field_name, "region_names") or            std.mem.eql(u8, field_name, "successors") or            std.mem.eql(u8, field_name, "successor_names") or            std.mem.eql(u8, field_name, "traits") or            std.mem.eql(u8, field_name, "attrs") or            std.mem.eql(u8, field_name, "required_attrs") or            std.mem.eql(u8, field_name, "operand_segments") or            std.mem.eql(u8, field_name, "result_segments") or            std.mem.eql(u8, field_name, "operand_types") or            std.mem.eql(u8, field_name, "result_types") or            std.mem.eql(u8, field_name, "properties") or            std.mem.eql(u8, field_name, "interfaces") or            std.mem.eql(u8, field_name, "dynamic_traits");    }    fn namesFor(comptime Target: type) type {        if (comptime isDialectType(Target)) return operationNames(Target);        if (comptime isOperationNamesType(Target)) return Target;        @compileError("opSpec.dialect expects a dialect type or operationNames result");    }    fn isDialectType(comptime Target: type) bool {        if (!@hasDecl(Target, "name")) return false;        return switch (@typeInfo(@TypeOf(@field(Target, "name")))) {            .pointer => true,            else => false,        };    }    fn isOperationNamesType(comptime Target: type) bool {        if (!@hasDecl(Target, "name")) return false;        if (!@hasDecl(Target, "state")) return false;        return switch (@typeInfo(@TypeOf(@field(Target, "name")))) {            .@"fn" => true,            else => false,        };    }};

Source: lib/choir/src/core/dialects/root.zig:48

zig
pub const opSpec = spec.opSpec;
Called byCallstest sourcelib.choir.src.core.dialects.spectest: opSpec names components indepen...test sourcelib.choir.src.core.dialects.spectest: operation descriptor DSL accept...test sourcelib.choir.src.core.dialects.spectest: operation descriptor DSL accept...test sourcelib.choir.src.core.dialects.spectest: operation descriptor DSL carrie...private sourcelib.choir.src.core.dialects.spec.opSpeclayoutFromDeclprivate sourcelib.choir.src.core.dialects.spec.opSpecoptionsFromDeclprivate sourcelib.choir.src.core.dialects.spec.opSpecshapeFromDeclprivate sourcelib.choir.src.core.dialects.spec.opSpecshapedWithLayoutprivate sourcelib.choir.src.core.dialects.spec.opSpecvalidateDeclir.dialects.opSpecdefine
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsir.dialects.operationTemplateexplicitir.dialects.operationTemplateexplicitLeafir.dialects.operationTemplateexplicitTerminatortest sourcelib.choir.src.core.dialects.spectest: DialectSpec derives verifier an...test sourcelib.choir.src.core.dialects.spectest: DialectSpec registers operation...+5 moreprivate sourcelib.choir.src.core.dialects.spec.opSpeclayoutFromDeclprivate sourcelib.choir.src.core.dialects.spec.opSpecleafShapeFromDeclprivate sourcelib.choir.src.core.dialects.spec.opSpecnamesForprivate sourcelib.choir.src.core.dialects.spec.opSpecoptionsFromDeclprivate sourcelib.choir.src.core.dialects.spec.opSpecshapeFromDecl+4 moreir.dialects.opSpecdialect
Static calls · unresolved targets: 2 · external targets: 0.
Called byCallsprivate sourcelib.choir.src.core.dialects.spec.opSpecoptionsFromDecltest sourcelib.choir.src.core.dialects.spectest: operationTemplate generates fix...test sourcelib.choir.src.core.dialects.spectest: operation descriptor DSL accept...private sourcelib.choir.src.core.dialects.spec.opSpecasSliceir.dialects.opSpecdynamicTraits
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsprivate sourcelib.choir.src.core.dialects.spec.operationTem...binaryFixedResultImplprivate sourcelib.choir.src.core.dialects.spec.operationTem...binarySameTypeImplprivate sourcelib.choir.src.core.dialects.spec.operationTem...selectSameTypeImplprivate sourcelib.choir.src.core.dialects.spec.operationTem...ternarySameTypeImplprivate sourcelib.choir.src.core.dialects.spec.operationTem...unaryExplicitTypeImpl+4 moreprivate sourcelib.choir.src.core.dialects.spec.opSpecshapedWithLayoutir.dialects.opSpecshaped
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.choir.src.core.dialects.spectest: operation descriptor DSL derive...private sourcelib.choir.src.core.dialects.spec.opSpeclayoutFromDeclprivate sourcelib.choir.src.core.dialects.spec.opSpecshapedWithLayoutprivate sourcelib.choir.src.core.dialects.spec.opSpecterminatorOptionsFromDeclprivate sourcelib.choir.src.core.dialects.spec.opSpecterminatorShapeFromDeclprivate sourcelib.choir.src.core.dialects.spec.opSpecvalidateDeclir.dialects.opSpecterminator
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.choir.src.core.dialects.spectest: operationTemplate carries verif...test sourcelib.choir.src.core.dialects.spectest: operationTemplate nested defini...ir.VerifyOpInterfaceentryForir.dialects.opSpecverifier
Static calls · unresolved targets: 1 · external targets: 0.

Also reachable as

backends.wasm.emission.module_encoding.common.ir.dialects.opSpec.

Complete caller list for ir.dialects.opSpec.dialect

10 direct callers.

Complete call list for ir.dialects.opSpec.dialect

9 direct calls.

Complete caller list for ir.dialects.opSpec.shaped

9 direct callers.

Audit

Definitions8
Public names16
Members11
Version26.7.0
Revisiondaab053ee433