Commit 287ff4ab58

Andrew Kelley <andrew@ziglang.org>
2022-01-31 01:23:14
stage2: add more float arithmetic and f80 support
AstGen: Fixed bug where f80 types in source were triggering illegal behavior. Value: handle f80 in floating point arithmetic functions. Value: implement floatRem and floatMod This commit introduces dependencies on compiler-rt that are not implemented. Those are a prerequisite to merging this branch.
1 parent fd1284e
Changed files (4)
src/AstGen.zig
@@ -8409,10 +8409,11 @@ fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.In
                     .c_ushort_type,
                     .comptime_float_type,
                     .comptime_int_type,
-                    .f128_type,
                     .f16_type,
                     .f32_type,
                     .f64_type,
+                    .f80_type,
+                    .f128_type,
                     .i16_type,
                     .i32_type,
                     .i64_type,
@@ -8648,10 +8649,11 @@ fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool {
                     .c_ulong_type,
                     .c_ulonglong_type,
                     .c_ushort_type,
-                    .f128_type,
                     .f16_type,
                     .f32_type,
                     .f64_type,
+                    .f80_type,
+                    .f128_type,
                     .i16_type,
                     .i32_type,
                     .i64_type,
src/Sema.zig
@@ -8187,7 +8187,7 @@ fn analyzeArithmetic(
                         } else {
                             return sema.addConstant(
                                 scalar_type,
-                                try lhs_val.floatAdd(rhs_val, scalar_type, sema.arena),
+                                try lhs_val.floatAdd(rhs_val, scalar_type, sema.arena, target),
                             );
                         }
                     } else break :rs .{ .src = rhs_src, .air_tag = .add };
@@ -8280,7 +8280,7 @@ fn analyzeArithmetic(
                         } else {
                             return sema.addConstant(
                                 scalar_type,
-                                try lhs_val.floatSub(rhs_val, scalar_type, sema.arena),
+                                try lhs_val.floatSub(rhs_val, scalar_type, sema.arena, target),
                             );
                         }
                     } else break :rs .{ .src = rhs_src, .air_tag = .sub };
@@ -8396,7 +8396,7 @@ fn analyzeArithmetic(
                         } else {
                             return sema.addConstant(
                                 scalar_type,
-                                try lhs_val.floatDiv(rhs_val, scalar_type, sema.arena),
+                                try lhs_val.floatDiv(rhs_val, scalar_type, sema.arena, target),
                             );
                         }
                     } else {
@@ -8471,7 +8471,7 @@ fn analyzeArithmetic(
                         } else {
                             return sema.addConstant(
                                 scalar_type,
-                                try lhs_val.floatDivTrunc(rhs_val, scalar_type, sema.arena),
+                                try lhs_val.floatDivTrunc(rhs_val, scalar_type, sema.arena, target),
                             );
                         }
                     } else break :rs .{ .src = rhs_src, .air_tag = .div_trunc };
@@ -8534,7 +8534,7 @@ fn analyzeArithmetic(
                         } else {
                             return sema.addConstant(
                                 scalar_type,
-                                try lhs_val.floatDivFloor(rhs_val, scalar_type, sema.arena),
+                                try lhs_val.floatDivFloor(rhs_val, scalar_type, sema.arena, target),
                             );
                         }
                     } else break :rs .{ .src = rhs_src, .air_tag = .div_floor };
@@ -8586,7 +8586,7 @@ fn analyzeArithmetic(
                             // TODO: emit compile error if there is a remainder
                             return sema.addConstant(
                                 scalar_type,
-                                try lhs_val.floatDiv(rhs_val, scalar_type, sema.arena),
+                                try lhs_val.floatDiv(rhs_val, scalar_type, sema.arena, target),
                             );
                         }
                     } else break :rs .{ .src = rhs_src, .air_tag = .div_exact };
@@ -8641,7 +8641,7 @@ fn analyzeArithmetic(
                         } else {
                             return sema.addConstant(
                                 scalar_type,
-                                try lhs_val.floatMul(rhs_val, scalar_type, sema.arena),
+                                try lhs_val.floatMul(rhs_val, scalar_type, sema.arena, target),
                             );
                         }
                     } else break :rs .{ .src = lhs_src, .air_tag = .mul };
