struct Instruction [src]

Alias for std.zig.llvm.Builder.Function.Instruction

Fields

tag: Tag
data: u32

Members

Source

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