enum Constant [src]
Fields
false
true
@"0"
@"1"
none
no_init = (1 << 30) - 1
_
Members
- Aggregate (struct)
- Assembly (extern struct)
- Binary (extern struct)
- BlockAddress (extern struct)
- Cast (extern struct)
- Double (struct)
- fmt (Function)
- Fp128 (struct)
- Fp80 (struct)
- getBase (Function)
- GetElementPtr (struct)
- Integer (struct)
- isZeroInit (Function)
- Item (struct)
- Splat (extern struct)
- Tag (enum)
- toValue (Function)
- typeOf (Function)
- unwrap (Type Function)
Source
pub const Constant = enum(u32) {
false,
true,
@"0",
@"1",
none,
no_init = (1 << 30) - 1,
_,
const first_global: Constant = @enumFromInt(1 << 29);
pub const Tag = enum(u7) {
positive_integer,
negative_integer,
half,
bfloat,
float,
double,
fp128,
x86_fp80,
ppc_fp128,
null,
none,
structure,
packed_structure,
array,
string,
vector,
splat,
zeroinitializer,
undef,
poison,
blockaddress,
dso_local_equivalent,
no_cfi,
trunc,
ptrtoint,
inttoptr,
bitcast,
addrspacecast,
getelementptr,
@"getelementptr inbounds",
add,
@"add nsw",
@"add nuw",
sub,
@"sub nsw",
@"sub nuw",
shl,
xor,
@"asm",
@"asm sideeffect",
@"asm alignstack",
@"asm sideeffect alignstack",
@"asm inteldialect",
@"asm sideeffect inteldialect",
@"asm alignstack inteldialect",
@"asm sideeffect alignstack inteldialect",
@"asm unwind",
@"asm sideeffect unwind",
@"asm alignstack unwind",
@"asm sideeffect alignstack unwind",
@"asm inteldialect unwind",
@"asm sideeffect inteldialect unwind",
@"asm alignstack inteldialect unwind",
@"asm sideeffect alignstack inteldialect unwind",
pub fn toBinaryOpcode(self: Tag) BinaryOpcode {
return switch (self) {
.add,
.@"add nsw",
.@"add nuw",
=> .add,
.sub,
.@"sub nsw",
.@"sub nuw",
=> .sub,
.shl => .shl,
.xor => .xor,
else => unreachable,
};
}
pub fn toCastOpcode(self: Tag) CastOpcode {
return switch (self) {
.trunc => .trunc,
.ptrtoint => .ptrtoint,
.inttoptr => .inttoptr,
.bitcast => .bitcast,
.addrspacecast => .addrspacecast,
else => unreachable,
};
}
};
pub const Item = struct {
tag: Tag,
data: ExtraIndex,
const ExtraIndex = u32;
};
pub const Integer = packed struct(u64) {
type: Type,
limbs_len: u32,
pub const limbs = @divExact(@bitSizeOf(Integer), @bitSizeOf(std.math.big.Limb));
};
pub const Double = struct {
lo: u32,
hi: u32,
};
pub const Fp80 = struct {
lo_lo: u32,
lo_hi: u32,
hi: u32,
};
pub const Fp128 = struct {
lo_lo: u32,
lo_hi: u32,
hi_lo: u32,
hi_hi: u32,
};
pub const Aggregate = struct {
type: Type,
//fields: [type.aggregateLen(builder)]Constant,
};
pub const Splat = extern struct {
type: Type,
value: Constant,
};
pub const BlockAddress = extern struct {
function: Function.Index,
block: Function.Block.Index,
};
pub const Cast = extern struct {
val: Constant,
type: Type,
pub const Signedness = enum { unsigned, signed, unneeded };
};
pub const GetElementPtr = struct {
type: Type,
base: Constant,
info: Info,
//indices: [info.indices_len]Constant,
pub const Kind = enum { normal, inbounds };
pub const InRangeIndex = enum(u16) { none = std.math.maxInt(u16), _ };
pub const Info = packed struct(u32) { indices_len: u16, inrange: InRangeIndex };
};
pub const Binary = extern struct {
lhs: Constant,
rhs: Constant,
};
pub const Assembly = extern struct {
type: Type,
assembly: String,
constraints: String,
pub const Info = packed struct {
sideeffect: bool = false,
alignstack: bool = false,
inteldialect: bool = false,
unwind: bool = false,
};
};
pub fn unwrap(self: Constant) union(enum) {
constant: u30,
global: Global.Index,
} {
return if (@intFromEnum(self) < @intFromEnum(first_global))
.{ .constant = @intCast(@intFromEnum(self)) }
else
.{ .global = @enumFromInt(@intFromEnum(self) - @intFromEnum(first_global)) };
}
pub fn toValue(self: Constant) Value {
return @enumFromInt(Value.first_constant + @intFromEnum(self));
}
pub fn typeOf(self: Constant, builder: *Builder) Type {
switch (self.unwrap()) {
.constant => |constant| {
const item = builder.constant_items.get(constant);
return switch (item.tag) {
.positive_integer,
.negative_integer,
=> @as(
*align(@alignOf(std.math.big.Limb)) Integer,
@ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]),
).type,
.half => .half,
.bfloat => .bfloat,
.float => .float,
.double => .double,
.fp128 => .fp128,
.x86_fp80 => .x86_fp80,
.ppc_fp128 => .ppc_fp128,
.null,
.none,
.zeroinitializer,
.undef,
.poison,
=> @enumFromInt(item.data),
.structure,
.packed_structure,
.array,
.vector,
=> builder.constantExtraData(Aggregate, item.data).type,
.splat => builder.constantExtraData(Splat, item.data).type,
.string => builder.arrayTypeAssumeCapacity(
@as(String, @enumFromInt(item.data)).slice(builder).?.len,
.i8,
),
.blockaddress => builder.ptrTypeAssumeCapacity(
builder.constantExtraData(BlockAddress, item.data)
.function.ptrConst(builder).global.ptrConst(builder).addr_space,
),
.dso_local_equivalent,
.no_cfi,
=> builder.ptrTypeAssumeCapacity(@as(Function.Index, @enumFromInt(item.data))
.ptrConst(builder).global.ptrConst(builder).addr_space),
.trunc,
.ptrtoint,
.inttoptr,
.bitcast,
.addrspacecast,
=> builder.constantExtraData(Cast, item.data).type,
.getelementptr,
.@"getelementptr inbounds",
=> {
var extra = builder.constantExtraDataTrail(GetElementPtr, item.data);
const indices =
extra.trail.next(extra.data.info.indices_len, Constant, builder);
const base_ty = extra.data.base.typeOf(builder);
if (!base_ty.isVector(builder)) for (indices) |index| {
const index_ty = index.typeOf(builder);
if (!index_ty.isVector(builder)) continue;
return index_ty.changeScalarAssumeCapacity(base_ty, builder);
};
return base_ty;
},
.add,
.@"add nsw",
.@"add nuw",
.sub,
.@"sub nsw",
.@"sub nuw",
.shl,
.xor,
=> builder.constantExtraData(Binary, item.data).lhs.typeOf(builder),
.@"asm",
.@"asm sideeffect",
.@"asm alignstack",
.@"asm sideeffect alignstack",
.@"asm inteldialect",
.@"asm sideeffect inteldialect",
.@"asm alignstack inteldialect",
.@"asm sideeffect alignstack inteldialect",
.@"asm unwind",
.@"asm sideeffect unwind",
.@"asm alignstack unwind",
.@"asm sideeffect alignstack unwind",
.@"asm inteldialect unwind",
.@"asm sideeffect inteldialect unwind",
.@"asm alignstack inteldialect unwind",
.@"asm sideeffect alignstack inteldialect unwind",
=> .ptr,
};
},
.global => |global| return builder.ptrTypeAssumeCapacity(
global.ptrConst(builder).addr_space,
),
}
}
pub fn isZeroInit(self: Constant, builder: *const Builder) bool {
switch (self.unwrap()) {
.constant => |constant| {
const item = builder.constant_items.get(constant);
return switch (item.tag) {
.positive_integer => {
const extra: *align(@alignOf(std.math.big.Limb)) Integer =
@ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]);
const limbs = builder.constant_limbs
.items[item.data + Integer.limbs ..][0..extra.limbs_len];
return std.mem.eql(std.math.big.Limb, limbs, &.{0});
},
.half, .bfloat, .float => item.data == 0,
.double => {
const extra = builder.constantExtraData(Constant.Double, item.data);
return extra.lo == 0 and extra.hi == 0;
},
.fp128, .ppc_fp128 => {
const extra = builder.constantExtraData(Constant.Fp128, item.data);
return extra.lo_lo == 0 and extra.lo_hi == 0 and
extra.hi_lo == 0 and extra.hi_hi == 0;
},
.x86_fp80 => {
const extra = builder.constantExtraData(Constant.Fp80, item.data);
return extra.lo_lo == 0 and extra.lo_hi == 0 and extra.hi == 0;
},
.vector => {
var extra = builder.constantExtraDataTrail(Aggregate, item.data);
const len: u32 = @intCast(extra.data.type.aggregateLen(builder));
const vals = extra.trail.next(len, Constant, builder);
for (vals) |val| if (!val.isZeroInit(builder)) return false;
return true;
},
.null, .zeroinitializer => true,
else => false,
};
},
.global => return false,
}
}
pub fn getBase(self: Constant, builder: *const Builder) Global.Index {
var cur = self;
while (true) switch (cur.unwrap()) {
.constant => |constant| {
const item = builder.constant_items.get(constant);
switch (item.tag) {
.ptrtoint,
.inttoptr,
.bitcast,
=> cur = builder.constantExtraData(Cast, item.data).val,
.getelementptr => cur = builder.constantExtraData(GetElementPtr, item.data).base,
.add => {
const extra = builder.constantExtraData(Binary, item.data);
const lhs_base = extra.lhs.getBase(builder);
const rhs_base = extra.rhs.getBase(builder);
return if (lhs_base != .none and rhs_base != .none)
.none
else if (lhs_base != .none) lhs_base else rhs_base;
},
.sub => {
const extra = builder.constantExtraData(Binary, item.data);
if (extra.rhs.getBase(builder) != .none) return .none;
cur = extra.lhs;
},
else => return .none,
}
},
.global => |global| switch (global.ptrConst(builder).kind) {
.alias => |alias| cur = alias.ptrConst(builder).aliasee,
.variable, .function => return global,
.replaced => unreachable,
},
};
}
const FormatData = struct {
constant: Constant,
builder: *Builder,
};
fn format(
data: FormatData,
comptime fmt_str: []const u8,
_: std.fmt.FormatOptions,
writer: anytype,
) @TypeOf(writer).Error!void {
if (comptime std.mem.indexOfNone(u8, fmt_str, ", %")) |_|
@compileError("invalid format string: '" ++ fmt_str ++ "'");
if (comptime std.mem.indexOfScalar(u8, fmt_str, ',') != null) {
if (data.constant == .no_init) return;
try writer.writeByte(',');
}
if (comptime std.mem.indexOfScalar(u8, fmt_str, ' ') != null) {
if (data.constant == .no_init) return;
try writer.writeByte(' ');
}
if (comptime std.mem.indexOfScalar(u8, fmt_str, '%') != null)
try writer.print("{%} ", .{data.constant.typeOf(data.builder).fmt(data.builder)});
assert(data.constant != .no_init);
if (std.enums.tagName(Constant, data.constant)) |name| return writer.writeAll(name);
switch (data.constant.unwrap()) {
.constant => |constant| {
const item = data.builder.constant_items.get(constant);
switch (item.tag) {
.positive_integer,
.negative_integer,
=> |tag| {
const extra: *align(@alignOf(std.math.big.Limb)) const Integer =
@ptrCast(data.builder.constant_limbs.items[item.data..][0..Integer.limbs]);
const limbs = data.builder.constant_limbs
.items[item.data + Integer.limbs ..][0..extra.limbs_len];
const bigint: std.math.big.int.Const = .{
.limbs = limbs,
.positive = switch (tag) {
.positive_integer => true,
.negative_integer => false,
else => unreachable,
},
};
const ExpectedContents = extern struct {
const expected_limbs = @divExact(512, @bitSizeOf(std.math.big.Limb));
string: [
(std.math.big.int.Const{
.limbs = &([1]std.math.big.Limb{
std.math.maxInt(std.math.big.Limb),
} ** expected_limbs),
.positive = false,
}).sizeInBaseUpperBound(10)
]u8,
limbs: [
std.math.big.int.calcToStringLimbsBufferLen(expected_limbs, 10)
]std.math.big.Limb,
};
var stack align(@alignOf(ExpectedContents)) =
std.heap.stackFallback(@sizeOf(ExpectedContents), data.builder.gpa);
const allocator = stack.get();
const str = try bigint.toStringAlloc(allocator, 10, undefined);
defer allocator.free(str);
try writer.writeAll(str);
},
.half,
.bfloat,
=> |tag| try writer.print("0x{c}{X:0>4}", .{ @as(u8, switch (tag) {
.half => 'H',
.bfloat => 'R',
else => unreachable,
}), item.data >> switch (tag) {
.half => 0,
.bfloat => 16,
else => unreachable,
} }),
.float => {
const Float = struct {
fn Repr(comptime T: type) type {
return packed struct(std.meta.Int(.unsigned, @bitSizeOf(T))) {
mantissa: std.meta.Int(.unsigned, std.math.floatMantissaBits(T)),
exponent: std.meta.Int(.unsigned, std.math.floatExponentBits(T)),
sign: u1,
};
}
};
const Mantissa64 = std.meta.FieldType(Float.Repr(f64), .mantissa);
const Exponent32 = std.meta.FieldType(Float.Repr(f32), .exponent);
const Exponent64 = std.meta.FieldType(Float.Repr(f64), .exponent);
const repr: Float.Repr(f32) = @bitCast(item.data);
const denormal_shift = switch (repr.exponent) {
std.math.minInt(Exponent32) => @as(
std.math.Log2Int(Mantissa64),
@clz(repr.mantissa),
) + 1,
else => 0,
};
try writer.print("0x{X:0>16}", .{@as(u64, @bitCast(Float.Repr(f64){
.mantissa = std.math.shl(
Mantissa64,
repr.mantissa,
std.math.floatMantissaBits(f64) - std.math.floatMantissaBits(f32) +
denormal_shift,
),
.exponent = switch (repr.exponent) {
std.math.minInt(Exponent32) => if (repr.mantissa > 0)
@as(Exponent64, std.math.floatExponentMin(f32) +
std.math.floatExponentMax(f64)) - denormal_shift
else
std.math.minInt(Exponent64),
else => @as(Exponent64, repr.exponent) +
(std.math.floatExponentMax(f64) - std.math.floatExponentMax(f32)),
std.math.maxInt(Exponent32) => std.math.maxInt(Exponent64),
},
.sign = repr.sign,
}))});
},
.double => {
const extra = data.builder.constantExtraData(Double, item.data);
try writer.print("0x{X:0>8}{X:0>8}", .{ extra.hi, extra.lo });
},
.fp128,
.ppc_fp128,
=> |tag| {
const extra = data.builder.constantExtraData(Fp128, item.data);
try writer.print("0x{c}{X:0>8}{X:0>8}{X:0>8}{X:0>8}", .{
@as(u8, switch (tag) {
.fp128 => 'L',
.ppc_fp128 => 'M',
else => unreachable,
}),
extra.lo_hi,
extra.lo_lo,
extra.hi_hi,
extra.hi_lo,
});
},
.x86_fp80 => {
const extra = data.builder.constantExtraData(Fp80, item.data);
try writer.print("0xK{X:0>4}{X:0>8}{X:0>8}", .{
extra.hi, extra.lo_hi, extra.lo_lo,
});
},
.null,
.none,
.zeroinitializer,
.undef,
.poison,
=> |tag| try writer.writeAll(@tagName(tag)),
.structure,
.packed_structure,
.array,
.vector,
=> |tag| {
var extra = data.builder.constantExtraDataTrail(Aggregate, item.data);
const len: u32 = @intCast(extra.data.type.aggregateLen(data.builder));
const vals = extra.trail.next(len, Constant, data.builder);
try writer.writeAll(switch (tag) {
.structure => "{ ",
.packed_structure => "<{ ",
.array => "[",
.vector => "<",
else => unreachable,
});
for (vals, 0..) |val, index| {
if (index > 0) try writer.writeAll(", ");
try writer.print("{%}", .{val.fmt(data.builder)});
}
try writer.writeAll(switch (tag) {
.structure => " }",
.packed_structure => " }>",
.array => "]",
.vector => ">",
else => unreachable,
});
},
.splat => {
const extra = data.builder.constantExtraData(Splat, item.data);
const len = extra.type.vectorLen(data.builder);
try writer.writeByte('<');
for (0..len) |index| {
if (index > 0) try writer.writeAll(", ");
try writer.print("{%}", .{extra.value.fmt(data.builder)});
}
try writer.writeByte('>');
},
.string => try writer.print("c{\"}", .{
@as(String, @enumFromInt(item.data)).fmt(data.builder),
}),
.blockaddress => |tag| {
const extra = data.builder.constantExtraData(BlockAddress, item.data);
const function = extra.function.ptrConst(data.builder);
try writer.print("{s}({}, {})", .{
@tagName(tag),
function.global.fmt(data.builder),
extra.block.toInst(function).fmt(extra.function, data.builder),
});
},
.dso_local_equivalent,
.no_cfi,
=> |tag| {
const function: Function.Index = @enumFromInt(item.data);
try writer.print("{s} {}", .{
@tagName(tag),
function.ptrConst(data.builder).global.fmt(data.builder),
});
},
.trunc,
.ptrtoint,
.inttoptr,
.bitcast,
.addrspacecast,
=> |tag| {
const extra = data.builder.constantExtraData(Cast, item.data);
try writer.print("{s} ({%} to {%})", .{
@tagName(tag),
extra.val.fmt(data.builder),
extra.type.fmt(data.builder),
});
},
.getelementptr,
.@"getelementptr inbounds",
=> |tag| {
var extra = data.builder.constantExtraDataTrail(GetElementPtr, item.data);
const indices =
extra.trail.next(extra.data.info.indices_len, Constant, data.builder);
try writer.print("{s} ({%}, {%}", .{
@tagName(tag),
extra.data.type.fmt(data.builder),
extra.data.base.fmt(data.builder),
});
for (indices) |index| try writer.print(", {%}", .{index.fmt(data.builder)});
try writer.writeByte(')');
},
.add,
.@"add nsw",
.@"add nuw",
.sub,
.@"sub nsw",
.@"sub nuw",
.shl,
.xor,
=> |tag| {
const extra = data.builder.constantExtraData(Binary, item.data);
try writer.print("{s} ({%}, {%})", .{
@tagName(tag),
extra.lhs.fmt(data.builder),
extra.rhs.fmt(data.builder),
});
},
.@"asm",
.@"asm sideeffect",
.@"asm alignstack",
.@"asm sideeffect alignstack",
.@"asm inteldialect",
.@"asm sideeffect inteldialect",
.@"asm alignstack inteldialect",
.@"asm sideeffect alignstack inteldialect",
.@"asm unwind",
.@"asm sideeffect unwind",
.@"asm alignstack unwind",
.@"asm sideeffect alignstack unwind",
.@"asm inteldialect unwind",
.@"asm sideeffect inteldialect unwind",
.@"asm alignstack inteldialect unwind",
.@"asm sideeffect alignstack inteldialect unwind",
=> |tag| {
const extra = data.builder.constantExtraData(Assembly, item.data);
try writer.print("{s} {\"}, {\"}", .{
@tagName(tag),
extra.assembly.fmt(data.builder),
extra.constraints.fmt(data.builder),
});
},
}
},
.global => |global| try writer.print("{}", .{global.fmt(data.builder)}),
}
}
pub fn fmt(self: Constant, builder: *Builder) std.fmt.Formatter(format) {
return .{ .data = .{ .constant = self, .builder = builder } };
}
}