enumstd.zig.llvm.Builder.Function.Instruction.Index[src]

Fields

none = std.math.maxInt(u31)
_

Functions

Functionname[src]

pub fn name(self: Instruction.Index, function: *const Function) String

Parameters

function: *const Function

Source Code

Source code
pub fn name(self: Instruction.Index, function: *const Function) String {
    return function.names[@intFromEnum(self)];
}

FunctionvalueIndex[src]

pub fn valueIndex(self: Instruction.Index, function: *const Function) u32

Parameters

function: *const Function

Source Code

Source code
pub fn valueIndex(self: Instruction.Index, function: *const Function) u32 {
    return function.value_indices[@intFromEnum(self)];
}

FunctiontoValue[src]

pub fn toValue(self: Instruction.Index) Value

Parameters

Source Code

Source code
pub fn toValue(self: Instruction.Index) Value {
    return @enumFromInt(@intFromEnum(self));
}

FunctionisTerminatorWip[src]

pub fn isTerminatorWip(self: Instruction.Index, wip: *const WipFunction) bool

Parameters

wip: *const WipFunction

Source Code

Source code
pub fn isTerminatorWip(self: Instruction.Index, wip: *const WipFunction) bool {
    return switch (wip.instructions.items(.tag)[@intFromEnum(self)]) {
        .br,
        .br_cond,
        .indirectbr,
        .ret,
        .@"ret void",
        .@"switch",
        .@"unreachable",
        => true,
        else => false,
    };
}

FunctionhasResultWip[src]

pub fn hasResultWip(self: Instruction.Index, wip: *const WipFunction) bool

Parameters

wip: *const WipFunction

Source Code

Source code
pub fn hasResultWip(self: Instruction.Index, wip: *const WipFunction) bool {
    return switch (wip.instructions.items(.tag)[@intFromEnum(self)]) {
        .br,
        .br_cond,
        .fence,
        .indirectbr,
        .ret,
        .@"ret void",
        .store,
        .@"store atomic",
        .@"switch",
        .@"unreachable",
        .block,
        => false,
        .call,
        .@"call fast",
        .@"musttail call",
        .@"musttail call fast",
        .@"notail call",
        .@"notail call fast",
        .@"tail call",
        .@"tail call fast",
        => self.typeOfWip(wip) != .void,
        else => true,
    };
}

FunctiontypeOfWip[src]

pub fn typeOfWip(self: Instruction.Index, wip: *const WipFunction) Type

Parameters

wip: *const WipFunction

Source Code

