enumstd.zig.llvm.Builder.Constant[src]

Types

Type Functionunwrap[src]

Parameters

self: Constant

Source Code

Source code
pub fn unwrap(self: Constant) union(enum) {
    constant: u30,
    global: Global.Index,
} {
    return if (@intFromEnum(self) < @intFromEnum(first_global))
        .{ .constant = @intCast(@intFromEnum(self)) }
    else
        .{ .global = @enumFromInt(@intFromEnum(self) - @intFromEnum(first_global)) };
}

Fields

false
true
@"0"
@"1"
none
no_init = (1 << 30) - 1
_

Functions

FunctiontoValue[src]

pub fn toValue(self: Constant) Value

Parameters

self: Constant

Source Code

Source code
pub fn toValue(self: Constant) Value {
    return @enumFromInt(Value.first_constant + @intFromEnum(self));
}

FunctiontypeOf[src]

pub fn typeOf(self: Constant, builder: *Builder) Type

Parameters

self: Constant
builder: *Builder

Source Code

Source code
pub fn typeOf(self: Constant, builder: *Builder) Type {
    switch (self.unwrap()) {
        .constant => |constant| {
            const item = builder.constant_items.get(constant);
            return switch (item.tag) {
                .positive_integer,
                .negative_integer,
                => @as(
                    *align(@alignOf(std.math.big.Limb)) Integer,
                    @ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]),
                ).type,
                .half => .half,
                .bfloat => .bfloat,
                .float => .float,
                .double => .double,
                .fp128 => .fp128,
                .x86_fp80 => .x86_fp80,
                .ppc_fp128 => .ppc_fp128,
                .null,
                .none,
                .zeroinitializer,
                .undef,
                .poison,
                => @enumFromInt(item.data),
                .structure,
                .packed_structure,
                .array,
                .vector,
                => builder.constantExtraData(Aggregate, item.data).type,
                .splat => builder.constantExtraData(Splat, item.data).type,
                .string => builder.arrayTypeAssumeCapacity(
                    @as(String, @enumFromInt(item.data)).slice(builder).?.len,
                    .i8,
                ),
                .blockaddress => builder.ptrTypeAssumeCapacity(
                    builder.constantExtraData(BlockAddress, item.data)
                        .function.ptrConst(builder).global.ptrConst(builder).addr_space,
                ),
                .dso_local_equivalent,
                .no_cfi,
                => builder.ptrTypeAssumeCapacity(@as(Function.Index, @enumFromInt(item.data))
                    .ptrConst(builder).global.ptrConst(builder).addr_space),
                .trunc,
                .ptrtoint,
                .inttoptr,
                .bitcast,
                .addrspacecast,
                => builder.constantExtraData(Cast, item.data).type,
                .getelementptr,
                .@"getelementptr inbounds",
                => {
                    var extra = builder.constantExtraDataTrail(GetElementPtr, item.data);
                    const indices =
                        extra.trail.next(extra.data.info.indices_len, Constant, builder);
                    const base_ty = extra.data.base.typeOf(builder);
                    if (!base_ty.isVector(builder)) for (indices) |index| {
                        const index_ty = index.typeOf(builder);
                        if (!index_ty.isVector(builder)) continue;
                        return index_ty.changeScalarAssumeCapacity(base_ty, builder);
                    };
                    return base_ty;
                },
                .add,
                .@"add nsw",
                .@"add nuw",
                .sub,
                .@"sub nsw",
                .@"sub nuw",
                .shl,
                .xor,
                => builder.constantExtraData(Binary, item.data).lhs.typeOf(builder),
                .@"asm",
                .@"asm sideeffect",
                .@"asm alignstack",
                .@"asm sideeffect alignstack",
                .@"asm inteldialect",
                .@"asm sideeffect inteldialect",
                .@"asm alignstack inteldialect",
                .@"asm sideeffect alignstack inteldialect",
                .@"asm unwind",
                .@"asm sideeffect unwind",
                .@"asm alignstack unwind",
                .@"asm sideeffect alignstack unwind",
                .@"asm inteldialect unwind",
                .@"asm sideeffect inteldialect unwind",
                .@"asm alignstack inteldialect unwind",
                .@"asm sideeffect alignstack inteldialect unwind",
                => .ptr,
            };
        },
        .global => |global| return builder.ptrTypeAssumeCapacity(
            global.ptrConst(builder).addr_space,
        ),
    }
}

