struct Instruction [src]
Alias for std.zig.llvm.Builder.Function.Instruction
Fields
tag: Tag
data: u32
Members
- Alloca (struct)
- AtomicRmw (struct)
- Binary (struct)
- BrCond (struct)
- Call (struct)
- Cast (struct)
- CmpXchg (struct)
- ExtractElement (struct)
- ExtractValue (struct)
- ExtraIndex (Type)
- GetElementPtr (struct)
- Index (enum)
- IndirectBr (struct)
- InsertElement (struct)
- InsertValue (struct)
- Load (struct)
- Phi (struct)
- Select (struct)
- ShuffleVector (struct)
- Store (struct)
- Switch (struct)
- Tag (enum)
- VaArg (struct)
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,
};
}