Source code
pub fn typeOfWip(self: Instruction.Index, wip: *const WipFunction) Type {
    const instruction = wip.instructions.get(@intFromEnum(self));
    return switch (instruction.tag) {
        .add,
        .@"add nsw",
        .@"add nuw",
        .@"add nuw nsw",
        .@"and",
        .ashr,
        .@"ashr exact",
        .fadd,
        .@"fadd fast",
        .fdiv,
        .@"fdiv fast",
        .fmul,
        .@"fmul fast",
        .frem,
        .@"frem fast",
        .fsub,
        .@"fsub fast",
        .lshr,
        .@"lshr exact",
        .mul,
        .@"mul nsw",
        .@"mul nuw",
        .@"mul nuw nsw",
        .@"or",
        .sdiv,
        .@"sdiv exact",
        .shl,
        .@"shl nsw",
        .@"shl nuw",
        .@"shl nuw nsw",
        .srem,
        .sub,
        .@"sub nsw",
        .@"sub nuw",
        .@"sub nuw nsw",
        .udiv,
        .@"udiv exact",
        .urem,
        .xor,
        => wip.extraData(Binary, instruction.data).lhs.typeOfWip(wip),
        .addrspacecast,
        .bitcast,
        .fpext,
        .fptosi,
        .fptoui,
        .fptrunc,
        .inttoptr,
        .ptrtoint,
        .sext,
        .sitofp,
        .trunc,
        .uitofp,
        .zext,
        => wip.extraData(Cast, instruction.data).type,
        .alloca,
        .@"alloca inalloca",
        => wip.builder.ptrTypeAssumeCapacity(
            wip.extraData(Alloca, instruction.data).info.addr_space,
        ),
        .arg => wip.function.typeOf(wip.builder)
            .functionParameters(wip.builder)[instruction.data],
        .atomicrmw => wip.extraData(AtomicRmw, instruction.data).val.typeOfWip(wip),
        .block => .label,
        .br,
        .br_cond,
        .fence,
        .indirectbr,
        .ret,
        .@"ret void",
        .store,
        .@"store atomic",
        .@"switch",
        .@"unreachable",
        => .none,
        .call,
        .@"call fast",
        .@"musttail call",
        .@"musttail call fast",
        .@"notail call",
        .@"notail call fast",
        .@"tail call",
        .@"tail call fast",
        => wip.extraData(Call, instruction.data).ty.functionReturn(wip.builder),
        .cmpxchg,
        .@"cmpxchg weak",
        => wip.builder.structTypeAssumeCapacity(.normal, &.{
            wip.extraData(CmpXchg, instruction.data).cmp.typeOfWip(wip),
            .i1,
        }),
        .extractelement => wip.extraData(ExtractElement, instruction.data)
            .val.typeOfWip(wip).childType(wip.builder),
        .extractvalue => {
            var extra = wip.extraDataTrail(ExtractValue, instruction.data);
            const indices = extra.trail.next(extra.data.indices_len, u32, wip);
            return extra.data.val.typeOfWip(wip).childTypeAt(indices, wip.builder);
        },
        .@"fcmp false",
        .@"fcmp fast false",
        .@"fcmp fast oeq",
        .@"fcmp fast oge",
        .@"fcmp fast ogt",
        .@"fcmp fast ole",
        .@"fcmp fast olt",
        .@"fcmp fast one",
        .@"fcmp fast ord",
        .@"fcmp fast true",
        .@"fcmp fast ueq",
        .@"fcmp fast uge",
        .@"fcmp fast ugt",
        .@"fcmp fast ule",
        .@"fcmp fast ult",
        .@"fcmp fast une",
        .@"fcmp fast uno",
        .@"fcmp oeq",
        .@"fcmp oge",
        .@"fcmp ogt",
        .@"fcmp ole",
        .@"fcmp olt",
        .@"fcmp one",
        .@"fcmp ord",
        .@"fcmp true",
        .@"fcmp ueq",
        .@"fcmp uge",
        .@"fcmp ugt",
        .@"fcmp ule",
        .@"fcmp ult",
        .@"fcmp une",
        .@"fcmp uno",
        .@"icmp eq",
        .@"icmp ne",
        .@"icmp sge",
        .@"icmp sgt",
        .@"icmp sle",
        .@"icmp slt",
        .@"icmp uge",
        .@"icmp ugt",
        .@"icmp ule",
        .@"icmp ult",
        => wip.extraData(Binary, instruction.data).lhs.typeOfWip(wip)
            .changeScalarAssumeCapacity(.i1, wip.builder),
        .fneg,
        .@"fneg fast",
        => @as(Value, @enumFromInt(instruction.data)).typeOfWip(wip),
        .getelementptr,
        .@"getelementptr inbounds",
        => {
            var extra = wip.extraDataTrail(GetElementPtr, instruction.data);
            const indices = extra.trail.next(extra.data.indices_len, Value, wip);
            const base_ty = extra.data.base.typeOfWip(wip);
            if (!base_ty.isVector(wip.builder)) for (indices) |index| {
                const index_ty = index.typeOfWip(wip);
                if (!index_ty.isVector(wip.builder)) continue;
                return index_ty.changeScalarAssumeCapacity(base_ty, wip.builder);
            };
            return base_ty;
        },
        .insertelement => wip.extraData(InsertElement, instruction.data).val.typeOfWip(wip),
        .insertvalue => wip.extraData(InsertValue, instruction.data).val.typeOfWip(wip),
        .load,
        .@"load atomic",
        => wip.extraData(Load, instruction.data).type,
        .phi,
        .@"phi fast",
        => wip.extraData(Phi, instruction.data).type,
        .select,
        .@"select fast",
        => wip.extraData(Select, instruction.data).lhs.typeOfWip(wip),
        .shufflevector => {
            const extra = wip.extraData(ShuffleVector, instruction.data);
            return extra.lhs.typeOfWip(wip).changeLengthAssumeCapacity(
                extra.mask.typeOfWip(wip).vectorLen(wip.builder),
                wip.builder,
            );
        },
        .va_arg => wip.extraData(VaArg, instruction.data).type,
    };
}

FunctiontypeOf[src]