FunctionisZeroInit[src]

pub fn isZeroInit(self: Constant, builder: *const Builder) bool

Parameters

self: Constant
builder: *const Builder

Source Code

Source code
pub fn isZeroInit(self: Constant, builder: *const Builder) bool {
    switch (self.unwrap()) {
        .constant => |constant| {
            const item = builder.constant_items.get(constant);
            return switch (item.tag) {
                .positive_integer => {
                    const extra: *align(@alignOf(std.math.big.Limb)) Integer =
                        @ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]);
                    const limbs = builder.constant_limbs
                        .items[item.data + Integer.limbs ..][0..extra.limbs_len];
                    return std.mem.eql(std.math.big.Limb, limbs, &.{0});
                },
                .half, .bfloat, .float => item.data == 0,
                .double => {
                    const extra = builder.constantExtraData(Constant.Double, item.data);
                    return extra.lo == 0 and extra.hi == 0;
                },
                .fp128, .ppc_fp128 => {
                    const extra = builder.constantExtraData(Constant.Fp128, item.data);
                    return extra.lo_lo == 0 and extra.lo_hi == 0 and
                        extra.hi_lo == 0 and extra.hi_hi == 0;
                },
                .x86_fp80 => {
                    const extra = builder.constantExtraData(Constant.Fp80, item.data);
                    return extra.lo_lo == 0 and extra.lo_hi == 0 and extra.hi == 0;
                },
                .vector => {
                    var extra = builder.constantExtraDataTrail(Aggregate, item.data);
                    const len: u32 = @intCast(extra.data.type.aggregateLen(builder));
                    const vals = extra.trail.next(len, Constant, builder);
                    for (vals) |val| if (!val.isZeroInit(builder)) return false;
                    return true;
                },
                .null, .zeroinitializer => true,
                else => false,
            };
        },
        .global => return false,
    }
}

FunctiongetBase[src]

pub fn getBase(self: Constant, builder: *const Builder) Global.Index

Parameters

self: Constant
builder: *const Builder

Source Code

Source code
pub fn getBase(self: Constant, builder: *const Builder) Global.Index {
    var cur = self;
    while (true) switch (cur.unwrap()) {
        .constant => |constant| {
            const item = builder.constant_items.get(constant);
            switch (item.tag) {
                .ptrtoint,
                .inttoptr,
                .bitcast,
                => cur = builder.constantExtraData(Cast, item.data).val,
                .getelementptr => cur = builder.constantExtraData(GetElementPtr, item.data).base,
                .add => {
                    const extra = builder.constantExtraData(Binary, item.data);
                    const lhs_base = extra.lhs.getBase(builder);
                    const rhs_base = extra.rhs.getBase(builder);
                    return if (lhs_base != .none and rhs_base != .none)
                        .none
                    else if (lhs_base != .none) lhs_base else rhs_base;
                },
                .sub => {
                    const extra = builder.constantExtraData(Binary, item.data);
                    if (extra.rhs.getBase(builder) != .none) return .none;
                    cur = extra.lhs;
                },
                else => return .none,
            }
        },
        .global => |global| switch (global.ptrConst(builder).kind) {
            .alias => |alias| cur = alias.ptrConst(builder).aliasee,
            .variable, .function => return global,
            .replaced => unreachable,
        },
    };
}

Functionfmt[src]

pub fn fmt(self: Constant, builder: *Builder) std.fmt.Formatter(format)

Parameters

self: Constant
builder: *Builder

Source Code

Source code
pub fn fmt(self: Constant, builder: *Builder) std.fmt.Formatter(format) {
    return .{ .data = .{ .constant = self, .builder = builder } };
}

Source Code

