enum Constant [src]

Fields

false
true
@"0"
@"1"
none
no_init = (1 << 30) - 1
_

Members

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