pub fn typeOf( self: Instruction.Index, function_index: Function.Index, builder: *Builder, ) Type

Parameters

function_index: Function.Index
builder: *Builder

Source Code

Source code
pub fn typeOf(
    self: Instruction.Index,
    function_index: Function.Index,
    builder: *Builder,
) Type {
    const function = function_index.ptrConst(builder);
    const instruction = function.instructions.get(@intFromEnum(self));
    return switch (instruction.tag) {
        .add,
        .@"add nsw",
        .@"add nuw",
        .@"add nuw nsw",
        .@"and",
        .ashr,
        .@"ashr exact",
        .fadd,
        .@"fadd fast",
        .fdiv,
        .@"fdiv fast",
        .fmul,
        .@"fmul fast",
        .frem,
        .@"frem fast",
        .fsub,
        .@"fsub fast",
        .lshr,
        .@"lshr exact",
        .mul,
        .@"mul nsw",
        .@"mul nuw",
        .@"mul nuw nsw",
        .@"or",
        .sdiv,
        .@"sdiv exact",
        .shl,
        .@"shl nsw",
        .@"shl nuw",
        .@"shl nuw nsw",
        .srem,
        .sub,
        .@"sub nsw",
        .@"sub nuw",
        .@"sub nuw nsw",
        .udiv,
        .@"udiv exact",
        .urem,
        .xor,
        => function.extraData(Binary, instruction.data).lhs.typeOf(function_index, builder),
        .addrspacecast,
        .bitcast,
        .fpext,
        .fptosi,
        .fptoui,
        .fptrunc,
        .inttoptr,
        .ptrtoint,
        .sext,
        .sitofp,
        .trunc,
        .uitofp,
        .zext,
        => function.extraData(Cast, instruction.data).type,
        .alloca,
        .@"alloca inalloca",
        => builder.ptrTypeAssumeCapacity(
            function.extraData(Alloca, instruction.data).info.addr_space,
        ),
        .arg => function.global.typeOf(builder)
            .functionParameters(builder)[instruction.data],
        .atomicrmw => function.extraData(AtomicRmw, instruction.data)
            .val.typeOf(function_index, builder),
        .block => .label,
        .br,
        .br_cond,
        .fence,
        .indirectbr,
        .ret,
        .@"ret void",
        .store,
        .@"store atomic",
        .@"switch",
        .@"unreachable",
        => .none,
        .call,
        .@"call fast",
        .@"musttail call",
        .@"musttail call fast",
        .@"notail call",
        .@"notail call fast",
        .@"tail call",
        .@"tail call fast",
        => function.extraData(Call, instruction.data).ty.functionReturn(builder),
        .cmpxchg,
        .@"cmpxchg weak",
        => builder.structTypeAssumeCapacity(.normal, &.{
            function.extraData(CmpXchg, instruction.data)
                .cmp.typeOf(function_index, builder),
            .i1,
        }),
        .extractelement => function.extraData(ExtractElement, instruction.data)
            .val.typeOf(function_index, builder).childType(builder),
        .extractvalue => {
            var extra = function.extraDataTrail(ExtractValue, instruction.data);
            const indices = extra.trail.next(extra.data.indices_len, u32, function);
            return extra.data.val.typeOf(function_index, builder)
                .childTypeAt(indices, builder);
        },
        .@"fcmp false",
        .@"fcmp fast false",
        .@"fcmp fast oeq",
        .@"fcmp fast oge",
        .@"fcmp fast ogt",
        .@"fcmp fast ole",
        .@"fcmp fast olt",
        .@"fcmp fast one",
        .@"fcmp fast ord",
        .@"fcmp fast true",
        .@"fcmp fast ueq",
        .@"fcmp fast uge",
        .@"fcmp fast ugt",
        .@"fcmp fast ule",
        .@"fcmp fast ult",
        .@"fcmp fast une",
        .@"fcmp fast uno",
        .@"fcmp oeq",
        .@"fcmp oge",
        .@"fcmp ogt",
        .@"fcmp ole",
        .@"fcmp olt",
        .@"fcmp one",
        .@"fcmp ord",
        .@"fcmp true",
        .@"fcmp ueq",
        .@"fcmp uge",
        .@"fcmp ugt",
        .@"fcmp ule",
        .@"fcmp ult",
        .@"fcmp une",
        .@"fcmp uno",
        .@"icmp eq",
        .@"icmp ne",
        .@"icmp sge",
        .@"icmp sgt",
        .@"icmp sle",
        .@"icmp slt",
        .@"icmp uge",
        .@"icmp ugt",
        .@"icmp ule",
        .@"icmp ult",
        => function.extraData(Binary, instruction.data).lhs.typeOf(function_index, builder)
            .changeScalarAssumeCapacity(.i1, builder),
        .fneg,
        .@"fneg fast",
        => @as(Value, @enumFromInt(instruction.data)).typeOf(function_index, builder),
        .getelementptr,
        .@"getelementptr inbounds",
        => {
            var extra = function.extraDataTrail(GetElementPtr, instruction.data);
            const indices = extra.trail.next(extra.data.indices_len, Value, function);
            const base_ty = extra.data.base.typeOf(function_index, builder);
            if (!base_ty.isVector(builder)) for (indices) |index| {
                const index_ty = index.typeOf(function_index, builder);
                if (!index_ty.isVector(builder)) continue;
                return index_ty.changeScalarAssumeCapacity(base_ty, builder);
            };
            return base_ty;
        },
        .insertelement => function.extraData(InsertElement, instruction.data)
            .val.typeOf(function_index, builder),
        .insertvalue => function.extraData(InsertValue, instruction.data)
            .val.typeOf(function_index, builder),
        .load,
        .@"load atomic",
        => function.extraData(Load, instruction.data).type,
        .phi,
        .@"phi fast",
        => function.extraData(Phi, instruction.data).type,
        .select,
        .@"select fast",
        => function.extraData(Select, instruction.data).lhs.typeOf(function_index, builder),
        .shufflevector => {
            const extra = function.extraData(ShuffleVector, instruction.data);
            return extra.lhs.typeOf(function_index, builder).changeLengthAssumeCapacity(
                extra.mask.typeOf(function_index, builder).vectorLen(builder),
                builder,
            );
        },
        .va_arg => function.extraData(VaArg, instruction.data).type,
    };
}