Source code
pub const Constant = enum(u32) {
    false,
    true,
    @"0",
    @"1",
    none,
    no_init = (1 << 30) - 1,
    _,

    const first_global: Constant = @enumFromInt(1 << 29);

    pub const Tag = enum(u7) {
        positive_integer,
        negative_integer,
        half,
        bfloat,
        float,
        double,
        fp128,
        x86_fp80,
        ppc_fp128,
        null,
        none,
        structure,
        packed_structure,
        array,
        string,
        vector,
        splat,
        zeroinitializer,
        undef,
        poison,
        blockaddress,
        dso_local_equivalent,
        no_cfi,
        trunc,
        ptrtoint,
        inttoptr,
        bitcast,
        addrspacecast,
        getelementptr,
        @"getelementptr inbounds",
        add,
        @"add nsw",
        @"add nuw",
        sub,
        @"sub nsw",
        @"sub nuw",
        shl,
        xor,
        @"asm",
        @"asm sideeffect",
        @"asm alignstack",
        @"asm sideeffect alignstack",
        @"asm inteldialect",
        @"asm sideeffect inteldialect",
        @"asm alignstack inteldialect",
        @"asm sideeffect alignstack inteldialect",
        @"asm unwind",
        @"asm sideeffect unwind",
        @"asm alignstack unwind",
        @"asm sideeffect alignstack unwind",
        @"asm inteldialect unwind",
        @"asm sideeffect inteldialect unwind",
        @"asm alignstack inteldialect unwind",
        @"asm sideeffect alignstack inteldialect unwind",

        pub fn toBinaryOpcode(self: Tag) BinaryOpcode {
            return switch (self) {
                .add,
                .@"add nsw",
                .@"add nuw",
                => .add,
                .sub,
                .@"sub nsw",
                .@"sub nuw",
                => .sub,
                .shl => .shl,
                .xor => .xor,
                else => unreachable,
            };
        }

        pub fn toCastOpcode(self: Tag) CastOpcode {
            return switch (self) {
                .trunc => .trunc,
                .ptrtoint => .ptrtoint,
                .inttoptr => .inttoptr,
                .bitcast => .bitcast,
                .addrspacecast => .addrspacecast,
                else => unreachable,
            };
        }
    };

    pub const Item = struct {
        tag: Tag,
        data: ExtraIndex,

        const ExtraIndex = u32;
    };

    pub const Integer = packed struct(u64) {
        type: Type,
        limbs_len: u32,

        pub const limbs = @divExact(@bitSizeOf(Integer), @bitSizeOf(std.math.big.Limb));
    };

    pub const Double = struct {
        lo: u32,
        hi: u32,
    };

    pub const Fp80 = struct {
        lo_lo: u32,
        lo_hi: u32,
        hi: u32,
    };

    pub const Fp128 = struct {
        lo_lo: u32,
        lo_hi: u32,
        hi_lo: u32,
        hi_hi: u32,
    };

    pub const Aggregate = struct {
        type: Type,
        //fields: [type.aggregateLen(builder)]Constant,
    };

    pub const Splat = extern struct {
        type: Type,
        value: Constant,
    };

    pub const BlockAddress = extern struct {
        function: Function.Index,
        block: Function.Block.Index,
    };

    pub const Cast = extern struct {
        val: Constant,
        type: Type,

        pub const Signedness = enum { unsigned, signed, unneeded };
    };

    pub const GetElementPtr = struct {
        type: Type,
        base: Constant,
        info: Info,
        //indices: [info.indices_len]Constant,

        pub const Kind = enum { normal, inbounds };
        pub const InRangeIndex = enum(u16) { none = std.math.maxInt(u16), _ };
        pub const Info = packed struct(u32) { indices_len: u16, inrange: InRangeIndex };
    };

    pub const Binary = extern struct {
        lhs: Constant,
        rhs: Constant,
    };

    pub const Assembly = extern struct {
        type: Type,
        assembly: String,
        constraints: String,

        pub const Info = packed struct {
            sideeffect: bool = false,
            alignstack: bool = false,
            inteldialect: bool = false,
            unwind: bool = false,
        };
    };

    pub fn unwrap(self: Constant) union(enum) {
        constant: u30,
        global: Global.Index,
    } {
        return if (@intFromEnum(self) < @intFromEnum(first_global))
            .{ .constant = @intCast(@intFromEnum(self)) }
        else
            .{ .global = @enumFromInt(@intFromEnum(self) - @intFromEnum(first_global)) };
    }

    pub fn toValue(self: Constant) Value {
        return @enumFromInt(Value.first_constant + @intFromEnum(self));
    }

    pub fn typeOf(self: Constant, builder: *Builder) Type {
        switch (self.unwrap()) {
            .constant => |constant| {
                const item = builder.constant_items.get(constant);
                return switch (item.tag) {
                    .positive_integer,
                    .negative_integer,
                    => @as(
                        *align(@alignOf(std.math.big.Limb)) Integer,
                        @ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]),
                    ).type,
                    .half => .half,
                    .bfloat => .bfloat,
                    .float => .float,
                    .double => .double,
                    .fp128 => .fp128,
                    .x86_fp80 => .x86_fp80,
                    .ppc_fp128 => .ppc_fp128,
                    .null,
                    .none,
                    .zeroinitializer,
                    .undef,
                    .poison,
                    => @enumFromInt(item.data),
                    .structure,
                    .packed_structure,
                    .array,
                    .vector,
                    => builder.constantExtraData(Aggregate, item.data).type,
                    .splat => builder.constantExtraData(Splat, item.data).type,
                    .string => builder.arrayTypeAssumeCapacity(
                        @as(String, @enumFromInt(item.data)).slice(builder).?.len,
                        .i8,
                    ),
                    .blockaddress => builder.ptrTypeAssumeCapacity(
                        builder.constantExtraData(BlockAddress, item.data)
                            .function.ptrConst(builder).global.ptrConst(builder).addr_space,
                    ),
                    .dso_local_equivalent,
                    .no_cfi,
                    => builder.ptrTypeAssumeCapacity(@as(Function.Index, @enumFromInt(item.data))
                        .ptrConst(builder).global.ptrConst(builder).addr_space),
                    .trunc,
                    .ptrtoint,
                    .inttoptr,
                    .bitcast,
                    .addrspacecast,
                    => builder.constantExtraData(Cast, item.data).type,
                    .getelementptr,
                    .@"getelementptr inbounds",
                    => {
                        var extra = builder.constantExtraDataTrail(GetElementPtr, item.data);
                        const indices =
                            extra.trail.next(extra.data.info.indices_len, Constant, builder);
                        const base_ty = extra.data.base.typeOf(builder);
                        if (!base_ty.isVector(builder)) for (indices) |index| {
                            const index_ty = index.typeOf(builder);
                            if (!index_ty.isVector(builder)) continue;
                            return index_ty.changeScalarAssumeCapacity(base_ty, builder);
                        };
                        return base_ty;
                    },
                    .add,
                    .@"add nsw",
                    .@"add nuw",
                    .sub,
                    .@"sub nsw",
                    .@"sub nuw",
                    .shl,
                    .xor,
                    => builder.constantExtraData(Binary, item.data).lhs.typeOf(builder),
                    .@"asm",
                    .@"asm sideeffect",
                    .@"asm alignstack",
                    .@"asm sideeffect alignstack",
                    .@"asm inteldialect",
                    .@"asm sideeffect inteldialect",
                    .@"asm alignstack inteldialect",
                    .@"asm sideeffect alignstack inteldialect",
                    .@"asm unwind",
                    .@"asm sideeffect unwind",
                    .@"asm alignstack unwind",
                    .@"asm sideeffect alignstack unwind",
                    .@"asm inteldialect unwind",
                    .@"asm sideeffect inteldialect unwind",
                    .@"asm alignstack inteldialect unwind",
                    .@"asm sideeffect alignstack inteldialect unwind",
                    => .ptr,
                };
            },
            .global => |global| return builder.ptrTypeAssumeCapacity(
                global.ptrConst(builder).addr_space,
            ),
        }
    }

    pub fn isZeroInit(self: Constant, builder: *const Builder) bool {
        switch (self.unwrap()) {
            .constant => |constant| {
                const item = builder.constant_items.get(constant);
                return switch (item.tag) {
                    .positive_integer => {
                        const extra: *align(@alignOf(std.math.big.Limb)) Integer =
                            @ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]);
                        const limbs = builder.constant_limbs
                            .items[item.data + Integer.limbs ..][0..extra.limbs_len];
                        return std.mem.eql(std.math.big.Limb, limbs, &.{0});
                    },
                    .half, .bfloat, .float => item.data == 0,
                    .double => {
                        const extra = builder.constantExtraData(Constant.Double, item.data);
                        return extra.lo == 0 and extra.hi == 0;
                    },
                    .fp128, .ppc_fp128 => {
                        const extra = builder.constantExtraData(Constant.Fp128, item.data);
                        return extra.lo_lo == 0 and extra.lo_hi == 0 and
                            extra.hi_lo == 0 and extra.hi_hi == 0;
                    },
                    .x86_fp80 => {
                        const extra = builder.constantExtraData(Constant.Fp80, item.data);
                        return extra.lo_lo == 0 and extra.lo_hi == 0 and extra.hi == 0;
                    },
                    .vector => {
                        var extra = builder.constantExtraDataTrail(Aggregate, item.data);
                        const len: u32 = @intCast(extra.data.type.aggregateLen(builder));
                        const vals = extra.trail.next(len, Constant, builder);
                        for (vals) |val| if (!val.isZeroInit(builder)) return false;
                        return true;
                    },
                    .null, .zeroinitializer => true,
                    else => false,
                };
            },
            .global => return false,
        }
    }

    pub fn getBase(self: Constant, builder: *const Builder) Global.Index {
        var cur = self;
        while (true) switch (cur.unwrap()) {
            .constant => |constant| {
                const item = builder.constant_items.get(constant);
                switch (item.tag) {
                    .ptrtoint,
                    .inttoptr,
                    .bitcast,
                    => cur = builder.constantExtraData(Cast, item.data).val,
                    .getelementptr => cur = builder.constantExtraData(GetElementPtr, item.data).base,
                    .add => {
                        const extra = builder.constantExtraData(Binary, item.data);
                        const lhs_base = extra.lhs.getBase(builder);
                        const rhs_base = extra.rhs.getBase(builder);
                        return if (lhs_base != .none and rhs_base != .none)
                            .none
                        else if (lhs_base != .none) lhs_base else rhs_base;
                    },
                    .sub => {
                        const extra = builder.constantExtraData(Binary, item.data);
                        if (extra.rhs.getBase(builder) != .none) return .none;
                        cur = extra.lhs;
                    },
                    else => return .none,
                }
            },
            .global => |global| switch (global.ptrConst(builder).kind) {
                .alias => |alias| cur = alias.ptrConst(builder).aliasee,
                .variable, .function => return global,
                .replaced => unreachable,
            },
        };
    }

    const FormatData = struct {
        constant: Constant,
        builder: *Builder,
    };
    fn format(
        data: FormatData,
        comptime fmt_str: []const u8,
        _: std.fmt.FormatOptions,
        writer: anytype,
    ) @TypeOf(writer).Error!void {
        if (comptime std.mem.indexOfNone(u8, fmt_str, ", %")) |_|
            @compileError("invalid format string: '" ++ fmt_str ++ "'");
        if (comptime std.mem.indexOfScalar(u8, fmt_str, ',') != null) {
            if (data.constant == .no_init) return;
            try writer.writeByte(',');
        }
        if (comptime std.mem.indexOfScalar(u8, fmt_str, ' ') != null) {
            if (data.constant == .no_init) return;
            try writer.writeByte(' ');
        }
        if (comptime std.mem.indexOfScalar(u8, fmt_str, '%') != null)
            try writer.print("{%} ", .{data.constant.typeOf(data.builder).fmt(data.builder)});
        assert(data.constant != .no_init);
        if (std.enums.tagName(Constant, data.constant)) |name| return writer.writeAll(name);
        switch (data.constant.unwrap()) {
            .constant => |constant| {
                const item = data.builder.constant_items.get(constant);
                switch (item.tag) {
                    .positive_integer,
                    .negative_integer,
                    => |tag| {
                        const extra: *align(@alignOf(std.math.big.Limb)) const Integer =
                            @ptrCast(data.builder.constant_limbs.items[item.data..][0..Integer.limbs]);
                        const limbs = data.builder.constant_limbs
                            .items[item.data + Integer.limbs ..][0..extra.limbs_len];
                        const bigint: std.math.big.int.Const = .{
                            .limbs = limbs,
                            .positive = switch (tag) {
                                .positive_integer => true,
                                .negative_integer => false,
                                else => unreachable,
                            },
                        };
                        const ExpectedContents = extern struct {
                            const expected_limbs = @divExact(512, @bitSizeOf(std.math.big.Limb));
                            string: [
                                (std.math.big.int.Const{
                                    .limbs = &([1]std.math.big.Limb{
                                        std.math.maxInt(std.math.big.Limb),
                                    } ** expected_limbs),
                                    .positive = false,
                                }).sizeInBaseUpperBound(10)
                            ]u8,
                            limbs: [
                                std.math.big.int.calcToStringLimbsBufferLen(expected_limbs, 10)
                            ]std.math.big.Limb,
                        };
                        var stack align(@alignOf(ExpectedContents)) =
                            std.heap.stackFallback(@sizeOf(ExpectedContents), data.builder.gpa);
                        const allocator = stack.get();
                        const str = try bigint.toStringAlloc(allocator, 10, undefined);
                        defer allocator.free(str);
                        try writer.writeAll(str);
                    },
                    .half,
                    .bfloat,
                    => |tag| try writer.print("0x{c}{X:0>4}", .{ @as(u8, switch (tag) {
                        .half => 'H',
                        .bfloat => 'R',
                        else => unreachable,
                    }), item.data >> switch (tag) {
                        .half => 0,
                        .bfloat => 16,
                        else => unreachable,
                    } }),
                    .float => {
                        const Float = struct {
                            fn Repr(comptime T: type) type {
                                return packed struct(std.meta.Int(.unsigned, @bitSizeOf(T))) {
                                    mantissa: std.meta.Int(.unsigned, std.math.floatMantissaBits(T)),
                                    exponent: std.meta.Int(.unsigned, std.math.floatExponentBits(T)),
                                    sign: u1,
                                };
                            }
                        };
                        const Mantissa64 = @FieldType(Float.Repr(f64), "mantissa");
                        const Exponent32 = @FieldType(Float.Repr(f32), "exponent");
                        const Exponent64 = @FieldType(Float.Repr(f64), "exponent");

                        const repr: Float.Repr(f32) = @bitCast(item.data);
                        const denormal_shift = switch (repr.exponent) {
                            std.math.minInt(Exponent32) => @as(
                                std.math.Log2Int(Mantissa64),
                                @clz(repr.mantissa),
                            ) + 1,
                            else => 0,
                        };
                        try writer.print("0x{X:0>16}", .{@as(u64, @bitCast(Float.Repr(f64){
                            .mantissa = std.math.shl(
                                Mantissa64,
                                repr.mantissa,
                                std.math.floatMantissaBits(f64) - std.math.floatMantissaBits(f32) +
                                    denormal_shift,
                            ),
                            .exponent = switch (repr.exponent) {
                                std.math.minInt(Exponent32) => if (repr.mantissa > 0)
                                    @as(Exponent64, std.math.floatExponentMin(f32) +
                                        std.math.floatExponentMax(f64)) - denormal_shift
                                else
                                    std.math.minInt(Exponent64),
                                else => @as(Exponent64, repr.exponent) +
                                    (std.math.floatExponentMax(f64) - std.math.floatExponentMax(f32)),
                                std.math.maxInt(Exponent32) => std.math.maxInt(Exponent64),
                            },
                            .sign = repr.sign,
                        }))});
                    },
                    .double => {
                        const extra = data.builder.constantExtraData(Double, item.data);
                        try writer.print("0x{X:0>8}{X:0>8}", .{ extra.hi, extra.lo });
                    },
                    .fp128,
                    .ppc_fp128,
                    => |tag| {
                        const extra = data.builder.constantExtraData(Fp128, item.data);
                        try writer.print("0x{c}{X:0>8}{X:0>8}{X:0>8}{X:0>8}", .{
                            @as(u8, switch (tag) {
                                .fp128 => 'L',
                                .ppc_fp128 => 'M',
                                else => unreachable,
                            }),
                            extra.lo_hi,
                            extra.lo_lo,
                            extra.hi_hi,
                            extra.hi_lo,
                        });
                    },
                    .x86_fp80 => {
                        const extra = data.builder.constantExtraData(Fp80, item.data);
                        try writer.print("0xK{X:0>4}{X:0>8}{X:0>8}", .{
                            extra.hi, extra.lo_hi, extra.lo_lo,
                        });
                    },
                    .null,
                    .none,
                    .zeroinitializer,
                    .undef,
                    .poison,
                    => |tag| try writer.writeAll(@tagName(tag)),
                    .structure,
                    .packed_structure,
                    .array,
                    .vector,
                    => |tag| {
                        var extra = data.builder.constantExtraDataTrail(Aggregate, item.data);
                        const len: u32 = @intCast(extra.data.type.aggregateLen(data.builder));
                        const vals = extra.trail.next(len, Constant, data.builder);
                        try writer.writeAll(switch (tag) {
                            .structure => "{ ",
                            .packed_structure => "<{ ",
                            .array => "[",
                            .vector => "<",
                            else => unreachable,
                        });
                        for (vals, 0..) |val, index| {
                            if (index > 0) try writer.writeAll(", ");
                            try writer.print("{%}", .{val.fmt(data.builder)});
                        }
                        try writer.writeAll(switch (tag) {
                            .structure => " }",
                            .packed_structure => " }>",
                            .array => "]",
                            .vector => ">",
                            else => unreachable,
                        });
                    },
                    .splat => {
                        const extra = data.builder.constantExtraData(Splat, item.data);
                        const len = extra.type.vectorLen(data.builder);
                        try writer.writeByte('<');
                        for (0..len) |index| {
                            if (index > 0) try writer.writeAll(", ");
                            try writer.print("{%}", .{extra.value.fmt(data.builder)});
                        }
                        try writer.writeByte('>');
                    },
                    .string => try writer.print("c{\"}", .{
                        @as(String, @enumFromInt(item.data)).fmt(data.builder),
                    }),
                    .blockaddress => |tag| {
                        const extra = data.builder.constantExtraData(BlockAddress, item.data);
                        const function = extra.function.ptrConst(data.builder);
                        try writer.print("{s}({}, {})", .{
                            @tagName(tag),
                            function.global.fmt(data.builder),
                            extra.block.toInst(function).fmt(extra.function, data.builder),
                        });
                    },
                    .dso_local_equivalent,
                    .no_cfi,
                    => |tag| {
                        const function: Function.Index = @enumFromInt(item.data);
                        try writer.print("{s} {}", .{
                            @tagName(tag),
                            function.ptrConst(data.builder).global.fmt(data.builder),
                        });
                    },
                    .trunc,
                    .ptrtoint,
                    .inttoptr,
                    .bitcast,
                    .addrspacecast,
                    => |tag| {
                        const extra = data.builder.constantExtraData(Cast, item.data);
                        try writer.print("{s} ({%} to {%})", .{
                            @tagName(tag),
                            extra.val.fmt(data.builder),
                            extra.type.fmt(data.builder),
                        });
                    },
                    .getelementptr,
                    .@"getelementptr inbounds",
                    => |tag| {
                        var extra = data.builder.constantExtraDataTrail(GetElementPtr, item.data);
                        const indices =
                            extra.trail.next(extra.data.info.indices_len, Constant, data.builder);
                        try writer.print("{s} ({%}, {%}", .{
                            @tagName(tag),
                            extra.data.type.fmt(data.builder),
                            extra.data.base.fmt(data.builder),
                        });
                        for (indices) |index| try writer.print(", {%}", .{index.fmt(data.builder)});
                        try writer.writeByte(')');
                    },
                    .add,
                    .@"add nsw",
                    .@"add nuw",
                    .sub,
                    .@"sub nsw",
                    .@"sub nuw",
                    .shl,
                    .xor,
                    => |tag| {
                        const extra = data.builder.constantExtraData(Binary, item.data);
                        try writer.print("{s} ({%}, {%})", .{
                            @tagName(tag),
                            extra.lhs.fmt(data.builder),
                            extra.rhs.fmt(data.builder),
                        });
                    },
                    .@"asm",
                    .@"asm sideeffect",
                    .@"asm alignstack",
                    .@"asm sideeffect alignstack",
                    .@"asm inteldialect",
                    .@"asm sideeffect inteldialect",
                    .@"asm alignstack inteldialect",
                    .@"asm sideeffect alignstack inteldialect",
                    .@"asm unwind",
                    .@"asm sideeffect unwind",
                    .@"asm alignstack unwind",
                    .@"asm sideeffect alignstack unwind",
                    .@"asm inteldialect unwind",
                    .@"asm sideeffect inteldialect unwind",
                    .@"asm alignstack inteldialect unwind",
                    .@"asm sideeffect alignstack inteldialect unwind",
                    => |tag| {
                        const extra = data.builder.constantExtraData(Assembly, item.data);
                        try writer.print("{s} {\"}, {\"}", .{
                            @tagName(tag),
                            extra.assembly.fmt(data.builder),
                            extra.constraints.fmt(data.builder),
                        });
                    },
                }
            },
            .global => |global| try writer.print("{}", .{global.fmt(data.builder)}),
        }
    }
    pub fn fmt(self: Constant, builder: *Builder) std.fmt.Formatter(format) {
        return .{ .data = .{ .constant = self, .builder = builder } };
    }
}