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, diff --git a/src/Module.zig b/src/Module.zig index 6bcd148e67..b32904e165 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -6940,6 +6940,24 @@ pub fn unionValue(mod: *Module, union_ty: Type, tag: Value, val: Value) Allocato return i.toValue(); } +/// This function casts the float representation down to the representation of the type, potentially +/// losing data if the representation wasn't correct. +pub fn floatValue(mod: *Module, ty: Type, x: anytype) Allocator.Error!Value { + const storage: InternPool.Key.Float.Storage = switch (ty.floatBits(mod.getTarget())) { + 16 => .{ .f16 = @floatCast(f16, x) }, + 32 => .{ .f32 = @floatCast(f32, x) }, + 64 => .{ .f64 = @floatCast(f64, x) }, + 80 => .{ .f80 = @floatCast(f80, x) }, + 128 => .{ .f128 = @floatCast(f128, x) }, + else => unreachable, + }; + const i = try intern(mod, .{ .float = .{ + .ty = ty.ip_index, + .storage = storage, + } }); + return i.toValue(); +} + pub fn smallestUnsignedInt(mod: *Module, max: u64) Allocator.Error!Type { return intType(mod, .unsigned, Type.smallestUnsignedBits(max)); } diff --git a/src/Sema.zig b/src/Sema.zig index b94f995b46..b5baf4dde3 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3225,7 +3225,7 @@ fn zirOpaqueDecl( const new_namespace = mod.namespacePtr(new_namespace_index); errdefer mod.destroyNamespace(new_namespace_index); - const opaque_ty = try mod.intern_pool.get(gpa, .{ .opaque_type = .{ + const opaque_ty = try mod.intern(.{ .opaque_type = .{ .decl = new_decl_index, .namespace = new_namespace_index, } }); @@ -5196,23 +5196,21 @@ fn zirIntBig(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. fn zirFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { _ = block; - const arena = sema.arena; const number = sema.code.instructions.items(.data)[inst].float; return sema.addConstant( Type.comptime_float, - try Value.Tag.float_64.create(arena, number), + try sema.mod.floatValue(Type.comptime_float, number), ); } fn zirFloat128(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { _ = block; - const arena = sema.arena; const inst_data = sema.code.instructions.items(.data)[inst].pl_node; const extra = sema.code.extraData(Zir.Inst.Float128, inst_data.payload_index).data; const number = extra.get(); return sema.addConstant( Type.comptime_float, - try Value.Tag.float_128.create(arena, number), + try sema.mod.floatValue(Type.comptime_float, number), ); } @@ -9952,7 +9950,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A } if (try sema.resolveMaybeUndefVal(operand)) |operand_val| { - return sema.addConstant(dest_ty, try operand_val.floatCast(sema.arena, dest_ty, mod)); + return sema.addConstant(dest_ty, try operand_val.floatCast(dest_ty, mod)); } if (dest_is_comptime_float) { return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_float'", .{}); @@ -13302,7 +13300,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins if (!lhs_val.isUndef()) { if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { const scalar_zero = switch (scalar_tag) { - .ComptimeFloat, .Float => Value.float_zero, // TODO migrate to internpool + .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0), .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), else => unreachable, }; @@ -13441,7 +13439,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } else { if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { const scalar_zero = switch (scalar_tag) { - .ComptimeFloat, .Float => Value.float_zero, // TODO migrate to internpool + .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0), .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), else => unreachable, }; @@ -13526,7 +13524,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const remainder = try block.addBinOp(.rem, casted_lhs, casted_rhs); const scalar_zero = switch (scalar_tag) { - .ComptimeFloat, .Float => Value.float_zero, // TODO migrate to internpool + .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0), .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), else => unreachable, }; @@ -13616,7 +13614,7 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai if (!lhs_val.isUndef()) { if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { const scalar_zero = switch (scalar_tag) { - .ComptimeFloat, .Float => Value.float_zero, // TODO migrate to internpool + .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0), .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), else => unreachable, }; @@ -13737,7 +13735,7 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai if (!lhs_val.isUndef()) { if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { const scalar_zero = switch (scalar_tag) { - .ComptimeFloat, .Float => Value.float_zero, // TODO migrate to internpool + .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0), .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), else => unreachable, }; @@ -13895,7 +13893,10 @@ fn addDivByZeroSafety( if (maybe_rhs_val != null) return; const mod = sema.mod; - const scalar_zero = if (is_int) try mod.intValue(resolved_type.scalarType(mod), 0) else Value.float_zero; // TODO migrate to internpool + const scalar_zero = if (is_int) + try mod.intValue(resolved_type.scalarType(mod), 0) + else + try mod.floatValue(resolved_type.scalarType(mod), 0); const ok = if (resolved_type.zigTypeTag(mod) == .Vector) ok: { const zero_val = try Value.Tag.repeated.create(sema.arena, scalar_zero); const zero = try sema.addConstant(resolved_type, zero_val); @@ -13981,7 +13982,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. } if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { const scalar_zero = switch (scalar_tag) { - .ComptimeFloat, .Float => Value.float_zero, // TODO migrate to internpool + .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0), .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), else => unreachable, }; @@ -14641,7 +14642,7 @@ fn analyzeArithmetic( } else { return sema.addConstant( resolved_type, - try sema.floatAdd(lhs_val, rhs_val, resolved_type), + try Value.floatAdd(lhs_val, rhs_val, resolved_type, sema.arena, mod), ); } } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; @@ -14738,7 +14739,7 @@ fn analyzeArithmetic( } else { return sema.addConstant( resolved_type, - try sema.floatSub(lhs_val, rhs_val, resolved_type), + try Value.floatSub(lhs_val, rhs_val, resolved_type, sema.arena, mod), ); } } else break :rs .{ .src = rhs_src, .air_tag = air_tag }; @@ -14808,22 +14809,25 @@ fn analyzeArithmetic( // the result is nan. // If either of the operands are nan, the result is nan. const scalar_zero = switch (scalar_tag) { - .ComptimeFloat, .Float => Value.float_zero, // TODO migrate to internpool + .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0), .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), else => unreachable, }; if (maybe_lhs_val) |lhs_val| { if (!lhs_val.isUndef()) { - if (lhs_val.isNan()) { + if (lhs_val.isNan(mod)) { return sema.addConstant(resolved_type, lhs_val); } if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) lz: { if (maybe_rhs_val) |rhs_val| { - if (rhs_val.isNan()) { + if (rhs_val.isNan(mod)) { return sema.addConstant(resolved_type, rhs_val); } - if (rhs_val.isInf()) { - return sema.addConstant(resolved_type, try Value.Tag.float_32.create(sema.arena, std.math.nan_f32)); + if (rhs_val.isInf(mod)) { + return sema.addConstant( + resolved_type, + try mod.floatValue(resolved_type, std.math.nan_f128), + ); } } else if (resolved_type.isAnyFloat()) { break :lz; @@ -14847,13 +14851,16 @@ fn analyzeArithmetic( return sema.addConstUndef(resolved_type); } } - if (rhs_val.isNan()) { + if (rhs_val.isNan(mod)) { return sema.addConstant(resolved_type, rhs_val); } if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) rz: { if (maybe_lhs_val) |lhs_val| { - if (lhs_val.isInf()) { - return sema.addConstant(resolved_type, try Value.Tag.float_32.create(sema.arena, std.math.nan_f32)); + if (lhs_val.isInf(mod)) { + return sema.addConstant( + resolved_type, + try mod.floatValue(resolved_type, std.math.nan_f128), + ); } } else if (resolved_type.isAnyFloat()) { break :rz; @@ -14896,7 +14903,7 @@ fn analyzeArithmetic( // If either of the operands are one, result is the other operand. // If either of the operands are undefined, result is undefined. const scalar_zero = switch (scalar_tag) { - .ComptimeFloat, .Float => Value.float_zero, // TODO migrate to internpool + .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0), .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), else => unreachable, }; @@ -14944,7 +14951,7 @@ fn analyzeArithmetic( // If either of the operands are one, result is the other operand. // If either of the operands are undefined, result is undefined. const scalar_zero = switch (scalar_tag) { - .ComptimeFloat, .Float => Value.float_zero, // TODO migrate to internpool + .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0), .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), else => unreachable, }; @@ -19167,7 +19174,7 @@ fn zirReify( const new_namespace = mod.namespacePtr(new_namespace_index); errdefer mod.destroyNamespace(new_namespace_index); - const opaque_ty = try mod.intern_pool.get(gpa, .{ .opaque_type = .{ + const opaque_ty = try mod.intern(.{ .opaque_type = .{ .decl = new_decl_index, .namespace = new_namespace_index, } }); @@ -25678,7 +25685,7 @@ fn coerceExtra( // Keep the comptime Value representation; take the new type. return sema.addConstant(dest_ty, val); } else { - const new_val = try mod.intern_pool.getCoerced(mod.gpa, val.ip_index, dest_ty.ip_index); + const new_val = try mod.intern_pool.getCoerced(sema.gpa, val.ip_index, dest_ty.ip_index); return sema.addConstant(dest_ty, new_val.toValue()); } } @@ -26032,7 +26039,7 @@ fn coerceExtra( break :float; }; - if (val.floatHasFraction()) { + if (val.floatHasFraction(mod)) { return sema.fail( block, inst_src, @@ -26081,7 +26088,7 @@ fn coerceExtra( .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag(mod)) { .ComptimeFloat => { const val = try sema.resolveConstValue(block, .unneeded, inst, ""); - const result_val = try val.floatCast(sema.arena, dest_ty, mod); + const result_val = try val.floatCast(dest_ty, mod); return try sema.addConstant(dest_ty, result_val); }, .Float => { @@ -26089,7 +26096,7 @@ fn coerceExtra( return sema.addConstUndef(dest_ty); } if (try sema.resolveMaybeUndefVal(inst)) |val| { - const result_val = try val.floatCast(sema.arena, dest_ty, mod); + const result_val = try val.floatCast(dest_ty, mod); if (!val.eql(result_val, inst_ty, sema.mod)) { return sema.fail( block, @@ -30071,7 +30078,7 @@ fn cmpNumeric( if (lhs_val.isUndef() or rhs_val.isUndef()) { return sema.addConstUndef(Type.bool); } - if (lhs_val.isNan() or rhs_val.isNan()) { + if (lhs_val.isNan(mod) or rhs_val.isNan(mod)) { if (op == std.math.CompareOperator.neq) { return Air.Inst.Ref.bool_true; } else { @@ -30166,15 +30173,15 @@ fn cmpNumeric( try sema.resolveLazyValue(lhs_val); if (lhs_val.isUndef()) return sema.addConstUndef(Type.bool); - if (lhs_val.isNan()) switch (op) { + if (lhs_val.isNan(mod)) switch (op) { .neq => return Air.Inst.Ref.bool_true, else => return Air.Inst.Ref.bool_false, }; - if (lhs_val.isInf()) switch (op) { + if (lhs_val.isInf(mod)) switch (op) { .neq => return Air.Inst.Ref.bool_true, .eq => return Air.Inst.Ref.bool_false, - .gt, .gte => return if (lhs_val.isNegativeInf()) Air.Inst.Ref.bool_false else Air.Inst.Ref.bool_true, - .lt, .lte => return if (lhs_val.isNegativeInf()) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false, + .gt, .gte => return if (lhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_false else Air.Inst.Ref.bool_true, + .lt, .lte => return if (lhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false, }; if (!rhs_is_signed) { switch (lhs_val.orderAgainstZero(mod)) { @@ -30191,7 +30198,7 @@ fn cmpNumeric( } } if (lhs_is_float) { - if (lhs_val.floatHasFraction()) { + if (lhs_val.floatHasFraction(mod)) { switch (op) { .eq => return Air.Inst.Ref.bool_false, .neq => return Air.Inst.Ref.bool_true, @@ -30201,7 +30208,7 @@ fn cmpNumeric( var bigint = try float128IntPartToBigInt(sema.gpa, lhs_val.toFloat(f128, mod)); defer bigint.deinit(); - if (lhs_val.floatHasFraction()) { + if (lhs_val.floatHasFraction(mod)) { if (lhs_is_signed) { try bigint.addScalar(&bigint, -1); } else { @@ -30225,15 +30232,15 @@ fn cmpNumeric( try sema.resolveLazyValue(rhs_val); if (rhs_val.isUndef()) return sema.addConstUndef(Type.bool); - if (rhs_val.isNan()) switch (op) { + if (rhs_val.isNan(mod)) switch (op) { .neq => return Air.Inst.Ref.bool_true, else => return Air.Inst.Ref.bool_false, }; - if (rhs_val.isInf()) switch (op) { + if (rhs_val.isInf(mod)) switch (op) { .neq => return Air.Inst.Ref.bool_true, .eq => return Air.Inst.Ref.bool_false, - .gt, .gte => return if (rhs_val.isNegativeInf()) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false, - .lt, .lte => return if (rhs_val.isNegativeInf()) Air.Inst.Ref.bool_false else Air.Inst.Ref.bool_true, + .gt, .gte => return if (rhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false, + .lt, .lte => return if (rhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_false else Air.Inst.Ref.bool_true, }; if (!lhs_is_signed) { switch (rhs_val.orderAgainstZero(mod)) { @@ -30250,7 +30257,7 @@ fn cmpNumeric( } } if (rhs_is_float) { - if (rhs_val.floatHasFraction()) { + if (rhs_val.floatHasFraction(mod)) { switch (op) { .eq => return Air.Inst.Ref.bool_false, .neq => return Air.Inst.Ref.bool_true, @@ -30260,7 +30267,7 @@ fn cmpNumeric( var bigint = try float128IntPartToBigInt(sema.gpa, rhs_val.toFloat(f128, mod)); defer bigint.deinit(); - if (rhs_val.floatHasFraction()) { + if (rhs_val.floatHasFraction(mod)) { if (rhs_is_signed) { try bigint.addScalar(&bigint, -1); } else { @@ -31713,6 +31720,7 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { .simple_value => unreachable, .extern_func => unreachable, .int => unreachable, + .float => unreachable, .ptr => unreachable, .opt => unreachable, .enum_tag => unreachable, @@ -33216,6 +33224,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { .simple_value => unreachable, .extern_func => unreachable, .int => unreachable, + .float => unreachable, .ptr => unreachable, .opt => unreachable, .enum_tag => unreachable, @@ -33777,6 +33786,7 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { .simple_value => unreachable, .extern_func => unreachable, .int => unreachable, + .float => unreachable, .ptr => unreachable, .opt => unreachable, .enum_tag => unreachable, @@ -33935,7 +33945,7 @@ fn numberAddWrapScalar( } if (ty.isAnyFloat()) { - return sema.floatAdd(lhs, rhs, ty); + return Value.floatAdd(lhs, rhs, ty, sema.arena, mod); } const overflow_result = try sema.intAddWithOverflow(lhs, rhs, ty); @@ -33989,127 +33999,13 @@ fn numberSubWrapScalar( } if (ty.isAnyFloat()) { - return sema.floatSub(lhs, rhs, ty); + return Value.floatSub(lhs, rhs, ty, sema.arena, mod); } const overflow_result = try sema.intSubWithOverflow(lhs, rhs, ty); return overflow_result.wrapped_result; } -fn floatAdd( - sema: *Sema, - lhs: Value, - rhs: Value, - float_type: Type, -) !Value { - const mod = sema.mod; - if (float_type.zigTypeTag(mod) == .Vector) { - const result_data = try sema.arena.alloc(Value, float_type.vectorLen(mod)); - for (result_data, 0..) |*scalar, i| { - const lhs_elem = try lhs.elemValue(sema.mod, i); - const rhs_elem = try rhs.elemValue(sema.mod, i); - scalar.* = try sema.floatAddScalar(lhs_elem, rhs_elem, float_type.scalarType(mod)); - } - return Value.Tag.aggregate.create(sema.arena, result_data); - } - return sema.floatAddScalar(lhs, rhs, float_type); -} - -fn floatAddScalar( - sema: *Sema, - lhs: Value, - rhs: Value, - float_type: Type, -) !Value { - const mod = sema.mod; - const target = sema.mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const lhs_val = lhs.toFloat(f16, mod); - const rhs_val = rhs.toFloat(f16, mod); - return Value.Tag.float_16.create(sema.arena, lhs_val + rhs_val); - }, - 32 => { - const lhs_val = lhs.toFloat(f32, mod); - const rhs_val = rhs.toFloat(f32, mod); - return Value.Tag.float_32.create(sema.arena, lhs_val + rhs_val); - }, - 64 => { - const lhs_val = lhs.toFloat(f64, mod); - const rhs_val = rhs.toFloat(f64, mod); - return Value.Tag.float_64.create(sema.arena, lhs_val + rhs_val); - }, - 80 => { - const lhs_val = lhs.toFloat(f80, mod); - const rhs_val = rhs.toFloat(f80, mod); - return Value.Tag.float_80.create(sema.arena, lhs_val + rhs_val); - }, - 128 => { - const lhs_val = lhs.toFloat(f128, mod); - const rhs_val = rhs.toFloat(f128, mod); - return Value.Tag.float_128.create(sema.arena, lhs_val + rhs_val); - }, - else => unreachable, - } -} - -fn floatSub( - sema: *Sema, - lhs: Value, - rhs: Value, - float_type: Type, -) !Value { - const mod = sema.mod; - if (float_type.zigTypeTag(mod) == .Vector) { - const result_data = try sema.arena.alloc(Value, float_type.vectorLen(mod)); - for (result_data, 0..) |*scalar, i| { - const lhs_elem = try lhs.elemValue(sema.mod, i); - const rhs_elem = try rhs.elemValue(sema.mod, i); - scalar.* = try sema.floatSubScalar(lhs_elem, rhs_elem, float_type.scalarType(mod)); - } - return Value.Tag.aggregate.create(sema.arena, result_data); - } - return sema.floatSubScalar(lhs, rhs, float_type); -} - -fn floatSubScalar( - sema: *Sema, - lhs: Value, - rhs: Value, - float_type: Type, -) !Value { - const mod = sema.mod; - const target = sema.mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const lhs_val = lhs.toFloat(f16, mod); - const rhs_val = rhs.toFloat(f16, mod); - return Value.Tag.float_16.create(sema.arena, lhs_val - rhs_val); - }, - 32 => { - const lhs_val = lhs.toFloat(f32, mod); - const rhs_val = rhs.toFloat(f32, mod); - return Value.Tag.float_32.create(sema.arena, lhs_val - rhs_val); - }, - 64 => { - const lhs_val = lhs.toFloat(f64, mod); - const rhs_val = rhs.toFloat(f64, mod); - return Value.Tag.float_64.create(sema.arena, lhs_val - rhs_val); - }, - 80 => { - const lhs_val = lhs.toFloat(f80, mod); - const rhs_val = rhs.toFloat(f80, mod); - return Value.Tag.float_80.create(sema.arena, lhs_val - rhs_val); - }, - 128 => { - const lhs_val = lhs.toFloat(f128, mod); - const rhs_val = rhs.toFloat(f128, mod); - return Value.Tag.float_128.create(sema.arena, lhs_val - rhs_val); - }, - else => unreachable, - } -} - fn intSubWithOverflow( sema: *Sema, lhs: Value, diff --git a/src/TypedValue.zig b/src/TypedValue.zig index 5f295e42f3..57ef662a9e 100644 --- a/src/TypedValue.zig +++ b/src/TypedValue.zig @@ -283,11 +283,6 @@ pub fn print( } return writer.writeAll(" }"); }, - .float_16 => return writer.print("{d}", .{val.castTag(.float_16).?.data}), - .float_32 => return writer.print("{d}", .{val.castTag(.float_32).?.data}), - .float_64 => return writer.print("{d}", .{val.castTag(.float_64).?.data}), - .float_80 => return writer.print("{d}", .{@floatCast(f64, val.castTag(.float_80).?.data)}), - .float_128 => return writer.print("{d}", .{@floatCast(f64, val.castTag(.float_128).?.data)}), .@"error" => return writer.print("error.{s}", .{val.castTag(.@"error").?.data.name}), .eu_payload => { val = val.castTag(.eu_payload).?.data; @@ -363,6 +358,9 @@ pub fn print( .int => |int| switch (int.storage) { inline .u64, .i64, .big_int => |x| return writer.print("{}", .{x}), }, + .float => |float| switch (float.storage) { + inline else => |x| return writer.print("{}", .{x}), + }, else => return writer.print("{}", .{val.ip_index}), } }, diff --git a/src/codegen/c.zig b/src/codegen/c.zig index a67d39471a..10a4856ad0 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -6612,7 +6612,6 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { const mod = f.object.dg.module; const reduce = f.air.instructions.items(.data)[inst].reduce; - const target = mod.getTarget(); const scalar_ty = f.typeOfIndex(inst); const operand = try f.resolveInst(reduce.operand); try reap(f, inst, &.{reduce.operand}); @@ -6679,16 +6678,6 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { var arena = std.heap.ArenaAllocator.init(f.object.dg.gpa); defer arena.deinit(); - const ExpectedContents = union { - f16: Value.Payload.Float_16, - f32: Value.Payload.Float_32, - f64: Value.Payload.Float_64, - f80: Value.Payload.Float_80, - f128: Value.Payload.Float_128, - }; - var stack align(@alignOf(ExpectedContents)) = - std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator()); - try f.object.dg.renderValue(writer, scalar_ty, switch (reduce.operation) { .Or, .Xor, .Add => try mod.intValue(scalar_ty, 0), .And => switch (scalar_ty.zigTypeTag(mod)) { @@ -6701,13 +6690,13 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { .Min => switch (scalar_ty.zigTypeTag(mod)) { .Bool => Value.one_comptime_int, .Int => try scalar_ty.maxIntScalar(mod, scalar_ty), - .Float => try Value.floatToValue(std.math.nan(f128), stack.get(), scalar_ty, target), + .Float => try mod.floatValue(scalar_ty, std.math.nan_f128), else => unreachable, }, .Max => switch (scalar_ty.zigTypeTag(mod)) { .Bool => try mod.intValue(scalar_ty, 0), - .Int => try scalar_ty.minInt(stack.get(), mod), - .Float => try Value.floatToValue(std.math.nan(f128), stack.get(), scalar_ty, target), + .Int => try scalar_ty.minInt(arena.allocator(), mod), + .Float => try mod.floatValue(scalar_ty, std.math.nan_f128), else => unreachable, }, .Mul => try mod.intValue(Type.comptime_int, 1), diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 583c08583c..cc766c9562 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -9238,22 +9238,19 @@ pub const FuncGen = struct { }) catch unreachable, else => unreachable, }; - var init_value_payload = Value.Payload.Float_32{ - .data = switch (reduce.operation) { - .Min => std.math.nan(f32), - .Max => std.math.nan(f32), - .Add => -0.0, - .Mul => 1.0, - else => unreachable, - }, - }; const param_llvm_ty = try self.dg.lowerType(scalar_ty); const param_types = [2]*llvm.Type{ param_llvm_ty, param_llvm_ty }; const libc_fn = self.getLibcFunction(fn_name, ¶m_types, param_llvm_ty); const init_value = try self.dg.lowerValue(.{ .ty = scalar_ty, - .val = Value.initPayload(&init_value_payload.base), + .val = try mod.floatValue(scalar_ty, switch (reduce.operation) { + .Min => std.math.nan(f32), + .Max => std.math.nan(f32), + .Add => -0.0, + .Mul => 1.0, + else => unreachable, + }), }); return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(mod), init_value); } diff --git a/src/type.zig b/src/type.zig index a2644ebff4..2e4e9ca6fe 100644 --- a/src/type.zig +++ b/src/type.zig @@ -133,6 +133,7 @@ pub const Type = struct { .un => unreachable, .extern_func => unreachable, .int => unreachable, + .float => unreachable, .ptr => unreachable, .opt => unreachable, .enum_tag => unreachable, @@ -1434,6 +1435,7 @@ pub const Type = struct { .simple_value => unreachable, .extern_func => unreachable, .int => unreachable, + .float => unreachable, .ptr => unreachable, .opt => unreachable, .enum_tag => unreachable, @@ -1687,6 +1689,7 @@ pub const Type = struct { .simple_value => unreachable, .extern_func => unreachable, .int => unreachable, + .float => unreachable, .ptr => unreachable, .opt => unreachable, .enum_tag => unreachable, @@ -1803,6 +1806,7 @@ pub const Type = struct { .simple_value => unreachable, .extern_func => unreachable, .int => unreachable, + .float => unreachable, .ptr => unreachable, .opt => unreachable, .enum_tag => unreachable, @@ -2195,6 +2199,7 @@ pub const Type = struct { .simple_value => unreachable, .extern_func => unreachable, .int => unreachable, + .float => unreachable, .ptr => unreachable, .opt => unreachable, .enum_tag => unreachable, @@ -2612,6 +2617,7 @@ pub const Type = struct { .simple_value => unreachable, .extern_func => unreachable, .int => unreachable, + .float => unreachable, .ptr => unreachable, .opt => unreachable, .enum_tag => unreachable, @@ -2866,6 +2872,7 @@ pub const Type = struct { .simple_value => unreachable, .extern_func => unreachable, .int => unreachable, + .float => unreachable, .ptr => unreachable, .opt => unreachable, .enum_tag => unreachable, @@ -3632,6 +3639,7 @@ pub const Type = struct { .simple_value => unreachable, .extern_func => unreachable, .int => unreachable, + .float => unreachable, .ptr => unreachable, .opt => unreachable, .enum_tag => unreachable, @@ -3996,6 +4004,7 @@ pub const Type = struct { .simple_value => unreachable, .extern_func => unreachable, .int => unreachable, + .float => unreachable, .ptr => unreachable, .opt => unreachable, .enum_tag => unreachable, @@ -4157,6 +4166,7 @@ pub const Type = struct { .simple_value => unreachable, .extern_func => unreachable, .int => unreachable, + .float => unreachable, .ptr => unreachable, .opt => unreachable, .enum_tag => unreachable, diff --git a/src/value.zig b/src/value.zig index 3f7e8050a4..bb3716d28e 100644 --- a/src/value.zig +++ b/src/value.zig @@ -72,11 +72,6 @@ pub const Value = struct { empty_array_sentinel, /// Pointer and length as sub `Value` objects. slice, - float_16, - float_32, - float_64, - float_80, - float_128, enum_literal, /// A specific enum tag, indicated by the field index (declaration order). enum_field_index, @@ -160,11 +155,6 @@ pub const Value = struct { .decl_ref_mut => Payload.DeclRefMut, .elem_ptr => Payload.ElemPtr, .field_ptr => Payload.FieldPtr, - .float_16 => Payload.Float_16, - .float_32 => Payload.Float_32, - .float_64 => Payload.Float_64, - .float_80 => Payload.Float_80, - .float_128 => Payload.Float_128, .@"error" => Payload.Error, .inferred_alloc => Payload.InferredAlloc, .inferred_alloc_comptime => Payload.InferredAllocComptime, @@ -395,11 +385,6 @@ pub const Value = struct { .legacy = .{ .ptr_otherwise = &new_payload.base }, }; }, - .float_16 => return self.copyPayloadShallow(arena, Payload.Float_16), - .float_32 => return self.copyPayloadShallow(arena, Payload.Float_32), - .float_64 => return self.copyPayloadShallow(arena, Payload.Float_64), - .float_80 => return self.copyPayloadShallow(arena, Payload.Float_80), - .float_128 => return self.copyPayloadShallow(arena, Payload.Float_128), .enum_literal => { const payload = self.castTag(.enum_literal).?; const new_payload = try arena.create(Payload.Bytes); @@ -544,11 +529,6 @@ pub const Value = struct { }, .empty_array_sentinel => return out_stream.writeAll("(empty array with sentinel)"), .slice => return out_stream.writeAll("(slice)"), - .float_16 => return out_stream.print("{}", .{val.castTag(.float_16).?.data}), - .float_32 => return out_stream.print("{}", .{val.castTag(.float_32).?.data}), - .float_64 => return out_stream.print("{}", .{val.castTag(.float_64).?.data}), - .float_80 => return out_stream.print("{}", .{val.castTag(.float_80).?.data}), - .float_128 => return out_stream.print("{}", .{val.castTag(.float_128).?.data}), .@"error" => return out_stream.print("error.{s}", .{val.castTag(.@"error").?.data.name}), .eu_payload => { try out_stream.writeAll("(eu_payload) "); @@ -1181,14 +1161,17 @@ pub const Value = struct { return mod.intValue_big(ty, bigint.toConst()); } }, - .Float => switch (ty.floatBits(target)) { - 16 => return Value.Tag.float_16.create(arena, @bitCast(f16, std.mem.readInt(u16, buffer[0..2], endian))), - 32 => return Value.Tag.float_32.create(arena, @bitCast(f32, std.mem.readInt(u32, buffer[0..4], endian))), - 64 => return Value.Tag.float_64.create(arena, @bitCast(f64, std.mem.readInt(u64, buffer[0..8], endian))), - 80 => return Value.Tag.float_80.create(arena, @bitCast(f80, std.mem.readInt(u80, buffer[0..10], endian))), - 128 => return Value.Tag.float_128.create(arena, @bitCast(f128, std.mem.readInt(u128, buffer[0..16], endian))), - else => unreachable, - }, + .Float => return (try mod.intern(.{ .float = .{ + .ty = ty.ip_index, + .storage = switch (ty.floatBits(target)) { + 16 => .{ .f16 = @bitCast(f16, std.mem.readInt(u16, buffer[0..2], endian)) }, + 32 => .{ .f32 = @bitCast(f32, std.mem.readInt(u32, buffer[0..4], endian)) }, + 64 => .{ .f64 = @bitCast(f64, std.mem.readInt(u64, buffer[0..8], endian)) }, + 80 => .{ .f80 = @bitCast(f80, std.mem.readInt(u80, buffer[0..10], endian)) }, + 128 => .{ .f128 = @bitCast(f128, std.mem.readInt(u128, buffer[0..16], endian)) }, + else => unreachable, + }, + } })).toValue(), .Array => { const elem_ty = ty.childType(mod); const elem_size = elem_ty.abiSize(mod); @@ -1294,14 +1277,17 @@ pub const Value = struct { return mod.intValue_big(ty, bigint.toConst()); } }, - .Float => switch (ty.floatBits(target)) { - 16 => return Value.Tag.float_16.create(arena, @bitCast(f16, std.mem.readPackedInt(u16, buffer, bit_offset, endian))), - 32 => return Value.Tag.float_32.create(arena, @bitCast(f32, std.mem.readPackedInt(u32, buffer, bit_offset, endian))), - 64 => return Value.Tag.float_64.create(arena, @bitCast(f64, std.mem.readPackedInt(u64, buffer, bit_offset, endian))), - 80 => return Value.Tag.float_80.create(arena, @bitCast(f80, std.mem.readPackedInt(u80, buffer, bit_offset, endian))), - 128 => return Value.Tag.float_128.create(arena, @bitCast(f128, std.mem.readPackedInt(u128, buffer, bit_offset, endian))), - else => unreachable, - }, + .Float => return (try mod.intern(.{ .float = .{ + .ty = ty.ip_index, + .storage = switch (ty.floatBits(target)) { + 16 => .{ .f16 = @bitCast(f16, std.mem.readPackedInt(u16, buffer, bit_offset, endian)) }, + 32 => .{ .f32 = @bitCast(f32, std.mem.readPackedInt(u32, buffer, bit_offset, endian)) }, + 64 => .{ .f64 = @bitCast(f64, std.mem.readPackedInt(u64, buffer, bit_offset, endian)) }, + 80 => .{ .f80 = @bitCast(f80, std.mem.readPackedInt(u80, buffer, bit_offset, endian)) }, + 128 => .{ .f128 = @bitCast(f128, std.mem.readPackedInt(u128, buffer, bit_offset, endian)) }, + else => unreachable, + }, + } })).toValue(), .Vector => { const elem_ty = ty.childType(mod); const elems = try arena.alloc(Value, @intCast(usize, ty.arrayLen(mod))); @@ -1346,28 +1332,20 @@ pub const Value = struct { /// Asserts that the value is a float or an integer. pub fn toFloat(val: Value, comptime T: type, mod: *const Module) T { - return switch (val.ip_index) { - .none => switch (val.tag()) { - .float_16 => @floatCast(T, val.castTag(.float_16).?.data), - .float_32 => @floatCast(T, val.castTag(.float_32).?.data), - .float_64 => @floatCast(T, val.castTag(.float_64).?.data), - .float_80 => @floatCast(T, val.castTag(.float_80).?.data), - .float_128 => @floatCast(T, val.castTag(.float_128).?.data), - - else => unreachable, - }, - else => switch (mod.intern_pool.indexToKey(val.ip_index)) { - .int => |int| switch (int.storage) { - .big_int => |big_int| @floatCast(T, bigIntToFloat(big_int.limbs, big_int.positive)), - inline .u64, .i64 => |x| { - if (T == f80) { - @panic("TODO we can't lower this properly on non-x86 llvm backend yet"); - } - return @intToFloat(T, x); - }, + return switch (mod.intern_pool.indexToKey(val.ip_index)) { + .int => |int| switch (int.storage) { + .big_int => |big_int| @floatCast(T, bigIntToFloat(big_int.limbs, big_int.positive)), + inline .u64, .i64 => |x| { + if (T == f80) { + @panic("TODO we can't lower this properly on non-x86 llvm backend yet"); + } + return @intToFloat(T, x); }, - else => unreachable, }, + .float => |float| switch (float.storage) { + inline else => |x| @floatCast(T, x), + }, + else => unreachable, }; } @@ -1552,28 +1530,27 @@ pub const Value = struct { /// Converts an integer or a float to a float. May result in a loss of information. /// Caller can find out by equality checking the result against the operand. - pub fn floatCast(self: Value, arena: Allocator, dest_ty: Type, mod: *const Module) !Value { + pub fn floatCast(self: Value, dest_ty: Type, mod: *Module) !Value { const target = mod.getTarget(); - switch (dest_ty.floatBits(target)) { - 16 => return Value.Tag.float_16.create(arena, self.toFloat(f16, mod)), - 32 => return Value.Tag.float_32.create(arena, self.toFloat(f32, mod)), - 64 => return Value.Tag.float_64.create(arena, self.toFloat(f64, mod)), - 80 => return Value.Tag.float_80.create(arena, self.toFloat(f80, mod)), - 128 => return Value.Tag.float_128.create(arena, self.toFloat(f128, mod)), - else => unreachable, - } + return (try mod.intern(.{ .float = .{ + .ty = dest_ty.ip_index, + .storage = switch (dest_ty.floatBits(target)) { + 16 => .{ .f16 = self.toFloat(f16, mod) }, + 32 => .{ .f32 = self.toFloat(f32, mod) }, + 64 => .{ .f64 = self.toFloat(f64, mod) }, + 80 => .{ .f80 = self.toFloat(f80, mod) }, + 128 => .{ .f128 = self.toFloat(f128, mod) }, + else => unreachable, + }, + } })).toValue(); } /// Asserts the value is a float - pub fn floatHasFraction(self: Value) bool { - return switch (self.tag()) { - .float_16 => @rem(self.castTag(.float_16).?.data, 1) != 0, - .float_32 => @rem(self.castTag(.float_32).?.data, 1) != 0, - .float_64 => @rem(self.castTag(.float_64).?.data, 1) != 0, - //.float_80 => @rem(self.castTag(.float_80).?.data, 1) != 0, - .float_80 => @panic("TODO implement __remx in compiler-rt"), - .float_128 => @rem(self.castTag(.float_128).?.data, 1) != 0, - + pub fn floatHasFraction(self: Value, mod: *const Module) bool { + return switch (mod.intern_pool.indexToKey(self.ip_index)) { + .float => |float| switch (float.storage) { + inline else => |x| @rem(x, 1) != 0, + }, else => unreachable, }; } @@ -1634,12 +1611,6 @@ pub const Value = struct { } }, - .float_16 => std.math.order(lhs.castTag(.float_16).?.data, 0), - .float_32 => std.math.order(lhs.castTag(.float_32).?.data, 0), - .float_64 => std.math.order(lhs.castTag(.float_64).?.data, 0), - .float_80 => std.math.order(lhs.castTag(.float_80).?.data, 0), - .float_128 => std.math.order(lhs.castTag(.float_128).?.data, 0), - .elem_ptr => { const elem_ptr = lhs.castTag(.elem_ptr).?.data; switch (try elem_ptr.array_ptr.orderAgainstZeroAdvanced(mod, opt_sema)) { @@ -1662,6 +1633,9 @@ pub const Value = struct { .big_int => |big_int| big_int.orderAgainstScalar(0), inline .u64, .i64 => |x| std.math.order(x, 0), }, + .float => |float| switch (float.storage) { + inline else => |x| std.math.order(x, 0), + }, else => unreachable, }, } @@ -1688,20 +1662,21 @@ pub const Value = struct { .gt => {}, } - const lhs_float = lhs.isFloat(); - const rhs_float = rhs.isFloat(); + const lhs_float = lhs.isFloat(mod); + const rhs_float = rhs.isFloat(mod); if (lhs_float and rhs_float) { const lhs_tag = lhs.tag(); const rhs_tag = rhs.tag(); if (lhs_tag == rhs_tag) { - return switch (lhs.tag()) { - .float_16 => return std.math.order(lhs.castTag(.float_16).?.data, rhs.castTag(.float_16).?.data), - .float_32 => return std.math.order(lhs.castTag(.float_32).?.data, rhs.castTag(.float_32).?.data), - .float_64 => return std.math.order(lhs.castTag(.float_64).?.data, rhs.castTag(.float_64).?.data), - .float_80 => return std.math.order(lhs.castTag(.float_80).?.data, rhs.castTag(.float_80).?.data), - .float_128 => return std.math.order(lhs.castTag(.float_128).?.data, rhs.castTag(.float_128).?.data), - else => unreachable, + const lhs_storage = mod.intern_pool.indexToKey(lhs.ip_index).float.storage; + const rhs_storage = mod.intern_pool.indexToKey(rhs.ip_index).float.storage; + const lhs128: f128 = switch (lhs_storage) { + inline else => |x| x, }; + const rhs128: f128 = switch (rhs_storage) { + inline else => |x| x, + }; + return std.math.order(lhs128, rhs128); } } if (lhs_float or rhs_float) { @@ -1808,12 +1783,12 @@ pub const Value = struct { mod: *Module, opt_sema: ?*Sema, ) Module.CompileError!bool { - if (lhs.isInf()) { + if (lhs.isInf(mod)) { switch (op) { .neq => return true, .eq => return false, - .gt, .gte => return !lhs.isNegativeInf(), - .lt, .lte => return lhs.isNegativeInf(), + .gt, .gte => return !lhs.isNegativeInf(mod), + .lt, .lte => return lhs.isNegativeInf(mod), } } @@ -1841,14 +1816,14 @@ pub const Value = struct { } return true; }, - .float_16 => if (std.math.isNan(lhs.castTag(.float_16).?.data)) return op == .neq, - .float_32 => if (std.math.isNan(lhs.castTag(.float_32).?.data)) return op == .neq, - .float_64 => if (std.math.isNan(lhs.castTag(.float_64).?.data)) return op == .neq, - .float_80 => if (std.math.isNan(lhs.castTag(.float_80).?.data)) return op == .neq, - .float_128 => if (std.math.isNan(lhs.castTag(.float_128).?.data)) return op == .neq, else => {}, }, - else => {}, + else => switch (mod.intern_pool.indexToKey(lhs.ip_index)) { + .float => |float| switch (float.storage) { + inline else => |x| if (std.math.isNan(x)) return op == .neq, + }, + else => {}, + }, } return (try orderAgainstZeroAdvanced(lhs, mod, opt_sema)).compare(op); } @@ -2919,22 +2894,18 @@ pub const Value = struct { } /// Valid for all types. Asserts the value is not undefined. - pub fn isFloat(self: Value) bool { + pub fn isFloat(self: Value, mod: *const Module) bool { return switch (self.ip_index) { .undef => unreachable, .none => switch (self.tag()) { .inferred_alloc => unreachable, .inferred_alloc_comptime => unreachable, - - .float_16, - .float_32, - .float_64, - .float_80, - .float_128, - => true, else => false, }, - else => false, + else => switch (mod.intern_pool.indexToKey(self.ip_index)) { + .float => true, + else => false, + }, }; } @@ -2951,33 +2922,32 @@ pub const Value = struct { const scalar_ty = float_ty.scalarType(mod); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try intToFloatScalar(elem_val, arena, scalar_ty, mod, opt_sema); + scalar.* = try intToFloatScalar(elem_val, scalar_ty, mod, opt_sema); } return Value.Tag.aggregate.create(arena, result_data); } - return intToFloatScalar(val, arena, float_ty, mod, opt_sema); + return intToFloatScalar(val, float_ty, mod, opt_sema); } - pub fn intToFloatScalar(val: Value, arena: Allocator, float_ty: Type, mod: *Module, opt_sema: ?*Sema) !Value { - const target = mod.getTarget(); + pub fn intToFloatScalar(val: Value, float_ty: Type, mod: *Module, opt_sema: ?*Sema) !Value { switch (val.ip_index) { .undef => return val, .none => switch (val.tag()) { - .the_only_possible_value => return Value.float_zero, // for i0, u0 + .the_only_possible_value => return mod.floatValue(float_ty, 0), // for i0, u0 .lazy_align => { const ty = val.castTag(.lazy_align).?.data; if (opt_sema) |sema| { - return intToFloatInner((try ty.abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar, arena, float_ty, target); + return intToFloatInner((try ty.abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod); } else { - return intToFloatInner(ty.abiAlignment(mod), arena, float_ty, target); + return intToFloatInner(ty.abiAlignment(mod), float_ty, mod); } }, .lazy_size => { const ty = val.castTag(.lazy_size).?.data; if (opt_sema) |sema| { - return intToFloatInner((try ty.abiSizeAdvanced(mod, .{ .sema = sema })).scalar, arena, float_ty, target); + return intToFloatInner((try ty.abiSizeAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod); } else { - return intToFloatInner(ty.abiSize(mod), arena, float_ty, target); + return intToFloatInner(ty.abiSize(mod), float_ty, mod); } }, else => unreachable, @@ -2986,35 +2956,29 @@ pub const Value = struct { .int => |int| switch (int.storage) { .big_int => |big_int| { const float = bigIntToFloat(big_int.limbs, big_int.positive); - return floatToValue(float, arena, float_ty, target); + return mod.floatValue(float_ty, float); }, - inline .u64, .i64 => |x| intToFloatInner(x, arena, float_ty, target), + inline .u64, .i64 => |x| intToFloatInner(x, float_ty, mod), }, else => unreachable, }, } } - fn intToFloatInner(x: anytype, arena: Allocator, dest_ty: Type, target: Target) !Value { - switch (dest_ty.floatBits(target)) { - 16 => return Value.Tag.float_16.create(arena, @intToFloat(f16, x)), - 32 => return Value.Tag.float_32.create(arena, @intToFloat(f32, x)), - 64 => return Value.Tag.float_64.create(arena, @intToFloat(f64, x)), - 80 => return Value.Tag.float_80.create(arena, @intToFloat(f80, x)), - 128 => return Value.Tag.float_128.create(arena, @intToFloat(f128, x)), + fn intToFloatInner(x: anytype, dest_ty: Type, mod: *Module) !Value { + const target = mod.getTarget(); + const storage: InternPool.Key.Float.Storage = switch (dest_ty.floatBits(target)) { + 16 => .{ .f16 = @intToFloat(f16, x) }, + 32 => .{ .f32 = @intToFloat(f32, x) }, + 64 => .{ .f64 = @intToFloat(f64, x) }, + 80 => .{ .f80 = @intToFloat(f80, x) }, + 128 => .{ .f128 = @intToFloat(f128, x) }, else => unreachable, - } - } - - pub fn floatToValue(float: f128, arena: Allocator, dest_ty: Type, target: Target) !Value { - switch (dest_ty.floatBits(target)) { - 16 => return Value.Tag.float_16.create(arena, @floatCast(f16, float)), - 32 => return Value.Tag.float_32.create(arena, @floatCast(f32, float)), - 64 => return Value.Tag.float_64.create(arena, @floatCast(f64, float)), - 80 => return Value.Tag.float_80.create(arena, @floatCast(f80, float)), - 128 => return Value.Tag.float_128.create(arena, float), - else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = dest_ty.ip_index, + .storage = storage, + } })).toValue(); } fn calcLimbLenFloat(scalar: anytype) usize { @@ -3286,8 +3250,8 @@ pub const Value = struct { /// Supports both floats and ints; handles undefined. pub fn numberMax(lhs: Value, rhs: Value, mod: *Module) Value { if (lhs.isUndef() or rhs.isUndef()) return undef; - if (lhs.isNan()) return rhs; - if (rhs.isNan()) return lhs; + if (lhs.isNan(mod)) return rhs; + if (rhs.isNan(mod)) return lhs; return switch (order(lhs, rhs, mod)) { .lt => rhs, @@ -3298,8 +3262,8 @@ pub const Value = struct { /// Supports both floats and ints; handles undefined. pub fn numberMin(lhs: Value, rhs: Value, mod: *Module) Value { if (lhs.isUndef() or rhs.isUndef()) return undef; - if (lhs.isNan()) return rhs; - if (rhs.isNan()) return lhs; + if (lhs.isNan(mod)) return rhs; + if (rhs.isNan(mod)) return lhs; return switch (order(lhs, rhs, mod)) { .lt => lhs, @@ -3587,44 +3551,32 @@ pub const Value = struct { } /// Returns true if the value is a floating point type and is NaN. Returns false otherwise. - pub fn isNan(val: Value) bool { - return switch (val.ip_index) { - .none => switch (val.tag()) { - .float_16 => std.math.isNan(val.castTag(.float_16).?.data), - .float_32 => std.math.isNan(val.castTag(.float_32).?.data), - .float_64 => std.math.isNan(val.castTag(.float_64).?.data), - .float_80 => std.math.isNan(val.castTag(.float_80).?.data), - .float_128 => std.math.isNan(val.castTag(.float_128).?.data), - else => false, + pub fn isNan(val: Value, mod: *const Module) bool { + if (val.ip_index == .none) return false; + return switch (mod.intern_pool.indexToKey(val.ip_index)) { + .float => |float| switch (float.storage) { + inline else => |x| std.math.isNan(x), }, else => false, }; } /// Returns true if the value is a floating point type and is infinite. Returns false otherwise. - pub fn isInf(val: Value) bool { - return switch (val.ip_index) { - .none => switch (val.tag()) { - .float_16 => std.math.isInf(val.castTag(.float_16).?.data), - .float_32 => std.math.isInf(val.castTag(.float_32).?.data), - .float_64 => std.math.isInf(val.castTag(.float_64).?.data), - .float_80 => std.math.isInf(val.castTag(.float_80).?.data), - .float_128 => std.math.isInf(val.castTag(.float_128).?.data), - else => false, + pub fn isInf(val: Value, mod: *const Module) bool { + if (val.ip_index == .none) return false; + return switch (mod.intern_pool.indexToKey(val.ip_index)) { + .float => |float| switch (float.storage) { + inline else => |x| std.math.isInf(x), }, else => false, }; } - pub fn isNegativeInf(val: Value) bool { - return switch (val.ip_index) { - .none => switch (val.tag()) { - .float_16 => std.math.isNegativeInf(val.castTag(.float_16).?.data), - .float_32 => std.math.isNegativeInf(val.castTag(.float_32).?.data), - .float_64 => std.math.isNegativeInf(val.castTag(.float_64).?.data), - .float_80 => std.math.isNegativeInf(val.castTag(.float_80).?.data), - .float_128 => std.math.isNegativeInf(val.castTag(.float_128).?.data), - else => false, + pub fn isNegativeInf(val: Value, mod: *const Module) bool { + if (val.ip_index == .none) return false; + return switch (mod.intern_pool.indexToKey(val.ip_index)) { + .float => |float| switch (float.storage) { + inline else => |x| std.math.isNegativeInf(x), }, else => false, }; @@ -3636,43 +3588,27 @@ pub const Value = struct { for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try floatRemScalar(lhs_elem, rhs_elem, float_type.scalarType(mod), arena, mod); + scalar.* = try floatRemScalar(lhs_elem, rhs_elem, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return floatRemScalar(lhs, rhs, float_type, arena, mod); + return floatRemScalar(lhs, rhs, float_type, mod); } - pub fn floatRemScalar(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, mod: *const Module) !Value { + pub fn floatRemScalar(lhs: Value, rhs: Value, float_type: Type, mod: *Module) !Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const lhs_val = lhs.toFloat(f16, mod); - const rhs_val = rhs.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, @rem(lhs_val, rhs_val)); - }, - 32 => { - const lhs_val = lhs.toFloat(f32, mod); - const rhs_val = rhs.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, @rem(lhs_val, rhs_val)); - }, - 64 => { - const lhs_val = lhs.toFloat(f64, mod); - const rhs_val = rhs.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, @rem(lhs_val, rhs_val)); - }, - 80 => { - const lhs_val = lhs.toFloat(f80, mod); - const rhs_val = rhs.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, @rem(lhs_val, rhs_val)); - }, - 128 => { - const lhs_val = lhs.toFloat(f128, mod); - const rhs_val = rhs.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, @rem(lhs_val, rhs_val)); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = @rem(lhs.toFloat(f16, mod), rhs.toFloat(f16, mod)) }, + 32 => .{ .f32 = @rem(lhs.toFloat(f32, mod), rhs.toFloat(f32, mod)) }, + 64 => .{ .f64 = @rem(lhs.toFloat(f64, mod), rhs.toFloat(f64, mod)) }, + 80 => .{ .f80 = @rem(lhs.toFloat(f80, mod), rhs.toFloat(f80, mod)) }, + 128 => .{ .f128 = @rem(lhs.toFloat(f128, mod), rhs.toFloat(f128, mod)) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn floatMod(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { @@ -3681,43 +3617,27 @@ pub const Value = struct { for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try floatModScalar(lhs_elem, rhs_elem, float_type.scalarType(mod), arena, mod); + scalar.* = try floatModScalar(lhs_elem, rhs_elem, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return floatModScalar(lhs, rhs, float_type, arena, mod); + return floatModScalar(lhs, rhs, float_type, mod); } - pub fn floatModScalar(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, mod: *const Module) !Value { + pub fn floatModScalar(lhs: Value, rhs: Value, float_type: Type, mod: *Module) !Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const lhs_val = lhs.toFloat(f16, mod); - const rhs_val = rhs.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, @mod(lhs_val, rhs_val)); - }, - 32 => { - const lhs_val = lhs.toFloat(f32, mod); - const rhs_val = rhs.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, @mod(lhs_val, rhs_val)); - }, - 64 => { - const lhs_val = lhs.toFloat(f64, mod); - const rhs_val = rhs.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, @mod(lhs_val, rhs_val)); - }, - 80 => { - const lhs_val = lhs.toFloat(f80, mod); - const rhs_val = rhs.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, @mod(lhs_val, rhs_val)); - }, - 128 => { - const lhs_val = lhs.toFloat(f128, mod); - const rhs_val = rhs.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, @mod(lhs_val, rhs_val)); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = @mod(lhs.toFloat(f16, mod), rhs.toFloat(f16, mod)) }, + 32 => .{ .f32 = @mod(lhs.toFloat(f32, mod), rhs.toFloat(f32, mod)) }, + 64 => .{ .f64 = @mod(lhs.toFloat(f64, mod), rhs.toFloat(f64, mod)) }, + 80 => .{ .f80 = @mod(lhs.toFloat(f80, mod), rhs.toFloat(f80, mod)) }, + 128 => .{ .f128 = @mod(lhs.toFloat(f128, mod), rhs.toFloat(f128, mod)) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn intMul(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *Module) !Value { @@ -4035,28 +3955,111 @@ pub const Value = struct { const result_data = try arena.alloc(Value, float_type.vectorLen(mod)); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try floatNegScalar(elem_val, float_type.scalarType(mod), arena, mod); + scalar.* = try floatNegScalar(elem_val, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return floatNegScalar(val, float_type, arena, mod); + return floatNegScalar(val, float_type, mod); } pub fn floatNegScalar( val: Value, float_type: Type, - arena: Allocator, - mod: *const Module, + mod: *Module, ) !Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => return Value.Tag.float_16.create(arena, -val.toFloat(f16, mod)), - 32 => return Value.Tag.float_32.create(arena, -val.toFloat(f32, mod)), - 64 => return Value.Tag.float_64.create(arena, -val.toFloat(f64, mod)), - 80 => return Value.Tag.float_80.create(arena, -val.toFloat(f80, mod)), - 128 => return Value.Tag.float_128.create(arena, -val.toFloat(f128, mod)), + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = -val.toFloat(f16, mod) }, + 32 => .{ .f32 = -val.toFloat(f32, mod) }, + 64 => .{ .f64 = -val.toFloat(f64, mod) }, + 80 => .{ .f80 = -val.toFloat(f80, mod) }, + 128 => .{ .f128 = -val.toFloat(f128, mod) }, else => unreachable, + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); + } + + pub fn floatAdd( + lhs: Value, + rhs: Value, + float_type: Type, + arena: Allocator, + mod: *Module, + ) !Value { + if (float_type.zigTypeTag(mod) == .Vector) { + const result_data = try arena.alloc(Value, float_type.vectorLen(mod)); + for (result_data, 0..) |*scalar, i| { + const lhs_elem = try lhs.elemValue(mod, i); + const rhs_elem = try rhs.elemValue(mod, i); + scalar.* = try floatAddScalar(lhs_elem, rhs_elem, float_type.scalarType(mod), mod); + } + return Value.Tag.aggregate.create(arena, result_data); } + return floatAddScalar(lhs, rhs, float_type, mod); + } + + pub fn floatAddScalar( + lhs: Value, + rhs: Value, + float_type: Type, + mod: *Module, + ) !Value { + const target = mod.getTarget(); + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = lhs.toFloat(f16, mod) + rhs.toFloat(f16, mod) }, + 32 => .{ .f32 = lhs.toFloat(f32, mod) + rhs.toFloat(f32, mod) }, + 64 => .{ .f64 = lhs.toFloat(f64, mod) + rhs.toFloat(f64, mod) }, + 80 => .{ .f80 = lhs.toFloat(f80, mod) + rhs.toFloat(f80, mod) }, + 128 => .{ .f128 = lhs.toFloat(f128, mod) + rhs.toFloat(f128, mod) }, + else => unreachable, + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); + } + + pub fn floatSub( + lhs: Value, + rhs: Value, + float_type: Type, + arena: Allocator, + mod: *Module, + ) !Value { + if (float_type.zigTypeTag(mod) == .Vector) { + const result_data = try arena.alloc(Value, float_type.vectorLen(mod)); + for (result_data, 0..) |*scalar, i| { + const lhs_elem = try lhs.elemValue(mod, i); + const rhs_elem = try rhs.elemValue(mod, i); + scalar.* = try floatSubScalar(lhs_elem, rhs_elem, float_type.scalarType(mod), mod); + } + return Value.Tag.aggregate.create(arena, result_data); + } + return floatSubScalar(lhs, rhs, float_type, mod); + } + + pub fn floatSubScalar( + lhs: Value, + rhs: Value, + float_type: Type, + mod: *Module, + ) !Value { + const target = mod.getTarget(); + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = lhs.toFloat(f16, mod) - rhs.toFloat(f16, mod) }, + 32 => .{ .f32 = lhs.toFloat(f32, mod) - rhs.toFloat(f32, mod) }, + 64 => .{ .f64 = lhs.toFloat(f64, mod) - rhs.toFloat(f64, mod) }, + 80 => .{ .f80 = lhs.toFloat(f80, mod) - rhs.toFloat(f80, mod) }, + 128 => .{ .f128 = lhs.toFloat(f128, mod) - rhs.toFloat(f128, mod) }, + else => unreachable, + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn floatDiv( @@ -4071,49 +4074,32 @@ pub const Value = struct { for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try floatDivScalar(lhs_elem, rhs_elem, float_type.scalarType(mod), arena, mod); + scalar.* = try floatDivScalar(lhs_elem, rhs_elem, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return floatDivScalar(lhs, rhs, float_type, arena, mod); + return floatDivScalar(lhs, rhs, float_type, mod); } pub fn floatDivScalar( lhs: Value, rhs: Value, float_type: Type, - arena: Allocator, - mod: *const Module, + mod: *Module, ) !Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const lhs_val = lhs.toFloat(f16, mod); - const rhs_val = rhs.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, lhs_val / rhs_val); - }, - 32 => { - const lhs_val = lhs.toFloat(f32, mod); - const rhs_val = rhs.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, lhs_val / rhs_val); - }, - 64 => { - const lhs_val = lhs.toFloat(f64, mod); - const rhs_val = rhs.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, lhs_val / rhs_val); - }, - 80 => { - const lhs_val = lhs.toFloat(f80, mod); - const rhs_val = rhs.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, lhs_val / rhs_val); - }, - 128 => { - const lhs_val = lhs.toFloat(f128, mod); - const rhs_val = rhs.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, lhs_val / rhs_val); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = lhs.toFloat(f16, mod) / rhs.toFloat(f16, mod) }, + 32 => .{ .f32 = lhs.toFloat(f32, mod) / rhs.toFloat(f32, mod) }, + 64 => .{ .f64 = lhs.toFloat(f64, mod) / rhs.toFloat(f64, mod) }, + 80 => .{ .f80 = lhs.toFloat(f80, mod) / rhs.toFloat(f80, mod) }, + 128 => .{ .f128 = lhs.toFloat(f128, mod) / rhs.toFloat(f128, mod) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn floatDivFloor( @@ -4128,49 +4114,32 @@ pub const Value = struct { for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try floatDivFloorScalar(lhs_elem, rhs_elem, float_type.scalarType(mod), arena, mod); + scalar.* = try floatDivFloorScalar(lhs_elem, rhs_elem, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return floatDivFloorScalar(lhs, rhs, float_type, arena, mod); + return floatDivFloorScalar(lhs, rhs, float_type, mod); } pub fn floatDivFloorScalar( lhs: Value, rhs: Value, float_type: Type, - arena: Allocator, - mod: *const Module, + mod: *Module, ) !Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const lhs_val = lhs.toFloat(f16, mod); - const rhs_val = rhs.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, @divFloor(lhs_val, rhs_val)); - }, - 32 => { - const lhs_val = lhs.toFloat(f32, mod); - const rhs_val = rhs.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, @divFloor(lhs_val, rhs_val)); - }, - 64 => { - const lhs_val = lhs.toFloat(f64, mod); - const rhs_val = rhs.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, @divFloor(lhs_val, rhs_val)); - }, - 80 => { - const lhs_val = lhs.toFloat(f80, mod); - const rhs_val = rhs.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, @divFloor(lhs_val, rhs_val)); - }, - 128 => { - const lhs_val = lhs.toFloat(f128, mod); - const rhs_val = rhs.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, @divFloor(lhs_val, rhs_val)); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = @divFloor(lhs.toFloat(f16, mod), rhs.toFloat(f16, mod)) }, + 32 => .{ .f32 = @divFloor(lhs.toFloat(f32, mod), rhs.toFloat(f32, mod)) }, + 64 => .{ .f64 = @divFloor(lhs.toFloat(f64, mod), rhs.toFloat(f64, mod)) }, + 80 => .{ .f80 = @divFloor(lhs.toFloat(f80, mod), rhs.toFloat(f80, mod)) }, + 128 => .{ .f128 = @divFloor(lhs.toFloat(f128, mod), rhs.toFloat(f128, mod)) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn floatDivTrunc( @@ -4185,49 +4154,32 @@ pub const Value = struct { for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try floatDivTruncScalar(lhs_elem, rhs_elem, float_type.scalarType(mod), arena, mod); + scalar.* = try floatDivTruncScalar(lhs_elem, rhs_elem, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return floatDivTruncScalar(lhs, rhs, float_type, arena, mod); + return floatDivTruncScalar(lhs, rhs, float_type, mod); } pub fn floatDivTruncScalar( lhs: Value, rhs: Value, float_type: Type, - arena: Allocator, - mod: *const Module, + mod: *Module, ) !Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const lhs_val = lhs.toFloat(f16, mod); - const rhs_val = rhs.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, @divTrunc(lhs_val, rhs_val)); - }, - 32 => { - const lhs_val = lhs.toFloat(f32, mod); - const rhs_val = rhs.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, @divTrunc(lhs_val, rhs_val)); - }, - 64 => { - const lhs_val = lhs.toFloat(f64, mod); - const rhs_val = rhs.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, @divTrunc(lhs_val, rhs_val)); - }, - 80 => { - const lhs_val = lhs.toFloat(f80, mod); - const rhs_val = rhs.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, @divTrunc(lhs_val, rhs_val)); - }, - 128 => { - const lhs_val = lhs.toFloat(f128, mod); - const rhs_val = rhs.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, @divTrunc(lhs_val, rhs_val)); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = @divTrunc(lhs.toFloat(f16, mod), rhs.toFloat(f16, mod)) }, + 32 => .{ .f32 = @divTrunc(lhs.toFloat(f32, mod), rhs.toFloat(f32, mod)) }, + 64 => .{ .f64 = @divTrunc(lhs.toFloat(f64, mod), rhs.toFloat(f64, mod)) }, + 80 => .{ .f80 = @divTrunc(lhs.toFloat(f80, mod), rhs.toFloat(f80, mod)) }, + 128 => .{ .f128 = @divTrunc(lhs.toFloat(f128, mod), rhs.toFloat(f128, mod)) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn floatMul( @@ -4242,49 +4194,32 @@ pub const Value = struct { for (result_data, 0..) |*scalar, i| { const lhs_elem = try lhs.elemValue(mod, i); const rhs_elem = try rhs.elemValue(mod, i); - scalar.* = try floatMulScalar(lhs_elem, rhs_elem, float_type.scalarType(mod), arena, mod); + scalar.* = try floatMulScalar(lhs_elem, rhs_elem, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return floatMulScalar(lhs, rhs, float_type, arena, mod); + return floatMulScalar(lhs, rhs, float_type, mod); } pub fn floatMulScalar( lhs: Value, rhs: Value, float_type: Type, - arena: Allocator, - mod: *const Module, + mod: *Module, ) !Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const lhs_val = lhs.toFloat(f16, mod); - const rhs_val = rhs.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, lhs_val * rhs_val); - }, - 32 => { - const lhs_val = lhs.toFloat(f32, mod); - const rhs_val = rhs.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, lhs_val * rhs_val); - }, - 64 => { - const lhs_val = lhs.toFloat(f64, mod); - const rhs_val = rhs.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, lhs_val * rhs_val); - }, - 80 => { - const lhs_val = lhs.toFloat(f80, mod); - const rhs_val = rhs.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, lhs_val * rhs_val); - }, - 128 => { - const lhs_val = lhs.toFloat(f128, mod); - const rhs_val = rhs.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, lhs_val * rhs_val); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = lhs.toFloat(f16, mod) * rhs.toFloat(f16, mod) }, + 32 => .{ .f32 = lhs.toFloat(f32, mod) * rhs.toFloat(f32, mod) }, + 64 => .{ .f64 = lhs.toFloat(f64, mod) * rhs.toFloat(f64, mod) }, + 80 => .{ .f80 = lhs.toFloat(f80, mod) * rhs.toFloat(f80, mod) }, + 128 => .{ .f128 = lhs.toFloat(f128, mod) * rhs.toFloat(f128, mod) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn sqrt(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { @@ -4292,38 +4227,27 @@ pub const Value = struct { const result_data = try arena.alloc(Value, float_type.vectorLen(mod)); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try sqrtScalar(elem_val, float_type.scalarType(mod), arena, mod); + scalar.* = try sqrtScalar(elem_val, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return sqrtScalar(val, float_type, arena, mod); + return sqrtScalar(val, float_type, mod); } - pub fn sqrtScalar(val: Value, float_type: Type, arena: Allocator, mod: *const Module) Allocator.Error!Value { + pub fn sqrtScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const f = val.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, @sqrt(f)); - }, - 32 => { - const f = val.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, @sqrt(f)); - }, - 64 => { - const f = val.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, @sqrt(f)); - }, - 80 => { - const f = val.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, @sqrt(f)); - }, - 128 => { - const f = val.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, @sqrt(f)); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = @sqrt(val.toFloat(f16, mod)) }, + 32 => .{ .f32 = @sqrt(val.toFloat(f32, mod)) }, + 64 => .{ .f64 = @sqrt(val.toFloat(f64, mod)) }, + 80 => .{ .f80 = @sqrt(val.toFloat(f80, mod)) }, + 128 => .{ .f128 = @sqrt(val.toFloat(f128, mod)) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn sin(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { @@ -4331,38 +4255,27 @@ pub const Value = struct { const result_data = try arena.alloc(Value, float_type.vectorLen(mod)); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try sinScalar(elem_val, float_type.scalarType(mod), arena, mod); + scalar.* = try sinScalar(elem_val, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return sinScalar(val, float_type, arena, mod); + return sinScalar(val, float_type, mod); } - pub fn sinScalar(val: Value, float_type: Type, arena: Allocator, mod: *const Module) Allocator.Error!Value { + pub fn sinScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const f = val.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, @sin(f)); - }, - 32 => { - const f = val.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, @sin(f)); - }, - 64 => { - const f = val.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, @sin(f)); - }, - 80 => { - const f = val.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, @sin(f)); - }, - 128 => { - const f = val.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, @sin(f)); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = @sin(val.toFloat(f16, mod)) }, + 32 => .{ .f32 = @sin(val.toFloat(f32, mod)) }, + 64 => .{ .f64 = @sin(val.toFloat(f64, mod)) }, + 80 => .{ .f80 = @sin(val.toFloat(f80, mod)) }, + 128 => .{ .f128 = @sin(val.toFloat(f128, mod)) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn cos(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { @@ -4370,38 +4283,27 @@ pub const Value = struct { const result_data = try arena.alloc(Value, float_type.vectorLen(mod)); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try cosScalar(elem_val, float_type.scalarType(mod), arena, mod); + scalar.* = try cosScalar(elem_val, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return cosScalar(val, float_type, arena, mod); + return cosScalar(val, float_type, mod); } - pub fn cosScalar(val: Value, float_type: Type, arena: Allocator, mod: *const Module) Allocator.Error!Value { + pub fn cosScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const f = val.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, @cos(f)); - }, - 32 => { - const f = val.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, @cos(f)); - }, - 64 => { - const f = val.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, @cos(f)); - }, - 80 => { - const f = val.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, @cos(f)); - }, - 128 => { - const f = val.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, @cos(f)); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = @cos(val.toFloat(f16, mod)) }, + 32 => .{ .f32 = @cos(val.toFloat(f32, mod)) }, + 64 => .{ .f64 = @cos(val.toFloat(f64, mod)) }, + 80 => .{ .f80 = @cos(val.toFloat(f80, mod)) }, + 128 => .{ .f128 = @cos(val.toFloat(f128, mod)) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn tan(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { @@ -4409,38 +4311,27 @@ pub const Value = struct { const result_data = try arena.alloc(Value, float_type.vectorLen(mod)); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try tanScalar(elem_val, float_type.scalarType(mod), arena, mod); + scalar.* = try tanScalar(elem_val, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return tanScalar(val, float_type, arena, mod); + return tanScalar(val, float_type, mod); } - pub fn tanScalar(val: Value, float_type: Type, arena: Allocator, mod: *const Module) Allocator.Error!Value { + pub fn tanScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const f = val.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, @tan(f)); - }, - 32 => { - const f = val.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, @tan(f)); - }, - 64 => { - const f = val.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, @tan(f)); - }, - 80 => { - const f = val.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, @tan(f)); - }, - 128 => { - const f = val.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, @tan(f)); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = @tan(val.toFloat(f16, mod)) }, + 32 => .{ .f32 = @tan(val.toFloat(f32, mod)) }, + 64 => .{ .f64 = @tan(val.toFloat(f64, mod)) }, + 80 => .{ .f80 = @tan(val.toFloat(f80, mod)) }, + 128 => .{ .f128 = @tan(val.toFloat(f128, mod)) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn exp(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { @@ -4448,38 +4339,27 @@ pub const Value = struct { const result_data = try arena.alloc(Value, float_type.vectorLen(mod)); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try expScalar(elem_val, float_type.scalarType(mod), arena, mod); + scalar.* = try expScalar(elem_val, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return expScalar(val, float_type, arena, mod); + return expScalar(val, float_type, mod); } - pub fn expScalar(val: Value, float_type: Type, arena: Allocator, mod: *const Module) Allocator.Error!Value { + pub fn expScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const f = val.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, @exp(f)); - }, - 32 => { - const f = val.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, @exp(f)); - }, - 64 => { - const f = val.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, @exp(f)); - }, - 80 => { - const f = val.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, @exp(f)); - }, - 128 => { - const f = val.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, @exp(f)); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = @exp(val.toFloat(f16, mod)) }, + 32 => .{ .f32 = @exp(val.toFloat(f32, mod)) }, + 64 => .{ .f64 = @exp(val.toFloat(f64, mod)) }, + 80 => .{ .f80 = @exp(val.toFloat(f80, mod)) }, + 128 => .{ .f128 = @exp(val.toFloat(f128, mod)) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn exp2(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { @@ -4487,38 +4367,27 @@ pub const Value = struct { const result_data = try arena.alloc(Value, float_type.vectorLen(mod)); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try exp2Scalar(elem_val, float_type.scalarType(mod), arena, mod); + scalar.* = try exp2Scalar(elem_val, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return exp2Scalar(val, float_type, arena, mod); + return exp2Scalar(val, float_type, mod); } - pub fn exp2Scalar(val: Value, float_type: Type, arena: Allocator, mod: *const Module) Allocator.Error!Value { + pub fn exp2Scalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const f = val.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, @exp2(f)); - }, - 32 => { - const f = val.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, @exp2(f)); - }, - 64 => { - const f = val.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, @exp2(f)); - }, - 80 => { - const f = val.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, @exp2(f)); - }, - 128 => { - const f = val.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, @exp2(f)); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = @exp2(val.toFloat(f16, mod)) }, + 32 => .{ .f32 = @exp2(val.toFloat(f32, mod)) }, + 64 => .{ .f64 = @exp2(val.toFloat(f64, mod)) }, + 80 => .{ .f80 = @exp2(val.toFloat(f80, mod)) }, + 128 => .{ .f128 = @exp2(val.toFloat(f128, mod)) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn log(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { @@ -4526,38 +4395,27 @@ pub const Value = struct { const result_data = try arena.alloc(Value, float_type.vectorLen(mod)); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try logScalar(elem_val, float_type.scalarType(mod), arena, mod); + scalar.* = try logScalar(elem_val, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return logScalar(val, float_type, arena, mod); + return logScalar(val, float_type, mod); } - pub fn logScalar(val: Value, float_type: Type, arena: Allocator, mod: *const Module) Allocator.Error!Value { + pub fn logScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const f = val.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, @log(f)); - }, - 32 => { - const f = val.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, @log(f)); - }, - 64 => { - const f = val.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, @log(f)); - }, - 80 => { - const f = val.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, @log(f)); - }, - 128 => { - const f = val.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, @log(f)); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = @log(val.toFloat(f16, mod)) }, + 32 => .{ .f32 = @log(val.toFloat(f32, mod)) }, + 64 => .{ .f64 = @log(val.toFloat(f64, mod)) }, + 80 => .{ .f80 = @log(val.toFloat(f80, mod)) }, + 128 => .{ .f128 = @log(val.toFloat(f128, mod)) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn log2(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { @@ -4565,38 +4423,27 @@ pub const Value = struct { const result_data = try arena.alloc(Value, float_type.vectorLen(mod)); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try log2Scalar(elem_val, float_type.scalarType(mod), arena, mod); + scalar.* = try log2Scalar(elem_val, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return log2Scalar(val, float_type, arena, mod); + return log2Scalar(val, float_type, mod); } - pub fn log2Scalar(val: Value, float_type: Type, arena: Allocator, mod: *const Module) Allocator.Error!Value { + pub fn log2Scalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const f = val.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, @log2(f)); - }, - 32 => { - const f = val.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, @log2(f)); - }, - 64 => { - const f = val.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, @log2(f)); - }, - 80 => { - const f = val.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, @log2(f)); - }, - 128 => { - const f = val.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, @log2(f)); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = @log2(val.toFloat(f16, mod)) }, + 32 => .{ .f32 = @log2(val.toFloat(f32, mod)) }, + 64 => .{ .f64 = @log2(val.toFloat(f64, mod)) }, + 80 => .{ .f80 = @log2(val.toFloat(f80, mod)) }, + 128 => .{ .f128 = @log2(val.toFloat(f128, mod)) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn log10(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { @@ -4604,38 +4451,27 @@ pub const Value = struct { const result_data = try arena.alloc(Value, float_type.vectorLen(mod)); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try log10Scalar(elem_val, float_type.scalarType(mod), arena, mod); + scalar.* = try log10Scalar(elem_val, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return log10Scalar(val, float_type, arena, mod); + return log10Scalar(val, float_type, mod); } - pub fn log10Scalar(val: Value, float_type: Type, arena: Allocator, mod: *const Module) Allocator.Error!Value { + pub fn log10Scalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const f = val.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, @log10(f)); - }, - 32 => { - const f = val.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, @log10(f)); - }, - 64 => { - const f = val.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, @log10(f)); - }, - 80 => { - const f = val.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, @log10(f)); - }, - 128 => { - const f = val.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, @log10(f)); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = @log10(val.toFloat(f16, mod)) }, + 32 => .{ .f32 = @log10(val.toFloat(f32, mod)) }, + 64 => .{ .f64 = @log10(val.toFloat(f64, mod)) }, + 80 => .{ .f80 = @log10(val.toFloat(f80, mod)) }, + 128 => .{ .f128 = @log10(val.toFloat(f128, mod)) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn fabs(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { @@ -4643,38 +4479,27 @@ pub const Value = struct { const result_data = try arena.alloc(Value, float_type.vectorLen(mod)); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try fabsScalar(elem_val, float_type.scalarType(mod), arena, mod); + scalar.* = try fabsScalar(elem_val, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return fabsScalar(val, float_type, arena, mod); + return fabsScalar(val, float_type, mod); } - pub fn fabsScalar(val: Value, float_type: Type, arena: Allocator, mod: *const Module) Allocator.Error!Value { + pub fn fabsScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const f = val.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, @fabs(f)); - }, - 32 => { - const f = val.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, @fabs(f)); - }, - 64 => { - const f = val.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, @fabs(f)); - }, - 80 => { - const f = val.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, @fabs(f)); - }, - 128 => { - const f = val.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, @fabs(f)); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = @fabs(val.toFloat(f16, mod)) }, + 32 => .{ .f32 = @fabs(val.toFloat(f32, mod)) }, + 64 => .{ .f64 = @fabs(val.toFloat(f64, mod)) }, + 80 => .{ .f80 = @fabs(val.toFloat(f80, mod)) }, + 128 => .{ .f128 = @fabs(val.toFloat(f128, mod)) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn floor(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { @@ -4682,38 +4507,27 @@ pub const Value = struct { const result_data = try arena.alloc(Value, float_type.vectorLen(mod)); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try floorScalar(elem_val, float_type.scalarType(mod), arena, mod); + scalar.* = try floorScalar(elem_val, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return floorScalar(val, float_type, arena, mod); + return floorScalar(val, float_type, mod); } - pub fn floorScalar(val: Value, float_type: Type, arena: Allocator, mod: *const Module) Allocator.Error!Value { + pub fn floorScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const f = val.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, @floor(f)); - }, - 32 => { - const f = val.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, @floor(f)); - }, - 64 => { - const f = val.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, @floor(f)); - }, - 80 => { - const f = val.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, @floor(f)); - }, - 128 => { - const f = val.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, @floor(f)); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = @floor(val.toFloat(f16, mod)) }, + 32 => .{ .f32 = @floor(val.toFloat(f32, mod)) }, + 64 => .{ .f64 = @floor(val.toFloat(f64, mod)) }, + 80 => .{ .f80 = @floor(val.toFloat(f80, mod)) }, + 128 => .{ .f128 = @floor(val.toFloat(f128, mod)) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn ceil(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { @@ -4721,38 +4535,27 @@ pub const Value = struct { const result_data = try arena.alloc(Value, float_type.vectorLen(mod)); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try ceilScalar(elem_val, float_type.scalarType(mod), arena, mod); + scalar.* = try ceilScalar(elem_val, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return ceilScalar(val, float_type, arena, mod); + return ceilScalar(val, float_type, mod); } - pub fn ceilScalar(val: Value, float_type: Type, arena: Allocator, mod: *const Module) Allocator.Error!Value { + pub fn ceilScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const f = val.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, @ceil(f)); - }, - 32 => { - const f = val.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, @ceil(f)); - }, - 64 => { - const f = val.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, @ceil(f)); - }, - 80 => { - const f = val.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, @ceil(f)); - }, - 128 => { - const f = val.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, @ceil(f)); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = @ceil(val.toFloat(f16, mod)) }, + 32 => .{ .f32 = @ceil(val.toFloat(f32, mod)) }, + 64 => .{ .f64 = @ceil(val.toFloat(f64, mod)) }, + 80 => .{ .f80 = @ceil(val.toFloat(f80, mod)) }, + 128 => .{ .f128 = @ceil(val.toFloat(f128, mod)) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn round(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { @@ -4760,38 +4563,27 @@ pub const Value = struct { const result_data = try arena.alloc(Value, float_type.vectorLen(mod)); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try roundScalar(elem_val, float_type.scalarType(mod), arena, mod); + scalar.* = try roundScalar(elem_val, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return roundScalar(val, float_type, arena, mod); + return roundScalar(val, float_type, mod); } - pub fn roundScalar(val: Value, float_type: Type, arena: Allocator, mod: *const Module) Allocator.Error!Value { + pub fn roundScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const f = val.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, @round(f)); - }, - 32 => { - const f = val.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, @round(f)); - }, - 64 => { - const f = val.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, @round(f)); - }, - 80 => { - const f = val.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, @round(f)); - }, - 128 => { - const f = val.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, @round(f)); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = @round(val.toFloat(f16, mod)) }, + 32 => .{ .f32 = @round(val.toFloat(f32, mod)) }, + 64 => .{ .f64 = @round(val.toFloat(f64, mod)) }, + 80 => .{ .f80 = @round(val.toFloat(f80, mod)) }, + 128 => .{ .f128 = @round(val.toFloat(f128, mod)) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn trunc(val: Value, float_type: Type, arena: Allocator, mod: *Module) !Value { @@ -4799,38 +4591,27 @@ pub const Value = struct { const result_data = try arena.alloc(Value, float_type.vectorLen(mod)); for (result_data, 0..) |*scalar, i| { const elem_val = try val.elemValue(mod, i); - scalar.* = try truncScalar(elem_val, float_type.scalarType(mod), arena, mod); + scalar.* = try truncScalar(elem_val, float_type.scalarType(mod), mod); } return Value.Tag.aggregate.create(arena, result_data); } - return truncScalar(val, float_type, arena, mod); + return truncScalar(val, float_type, mod); } - pub fn truncScalar(val: Value, float_type: Type, arena: Allocator, mod: *const Module) Allocator.Error!Value { + pub fn truncScalar(val: Value, float_type: Type, mod: *Module) Allocator.Error!Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const f = val.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, @trunc(f)); - }, - 32 => { - const f = val.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, @trunc(f)); - }, - 64 => { - const f = val.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, @trunc(f)); - }, - 80 => { - const f = val.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, @trunc(f)); - }, - 128 => { - const f = val.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, @trunc(f)); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = @trunc(val.toFloat(f16, mod)) }, + 32 => .{ .f32 = @trunc(val.toFloat(f32, mod)) }, + 64 => .{ .f64 = @trunc(val.toFloat(f64, mod)) }, + 80 => .{ .f80 = @trunc(val.toFloat(f80, mod)) }, + 128 => .{ .f128 = @trunc(val.toFloat(f128, mod)) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } pub fn mulAdd( @@ -4852,13 +4633,12 @@ pub const Value = struct { mulend1_elem, mulend2_elem, addend_elem, - arena, mod, ); } return Value.Tag.aggregate.create(arena, result_data); } - return mulAddScalar(float_type, mulend1, mulend2, addend, arena, mod); + return mulAddScalar(float_type, mulend1, mulend2, addend, mod); } pub fn mulAddScalar( @@ -4866,43 +4646,21 @@ pub const Value = struct { mulend1: Value, mulend2: Value, addend: Value, - arena: Allocator, - mod: *const Module, + mod: *Module, ) Allocator.Error!Value { const target = mod.getTarget(); - switch (float_type.floatBits(target)) { - 16 => { - const m1 = mulend1.toFloat(f16, mod); - const m2 = mulend2.toFloat(f16, mod); - const a = addend.toFloat(f16, mod); - return Value.Tag.float_16.create(arena, @mulAdd(f16, m1, m2, a)); - }, - 32 => { - const m1 = mulend1.toFloat(f32, mod); - const m2 = mulend2.toFloat(f32, mod); - const a = addend.toFloat(f32, mod); - return Value.Tag.float_32.create(arena, @mulAdd(f32, m1, m2, a)); - }, - 64 => { - const m1 = mulend1.toFloat(f64, mod); - const m2 = mulend2.toFloat(f64, mod); - const a = addend.toFloat(f64, mod); - return Value.Tag.float_64.create(arena, @mulAdd(f64, m1, m2, a)); - }, - 80 => { - const m1 = mulend1.toFloat(f80, mod); - const m2 = mulend2.toFloat(f80, mod); - const a = addend.toFloat(f80, mod); - return Value.Tag.float_80.create(arena, @mulAdd(f80, m1, m2, a)); - }, - 128 => { - const m1 = mulend1.toFloat(f128, mod); - const m2 = mulend2.toFloat(f128, mod); - const a = addend.toFloat(f128, mod); - return Value.Tag.float_128.create(arena, @mulAdd(f128, m1, m2, a)); - }, + const storage: InternPool.Key.Float.Storage = switch (float_type.floatBits(target)) { + 16 => .{ .f16 = @mulAdd(f16, mulend1.toFloat(f16, mod), mulend2.toFloat(f16, mod), addend.toFloat(f16, mod)) }, + 32 => .{ .f32 = @mulAdd(f32, mulend1.toFloat(f32, mod), mulend2.toFloat(f32, mod), addend.toFloat(f32, mod)) }, + 64 => .{ .f64 = @mulAdd(f64, mulend1.toFloat(f64, mod), mulend2.toFloat(f64, mod), addend.toFloat(f64, mod)) }, + 80 => .{ .f80 = @mulAdd(f80, mulend1.toFloat(f80, mod), mulend2.toFloat(f80, mod), addend.toFloat(f80, mod)) }, + 128 => .{ .f128 = @mulAdd(f128, mulend1.toFloat(f128, mod), mulend2.toFloat(f128, mod), addend.toFloat(f128, mod)) }, else => unreachable, - } + }; + return (try mod.intern(.{ .float = .{ + .ty = float_type.ip_index, + .storage = storage, + } })).toValue(); } /// If the value is represented in-memory as a series of bytes that all @@ -5053,41 +4811,6 @@ pub const Value = struct { data: Type, }; - pub const Float_16 = struct { - pub const base_tag = Tag.float_16; - - base: Payload = .{ .tag = base_tag }, - data: f16, - }; - - pub const Float_32 = struct { - pub const base_tag = Tag.float_32; - - base: Payload = .{ .tag = base_tag }, - data: f32, - }; - - pub const Float_64 = struct { - pub const base_tag = Tag.float_64; - - base: Payload = .{ .tag = base_tag }, - data: f64, - }; - - pub const Float_80 = struct { - pub const base_tag = Tag.float_80; - - base: Payload = .{ .tag = base_tag }, - data: f80, - }; - - pub const Float_128 = struct { - pub const base_tag = Tag.float_128; - - base: Payload = .{ .tag = base_tag }, - data: f128, - }; - pub const Error = struct { base: Payload = .{ .tag = .@"error" }, data: struct { @@ -5152,7 +4875,6 @@ pub const Value = struct { pub const one_comptime_int: Value = .{ .ip_index = .one, .legacy = undefined }; pub const negative_one_comptime_int: Value = .{ .ip_index = .negative_one, .legacy = undefined }; pub const undef: Value = .{ .ip_index = .undef, .legacy = undefined }; - pub const float_zero: Value = .{ .ip_index = .zero, .legacy = undefined }; // TODO: replace this! pub const @"void": Value = .{ .ip_index = .void_value, .legacy = undefined }; pub const @"null": Value = .{ .ip_index = .null_value, .legacy = undefined }; pub const @"false": Value = .{ .ip_index = .bool_false, .legacy = undefined };