@@ -8797,7 +8797,7 @@ fn analyzeArithmetic(
                         }
                         return sema.addConstant(
                             scalar_type,
-                            try lhs_val.floatRem(rhs_val, sema.arena),
+                            try lhs_val.floatRem(rhs_val, scalar_type, sema.arena, target),
                         );
                     } else {
                         return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
@@ -8858,7 +8858,7 @@ fn analyzeArithmetic(
                     if (maybe_rhs_val) |rhs_val| {
                         return sema.addConstant(
                             scalar_type,
-                            try lhs_val.floatRem(rhs_val, sema.arena),
+                            try lhs_val.floatRem(rhs_val, scalar_type, sema.arena, target),
                         );
                     } else break :rs .{ .src = rhs_src, .air_tag = .rem };
                 } else break :rs .{ .src = lhs_src, .air_tag = .rem };
@@ -8915,7 +8915,7 @@ fn analyzeArithmetic(
                     if (maybe_rhs_val) |rhs_val| {
                         return sema.addConstant(
                             scalar_type,
-                            try lhs_val.floatMod(rhs_val, sema.arena),
+                            try lhs_val.floatMod(rhs_val, scalar_type, sema.arena, target),
                         );
                     } else break :rs .{ .src = rhs_src, .air_tag = .mod };
                 } else break :rs .{ .src = lhs_src, .air_tag = .mod };
@@ -14195,12 +14195,12 @@ fn coerce(
         .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag()) {
             .ComptimeFloat => {
                 const val = try sema.resolveConstValue(block, inst_src, inst);
-                const result_val = try val.floatCast(sema.arena, dest_ty);
+                const result_val = try val.floatCast(sema.arena, dest_ty, target);
                 return try sema.addConstant(dest_ty, result_val);
             },
             .Float => {
                 if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {
-                    const result_val = try val.floatCast(sema.arena, dest_ty);
+                    const result_val = try val.floatCast(sema.arena, dest_ty, target);
                     if (!val.eql(result_val, dest_ty)) {
                         return sema.fail(
                             block,
src/value.zig
@@ -138,6 +138,7 @@ pub const Value = extern union {
         float_16,
         float_32,
         float_64,
+        float_80,
         float_128,
         enum_literal,
         /// A specific enum tag, indicated by the field index (declaration order).
@@ -295,6 +296,7 @@ pub const Value = extern union {
                 .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,
@@ -546,6 +548,7 @@ pub const Value = extern union {
             .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).?;
@@ -733,6 +736,7 @@ pub const Value = extern union {
             .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}),
             // TODO to print this it should be error{ Set, Items }!T(val), but we need the type for that
@@ -1083,6 +1087,7 @@ pub const Value = extern union {
                 16 => return Value.Tag.float_16.create(arena, floatReadFromMemory(f16, target, buffer)),
                 32 => return Value.Tag.float_32.create(arena, floatReadFromMemory(f32, target, buffer)),
                 64 => return Value.Tag.float_64.create(arena, floatReadFromMemory(f64, target, buffer)),
+                80 => return Value.Tag.float_80.create(arena, floatReadFromMemory(f80, target, buffer)),
                 128 => return Value.Tag.float_128.create(arena, floatReadFromMemory(f128, target, buffer)),
                 else => unreachable,
             },
@@ -1100,6 +1105,12 @@ pub const Value = extern union {
     }
 
     fn floatReadFromMemory(comptime F: type, target: Target, buffer: []const u8) F {
+        if (F == f80) {
+            // TODO: use std.math.F80Repr
+            const big_int = std.mem.readInt(u128, buffer[0..16], target.cpu.arch.endian());
+            const int = @truncate(u80, big_int);
+            return @bitCast(F, int);
+        }
         const Int = @Type(.{ .Int = .{
             .signedness = .unsigned,
             .bits = @typeInfo(F).Float.bits,
@@ -1114,6 +1125,7 @@ pub const Value = extern union {
             .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),
 
             .zero => 0,
@@ -1367,14 +1379,13 @@ pub const Value = extern union {
 
     /// 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) !Value {
-        switch (dest_ty.tag()) {
-            .f16 => return Value.Tag.float_16.create(arena, self.toFloat(f16)),
-            .f32 => return Value.Tag.float_32.create(arena, self.toFloat(f32)),
-            .f64 => return Value.Tag.float_64.create(arena, self.toFloat(f64)),
-            .f128, .comptime_float, .c_longdouble => {
-                return Value.Tag.float_128.create(arena, self.toFloat(f128));
-            },
+    pub fn floatCast(self: Value, arena: Allocator, dest_ty: Type, target: Target) !Value {
+        switch (dest_ty.floatBits(target)) {
+            16 => return Value.Tag.float_16.create(arena, self.toFloat(f16)),
+            32 => return Value.Tag.float_32.create(arena, self.toFloat(f32)),
+            64 => return Value.Tag.float_64.create(arena, self.toFloat(f64)),
+            80 => return Value.Tag.float_80.create(arena, self.toFloat(f80)),
+            128 => return Value.Tag.float_128.create(arena, self.toFloat(f128)),
             else => unreachable,
         }
     }
@@ -1389,8 +1400,8 @@ pub const Value = extern union {
             .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_128 => @rem(self.castTag(.float_128).?.data, 1) != 0,
-            .float_128 => @panic("TODO lld: error: undefined symbol: fmodl"),
+            .float_80 => @rem(self.castTag(.float_80).?.data, 1) != 0,
+            .float_128 => @rem(self.castTag(.float_128).?.data, 1) != 0,
 
             else => unreachable,
         };
@@ -1408,6 +1419,7 @@ pub const Value = extern union {
             .float_16 => self.castTag(.float_16).?.data == 0,
             .float_32 => self.castTag(.float_32).?.data == 0,
             .float_64 => self.castTag(.float_64).?.data == 0,
+            .float_80 => self.castTag(.float_80).?.data == 0,
             .float_128 => self.castTag(.float_128).?.data == 0,
 
             .int_big_positive => self.castTag(.int_big_positive).?.asBigInt().eqZero(),
@@ -1440,6 +1452,7 @@ pub const Value = extern union {
             .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),
 
             else => unreachable,
@@ -1471,6 +1484,7 @@ pub const Value = extern union {
                     .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,
                 };
@@ -2139,6 +2153,7 @@ pub const Value = extern union {
             .float_16,
             .float_32,
             .float_64,
+            .float_80,
             .float_128,
             => true,
             else => false,
@@ -2174,6 +2189,7 @@ pub const Value = extern union {
             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)),
             else => unreachable,
         }
@@ -2184,6 +2200,7 @@ pub const Value = extern union {
             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,
         }
@@ -2281,7 +2298,7 @@ pub const Value = extern union {
         }
 
         if (ty.isAnyFloat()) {
-            return floatAdd(lhs, rhs, ty, arena);
+            return floatAdd(lhs, rhs, ty, arena, target);
         }
 
         const overflow_result = try intAddWithOverflow(lhs, rhs, ty, arena, target);
@@ -2371,7 +2388,7 @@ pub const Value = extern union {
         }
 
         if (ty.isAnyFloat()) {
-            return floatSub(lhs, rhs, ty, arena);
+            return floatSub(lhs, rhs, ty, arena, target);
         }
 
         const overflow_result = try intSubWithOverflow(lhs, rhs, ty, arena, target);
@@ -2454,7 +2471,7 @@ pub const Value = extern union {
         }
 
         if (ty.isAnyFloat()) {
-            return floatMul(lhs, rhs, ty, arena);
+            return floatMul(lhs, rhs, ty, arena, target);
         }
 
         const overflow_result = try intMulWithOverflow(lhs, rhs, ty, arena, target);
@@ -2753,23 +2770,72 @@ pub const Value = extern union {
             .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 floatRem(lhs: Value, rhs: Value, allocator: Allocator) !Value {
-        _ = lhs;
-        _ = rhs;
-        _ = allocator;
-        @panic("TODO implement Value.floatRem");
+    pub fn floatRem(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, target: Target) !Value {
+        switch (float_type.floatBits(target)) {
+            16 => {
+                const lhs_val = lhs.toFloat(f16);
+                const rhs_val = rhs.toFloat(f16);
+                return Value.Tag.float_16.create(arena, @rem(lhs_val, rhs_val));
+            },
+            32 => {
+                const lhs_val = lhs.toFloat(f32);
+                const rhs_val = rhs.toFloat(f32);
+                return Value.Tag.float_32.create(arena, @rem(lhs_val, rhs_val));
+            },
+            64 => {
+                const lhs_val = lhs.toFloat(f64);
+                const rhs_val = rhs.toFloat(f64);
+                return Value.Tag.float_64.create(arena, @rem(lhs_val, rhs_val));
+            },
+            80 => {
+                const lhs_val = lhs.toFloat(f80);
+                const rhs_val = rhs.toFloat(f80);
+                return Value.Tag.float_80.create(arena, @rem(lhs_val, rhs_val));
+            },
+            128 => {
+                const lhs_val = lhs.toFloat(f128);
+                const rhs_val = rhs.toFloat(f128);
+                return Value.Tag.float_128.create(arena, @rem(lhs_val, rhs_val));
+            },
+            else => unreachable,
+        }
     }
 
-    pub fn floatMod(lhs: Value, rhs: Value, allocator: Allocator) !Value {
-        _ = lhs;
-        _ = rhs;
-        _ = allocator;
-        @panic("TODO implement Value.floatMod");
+    pub fn floatMod(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, target: Target) !Value {
+        switch (float_type.floatBits(target)) {
+            16 => {
+                const lhs_val = lhs.toFloat(f16);
+                const rhs_val = rhs.toFloat(f16);
+                return Value.Tag.float_16.create(arena, @mod(lhs_val, rhs_val));
+            },
+            32 => {
+                const lhs_val = lhs.toFloat(f32);
+                const rhs_val = rhs.toFloat(f32);
+                return Value.Tag.float_32.create(arena, @mod(lhs_val, rhs_val));
+            },
+            64 => {
+                const lhs_val = lhs.toFloat(f64);
+                const rhs_val = rhs.toFloat(f64);
+                return Value.Tag.float_64.create(arena, @mod(lhs_val, rhs_val));
+            },
+            80 => {
+                const lhs_val = lhs.toFloat(f80);
+                const rhs_val = rhs.toFloat(f80);
+                return Value.Tag.float_80.create(arena, @mod(lhs_val, rhs_val));
+            },
+            128 => {
+                const lhs_val = lhs.toFloat(f128);
+                const rhs_val = rhs.toFloat(f128);
+                return Value.Tag.float_128.create(arena, @mod(lhs_val, rhs_val));
+            },
+            else => unreachable,
+        }
     }
 
     pub fn intMul(lhs: Value, rhs: Value, allocator: Allocator) !Value {
@@ -2929,24 +2995,30 @@ pub const Value = extern union {
         rhs: Value,
         float_type: Type,
         arena: Allocator,
+        target: Target,
     ) !Value {
-        switch (float_type.tag()) {
-            .f16 => {
+        switch (float_type.floatBits(target)) {
+            16 => {
                 const lhs_val = lhs.toFloat(f16);
                 const rhs_val = rhs.toFloat(f16);
                 return Value.Tag.float_16.create(arena, lhs_val + rhs_val);
             },
-            .f32 => {
+            32 => {
                 const lhs_val = lhs.toFloat(f32);
                 const rhs_val = rhs.toFloat(f32);
                 return Value.Tag.float_32.create(arena, lhs_val + rhs_val);
             },
-            .f64 => {
+            64 => {
                 const lhs_val = lhs.toFloat(f64);
                 const rhs_val = rhs.toFloat(f64);
                 return Value.Tag.float_64.create(arena, lhs_val + rhs_val);
             },
-            .f128, .comptime_float, .c_longdouble => {
+            80 => {
+                const lhs_val = lhs.toFloat(f80);
+                const rhs_val = rhs.toFloat(f80);
+                return Value.Tag.float_80.create(arena, lhs_val + rhs_val);
+            },
+            128 => {
                 const lhs_val = lhs.toFloat(f128);
                 const rhs_val = rhs.toFloat(f128);
                 return Value.Tag.float_128.create(arena, lhs_val + rhs_val);
@@ -2960,24 +3032,30 @@ pub const Value = extern union {
         rhs: Value,
         float_type: Type,
         arena: Allocator,
+        target: Target,
     ) !Value {
-        switch (float_type.tag()) {
-            .f16 => {
+        switch (float_type.floatBits(target)) {
+            16 => {
                 const lhs_val = lhs.toFloat(f16);
                 const rhs_val = rhs.toFloat(f16);
                 return Value.Tag.float_16.create(arena, lhs_val - rhs_val);
             },
-            .f32 => {
+            32 => {
                 const lhs_val = lhs.toFloat(f32);
                 const rhs_val = rhs.toFloat(f32);
                 return Value.Tag.float_32.create(arena, lhs_val - rhs_val);
             },
-            .f64 => {
+            64 => {
                 const lhs_val = lhs.toFloat(f64);
                 const rhs_val = rhs.toFloat(f64);
                 return Value.Tag.float_64.create(arena, lhs_val - rhs_val);
             },
-            .f128, .comptime_float, .c_longdouble => {
+            80 => {
+                const lhs_val = lhs.toFloat(f80);
+                const rhs_val = rhs.toFloat(f80);
+                return Value.Tag.float_80.create(arena, lhs_val - rhs_val);
+            },
+            128 => {
                 const lhs_val = lhs.toFloat(f128);
                 const rhs_val = rhs.toFloat(f128);
                 return Value.Tag.float_128.create(arena, lhs_val - rhs_val);
@@ -2991,24 +3069,30 @@ pub const Value = extern union {
         rhs: Value,
         float_type: Type,
         arena: Allocator,
+        target: Target,
     ) !Value {
-        switch (float_type.tag()) {
-            .f16 => {
+        switch (float_type.floatBits(target)) {
+            16 => {
                 const lhs_val = lhs.toFloat(f16);
                 const rhs_val = rhs.toFloat(f16);
                 return Value.Tag.float_16.create(arena, lhs_val / rhs_val);
             },
-            .f32 => {
+            32 => {
                 const lhs_val = lhs.toFloat(f32);
                 const rhs_val = rhs.toFloat(f32);
                 return Value.Tag.float_32.create(arena, lhs_val / rhs_val);
             },
-            .f64 => {
+            64 => {
                 const lhs_val = lhs.toFloat(f64);
                 const rhs_val = rhs.toFloat(f64);
                 return Value.Tag.float_64.create(arena, lhs_val / rhs_val);
             },
-            .f128, .comptime_float, .c_longdouble => {
+            80 => {
+                const lhs_val = lhs.toFloat(f80);
+                const rhs_val = rhs.toFloat(f80);
+                return Value.Tag.float_80.create(arena, lhs_val / rhs_val);
+            },
+            128 => {
                 const lhs_val = lhs.toFloat(f128);
                 const rhs_val = rhs.toFloat(f128);
                 return Value.Tag.float_128.create(arena, lhs_val / rhs_val);
@@ -3022,24 +3106,30 @@ pub const Value = extern union {
         rhs: Value,
         float_type: Type,
         arena: Allocator,
+        target: Target,
     ) !Value {
-        switch (float_type.tag()) {
-            .f16 => {
+        switch (float_type.floatBits(target)) {
+            16 => {
                 const lhs_val = lhs.toFloat(f16);
                 const rhs_val = rhs.toFloat(f16);
                 return Value.Tag.float_16.create(arena, @divFloor(lhs_val, rhs_val));
             },
-            .f32 => {
+            32 => {
                 const lhs_val = lhs.toFloat(f32);
                 const rhs_val = rhs.toFloat(f32);
                 return Value.Tag.float_32.create(arena, @divFloor(lhs_val, rhs_val));
             },
-            .f64 => {
+            64 => {
                 const lhs_val = lhs.toFloat(f64);
                 const rhs_val = rhs.toFloat(f64);
                 return Value.Tag.float_64.create(arena, @divFloor(lhs_val, rhs_val));
             },
-            .f128, .comptime_float, .c_longdouble => {
+            80 => {
+                const lhs_val = lhs.toFloat(f80);
+                const rhs_val = rhs.toFloat(f80);
+                return Value.Tag.float_80.create(arena, @divFloor(lhs_val, rhs_val));
+            },
+            128 => {
                 const lhs_val = lhs.toFloat(f128);
                 const rhs_val = rhs.toFloat(f128);
                 return Value.Tag.float_128.create(arena, @divFloor(lhs_val, rhs_val));
@@ -3053,24 +3143,30 @@ pub const Value = extern union {
         rhs: Value,
         float_type: Type,
         arena: Allocator,
+        target: Target,
     ) !Value {
-        switch (float_type.tag()) {
-            .f16 => {
+        switch (float_type.floatBits(target)) {
+            16 => {
                 const lhs_val = lhs.toFloat(f16);
                 const rhs_val = rhs.toFloat(f16);
                 return Value.Tag.float_16.create(arena, @divTrunc(lhs_val, rhs_val));
             },
-            .f32 => {
+            32 => {
                 const lhs_val = lhs.toFloat(f32);
                 const rhs_val = rhs.toFloat(f32);
                 return Value.Tag.float_32.create(arena, @divTrunc(lhs_val, rhs_val));
             },
-            .f64 => {
+            64 => {
                 const lhs_val = lhs.toFloat(f64);
                 const rhs_val = rhs.toFloat(f64);
                 return Value.Tag.float_64.create(arena, @divTrunc(lhs_val, rhs_val));
             },
-            .f128, .comptime_float, .c_longdouble => {
+            80 => {
+                const lhs_val = lhs.toFloat(f80);
+                const rhs_val = rhs.toFloat(f80);
+                return Value.Tag.float_80.create(arena, @divTrunc(lhs_val, rhs_val));
+            },
+            128 => {
                 const lhs_val = lhs.toFloat(f128);
                 const rhs_val = rhs.toFloat(f128);
                 return Value.Tag.float_128.create(arena, @divTrunc(lhs_val, rhs_val));
@@ -3084,24 +3180,30 @@ pub const Value = extern union {
         rhs: Value,
         float_type: Type,
         arena: Allocator,
+        target: Target,
     ) !Value {
-        switch (float_type.tag()) {
-            .f16 => {
+        switch (float_type.floatBits(target)) {
+            16 => {
                 const lhs_val = lhs.toFloat(f16);
                 const rhs_val = rhs.toFloat(f16);
                 return Value.Tag.float_16.create(arena, lhs_val * rhs_val);
             },
-            .f32 => {
+            32 => {
                 const lhs_val = lhs.toFloat(f32);
                 const rhs_val = rhs.toFloat(f32);
                 return Value.Tag.float_32.create(arena, lhs_val * rhs_val);
             },
-            .f64 => {
+            64 => {
                 const lhs_val = lhs.toFloat(f64);
                 const rhs_val = rhs.toFloat(f64);
                 return Value.Tag.float_64.create(arena, lhs_val * rhs_val);
             },
-            .f128, .comptime_float, .c_longdouble => {
+            80 => {
+                const lhs_val = lhs.toFloat(f80);
+                const rhs_val = rhs.toFloat(f80);
+                return Value.Tag.float_80.create(arena, lhs_val * rhs_val);
+            },
+            128 => {
                 const lhs_val = lhs.toFloat(f128);
                 const rhs_val = rhs.toFloat(f128);
                 return Value.Tag.float_128.create(arena, lhs_val * rhs_val);
@@ -3250,6 +3352,13 @@ pub const Value = extern union {
             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;
 
test/behavior/math.zig
@@ -768,8 +768,6 @@ test "shift left/right on u0 operand" {
 }
 
 test "comptime float rem int" {
-    if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
-
     comptime {
         var x = @as(f32, 1) % 2;
         try expect(x == 1.0);