structstd.zig.llvm.Builder.Function.Instruction[src]

Types

TypeExtraIndex[src]

Source Code

Source code
pub const ExtraIndex = u32

Fields

tag: Tag
data: u32

Source Code

Source code
pub const Instruction = struct {
    tag: Tag,
    data: u32,

    pub const Tag = enum(u8) {
        add,
        @"add nsw",
        @"add nuw",
        @"add nuw nsw",
        addrspacecast,
        alloca,
        @"alloca inalloca",
        @"and",
        arg,
        ashr,
        @"ashr exact",
        atomicrmw,
        bitcast,
        block,
        br,
        br_cond,
        call,
        @"call fast",
        cmpxchg,
        @"cmpxchg weak",
        extractelement,
        extractvalue,
        fadd,
        @"fadd fast",
        @"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",
        fdiv,
        @"fdiv fast",
        fence,
        fmul,
        @"fmul fast",
        fneg,
        @"fneg fast",
        fpext,
        fptosi,
        fptoui,
        fptrunc,
        frem,
        @"frem fast",
        fsub,
        @"fsub fast",
        getelementptr,
        @"getelementptr inbounds",
        @"icmp eq",
        @"icmp ne",
        @"icmp sge",
        @"icmp sgt",
        @"icmp sle",
        @"icmp slt",
        @"icmp uge",
        @"icmp ugt",
        @"icmp ule",
        @"icmp ult",
        indirectbr,
        insertelement,
        insertvalue,
        inttoptr,
        load,
        @"load atomic",
        lshr,
        @"lshr exact",
        mul,
        @"mul nsw",
        @"mul nuw",
        @"mul nuw nsw",
        @"musttail call",
        @"musttail call fast",
        @"notail call",
        @"notail call fast",
        @"or",
        phi,
        @"phi fast",
        ptrtoint,
        ret,
        @"ret void",
        sdiv,
        @"sdiv exact",
        select,
        @"select fast",
        sext,
        shl,
        @"shl nsw",
        @"shl nuw",
        @"shl nuw nsw",
        shufflevector,
        sitofp,
        srem,
        store,
        @"store atomic",
        sub,
        @"sub nsw",
        @"sub nuw",
        @"sub nuw nsw",
        @"switch",
        @"tail call",
        @"tail call fast",
        trunc,
        udiv,
        @"udiv exact",
        urem,
        uitofp,
        @"unreachable",
        va_arg,
        xor,
        zext,

        pub fn toBinaryOpcode(self: Tag) BinaryOpcode {
            return switch (self) {
                .add,
                .@"add nsw",
                .@"add nuw",
                .@"add nuw nsw",
                .fadd,
                .@"fadd fast",
                => .add,
                .sub,
                .@"sub nsw",
                .@"sub nuw",
                .@"sub nuw nsw",
                .fsub,
                .@"fsub fast",
                => .sub,
                .sdiv,
                .@"sdiv exact",
                .fdiv,
                .@"fdiv fast",
                => .sdiv,
                .fmul,
                .@"fmul fast",
                .mul,
                .@"mul nsw",
                .@"mul nuw",
                .@"mul nuw nsw",
                => .mul,
                .srem,
                .frem,
                .@"frem fast",
                => .srem,
                .udiv,
                .@"udiv exact",
                => .udiv,
                .shl,
                .@"shl nsw",
                .@"shl nuw",
                .@"shl nuw nsw",
                => .shl,
                .lshr,
                .@"lshr exact",
                => .lshr,
                .ashr,
                .@"ashr exact",
                => .ashr,
                .@"and" => .@"and",
                .@"or" => .@"or",
                .xor => .xor,
                .urem => .urem,
                else => unreachable,
            };
        }

        pub fn toCastOpcode(self: Tag) CastOpcode {
            return switch (self) {
                .trunc => .trunc,
                .zext => .zext,
                .sext => .sext,
                .fptoui => .fptoui,
                .fptosi => .fptosi,
                .uitofp => .uitofp,
                .sitofp => .sitofp,
                .fptrunc => .fptrunc,
                .fpext => .fpext,
                .ptrtoint => .ptrtoint,
                .inttoptr => .inttoptr,
                .bitcast => .bitcast,
                .addrspacecast => .addrspacecast,
                else => unreachable,
            };
        }

        pub fn toCmpPredicate(self: Tag) CmpPredicate {
            return switch (self) {
                .@"fcmp false",
                .@"fcmp fast false",
                => .fcmp_false,
                .@"fcmp oeq",
                .@"fcmp fast oeq",
                => .fcmp_oeq,
                .@"fcmp oge",
                .@"fcmp fast oge",
                => .fcmp_oge,
                .@"fcmp ogt",
                .@"fcmp fast ogt",
                => .fcmp_ogt,
                .@"fcmp ole",
                .@"fcmp fast ole",
                => .fcmp_ole,
                .@"fcmp olt",
                .@"fcmp fast olt",
                => .fcmp_olt,
                .@"fcmp one",
                .@"fcmp fast one",
                => .fcmp_one,
                .@"fcmp ord",
                .@"fcmp fast ord",
                => .fcmp_ord,
                .@"fcmp true",
                .@"fcmp fast true",
                => .fcmp_true,
                .@"fcmp ueq",
                .@"fcmp fast ueq",
                => .fcmp_ueq,
                .@"fcmp uge",
                .@"fcmp fast uge",
                => .fcmp_uge,
                .@"fcmp ugt",
                .@"fcmp fast ugt",
                => .fcmp_ugt,
                .@"fcmp ule",
                .@"fcmp fast ule",
                => .fcmp_ule,
                .@"fcmp ult",
                .@"fcmp fast ult",
                => .fcmp_ult,
                .@"fcmp une",
                .@"fcmp fast une",
                => .fcmp_une,
                .@"fcmp uno",
                .@"fcmp fast uno",
                => .fcmp_uno,
                .@"icmp eq" => .icmp_eq,
                .@"icmp ne" => .icmp_ne,
                .@"icmp sge" => .icmp_sge,
                .@"icmp sgt" => .icmp_sgt,
                .@"icmp sle" => .icmp_sle,
                .@"icmp slt" => .icmp_slt,
                .@"icmp uge" => .icmp_uge,
                .@"icmp ugt" => .icmp_ugt,
                .@"icmp ule" => .icmp_ule,
                .@"icmp ult" => .icmp_ult,
                else => unreachable,
            };
        }
    };

    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 } };
        }
    };

    pub const ExtraIndex = u32;

    pub const BrCond = struct {
        cond: Value,
        then: Block.Index,
        @"else": Block.Index,
        weights: Weights,
        pub const Weights = enum(u32) {
            // We can do this as metadata indices 0 and 1 are reserved.
            none = 0,
            unpredictable = 1,
            /// These values should be converted to `Metadata` to be used
            /// in a `prof` annotation providing branch weights.
            _,
        };
    };

    pub const Switch = struct {
        val: Value,
        default: Block.Index,
        cases_len: u32,
        weights: BrCond.Weights,
        //case_vals: [cases_len]Constant,
        //case_blocks: [cases_len]Block.Index,
    };

    pub const IndirectBr = struct {
        addr: Value,
        targets_len: u32,
        //targets: [targets_len]Block.Index,
    };

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

    pub const ExtractElement = struct {
        val: Value,
        index: Value,
    };

    pub const InsertElement = struct {
        val: Value,
        elem: Value,
        index: Value,
    };

    pub const ShuffleVector = struct {
        lhs: Value,
        rhs: Value,
        mask: Value,
    };

    pub const ExtractValue = struct {
        val: Value,
        indices_len: u32,
        //indices: [indices_len]u32,
    };

    pub const InsertValue = struct {
        val: Value,
        elem: Value,
        indices_len: u32,
        //indices: [indices_len]u32,
    };

    pub const Alloca = struct {
        type: Type,
        len: Value,
        info: Info,

        pub const Kind = enum { normal, inalloca };
        pub const Info = packed struct(u32) {
            alignment: Alignment,
            addr_space: AddrSpace,
            _: u2 = undefined,
        };
    };

    pub const Load = struct {
        info: MemoryAccessInfo,
        type: Type,
        ptr: Value,
    };

    pub const Store = struct {
        info: MemoryAccessInfo,
        val: Value,
        ptr: Value,
    };

    pub const CmpXchg = struct {
        info: MemoryAccessInfo,
        ptr: Value,
        cmp: Value,
        new: Value,

        pub const Kind = enum { strong, weak };
    };

    pub const AtomicRmw = struct {
        info: MemoryAccessInfo,
        ptr: Value,
        val: Value,

        pub const Operation = enum(u5) {
            xchg = 0,
            add = 1,
            sub = 2,
            @"and" = 3,
            nand = 4,
            @"or" = 5,
            xor = 6,
            max = 7,
            min = 8,
            umax = 9,
            umin = 10,
            fadd = 11,
            fsub = 12,
            fmax = 13,
            fmin = 14,
            none = std.math.maxInt(u5),
        };
    };

    pub const GetElementPtr = struct {
        type: Type,
        base: Value,
        indices_len: u32,
        //indices: [indices_len]Value,

        pub const Kind = Constant.GetElementPtr.Kind;
    };

    pub const Cast = struct {
        val: Value,
        type: Type,

        pub const Signedness = Constant.Cast.Signedness;
    };

    pub const Phi = struct {
        type: Type,
        //incoming_vals: [block.incoming]Value,
        //incoming_blocks: [block.incoming]Block.Index,
    };

    pub const Select = struct {
        cond: Value,
        lhs: Value,
        rhs: Value,
    };

    pub const Call = struct {
        info: Info,
        attributes: FunctionAttributes,
        ty: Type,
        callee: Value,
        args_len: u32,
        //args: [args_len]Value,

        pub const Kind = enum {
            normal,
            fast,
            musttail,
            musttail_fast,
            notail,
            notail_fast,
            tail,
            tail_fast,
        };
        pub const Info = packed struct(u32) {
            call_conv: CallConv,
            has_op_bundle_cold: bool,
            _: u21 = undefined,
        };
    };

    pub const VaArg = struct {
        list: Value,
        type: Type,
    };
}