Functionfmt[src]

pub fn fmt( self: Instruction.Index, function: Function.Index, builder: *Builder, ) std.fmt.Formatter(format)

Parameters

function: Function.Index
builder: *Builder

Source Code

Source code
pub fn fmt(
    self: Instruction.Index,
    function: Function.Index,
    builder: *Builder,
) std.fmt.Formatter(format) {
    return .{ .data = .{ .instruction = self, .function = function, .builder = builder } };
}

Source Code

Source code
pub const Index = enum(u32) {
    none = std.math.maxInt(u31),
    _,

    pub fn name(self: Instruction.Index, function: *const Function) String {
        return function.names[@intFromEnum(self)];
    }

    pub fn valueIndex(self: Instruction.Index, function: *const Function) u32 {
        return function.value_indices[@intFromEnum(self)];
    }

    pub fn toValue(self: Instruction.Index) Value {
        return @enumFromInt(@intFromEnum(self));
    }

    pub fn isTerminatorWip(self: Instruction.Index, wip: *const WipFunction) bool {
        return switch (wip.instructions.items(.tag)[@intFromEnum(self)]) {
            .br,
            .br_cond,
            .indirectbr,
            .ret,
            .@"ret void",
            .@"switch",
            .@"unreachable",
            => true,
            else => false,
        };
    }

    pub fn hasResultWip(self: Instruction.Index, wip: *const WipFunction) bool {
        return switch (wip.instructions.items(.tag)[@intFromEnum(self)]) {
            .br,
            .br_cond,
            .fence,
            .indirectbr,
            .ret,
            .@"ret void",
            .store,
            .@"store atomic",
            .@"switch",
            .@"unreachable",
            .block,
            => false,
            .call,
            .@"call fast",
            .@"musttail call",
            .@"musttail call fast",
            .@"notail call",
            .@"notail call fast",
            .@"tail call",
            .@"tail call fast",
            => self.typeOfWip(wip) != .void,
            else => true,
        };
    }

    pub fn typeOfWip(self: Instruction.Index, wip: *const WipFunction) Type {
        const instruction = wip.instructions.get(@intFromEnum(self));
        return switch (instruction.tag) {
            .add,
            .@"add nsw",
            .@"add nuw",
            .@"add nuw nsw",
            .@"and",
            .ashr,
            .@"ashr exact",
            .fadd,
            .@"fadd fast",
            .fdiv,
            .@"fdiv fast",
            .fmul,
            .@"fmul fast",
            .frem,
            .@"frem fast",
            .fsub,
            .@"fsub fast",
            .lshr,
            .@"lshr exact",
            .mul,
            .@"mul nsw",
            .@"mul nuw",
            .@"mul nuw nsw",
            .@"or",
            .sdiv,
            .@"sdiv exact",
            .shl,
            .@"shl nsw",
            .@"shl nuw",
            .@"shl nuw nsw",
            .srem,
            .sub,
            .@"sub nsw",
            .@"sub nuw",
            .@"sub nuw nsw",
            .udiv,
            .@"udiv exact",
            .urem,
            .xor,
            => wip.extraData(Binary, instruction.data).lhs.typeOfWip(wip),
            .addrspacecast,
            .bitcast,
            .fpext,
            .fptosi,
            .fptoui,
            .fptrunc,
            .inttoptr,
            .ptrtoint,
            .sext,
            .sitofp,
            .trunc,
            .uitofp,
            .zext,
            => wip.extraData(Cast, instruction.data).type,
            .alloca,
            .@"alloca inalloca",
            => wip.builder.ptrTypeAssumeCapacity(
                wip.extraData(Alloca, instruction.data).info.addr_space,
            ),
            .arg => wip.function.typeOf(wip.builder)
                .functionParameters(wip.builder)[instruction.data],
            .atomicrmw => wip.extraData(AtomicRmw, instruction.data).val.typeOfWip(wip),
            .block => .label,
            .br,
            .br_cond,
            .fence,
            .indirectbr,
            .ret,
            .@"ret void",
            .store,
            .@"store atomic",
            .@"switch",
            .@"unreachable",
            => .none,
            .call,
            .@"call fast",
            .@"musttail call",
            .@"musttail call fast",
            .@"notail call",
            .@"notail call fast",
            .@"tail call",
            .@"tail call fast",
            => wip.extraData(Call, instruction.data).ty.functionReturn(wip.builder),
            .cmpxchg,
            .@"cmpxchg weak",
            => wip.builder.structTypeAssumeCapacity(.normal, &.{
                wip.extraData(CmpXchg, instruction.data).cmp.typeOfWip(wip),
                .i1,
            }),
            .extractelement => wip.extraData(ExtractElement, instruction.data)
                .val.typeOfWip(wip).childType(wip.builder),
            .extractvalue => {
                var extra = wip.extraDataTrail(ExtractValue, instruction.data);
                const indices = extra.trail.next(extra.data.indices_len, u32, wip);
                return extra.data.val.typeOfWip(wip).childTypeAt(indices, wip.builder);
            },
            .@"fcmp false",
            .@"fcmp fast false",
            .@"fcmp fast oeq",
            .@"fcmp fast oge",
            .@"fcmp fast ogt",
            .@"fcmp fast ole",
            .@"fcmp fast olt",
            .@"fcmp fast one",
            .@"fcmp fast ord",
            .@"fcmp fast true",
            .@"fcmp fast ueq",
            .@"fcmp fast uge",
            .@"fcmp fast ugt",
            .@"fcmp fast ule",
            .@"fcmp fast ult",
            .@"fcmp fast une",
            .@"fcmp fast uno",
            .@"fcmp oeq",
            .@"fcmp oge",
            .@"fcmp ogt",
            .@"fcmp ole",
            .@"fcmp olt",
            .@"fcmp one",
            .@"fcmp ord",
            .@"fcmp true",
            .@"fcmp ueq",
            .@"fcmp uge",
            .@"fcmp ugt",
            .@"fcmp ule",
            .@"fcmp ult",
            .@"fcmp une",
            .@"fcmp uno",
            .@"icmp eq",
            .@"icmp ne",
            .@"icmp sge",
            .@"icmp sgt",
            .@"icmp sle",
            .@"icmp slt",
            .@"icmp uge",
            .@"icmp ugt",
            .@"icmp ule",
            .@"icmp ult",
            => wip.extraData(Binary, instruction.data).lhs.typeOfWip(wip)
                .changeScalarAssumeCapacity(.i1, wip.builder),
            .fneg,
            .@"fneg fast",
            => @as(Value, @enumFromInt(instruction.data)).typeOfWip(wip),
            .getelementptr,
            .@"getelementptr inbounds",
            => {
                var extra = wip.extraDataTrail(GetElementPtr, instruction.data);
                const indices = extra.trail.next(extra.data.indices_len, Value, wip);
                const base_ty = extra.data.base.typeOfWip(wip);
                if (!base_ty.isVector(wip.builder)) for (indices) |index| {
                    const index_ty = index.typeOfWip(wip);
                    if (!index_ty.isVector(wip.builder)) continue;
                    return index_ty.changeScalarAssumeCapacity(base_ty, wip.builder);
                };
                return base_ty;
            },
            .insertelement => wip.extraData(InsertElement, instruction.data).val.typeOfWip(wip),
            .insertvalue => wip.extraData(InsertValue, instruction.data).val.typeOfWip(wip),
            .load,
            .@"load atomic",
            => wip.extraData(Load, instruction.data).type,
            .phi,
            .@"phi fast",
            => wip.extraData(Phi, instruction.data).type,
            .select,
            .@"select fast",
            => wip.extraData(Select, instruction.data).lhs.typeOfWip(wip),
            .shufflevector => {
                const extra = wip.extraData(ShuffleVector, instruction.data);
                return extra.lhs.typeOfWip(wip).changeLengthAssumeCapacity(
                    extra.mask.typeOfWip(wip).vectorLen(wip.builder),
                    wip.builder,
                );
            },
            .va_arg => wip.extraData(VaArg, instruction.data).type,
        };
    }

    pub fn typeOf(
        self: Instruction.Index,
        function_index: Function.Index,
        builder: *Builder,
    ) Type {
        const function = function_index.ptrConst(builder);
        const instruction = function.instructions.get(@intFromEnum(self));
        return switch (instruction.tag) {
            .add,
            .@"add nsw",
            .@"add nuw",
            .@"add nuw nsw",
            .@"and",
            .ashr,
            .@"ashr exact",
            .fadd,
            .@"fadd fast",
            .fdiv,
            .@"fdiv fast",
            .fmul,
            .@"fmul fast",
            .frem,
            .@"frem fast",
            .fsub,
            .@"fsub fast",
            .lshr,
            .@"lshr exact",
            .mul,
            .@"mul nsw",
            .@"mul nuw",
            .@"mul nuw nsw",
            .@"or",
            .sdiv,
            .@"sdiv exact",
            .shl,
            .@"shl nsw",
            .@"shl nuw",
            .@"shl nuw nsw",
            .srem,
            .sub,
            .@"sub nsw",
            .@"sub nuw",
            .@"sub nuw nsw",
            .udiv,
            .@"udiv exact",
            .urem,
            .xor,
            => function.extraData(Binary, instruction.data).lhs.typeOf(function_index, builder),
            .addrspacecast,
            .bitcast,
            .fpext,
            .fptosi,
            .fptoui,
            .fptrunc,
            .inttoptr,
            .ptrtoint,
            .sext,
            .sitofp,
            .trunc,
            .uitofp,
            .zext,
            => function.extraData(Cast, instruction.data).type,
            .alloca,
            .@"alloca inalloca",
            => builder.ptrTypeAssumeCapacity(
                function.extraData(Alloca, instruction.data).info.addr_space,
            ),
            .arg => function.global.typeOf(builder)
                .functionParameters(builder)[instruction.data],
            .atomicrmw => function.extraData(AtomicRmw, instruction.data)
                .val.typeOf(function_index, builder),
            .block => .label,
            .br,
            .br_cond,
            .fence,
            .indirectbr,
            .ret,
            .@"ret void",
            .store,
            .@"store atomic",
            .@"switch",
            .@"unreachable",
            => .none,
            .call,
            .@"call fast",
            .@"musttail call",
            .@"musttail call fast",
            .@"notail call",
            .@"notail call fast",
            .@"tail call",
            .@"tail call fast",
            => function.extraData(Call, instruction.data).ty.functionReturn(builder),
            .cmpxchg,
            .@"cmpxchg weak",
            => builder.structTypeAssumeCapacity(.normal, &.{
                function.extraData(CmpXchg, instruction.data)
                    .cmp.typeOf(function_index, builder),
                .i1,
            }),
            .extractelement => function.extraData(ExtractElement, instruction.data)
                .val.typeOf(function_index, builder).childType(builder),
            .extractvalue => {
                var extra = function.extraDataTrail(ExtractValue, instruction.data);
                const indices = extra.trail.next(extra.data.indices_len, u32, function);
                return extra.data.val.typeOf(function_index, builder)
                    .childTypeAt(indices, builder);
            },
            .@"fcmp false",
            .@"fcmp fast false",
            .@"fcmp fast oeq",
            .@"fcmp fast oge",
            .@"fcmp fast ogt",
            .@"fcmp fast ole",
            .@"fcmp fast olt",
            .@"fcmp fast one",
            .@"fcmp fast ord",
            .@"fcmp fast true",
            .@"fcmp fast ueq",
            .@"fcmp fast uge",
            .@"fcmp fast ugt",
            .@"fcmp fast ule",
            .@"fcmp fast ult",
            .@"fcmp fast une",
            .@"fcmp fast uno",
            .@"fcmp oeq",
            .@"fcmp oge",
            .@"fcmp ogt",
            .@"fcmp ole",
            .@"fcmp olt",
            .@"fcmp one",
            .@"fcmp ord",
            .@"fcmp true",
            .@"fcmp ueq",
            .@"fcmp uge",
            .@"fcmp ugt",
            .@"fcmp ule",
            .@"fcmp ult",
            .@"fcmp une",
            .@"fcmp uno",
            .@"icmp eq",
            .@"icmp ne",
            .@"icmp sge",
            .@"icmp sgt",
            .@"icmp sle",
            .@"icmp slt",
            .@"icmp uge",
            .@"icmp ugt",
            .@"icmp ule",
            .@"icmp ult",
            => function.extraData(Binary, instruction.data).lhs.typeOf(function_index, builder)
                .changeScalarAssumeCapacity(.i1, builder),
            .fneg,
            .@"fneg fast",
            => @as(Value, @enumFromInt(instruction.data)).typeOf(function_index, builder),
            .getelementptr,
            .@"getelementptr inbounds",
            => {
                var extra = function.extraDataTrail(GetElementPtr, instruction.data);
                const indices = extra.trail.next(extra.data.indices_len, Value, function);
                const base_ty = extra.data.base.typeOf(function_index, builder);
                if (!base_ty.isVector(builder)) for (indices) |index| {
                    const index_ty = index.typeOf(function_index, builder);
                    if (!index_ty.isVector(builder)) continue;
                    return index_ty.changeScalarAssumeCapacity(base_ty, builder);
                };
                return base_ty;
            },
            .insertelement => function.extraData(InsertElement, instruction.data)
                .val.typeOf(function_index, builder),
            .insertvalue => function.extraData(InsertValue, instruction.data)
                .val.typeOf(function_index, builder),
            .load,
            .@"load atomic",
            => function.extraData(Load, instruction.data).type,
            .phi,
            .@"phi fast",
            => function.extraData(Phi, instruction.data).type,
            .select,
            .@"select fast",
            => function.extraData(Select, instruction.data).lhs.typeOf(function_index, builder),
            .shufflevector => {
                const extra = function.extraData(ShuffleVector, instruction.data);
                return extra.lhs.typeOf(function_index, builder).changeLengthAssumeCapacity(
                    extra.mask.typeOf(function_index, builder).vectorLen(builder),
                    builder,
                );
            },
            .va_arg => function.extraData(VaArg, instruction.data).type,
        };
    }

    const FormatData = struct {
        instruction: Instruction.Index,
        function: Function.Index,
        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.instruction == .none) return;
            try writer.writeByte(',');
        }
        if (comptime std.mem.indexOfScalar(u8, fmt_str, ' ') != null) {
            if (data.instruction == .none) return;
            try writer.writeByte(' ');
        }
        if (comptime std.mem.indexOfScalar(u8, fmt_str, '%') != null) try writer.print(
            "{%} ",
            .{data.instruction.typeOf(data.function, data.builder).fmt(data.builder)},
        );
        assert(data.instruction != .none);
        try writer.print("%{}", .{
            data.instruction.name(data.function.ptrConst(data.builder)).fmt(data.builder),
        });
    }
    pub fn fmt(
        self: Instruction.Index,
        function: Function.Index,
        builder: *Builder,
    ) std.fmt.Formatter(format) {
        return .{ .data = .{ .instruction = self, .function = function, .builder = builder } };
    }
}