Commit e77ca6af70

Vexu <git@vexu.eu>
2020-07-20 17:11:40
stage2: add float values
1 parent fd2f034
Changed files (1)
src-self-hosted
src-self-hosted/value.zig
@@ -80,6 +80,11 @@ pub const Value = extern union {
         elem_ptr,
         bytes,
         repeated, // the value is a value repeated some number of times
+        float,
+        float_16,
+        float_32,
+        float_64,
+        float_128,
 
         pub const last_no_payload_tag = Tag.bool_false;
         pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
@@ -213,6 +218,10 @@ pub const Value = extern union {
                 };
                 return Value{ .ptr_otherwise = &new_payload.base };
             },
+            .float_16 => return self.copyPayloadShallow(allocator, Payload.Float_16),
+            .float_32 => return self.copyPayloadShallow(allocator, Payload.Float_32),
+            .float_64 => return self.copyPayloadShallow(allocator, Payload.Float_64),
+            .float_128, .float => return self.copyPayloadShallow(allocator, Payload.Float_128),
         }
     }
 
@@ -300,6 +309,10 @@ pub const Value = extern union {
                 try out_stream.writeAll("(repeated) ");
                 val = val.cast(Payload.Repeated).?.val;
             },
+            .float_16 => return out_stream.print("{}", .{val.cast(Payload.Float_16).?.val}),
+            .float_32 => return out_stream.print("{}", .{val.cast(Payload.Float_32).?.val}),
+            .float_64 => return out_stream.print("{}", .{val.cast(Payload.Float_64).?.val}),
+            .float_128, .float => return out_stream.print("{}", .{val.cast(Payload.Float_128).?.val}),
         };
     }
 
@@ -380,6 +393,11 @@ pub const Value = extern union {
             .elem_ptr,
             .bytes,
             .repeated,
+            .float,
+            .float_16,
+            .float_32,
+            .float_64,
+            .float_128,
             => unreachable,
         };
     }
