diff options
| author | mlugg <mlugg@mlugg.co.uk> | 2023-05-09 17:06:10 +0100 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-06-10 20:42:30 -0700 |
| commit | 466328d1ca29f3f6dd142f74dda13b26687e71e0 (patch) | |
| tree | 40d1310c7ae5dc98fce899884cfdaa2b310728b2 /src/InternPool.zig | |
| parent | 5881a2d63771b070107bdc2325aa1bc455b2d926 (diff) | |
| download | zig-466328d1ca29f3f6dd142f74dda13b26687e71e0.tar.gz zig-466328d1ca29f3f6dd142f74dda13b26687e71e0.zip | |
InternPool: transition float values
Diffstat (limited to 'src/InternPool.zig')
| -rw-r--r-- | src/InternPool.zig | 195 |
1 files changed, 191 insertions, 4 deletions
diff --git a/src/InternPool.zig b/src/InternPool.zig index 6ff68a7583..2677fba45d 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -155,6 +155,7 @@ pub const Key = union(enum) { lib_name: u32, }, int: Key.Int, + float: Key.Float, ptr: Ptr, opt: Opt, enum_tag: struct { @@ -361,6 +362,20 @@ pub const Key = union(enum) { }; }; + pub const Float = struct { + ty: Index, + /// The storage used must match the size of the float type being represented. + storage: Storage, + + pub const Storage = union(enum) { + f16: f16, + f32: f32, + f64: f64, + f80: f80, + f128: f128, + }; + }; + pub const Ptr = struct { ty: Index, addr: Addr, @@ -436,6 +451,16 @@ pub const Key = union(enum) { for (big_int.limbs) |limb| std.hash.autoHash(hasher, limb); }, + .float => |float| { + std.hash.autoHash(hasher, float.ty); + switch (float.storage) { + inline else => |val| std.hash.autoHash( + hasher, + @bitCast(std.meta.Int(.unsigned, @bitSizeOf(@TypeOf(val))), val), + ), + } + }, + .ptr => |ptr| { std.hash.autoHash(hasher, ptr.ty); // Int-to-ptr pointers are hashed separately than decl-referencing pointers. @@ -561,6 +586,32 @@ pub const Key = union(enum) { }; }, + .float => |a_info| { + const b_info = b.float; + + if (a_info.ty != b_info.ty) + return false; + + if (a_info.ty == .c_longdouble_type and a_info.storage != .f80) { + // These are strange: we'll sometimes represent them as f128, even if the + // underlying type is smaller. f80 is an exception: see float_c_longdouble_f80. + const a_val = switch (a_info.storage) { + inline else => |val| @floatCast(f128, val), + }; + const b_val = switch (b_info.storage) { + inline else => |val| @floatCast(f128, val), + }; + return a_val == b_val; + } + + const StorageTag = @typeInfo(Key.Float.Storage).Union.tag_type.?; + assert(@as(StorageTag, a_info.storage) == @as(StorageTag, b_info.storage)); + + return switch (a_info.storage) { + inline else => |val, tag| val == @field(b_info.storage, @tagName(tag)), + }; + }, + .enum_tag => |a_info| { const b_info = b.enum_tag; _ = a_info; @@ -601,6 +652,7 @@ pub const Key = union(enum) { inline .ptr, .int, + .float, .opt, .extern_func, .enum_tag, @@ -1115,15 +1167,35 @@ pub const Tag = enum(u8) { /// An enum tag identified by a negative integer value. /// data is a limbs index to Int. enum_tag_negative, + /// An f16 value. + /// data is float value bitcasted to u16 and zero-extended. + float_f16, /// An f32 value. /// data is float value bitcasted to u32. float_f32, /// An f64 value. /// data is extra index to Float64. float_f64, + /// An f80 value. + /// data is extra index to Float80. + float_f80, /// An f128 value. /// data is extra index to Float128. float_f128, + /// A c_longdouble value of 80 bits. + /// data is extra index to Float80. + /// This is used when a c_longdouble value is provided as an f80, because f80 has unnormalized + /// values which cannot be losslessly represented as f128. It should only be used when the type + /// underlying c_longdouble for the target is 80 bits. + float_c_longdouble_f80, + /// A c_longdouble value of 128 bits. + /// data is extra index to Float128. + /// This is used when a c_longdouble value is provided as any type other than an f80, since all + /// other float types can be losslessly converted to and from f128. + float_c_longdouble_f128, + /// A comptime_float value. + /// data is extra index to Float128. + float_comptime_float, /// An extern function. extern_func, /// A regular function. @@ -1339,7 +1411,38 @@ pub const Float64 = struct { pub fn get(self: Float64) f64 { const int_bits = @as(u64, self.piece0) | (@as(u64, self.piece1) << 32); - return @bitCast(u64, int_bits); + return @bitCast(f64, int_bits); + } + + fn pack(val: f64) Float64 { + const bits = @bitCast(u64, val); + return .{ + .piece0 = @truncate(u32, bits), + .piece1 = @truncate(u32, bits >> 32), + }; + } +}; + +/// A f80 value, broken up into 2 u32 parts and a u16 part zero-padded to a u32. +pub const Float80 = struct { + piece0: u32, + piece1: u32, + piece2: u32, // u16 part, top bits + + pub fn get(self: Float80) f80 { + const int_bits = @as(u80, self.piece0) | + (@as(u80, self.piece1) << 32) | + (@as(u80, self.piece2) << 64); + return @bitCast(f80, int_bits); + } + + fn pack(val: f80) Float80 { + const bits = @bitCast(u80, val); + return .{ + .piece0 = @truncate(u32, bits), + .piece1 = @truncate(u32, bits >> 32), + .piece2 = @truncate(u16, bits >> 64), + }; } }; @@ -1357,6 +1460,16 @@ pub const Float128 = struct { (@as(u128, self.piece3) << 96); return @bitCast(f128, int_bits); } + + fn pack(val: f128) Float128 { + const bits = @bitCast(u128, val); + return .{ + .piece0 = @truncate(u32, bits), + .piece1 = @truncate(u32, bits >> 32), + .piece2 = @truncate(u32, bits >> 64), + .piece3 = @truncate(u32, bits >> 96), + }; + } }; pub fn init(ip: *InternPool, gpa: Allocator) !void { @@ -1576,9 +1689,38 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { .int_negative => indexToKeyBigInt(ip, data, false), .enum_tag_positive => @panic("TODO"), .enum_tag_negative => @panic("TODO"), - .float_f32 => @panic("TODO"), - .float_f64 => @panic("TODO"), - .float_f128 => @panic("TODO"), + .float_f16 => .{ .float = .{ + .ty = .f16_type, + .storage = .{ .f16 = @bitCast(f16, @intCast(u16, data)) }, + } }, + .float_f32 => .{ .float = .{ + .ty = .f32_type, + .storage = .{ .f32 = @bitCast(f32, data) }, + } }, + .float_f64 => .{ .float = .{ + .ty = .f64_type, + .storage = .{ .f64 = ip.extraData(Float64, data).get() }, + } }, + .float_f80 => .{ .float = .{ + .ty = .f80_type, + .storage = .{ .f80 = ip.extraData(Float80, data).get() }, + } }, + .float_f128 => .{ .float = .{ + .ty = .f128_type, + .storage = .{ .f128 = ip.extraData(Float128, data).get() }, + } }, + .float_c_longdouble_f80 => .{ .float = .{ + .ty = .c_longdouble_type, + .storage = .{ .f80 = ip.extraData(Float80, data).get() }, + } }, + .float_c_longdouble_f128 => .{ .float = .{ + .ty = .c_longdouble_type, + .storage = .{ .f128 = ip.extraData(Float128, data).get() }, + } }, + .float_comptime_float => .{ .float = .{ + .ty = .comptime_float_type, + .storage = .{ .f128 = ip.extraData(Float128, data).get() }, + } }, .extern_func => @panic("TODO"), .func => @panic("TODO"), .only_possible_value => { @@ -1982,6 +2124,46 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { } }, + .float => |float| { + switch (float.ty) { + .f16_type => ip.items.appendAssumeCapacity(.{ + .tag = .float_f16, + .data = @bitCast(u16, float.storage.f16), + }), + .f32_type => ip.items.appendAssumeCapacity(.{ + .tag = .float_f32, + .data = @bitCast(u32, float.storage.f32), + }), + .f64_type => ip.items.appendAssumeCapacity(.{ + .tag = .float_f64, + .data = try ip.addExtra(gpa, Float64.pack(float.storage.f64)), + }), + .f80_type => ip.items.appendAssumeCapacity(.{ + .tag = .float_f80, + .data = try ip.addExtra(gpa, Float80.pack(float.storage.f80)), + }), + .f128_type => ip.items.appendAssumeCapacity(.{ + .tag = .float_f128, + .data = try ip.addExtra(gpa, Float128.pack(float.storage.f128)), + }), + .c_longdouble_type => switch (float.storage) { + .f80 => |x| ip.items.appendAssumeCapacity(.{ + .tag = .float_c_longdouble_f80, + .data = try ip.addExtra(gpa, Float80.pack(x)), + }), + inline .f16, .f32, .f64, .f128 => |x| ip.items.appendAssumeCapacity(.{ + .tag = .float_c_longdouble_f128, + .data = try ip.addExtra(gpa, Float128.pack(x)), + }), + }, + .comptime_float_type => ip.items.appendAssumeCapacity(.{ + .tag = .float_comptime_float, + .data = try ip.addExtra(gpa, Float128.pack(float.storage.f128)), + }), + else => unreachable, + } + }, + .enum_tag => |enum_tag| { const tag: Tag = if (enum_tag.tag.positive) .enum_tag_positive else .enum_tag_negative; try addInt(ip, gpa, enum_tag.ty, tag, enum_tag.tag.limbs); @@ -2645,9 +2827,14 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { break :b @sizeOf(Int) + int.limbs_len * 8; }, + .float_f16 => 0, .float_f32 => 0, .float_f64 => @sizeOf(Float64), + .float_f80 => @sizeOf(Float80), .float_f128 => @sizeOf(Float128), + .float_c_longdouble_f80 => @sizeOf(Float80), + .float_c_longdouble_f128 => @sizeOf(Float128), + .float_comptime_float => @sizeOf(Float128), .extern_func => @panic("TODO"), .func => @panic("TODO"), .only_possible_value => 0, |