@@ -435,6 +453,11 @@ pub const Value = extern union {
             .bytes,
             .undef,
             .repeated,
+            .float,
+            .float_16,
+            .float_32,
+            .float_64,
+            .float_128,
             => unreachable,
 
             .the_one_possible_value, // An integer with one possible value is always zero.
@@ -502,6 +525,11 @@ pub const Value = extern union {
             .bytes,
             .undef,
             .repeated,
+            .float,
+            .float_16,
+            .float_32,
+            .float_64,
+            .float_128,
             => unreachable,
 
             .zero,
@@ -518,6 +546,25 @@ pub const Value = extern union {
         }
     }
 
+    pub fn toBool(self: Value) bool {
+        return switch (self.tag()) {
+            .bool_true => true,
+            .bool_false, .zero => false,
+            else => unreachable,
+        };
+    }
+
+    /// Asserts that the value is a float.
+    pub fn toF128(self: Value) f128 {
+        return switch (self.tag()) {
+            .float_16 => self.cast(Payload.Float_16).?.val,
+            .float_32 => self.cast(Payload.Float_32).?.val,
+            .float_64 => self.cast(Payload.Float_64).?.val,
+            .float_128, .float => self.cast(Payload.Float_128).?.val,
+            else => unreachable,
+        };
+    }
+
     /// Asserts the value is an integer and not undefined.
     /// Returns the number of bits the value requires to represent stored in twos complement form.
     pub fn intBitCountTwosComp(self: Value) usize {
@@ -570,6 +617,11 @@ pub const Value = extern union {
             .bytes,
             .undef,
             .repeated,
+            .float,
+            .float_16,
+            .float_32,
+            .float_64,
+            .float_128,
             => unreachable,
 
             .the_one_possible_value, // an integer with one possible value is always zero
@@ -642,6 +694,11 @@ pub const Value = extern union {
             .elem_ptr,
             .bytes,
             .repeated,
+            .float,
+            .float_16,
+            .float_32,
+            .float_64,
+            .float_128,
             => unreachable,
 
             .zero,
@@ -762,11 +819,17 @@ pub const Value = extern union {
             => unreachable,
 
             .zero => false,
+
+            .float_16 => @rem(self.cast(Payload.Float_16).?.val, 1) != 0,
+            .float_32 => @rem(self.cast(Payload.Float_32).?.val, 1) != 0,
+            .float_64 => @rem(self.cast(Payload.Float_64).?.val, 1) != 0,
+            // .float_128, .float => @rem(self.cast(Payload.Float_128).?.val, 1) != 0,
+            .float_128, .float => @panic("TODO lld: error: undefined symbol: fmodl"),
         };
     }
 
     pub fn orderAgainstZero(lhs: Value) std.math.Order {
-        switch (lhs.tag()) {
+        return switch (lhs.tag()) {
             .ty,
             .u8_type,
             .i8_type,
@@ -820,15 +883,20 @@ pub const Value = extern union {
             .zero,
             .the_one_possible_value, // an integer with one possible value is always zero
             .bool_false,
-            => return .eq,
+            => .eq,
 
-            .bool_true => return .gt,
+            .bool_true => .gt,
 
-            .int_u64 => return std.math.order(lhs.cast(Payload.Int_u64).?.int, 0),
-            .int_i64 => return std.math.order(lhs.cast(Payload.Int_i64).?.int, 0),
-            .int_big_positive => return lhs.cast(Payload.IntBigPositive).?.asBigInt().orderAgainstScalar(0),
-            .int_big_negative => return lhs.cast(Payload.IntBigNegative).?.asBigInt().orderAgainstScalar(0),
-        }
+            .int_u64 => std.math.order(lhs.cast(Payload.Int_u64).?.int, 0),
+            .int_i64 => std.math.order(lhs.cast(Payload.Int_i64).?.int, 0),
+            .int_big_positive => lhs.cast(Payload.IntBigPositive).?.asBigInt().orderAgainstScalar(0),
+            .int_big_negative => lhs.cast(Payload.IntBigNegative).?.asBigInt().orderAgainstScalar(0),
+
+            .float_16 => std.math.order(lhs.cast(Payload.Float_16).?.val, 0),
+            .float_32 => std.math.order(lhs.cast(Payload.Float_32).?.val, 0),
+            .float_64 => std.math.order(lhs.cast(Payload.Float_64).?.val, 0),
+            .float_128, .float => std.math.order(lhs.cast(Payload.Float_128).?.val, 0),
+        };
     }
 
     /// Asserts the value is comparable.
@@ -840,7 +908,24 @@ pub const Value = extern union {
         if (lhs_is_zero) return rhs.orderAgainstZero().invert();
         if (rhs_is_zero) return lhs.orderAgainstZero();
 
-        // TODO floats
+        const lhs_float = lhs.isFloat();
+        const rhs_float = rhs.isFloat();
+        if (lhs_float and rhs_float) {
+            if (lhs_tag == rhs_tag) {
+                return switch (lhs.tag()) {
+                    .float_16 => return std.math.order(lhs.cast(Payload.Float_16).?.val, rhs.cast(Payload.Float_16).?.val),
+                    .float_32 => return std.math.order(lhs.cast(Payload.Float_32).?.val, rhs.cast(Payload.Float_32).?.val),
+                    .float_64 => return std.math.order(lhs.cast(Payload.Float_64).?.val, rhs.cast(Payload.Float_64).?.val),
+                    .float_128, .float => return std.math.order(lhs.cast(Payload.Float_128).?.val, rhs.cast(Payload.Float_128).?.val),
+                    else => unreachable,
+                };
+            }
+        }
+        if (lhs_float or rhs_float) {
+            const lhs_f128 = lhs.toF128();
+            const rhs_f128 = rhs.toF128();
+            return std.math.order(lhs_f128, rhs_f128);
+        }
 
         var lhs_bigint_space: BigIntSpace = undefined;
         var rhs_bigint_space: BigIntSpace = undefined;
@@ -864,14 +949,6 @@ pub const Value = extern union {
         return compare(a, .eq, b);
     }
 
-    pub fn toBool(self: Value) bool {
-        return switch (self.tag()) {
-            .bool_true => true,
-            .bool_false, .zero => false,
-            else => unreachable,
-        };
-    }
-
     /// Asserts the value is a pointer and dereferences it.
     /// Returns error.AnalysisFail if the pointer points to a Decl that failed semantic analysis.
     pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value {
@@ -928,6 +1005,11 @@ pub const Value = extern union {
             .bytes,
             .undef,
             .repeated,
+            .float,
+            .float_16,
+            .float_32,
+            .float_64,
+            .float_128,
             => unreachable,
 
             .the_one_possible_value => Value.initTag(.the_one_possible_value),
@@ -999,6 +1081,11 @@ pub const Value = extern union {
             .elem_ptr,
             .ref_val,
             .decl_ref,
+            .float,
+            .float_16,
+            .float_32,
+            .float_64,
+            .float_128,
             => unreachable,
 
             .bytes => {
@@ -1085,6 +1172,11 @@ pub const Value = extern union {
             .elem_ptr,
             .bytes,
             .repeated,
+            .float,
+            .float_16,
+            .float_32,
+            .float_64,
+            .float_128,
             => false,
 
             .undef => unreachable,
@@ -1092,6 +1184,21 @@ pub const Value = extern union {
         };
     }
 
+    /// Valid for all types. Asserts the value is not undefined.
+    pub fn isFloat(self: Value) bool {
+        return switch (self.tag()) {
+            .undef => unreachable,
+
+            .float,
+            .float_16,
+            .float_32,
+            .float_64,
+            .float_128,
+            => true,
+            else => false,
+        };
+    }
+
     /// This type is not copyable since it may contain pointers to its inner data.
     pub const Payload = struct {
         tag: Tag,
@@ -1168,6 +1275,26 @@ pub const Value = extern union {
             /// is stored externally.
             val: Value,
         };
+
+        pub const Float_16 = struct {
+            base: Payload = .{ .tag = .float_16 },
+            val: f16,
+        };
+
+        pub const Float_32 = struct {
+            base: Payload = .{ .tag = .float_32 },
+            val: f32,
+        };
+
+        pub const Float_64 = struct {
+            base: Payload = .{ .tag = .float_64 },
+            val: f64,
+        };
+
+        pub const Float_128 = struct {
+            base: Payload = .{ .tag = .float_128 },
+            val: f128,
+        };
     };
 
     /// Big enough to fit any non-BigInt value