Commit 7f0cf395aa

John Schmidt <john.schmidt.h@gmail.com>
2022-02-04 20:21:15
stage2: implement all builtin floatops for f{16,32,64}
- Merge `floatop.zig` and `floatop_stage1.zig` since most tests now pass on stage2. - Add more behavior tests for a bunch of functions.
1 parent 44b5fdf
src/arch/aarch64/CodeGen.zig
@@ -528,7 +528,20 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
             .max             => try self.airMax(inst),
             .slice           => try self.airSlice(inst),
 
-            .sqrt            => try self.airUnaryMath(inst),
+            .sqrt,
+            .sin,
+            .cos,
+            .exp,
+            .exp2,
+            .log,
+            .log2,
+            .log10,
+            .fabs,
+            .floor,
+            .ceil,
+            .round,
+            .trunc_float
+            => try self.airUnaryMath(inst),
 
             .add_with_overflow => try self.airAddWithOverflow(inst),
             .sub_with_overflow => try self.airSubWithOverflow(inst),
src/arch/arm/CodeGen.zig
@@ -520,7 +520,20 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
             .max             => try self.airMax(inst),
             .slice           => try self.airSlice(inst),
 
-            .sqrt            => try self.airUnaryMath(inst),
+            .sqrt,
+            .sin,
+            .cos,
+            .exp,
+            .exp2,
+            .log,
+            .log2,
+            .log10,
+            .fabs,
+            .floor,
+            .ceil,
+            .round,
+            .trunc_float,
+            => try self.airUnaryMath(inst),
 
             .add_with_overflow => try self.airAddWithOverflow(inst),
             .sub_with_overflow => try self.airSubWithOverflow(inst),
src/arch/riscv64/CodeGen.zig
@@ -507,7 +507,20 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
             .max             => try self.airMax(inst),
             .slice           => try self.airSlice(inst),
 
-            .sqrt            => try self.airUnaryMath(inst),
+            .sqrt,
+            .sin,
+            .cos,
+            .exp,
+            .exp2,
+            .log,
+            .log2,
+            .log10,
+            .fabs,
+            .floor,
+            .ceil,
+            .round,
+            .trunc_float,
+            => try self.airUnaryMath(inst),
 
             .add_with_overflow => try self.airAddWithOverflow(inst),
             .sub_with_overflow => try self.airSubWithOverflow(inst),
src/arch/wasm/CodeGen.zig
@@ -1679,6 +1679,18 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
         .unwrap_errunion_err_ptr,
 
         .sqrt,
+        .sin,
+        .cos,
+        .exp,
+        .exp2,
+        .log,
+        .log2,
+        .log10,
+        .fabs,
+        .floor,
+        .ceil,
+        .round,
+        .trunc_float,
 
         .ptr_slice_len_ptr,
         .ptr_slice_ptr_ptr,
src/arch/x86_64/CodeGen.zig
@@ -599,7 +599,20 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
             .max             => try self.airMax(inst),
             .slice           => try self.airSlice(inst),
 
-            .sqrt            => try self.airUnaryMath(inst),
+            .sqrt,
+            .sin,
+            .cos,
+            .exp,
+            .exp2,
+            .log,
+            .log2,
+            .log10,
+            .fabs,
+            .floor,
+            .ceil,
+            .round,
+            .trunc_float,
+            => try self.airUnaryMath(inst),
 
             .add_with_overflow => try self.airAddWithOverflow(inst),
             .sub_with_overflow => try self.airSubWithOverflow(inst),
src/codegen/c.zig
@@ -1446,7 +1446,20 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
             .mul_sat => try airSatOp(f, inst, "muls_"),
             .shl_sat => try airSatOp(f, inst, "shls_"),
 
-            .sqrt => try airSqrt(f, inst),
+            .sqrt,
+            .sin,
+            .cos,
+            .exp,
+            .exp2,
+            .log,
+            .log2,
+            .log10,
+            .fabs,
+            .floor,
+            .ceil,
+            .round,
+            .trunc_float,
+            => |tag| return f.fail("TODO: C backend: implement unary op for tag '{s}'", .{@tagName(tag)}),
 
             .add_with_overflow => try airAddWithOverflow(f, inst),
             .sub_with_overflow => try airSubWithOverflow(f, inst),
@@ -3395,12 +3408,6 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
     return CValue.none;
 }
 
-fn airSqrt(f: *Function, inst: Air.Inst.Index) !CValue {
-    _ = f;
-    _ = inst;
-    return f.fail("TODO: C backend: implement sqrt", .{});
-}
-
 fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {
     return switch (order) {
         .Unordered => "memory_order_relaxed",
src/codegen/llvm.zig
@@ -2050,7 +2050,19 @@ pub const FuncGen = struct {
                 .shr                => try self.airShr(inst, false),
                 .shr_exact          => try self.airShr(inst, true),
 
-                .sqrt => try self.airSqrt(inst),
+                .sqrt         => try self.airUnaryOp(inst, "llvm.sqrt"),
+                .sin          => try self.airUnaryOp(inst, "llvm.sin"),
+                .cos          => try self.airUnaryOp(inst, "llvm.cos"),
+                .exp          => try self.airUnaryOp(inst, "llvm.exp"),
+                .exp2         => try self.airUnaryOp(inst, "llvm.exp2"),
+                .log          => try self.airUnaryOp(inst, "llvm.log"),
+                .log2         => try self.airUnaryOp(inst, "llvm.log2"),
+                .log10        => try self.airUnaryOp(inst, "llvm.log10"),
+                .fabs         => try self.airUnaryOp(inst, "llvm.fabs"),
+                .floor        => try self.airUnaryOp(inst, "llvm.floor"),
+                .ceil         => try self.airUnaryOp(inst, "llvm.ceil"),
+                .round        => try self.airUnaryOp(inst, "llvm.round"),
+                .trunc_float  => try self.airUnaryOp(inst, "llvm.trunc"),
 
                 .cmp_eq  => try self.airCmp(inst, .eq),
                 .cmp_gt  => try self.airCmp(inst, .gt),
@@ -4213,7 +4225,7 @@ pub const FuncGen = struct {
         }
     }
 
-    fn airSqrt(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+    fn airUnaryOp(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*const llvm.Value {
         if (self.liveness.isUnused(inst)) return null;
 
         const un_op = self.air.instructions.items(.data)[inst].un_op;
@@ -4221,7 +4233,7 @@ pub const FuncGen = struct {
         const operand_ty = self.air.typeOf(un_op);
 
         const operand_llvm_ty = try self.dg.llvmType(operand_ty);
-        const fn_val = self.getIntrinsic("llvm.sqrt", &.{operand_llvm_ty});
+        const fn_val = self.getIntrinsic(llvm_fn_name, &.{operand_llvm_ty});
         const params = [_]*const llvm.Value{operand};
 
         return self.builder.buildCall(fn_val, &params, params.len, .C, .Auto, "");
src/Air.zig
@@ -237,9 +237,45 @@ pub const Inst = struct {
         /// Uses the `ty_op` field.
         popcount,
 
-        /// Computes the square root of a floating point number.
+        /// Square root of a floating point number.
         /// Uses the `un_op` field.
         sqrt,
+        /// Sine a floating point number.
+        /// Uses the `un_op` field.
+        sin,
+        /// Cosine a floating point number.
+        /// Uses the `un_op` field.
+        cos,
+        /// Base e exponential of a floating point number.
+        /// Uses the `un_op` field.
+        exp,
+        /// Base 2 exponential of a floating point number.
+        /// Uses the `un_op` field.
+        exp2,
+        /// Natural (base e) logarithm of a floating point number.
+        /// Uses the `un_op` field.
+        log,
+        /// Base 2 logarithm of a floating point number.
+        /// Uses the `un_op` field.
+        log2,
+        /// Base 10 logarithm of a floating point number.
+        /// Uses the `un_op` field.
+        log10,
+        /// Aboslute value of a floating point number.
+        /// Uses the `un_op` field.
+        fabs,
+        /// Floor: rounds a floating pointer number down to the nearest integer.
+        /// Uses the `un_op` field.
+        floor,
+        /// Ceiling: rounds a floating pointer number up to the nearest integer.
+        /// Uses the `un_op` field.
+        ceil,
+        /// Rounds a floating pointer number to the nearest integer.
+        /// Uses the `un_op` field.
+        round,
+        /// Rounds a floating pointer number to the nearest integer towards zero.
+        /// Uses the `un_op` field.
+        trunc_float,
 
         /// `<`. Result type is always bool.
         /// Uses the `bin_op` field.
@@ -754,7 +790,20 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
         .max,
         => return air.typeOf(datas[inst].bin_op.lhs),
 
-        .sqrt => return air.typeOf(datas[inst].un_op),
+        .sqrt,
+        .sin,
+        .cos,
+        .exp,
+        .exp2,
+        .log,
+        .log2,
+        .log10,
+        .fabs,
+        .floor,
+        .ceil,
+        .round,
+        .trunc_float,
+        => return air.typeOf(datas[inst].un_op),
 
         .cmp_lt,
         .cmp_lte,
src/Liveness.zig
@@ -339,6 +339,18 @@ fn analyzeInst(
         .tag_name,
         .error_name,
         .sqrt,
+        .sin,
+        .cos,
+        .exp,
+        .exp2,
+        .log,
+        .log2,
+        .log10,
+        .fabs,
+        .floor,
+        .ceil,
+        .round,
+        .trunc_float,
         => {
             const operand = inst_datas[inst].un_op;
             return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none });
src/print_air.zig
@@ -159,6 +159,18 @@ const Writer = struct {
             .tag_name,
             .error_name,
             .sqrt,
+            .sin,
+            .cos,
+            .exp,
+            .exp2,
+            .log,
+            .log2,
+            .log10,
+            .fabs,
+            .floor,
+            .ceil,
+            .round,
+            .trunc_float,
             => try w.writeUnOp(s, inst),
 
             .breakpoint,
src/Sema.zig
@@ -747,18 +747,18 @@ fn analyzeBodyInner(
             .ctz => try sema.zirClzCtz(block, inst, .ctz, Value.ctz),
 
             .sqrt  => try sema.zirUnaryMath(block, inst, .sqrt, Value.sqrt),
-            .sin   => @panic("TODO"),
-            .cos   => @panic("TODO"),
-            .exp   => @panic("TODO"),
-            .exp2  => @panic("TODO"),
-            .log   => @panic("TODO"),
-            .log2  => @panic("TODO"),
-            .log10 => @panic("TODO"),
-            .fabs  => @panic("TODO"),
-            .floor => @panic("TODO"),
-            .ceil  => @panic("TODO"),
-            .trunc => @panic("TODO"),
-            .round => @panic("TODO"),
+            .sin   => try sema.zirUnaryMath(block, inst, .sin, Value.sin),
+            .cos   => try sema.zirUnaryMath(block, inst, .cos, Value.cos),
+            .exp   => try sema.zirUnaryMath(block, inst, .exp, Value.exp),
+            .exp2  => try sema.zirUnaryMath(block, inst, .exp2, Value.exp2),
+            .log   => try sema.zirUnaryMath(block, inst, .log, Value.log),
+            .log2  => try sema.zirUnaryMath(block, inst, .log2, Value.log2),
+            .log10 => try sema.zirUnaryMath(block, inst, .log10, Value.log10),
+            .fabs  => try sema.zirUnaryMath(block, inst, .fabs, Value.fabs),
+            .floor => try sema.zirUnaryMath(block, inst, .floor, Value.floor),
+            .ceil  => try sema.zirUnaryMath(block, inst, .ceil, Value.ceil),
+            .round => try sema.zirUnaryMath(block, inst, .round, Value.round),
+            .trunc => try sema.zirUnaryMath(block, inst, .trunc_float, Value.trunc),
 
             .error_set_decl      => try sema.zirErrorSetDecl(block, inst, .parent),
             .error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon),
src/value.zig
@@ -3308,6 +3308,390 @@ pub const Value = extern union {
         }
     }
 
+    pub fn sin(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+        switch (float_type.floatBits(target)) {
+            16 => {
+                const f = val.toFloat(f16);
+                return Value.Tag.float_16.create(arena, @sin(f));
+            },
+            32 => {
+                const f = val.toFloat(f32);
+                return Value.Tag.float_32.create(arena, @sin(f));
+            },
+            64 => {
+                const f = val.toFloat(f64);
+                return Value.Tag.float_64.create(arena, @sin(f));
+            },
+            80 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt sin for f80");
+                }
+                const f = val.toFloat(f80);
+                return Value.Tag.float_80.create(arena, @sin(f));
+            },
+            128 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt sin for f128");
+                }
+                const f = val.toFloat(f128);
+                return Value.Tag.float_128.create(arena, @sin(f));
+            },
+            else => unreachable,
+        }
+    }
+
+    pub fn cos(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+        switch (float_type.floatBits(target)) {
+            16 => {
+                const f = val.toFloat(f16);
+                return Value.Tag.float_16.create(arena, @cos(f));
+            },
+            32 => {
+                const f = val.toFloat(f32);
+                return Value.Tag.float_32.create(arena, @cos(f));
+            },
+            64 => {
+                const f = val.toFloat(f64);
+                return Value.Tag.float_64.create(arena, @cos(f));
+            },
+            80 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt cos for f80");
+                }
+                const f = val.toFloat(f80);
+                return Value.Tag.float_80.create(arena, @cos(f));
+            },
+            128 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt cos for f128");
+                }
+                const f = val.toFloat(f128);
+                return Value.Tag.float_128.create(arena, @cos(f));
+            },
+            else => unreachable,
+        }
+    }
+
+    pub fn exp(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+        switch (float_type.floatBits(target)) {
+            16 => {
+                const f = val.toFloat(f16);
+                return Value.Tag.float_16.create(arena, @exp(f));
+            },
+            32 => {
+                const f = val.toFloat(f32);
+                return Value.Tag.float_32.create(arena, @exp(f));
+            },
+            64 => {
+                const f = val.toFloat(f64);
+                return Value.Tag.float_64.create(arena, @exp(f));
+            },
+            80 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt exp for f80");
+                }
+                const f = val.toFloat(f80);
+                return Value.Tag.float_80.create(arena, @exp(f));
+            },
+            128 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt exp for f128");
+                }
+                const f = val.toFloat(f128);
+                return Value.Tag.float_128.create(arena, @exp(f));
+            },
+            else => unreachable,
+        }
+    }
+
+    pub fn exp2(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+        switch (float_type.floatBits(target)) {
+            16 => {
+                const f = val.toFloat(f16);
+                return Value.Tag.float_16.create(arena, @exp2(f));
+            },
+            32 => {
+                const f = val.toFloat(f32);
+                return Value.Tag.float_32.create(arena, @exp2(f));
+            },
+            64 => {
+                const f = val.toFloat(f64);
+                return Value.Tag.float_64.create(arena, @exp2(f));
+            },
+            80 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt exp2 for f80");
+                }
+                const f = val.toFloat(f80);
+                return Value.Tag.float_80.create(arena, @exp2(f));
+            },
+            128 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt exp2 for f128");
+                }
+                const f = val.toFloat(f128);
+                return Value.Tag.float_128.create(arena, @exp2(f));
+            },
+            else => unreachable,
+        }
+    }
+
+    pub fn log(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+        switch (float_type.floatBits(target)) {
+            16 => {
+                const f = val.toFloat(f16);
+                return Value.Tag.float_16.create(arena, @log(f));
+            },
+            32 => {
+                const f = val.toFloat(f32);
+                return Value.Tag.float_32.create(arena, @log(f));
+            },
+            64 => {
+                const f = val.toFloat(f64);
+                return Value.Tag.float_64.create(arena, @log(f));
+            },
+            80 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt log for f80");
+                }
+                const f = val.toFloat(f80);
+                return Value.Tag.float_80.create(arena, @log(f));
+            },
+            128 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt log for f128");
+                }
+                const f = val.toFloat(f128);
+                return Value.Tag.float_128.create(arena, @log(f));
+            },
+            else => unreachable,
+        }
+    }
+
+    pub fn log2(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+        switch (float_type.floatBits(target)) {
+            16 => {
+                const f = val.toFloat(f16);
+                return Value.Tag.float_16.create(arena, @log2(f));
+            },
+            32 => {
+                const f = val.toFloat(f32);
+                return Value.Tag.float_32.create(arena, @log2(f));
+            },
+            64 => {
+                const f = val.toFloat(f64);
+                return Value.Tag.float_64.create(arena, @log2(f));
+            },
+            80 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt log2 for f80");
+                }
+                const f = val.toFloat(f80);
+                return Value.Tag.float_80.create(arena, @log2(f));
+            },
+            128 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt log2 for f128");
+                }
+                const f = val.toFloat(f128);
+                return Value.Tag.float_128.create(arena, @log2(f));
+            },
+            else => unreachable,
+        }
+    }
+
+    pub fn log10(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+        switch (float_type.floatBits(target)) {
+            16 => {
+                const f = val.toFloat(f16);
+                return Value.Tag.float_16.create(arena, @log10(f));
+            },
+            32 => {
+                const f = val.toFloat(f32);
+                return Value.Tag.float_32.create(arena, @log10(f));
+            },
+            64 => {
+                const f = val.toFloat(f64);
+                return Value.Tag.float_64.create(arena, @log10(f));
+            },
+            80 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt log10 for f80");
+                }
+                const f = val.toFloat(f80);
+                return Value.Tag.float_80.create(arena, @log10(f));
+            },
+            128 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt log10 for f128");
+                }
+                const f = val.toFloat(f128);
+                return Value.Tag.float_128.create(arena, @log10(f));
+            },
+            else => unreachable,
+        }
+    }
+
+    pub fn fabs(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+        switch (float_type.floatBits(target)) {
+            16 => {
+                const f = val.toFloat(f16);
+                return Value.Tag.float_16.create(arena, @fabs(f));
+            },
+            32 => {
+                const f = val.toFloat(f32);
+                return Value.Tag.float_32.create(arena, @fabs(f));
+            },
+            64 => {
+                const f = val.toFloat(f64);
+                return Value.Tag.float_64.create(arena, @fabs(f));
+            },
+            80 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt fabs for f80");
+                }
+                const f = val.toFloat(f80);
+                return Value.Tag.float_80.create(arena, @fabs(f));
+            },
+            128 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt fabs for f128");
+                }
+                const f = val.toFloat(f128);
+                return Value.Tag.float_128.create(arena, @fabs(f));
+            },
+            else => unreachable,
+        }
+    }
+
+    pub fn floor(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+        switch (float_type.floatBits(target)) {
+            16 => {
+                const f = val.toFloat(f16);
+                return Value.Tag.float_16.create(arena, @floor(f));
+            },
+            32 => {
+                const f = val.toFloat(f32);
+                return Value.Tag.float_32.create(arena, @floor(f));
+            },
+            64 => {
+                const f = val.toFloat(f64);
+                return Value.Tag.float_64.create(arena, @floor(f));
+            },
+            80 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt floor for f80");
+                }
+                const f = val.toFloat(f80);
+                return Value.Tag.float_80.create(arena, @floor(f));
+            },
+            128 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt floor for f128");
+                }
+                const f = val.toFloat(f128);
+                return Value.Tag.float_128.create(arena, @floor(f));
+            },
+            else => unreachable,
+        }
+    }
+
+    pub fn ceil(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+        switch (float_type.floatBits(target)) {
+            16 => {
+                const f = val.toFloat(f16);
+                return Value.Tag.float_16.create(arena, @ceil(f));
+            },
+            32 => {
+                const f = val.toFloat(f32);
+                return Value.Tag.float_32.create(arena, @ceil(f));
+            },
+            64 => {
+                const f = val.toFloat(f64);
+                return Value.Tag.float_64.create(arena, @ceil(f));
+            },
+            80 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt ceil for f80");
+                }
+                const f = val.toFloat(f80);
+                return Value.Tag.float_80.create(arena, @ceil(f));
+            },
+            128 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt ceil for f128");
+                }
+                const f = val.toFloat(f128);
+                return Value.Tag.float_128.create(arena, @ceil(f));
+            },
+            else => unreachable,
+        }
+    }
+
+    pub fn round(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+        switch (float_type.floatBits(target)) {
+            16 => {
+                const f = val.toFloat(f16);
+                return Value.Tag.float_16.create(arena, @round(f));
+            },
+            32 => {
+                const f = val.toFloat(f32);
+                return Value.Tag.float_32.create(arena, @round(f));
+            },
+            64 => {
+                const f = val.toFloat(f64);
+                return Value.Tag.float_64.create(arena, @round(f));
+            },
+            80 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt round for f80");
+                }
+                const f = val.toFloat(f80);
+                return Value.Tag.float_80.create(arena, @round(f));
+            },
+            128 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt round for f128");
+                }
+                const f = val.toFloat(f128);
+                return Value.Tag.float_128.create(arena, @round(f));
+            },
+            else => unreachable,
+        }
+    }
+
+    pub fn trunc(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+        switch (float_type.floatBits(target)) {
+            16 => {
+                const f = val.toFloat(f16);
+                return Value.Tag.float_16.create(arena, @trunc(f));
+            },
+            32 => {
+                const f = val.toFloat(f32);
+                return Value.Tag.float_32.create(arena, @trunc(f));
+            },
+            64 => {
+                const f = val.toFloat(f64);
+                return Value.Tag.float_64.create(arena, @trunc(f));
+            },
+            80 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt trunc for f80");
+                }
+                const f = val.toFloat(f80);
+                return Value.Tag.float_80.create(arena, @trunc(f));
+            },
+            128 => {
+                if (true) {
+                    @panic("TODO implement compiler_rt trunc for f128");
+                }
+                const f = val.toFloat(f128);
+                return Value.Tag.float_128.create(arena, @trunc(f));
+            },
+            else => unreachable,
+        }
+    }
+
     /// This type is not copyable since it may contain pointers to its inner data.
     pub const Payload = struct {
         tag: Tag,
test/behavior/floatop.zig
@@ -1,12 +1,22 @@
 const std = @import("std");
+const builtin = @import("builtin");
 const expect = std.testing.expect;
 const math = std.math;
 const pi = std.math.pi;
 const e = std.math.e;
 const Vector = std.meta.Vector;
+const has_f80_rt = @import("builtin").cpu.arch == .x86_64;
 
+const epsilon_16 = 0.001;
 const epsilon = 0.000001;
 
+fn epsForType(comptime T: type) T {
+    return switch (T) {
+        f16 => @as(f16, epsilon_16),
+        else => @as(T, epsilon),
+    };
+}
+
 test "floating point comparisons" {
     try testFloatComparisons();
     comptime try testFloatComparisons();
@@ -79,19 +89,37 @@ test "@sqrt" {
 }
 
 fn testSqrt() !void {
-    {
-        var a: f16 = 4;
-        try expect(@sqrt(a) == 2);
-    }
-    {
-        var a: f32 = 9;
-        try expect(@sqrt(a) == 3);
-        var b: f32 = 1.1;
-        try expect(math.approxEqAbs(f32, @sqrt(b), 1.0488088481701516, epsilon));
-    }
-    {
-        var a: f64 = 25;
-        try expect(@sqrt(a) == 5);
+    try expect(@sqrt(@as(f16, 4)) == 2);
+    try expect(@sqrt(@as(f32, 9)) == 3);
+    try expect(@sqrt(@as(f64, 25)) == 5);
+    try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 1.1)), 1.0488088481701516, epsilon));
+    try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 2.0)), 1.4142135623730950, epsilon));
+
+    if (builtin.zig_backend == .stage1) {
+        if (has_f80_rt) {
+            var a: f80 = 25;
+            try expect(@sqrt(a) == 5);
+        }
+        {
+            const a: comptime_float = 25.0;
+            try expect(@sqrt(a) == 5.0);
+        }
+        // TODO test f128, and c_longdouble
+        // https://github.com/ziglang/zig/issues/4026
+        //{
+        //    var a: f128 = 49;
+        //try expect(@sqrt(a) == 7);
+        //}
+
+        // TODO Implement Vector support for stage2
+        {
+            var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
+            var result = @sqrt(v);
+            try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 1.1)), result[0], epsilon));
+            try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 2.2)), result[1], epsilon));
+            try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 3.3)), result[2], epsilon));
+            try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 4.4)), result[3], epsilon));
+        }
     }
 }
 
@@ -114,3 +142,311 @@ test "more @sqrt f16 tests" {
     try expect(math.isNan(@sqrt(@as(f16, -1.0))));
     try expect(math.isNan(@sqrt(@as(f16, math.nan(f16)))));
 }
+
+test "@sin" {
+    comptime try testSin();
+    try testSin();
+}
+
+fn testSin() !void {
+    // TODO: Implement Vector support for other backends
+    if (builtin.zig_backend == .stage1) {
+        var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
+        var result = @sin(v);
+        try expect(math.approxEqAbs(f32, @sin(@as(f32, 1.1)), result[0], epsilon));
+        try expect(math.approxEqAbs(f32, @sin(@as(f32, 2.2)), result[1], epsilon));
+        try expect(math.approxEqAbs(f32, @sin(@as(f32, 3.3)), result[2], epsilon));
+        try expect(math.approxEqAbs(f32, @sin(@as(f32, 4.4)), result[3], epsilon));
+
+        // stage1 emits an incorrect compile error for `@as(ty, std.math.pi / 2)`
+        // so skip the rest of the tests.
+        return;
+    }
+
+    inline for ([_]type{ f16, f32, f64 }) |ty| {
+        const eps = epsForType(ty);
+        try expect(@sin(@as(ty, 0)) == 0);
+        try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi)), 0, eps));
+        try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 2)), 1, eps));
+        try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 4)), 0.7071067811865475, eps));
+    }
+}
+
+test "@cos" {
+    comptime try testCos();
+    try testCos();
+}
+
+fn testCos() !void {
+    // TODO: Implement Vector support for other backends
+    if (builtin.zig_backend == .stage1) {
+        var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
+        var result = @cos(v);
+        try expect(math.approxEqAbs(f32, @cos(@as(f32, 1.1)), result[0], epsilon));
+        try expect(math.approxEqAbs(f32, @cos(@as(f32, 2.2)), result[1], epsilon));
+        try expect(math.approxEqAbs(f32, @cos(@as(f32, 3.3)), result[2], epsilon));
+        try expect(math.approxEqAbs(f32, @cos(@as(f32, 4.4)), result[3], epsilon));
+
+        // stage1 emits an incorrect compile error for `@as(ty, std.math.pi / 2)`
+        // so skip the rest of the tests.
+        return;
+    }
+
+    inline for ([_]type{ f16, f32, f64 }) |ty| {
+        const eps = epsForType(ty);
+        try expect(@cos(@as(ty, 0)) == 1);
+        try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi)), -1, eps));
+        try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 2)), 0, eps));
+        try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 4)), 0.7071067811865475, eps));
+    }
+}
+
+test "@exp" {
+    comptime try testExp();
+    try testExp();
+}
+
+fn testExp() !void {
+    inline for ([_]type{ f16, f32, f64 }) |ty| {
+        const eps = epsForType(ty);
+        try expect(@exp(@as(ty, 0)) == 1);
+        try expect(math.approxEqAbs(ty, @exp(@as(ty, 2)), 7.389056098930650, eps));
+        try expect(math.approxEqAbs(ty, @exp(@as(ty, 5)), 148.4131591025766, eps));
+    }
+
+    // TODO: Implement Vector support for other backends
+    if (builtin.zig_backend == .stage1) {
+        var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
+        var result = @exp(v);
+        try expect(math.approxEqAbs(f32, @exp(@as(f32, 1.1)), result[0], epsilon));
+        try expect(math.approxEqAbs(f32, @exp(@as(f32, 2.2)), result[1], epsilon));
+        try expect(math.approxEqAbs(f32, @exp(@as(f32, 0.3)), result[2], epsilon));
+        try expect(math.approxEqAbs(f32, @exp(@as(f32, 0.4)), result[3], epsilon));
+    }
+}
+
+test "@exp2" {
+    comptime try testExp2();
+    try testExp2();
+}
+
+fn testExp2() !void {
+    inline for ([_]type{ f16, f32, f64 }) |ty| {
+        const eps = epsForType(ty);
+        try expect(@exp2(@as(ty, 2)) == 4);
+        try expect(math.approxEqAbs(ty, @exp2(@as(ty, 1.5)), 2.8284271247462, eps));
+        try expect(math.approxEqAbs(ty, @exp2(@as(ty, 4.5)), 22.627416997969, eps));
+    }
+
+    // TODO: Implement Vector support for other backends
+    if (builtin.zig_backend == .stage1) {
+        var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
+        var result = @exp2(v);
+        try expect(math.approxEqAbs(f32, @exp2(@as(f32, 1.1)), result[0], epsilon));
+        try expect(math.approxEqAbs(f32, @exp2(@as(f32, 2.2)), result[1], epsilon));
+        try expect(math.approxEqAbs(f32, @exp2(@as(f32, 0.3)), result[2], epsilon));
+        try expect(math.approxEqAbs(f32, @exp2(@as(f32, 0.4)), result[3], epsilon));
+    }
+}
+
+test "@log" {
+    // Old musl (and glibc?), and our current math.ln implementation do not return 1
+    // so also accept those values.
+    comptime try testLog();
+    try testLog();
+}
+
+fn testLog() !void {
+    {
+        var a: f16 = e;
+        try expect(math.approxEqAbs(f16, @log(a), 1, epsilon));
+    }
+    {
+        var a: f32 = e;
+        try expect(@log(a) == 1 or @log(a) == @bitCast(f32, @as(u32, 0x3f7fffff)));
+    }
+    {
+        var a: f64 = e;
+        try expect(@log(a) == 1 or @log(a) == @bitCast(f64, @as(u64, 0x3ff0000000000000)));
+    }
+    inline for ([_]type{ f16, f32, f64 }) |ty| {
+        const eps = epsForType(ty);
+        try expect(math.approxEqAbs(ty, @log(@as(ty, 2)), 0.6931471805599, eps));
+        try expect(math.approxEqAbs(ty, @log(@as(ty, 5)), 1.6094379124341, eps));
+    }
+
+    // TODO: Implement Vector support for other backends
+    if (builtin.zig_backend == .stage1) {
+        var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
+        var result = @log(v);
+        try expect(math.approxEqAbs(f32, @log(@as(f32, 1.1)), result[0], epsilon));
+        try expect(math.approxEqAbs(f32, @log(@as(f32, 2.2)), result[1], epsilon));
+        try expect(math.approxEqAbs(f32, @log(@as(f32, 0.3)), result[2], epsilon));
+        try expect(math.approxEqAbs(f32, @log(@as(f32, 0.4)), result[3], epsilon));
+    }
+}
+
+test "@log2" {
+    comptime try testLog2();
+    try testLog2();
+}
+
+fn testLog2() !void {
+    inline for ([_]type{ f16, f32, f64 }) |ty| {
+        const eps = epsForType(ty);
+        try expect(@log2(@as(ty, 4)) == 2);
+        try expect(math.approxEqAbs(ty, @log2(@as(ty, 6)), 2.5849625007212, eps));
+        try expect(math.approxEqAbs(ty, @log2(@as(ty, 10)), 3.3219280948874, eps));
+    }
+
+    // TODO: Implement Vector support for other backends
+    if (builtin.zig_backend == .stage1) {
+        var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
+        var result = @log2(v);
+        try expect(math.approxEqAbs(f32, @log2(@as(f32, 1.1)), result[0], epsilon));
+        try expect(math.approxEqAbs(f32, @log2(@as(f32, 2.2)), result[1], epsilon));
+        try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.3)), result[2], epsilon));
+        try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.4)), result[3], epsilon));
+    }
+}
+
+test "@log10" {
+    comptime try testLog10();
+    try testLog10();
+}
+
+fn testLog10() !void {
+    inline for ([_]type{ f16, f32, f64 }) |ty| {
+        const eps = epsForType(ty);
+        try expect(@log10(@as(ty, 100)) == 2);
+        try expect(math.approxEqAbs(ty, @log10(@as(ty, 15)), 1.176091259056, eps));
+        try expect(math.approxEqAbs(ty, @log10(@as(ty, 50)), 1.698970004336, eps));
+    }
+
+    // TODO: Implement Vector support for other backends
+    if (builtin.zig_backend == .stage1) {
+        var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
+        var result = @log10(v);
+        try expect(math.approxEqAbs(f32, @log10(@as(f32, 1.1)), result[0], epsilon));
+        try expect(math.approxEqAbs(f32, @log10(@as(f32, 2.2)), result[1], epsilon));
+        try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.3)), result[2], epsilon));
+        try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.4)), result[3], epsilon));
+    }
+}
+
+test "@fabs" {
+    comptime try testFabs();
+    try testFabs();
+}
+
+fn testFabs() !void {
+    try expect(@fabs(@as(f16, -2.5)) == 2.5);
+    try expect(@fabs(@as(f16, 2.5)) == 2.5);
+    try expect(@fabs(@as(f32, -2.5)) == 2.5);
+    try expect(@fabs(@as(f32, 2.5)) == 2.5);
+    try expect(@fabs(@as(f64, -2.5)) == 2.5);
+    try expect(@fabs(@as(f64, 2.5)) == 2.5);
+
+    // TODO test f128, and c_longdouble
+    // https://github.com/ziglang/zig/issues/4026
+    // {
+    //     var a: f80 = -2.5;
+    //     var b: f80 = 2.5;
+    //     try expect(@fabs(a) == 2.5);
+    //     try expect(@fabs(b) == 2.5);
+    // }
+
+    // TODO: Implement Vector support for other backends
+    if (builtin.zig_backend == .stage1) {
+        var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
+        var result = @fabs(v);
+        try expect(math.approxEqAbs(f32, @fabs(@as(f32, 1.1)), result[0], epsilon));
+        try expect(math.approxEqAbs(f32, @fabs(@as(f32, -2.2)), result[1], epsilon));
+        try expect(math.approxEqAbs(f32, @fabs(@as(f32, 0.3)), result[2], epsilon));
+        try expect(math.approxEqAbs(f32, @fabs(@as(f32, -0.4)), result[3], epsilon));
+    }
+}
+
+test "@floor" {
+    comptime try testFloor();
+    try testFloor();
+}
+
+fn testFloor() !void {
+    try expect(@floor(@as(f16, 2.1)) == 2);
+    try expect(@floor(@as(f32, 2.1)) == 2);
+    try expect(@floor(@as(f64, 3.5)) == 3);
+
+    // TODO test f128, and c_longdouble
+    // https://github.com/ziglang/zig/issues/4026
+    // {
+    //     var a: f80 = 3.5;
+    //     try expect(@floor(a) == 3);
+    // }
+
+    // TODO: Implement Vector support for other backends
+    if (builtin.zig_backend == .stage1) {
+        var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
+        var result = @floor(v);
+        try expect(math.approxEqAbs(f32, @floor(@as(f32, 1.1)), result[0], epsilon));
+        try expect(math.approxEqAbs(f32, @floor(@as(f32, -2.2)), result[1], epsilon));
+        try expect(math.approxEqAbs(f32, @floor(@as(f32, 0.3)), result[2], epsilon));
+        try expect(math.approxEqAbs(f32, @floor(@as(f32, -0.4)), result[3], epsilon));
+    }
+}
+
+test "@ceil" {
+    comptime try testCeil();
+    try testCeil();
+}
+
+fn testCeil() !void {
+    try expect(@ceil(@as(f16, 2.1)) == 3);
+    try expect(@ceil(@as(f32, 2.1)) == 3);
+    try expect(@ceil(@as(f64, 3.5)) == 4);
+
+    // TODO test f128, and c_longdouble
+    // https://github.com/ziglang/zig/issues/4026
+    // {
+    //     var a: f80 = 3.5;
+    //     try expect(@ceil(a) == 4);
+    // }
+
+    // TODO: Implement Vector support for other backends
+    if (builtin.zig_backend == .stage1) {
+        var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
+        var result = @ceil(v);
+        try expect(math.approxEqAbs(f32, @ceil(@as(f32, 1.1)), result[0], epsilon));
+        try expect(math.approxEqAbs(f32, @ceil(@as(f32, -2.2)), result[1], epsilon));
+        try expect(math.approxEqAbs(f32, @ceil(@as(f32, 0.3)), result[2], epsilon));
+        try expect(math.approxEqAbs(f32, @ceil(@as(f32, -0.4)), result[3], epsilon));
+    }
+}
+
+test "@trunc" {
+    comptime try testTrunc();
+    try testTrunc();
+}
+
+fn testTrunc() !void {
+    try expect(@trunc(@as(f16, 2.1)) == 2);
+    try expect(@trunc(@as(f32, 2.1)) == 2);
+    try expect(@trunc(@as(f64, -3.5)) == -3);
+
+    // TODO test f128, and c_longdouble
+    // https://github.com/ziglang/zig/issues/4026
+    // {
+    //     var a: f80 = -3.5;
+    //     try expect(@trunc(a) == -3);
+    // }
+
+    // TODO: Implement Vector support for other backends
+    if (builtin.zig_backend == .stage1) {
+        var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
+        var result = @trunc(v);
+        try expect(math.approxEqAbs(f32, @trunc(@as(f32, 1.1)), result[0], epsilon));
+        try expect(math.approxEqAbs(f32, @trunc(@as(f32, -2.2)), result[1], epsilon));
+        try expect(math.approxEqAbs(f32, @trunc(@as(f32, 0.3)), result[2], epsilon));
+        try expect(math.approxEqAbs(f32, @trunc(@as(f32, -0.4)), result[3], epsilon));
+    }
+}
test/behavior/floatop_stage1.zig
@@ -1,452 +0,0 @@
-const std = @import("std");
-const expect = std.testing.expect;
-const math = std.math;
-const pi = std.math.pi;
-const e = std.math.e;
-const Vector = std.meta.Vector;
-const has_f80_rt = @import("builtin").cpu.arch == .x86_64;
-
-const epsilon = 0.000001;
-
-test "@sqrt" {
-    comptime try testSqrt();
-    try testSqrt();
-}
-
-fn testSqrt() !void {
-    if (has_f80_rt) {
-        var a: f80 = 25;
-        try expect(@sqrt(a) == 5);
-    }
-    {
-        const a: comptime_float = 25.0;
-        try expect(@sqrt(a) == 5.0);
-    }
-    // TODO https://github.com/ziglang/zig/issues/4026
-    //{
-    //    var a: f128 = 49;
-    //try expect(@sqrt(a) == 7);
-    //}
-    {
-        var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
-        var result = @sqrt(v);
-        try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 1.1)), result[0], epsilon));
-        try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 2.2)), result[1], epsilon));
-        try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 3.3)), result[2], epsilon));
-        try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 4.4)), result[3], epsilon));
-    }
-}
-
-test "@sin" {
-    comptime try testSin();
-    try testSin();
-}
-
-fn testSin() !void {
-    // TODO test f128, and c_longdouble
-    // https://github.com/ziglang/zig/issues/4026
-    {
-        var a: f16 = 0;
-        try expect(@sin(a) == 0);
-    }
-    {
-        var a: f32 = 0;
-        try expect(@sin(a) == 0);
-    }
-    {
-        var a: f64 = 0;
-        try expect(@sin(a) == 0);
-    }
-    // {
-    //     var a: f80 = 0;
-    //     try expect(@sin(a) == 0);
-    // }
-    {
-        var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
-        var result = @sin(v);
-        try expect(math.approxEqAbs(f32, @sin(@as(f32, 1.1)), result[0], epsilon));
-        try expect(math.approxEqAbs(f32, @sin(@as(f32, 2.2)), result[1], epsilon));
-        try expect(math.approxEqAbs(f32, @sin(@as(f32, 3.3)), result[2], epsilon));
-        try expect(math.approxEqAbs(f32, @sin(@as(f32, 4.4)), result[3], epsilon));
-    }
-}
-
-test "@cos" {
-    comptime try testCos();
-    try testCos();
-}
-
-fn testCos() !void {
-    // TODO test f128, and c_longdouble
-    // https://github.com/ziglang/zig/issues/4026
-    {
-        var a: f16 = 0;
-        try expect(@cos(a) == 1);
-    }
-    {
-        var a: f32 = 0;
-        try expect(@cos(a) == 1);
-    }
-    {
-        var a: f64 = 0;
-        try expect(@cos(a) == 1);
-    }
-    // {
-    //     var a: f80 = 0;
-    //     try expect(@cos(a) == 1);
-    // }
-    {
-        var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
-        var result = @cos(v);
-        try expect(math.approxEqAbs(f32, @cos(@as(f32, 1.1)), result[0], epsilon));
-        try expect(math.approxEqAbs(f32, @cos(@as(f32, 2.2)), result[1], epsilon));
-        try expect(math.approxEqAbs(f32, @cos(@as(f32, 3.3)), result[2], epsilon));
-        try expect(math.approxEqAbs(f32, @cos(@as(f32, 4.4)), result[3], epsilon));
-    }
-}
-
-test "@exp" {
-    comptime try testExp();
-    try testExp();
-}
-
-fn testExp() !void {
-    // TODO test f128, and c_longdouble
-    // https://github.com/ziglang/zig/issues/4026
-    {
-        var a: f16 = 0;
-        try expect(@exp(a) == 1);
-    }
-    {
-        var a: f32 = 0;
-        try expect(@exp(a) == 1);
-    }
-    {
-        var a: f64 = 0;
-        try expect(@exp(a) == 1);
-    }
-    // {
-    //     var a: f80 = 0;
-    //     try expect(@exp(a) == 1);
-    // }
-    {
-        var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
-        var result = @exp(v);
-        try expect(math.approxEqAbs(f32, @exp(@as(f32, 1.1)), result[0], epsilon));
-        try expect(math.approxEqAbs(f32, @exp(@as(f32, 2.2)), result[1], epsilon));
-        try expect(math.approxEqAbs(f32, @exp(@as(f32, 0.3)), result[2], epsilon));
-        try expect(math.approxEqAbs(f32, @exp(@as(f32, 0.4)), result[3], epsilon));
-    }
-}
-
-test "@exp2" {
-    comptime try testExp2();
-    try testExp2();
-}
-
-fn testExp2() !void {
-    // TODO test f128, and c_longdouble
-    // https://github.com/ziglang/zig/issues/4026
-    {
-        var a: f16 = 2;
-        try expect(@exp2(a) == 4);
-    }
-    {
-        var a: f32 = 2;
-        try expect(@exp2(a) == 4);
-    }
-    {
-        var a: f64 = 2;
-        try expect(@exp2(a) == 4);
-    }
-    // {
-    //     var a: f80 = 2;
-    //     try expect(@exp2(a) == 4);
-    // }
-    {
-        var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
-        var result = @exp2(v);
-        try expect(math.approxEqAbs(f32, @exp2(@as(f32, 1.1)), result[0], epsilon));
-        try expect(math.approxEqAbs(f32, @exp2(@as(f32, 2.2)), result[1], epsilon));
-        try expect(math.approxEqAbs(f32, @exp2(@as(f32, 0.3)), result[2], epsilon));
-        try expect(math.approxEqAbs(f32, @exp2(@as(f32, 0.4)), result[3], epsilon));
-    }
-}
-
-test "@log" {
-    // Old musl (and glibc?), and our current math.ln implementation do not return 1
-    // so also accept those values.
-    comptime try testLog();
-    try testLog();
-}
-
-fn testLog() !void {
-    // TODO test f128, and c_longdouble
-    // https://github.com/ziglang/zig/issues/4026
-    {
-        var a: f16 = e;
-        try expect(math.approxEqAbs(f16, @log(a), 1, epsilon));
-    }
-    {
-        var a: f32 = e;
-        try expect(@log(a) == 1 or @log(a) == @bitCast(f32, @as(u32, 0x3f7fffff)));
-    }
-    {
-        var a: f64 = e;
-        try expect(@log(a) == 1 or @log(a) == @bitCast(f64, @as(u64, 0x3ff0000000000000)));
-    }
-    // {
-    //     var a: f80 = e;
-    //     try expect(@log(a) == 1);
-    // }
-    {
-        var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
-        var result = @log(v);
-        try expect(math.approxEqAbs(f32, @log(@as(f32, 1.1)), result[0], epsilon));
-        try expect(math.approxEqAbs(f32, @log(@as(f32, 2.2)), result[1], epsilon));
-        try expect(math.approxEqAbs(f32, @log(@as(f32, 0.3)), result[2], epsilon));
-        try expect(math.approxEqAbs(f32, @log(@as(f32, 0.4)), result[3], epsilon));
-    }
-}
-
-test "@log2" {
-    comptime try testLog2();
-    try testLog2();
-}
-
-fn testLog2() !void {
-    // TODO test f128, and c_longdouble
-    // https://github.com/ziglang/zig/issues/4026
-    {
-        var a: f16 = 4;
-        try expect(@log2(a) == 2);
-    }
-    {
-        var a: f32 = 4;
-        try expect(@log2(a) == 2);
-    }
-    {
-        var a: f64 = 4;
-        try expect(@log2(a) == 2);
-    }
-    // {
-    //     var a: f80 = 4;
-    //     try expect(@log2(a) == 2);
-    // }
-    {
-        var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
-        var result = @log2(v);
-        try expect(math.approxEqAbs(f32, @log2(@as(f32, 1.1)), result[0], epsilon));
-        try expect(math.approxEqAbs(f32, @log2(@as(f32, 2.2)), result[1], epsilon));
-        try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.3)), result[2], epsilon));
-        try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.4)), result[3], epsilon));
-    }
-}
-
-test "@log10" {
-    comptime try testLog10();
-    try testLog10();
-}
-
-fn testLog10() !void {
-    // TODO test f128, and c_longdouble
-    // https://github.com/ziglang/zig/issues/4026
-    {
-        var a: f16 = 100;
-        try expect(@log10(a) == 2);
-    }
-    {
-        var a: f32 = 100;
-        try expect(@log10(a) == 2);
-    }
-    {
-        var a: f64 = 1000;
-        try expect(@log10(a) == 3);
-    }
-    // {
-    //     var a: f80 = 1000;
-    //     try expect(@log10(a) == 3);
-    // }
-    {
-        var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
-        var result = @log10(v);
-        try expect(math.approxEqAbs(f32, @log10(@as(f32, 1.1)), result[0], epsilon));
-        try expect(math.approxEqAbs(f32, @log10(@as(f32, 2.2)), result[1], epsilon));
-        try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.3)), result[2], epsilon));
-        try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.4)), result[3], epsilon));
-    }
-}
-
-test "@fabs" {
-    comptime try testFabs();
-    try testFabs();
-}
-
-fn testFabs() !void {
-    // TODO test f128, and c_longdouble
-    // https://github.com/ziglang/zig/issues/4026
-    {
-        var a: f16 = -2.5;
-        var b: f16 = 2.5;
-        try expect(@fabs(a) == 2.5);
-        try expect(@fabs(b) == 2.5);
-    }
-    {
-        var a: f32 = -2.5;
-        var b: f32 = 2.5;
-        try expect(@fabs(a) == 2.5);
-        try expect(@fabs(b) == 2.5);
-    }
-    {
-        var a: f64 = -2.5;
-        var b: f64 = 2.5;
-        try expect(@fabs(a) == 2.5);
-        try expect(@fabs(b) == 2.5);
-    }
-    // {
-    //     var a: f80 = -2.5;
-    //     var b: f80 = 2.5;
-    //     try expect(@fabs(a) == 2.5);
-    //     try expect(@fabs(b) == 2.5);
-    // }
-    {
-        var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
-        var result = @fabs(v);
-        try expect(math.approxEqAbs(f32, @fabs(@as(f32, 1.1)), result[0], epsilon));
-        try expect(math.approxEqAbs(f32, @fabs(@as(f32, -2.2)), result[1], epsilon));
-        try expect(math.approxEqAbs(f32, @fabs(@as(f32, 0.3)), result[2], epsilon));
-        try expect(math.approxEqAbs(f32, @fabs(@as(f32, -0.4)), result[3], epsilon));
-    }
-}
-
-test "@floor" {
-    comptime try testFloor();
-    try testFloor();
-}
-
-fn testFloor() !void {
-    // TODO test f128, and c_longdouble
-    // https://github.com/ziglang/zig/issues/4026
-    {
-        var a: f16 = 2.1;
-        try expect(@floor(a) == 2);
-    }
-    {
-        var a: f32 = 2.1;
-        try expect(@floor(a) == 2);
-    }
-    {
-        var a: f64 = 3.5;
-        try expect(@floor(a) == 3);
-    }
-    // {
-    //     var a: f80 = 3.5;
-    //     try expect(@floor(a) == 3);
-    // }
-    {
-        var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
-        var result = @floor(v);
-        try expect(math.approxEqAbs(f32, @floor(@as(f32, 1.1)), result[0], epsilon));
-        try expect(math.approxEqAbs(f32, @floor(@as(f32, -2.2)), result[1], epsilon));
-        try expect(math.approxEqAbs(f32, @floor(@as(f32, 0.3)), result[2], epsilon));
-        try expect(math.approxEqAbs(f32, @floor(@as(f32, -0.4)), result[3], epsilon));
-    }
-}
-
-test "@ceil" {
-    comptime try testCeil();
-    try testCeil();
-}
-
-fn testCeil() !void {
-    // TODO test f128, and c_longdouble
-    // https://github.com/ziglang/zig/issues/4026
-    {
-        var a: f16 = 2.1;
-        try expect(@ceil(a) == 3);
-    }
-    {
-        var a: f32 = 2.1;
-        try expect(@ceil(a) == 3);
-    }
-    {
-        var a: f64 = 3.5;
-        try expect(@ceil(a) == 4);
-    }
-    // {
-    //     var a: f80 = 3.5;
-    //     try expect(@ceil(a) == 4);
-    // }
-    {
-        var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
-        var result = @ceil(v);
-        try expect(math.approxEqAbs(f32, @ceil(@as(f32, 1.1)), result[0], epsilon));
-        try expect(math.approxEqAbs(f32, @ceil(@as(f32, -2.2)), result[1], epsilon));
-        try expect(math.approxEqAbs(f32, @ceil(@as(f32, 0.3)), result[2], epsilon));
-        try expect(math.approxEqAbs(f32, @ceil(@as(f32, -0.4)), result[3], epsilon));
-    }
-}
-
-test "@trunc" {
-    comptime try testTrunc();
-    try testTrunc();
-}
-
-fn testTrunc() !void {
-    // TODO test f128, and c_longdouble
-    // https://github.com/ziglang/zig/issues/4026
-    {
-        var a: f16 = 2.1;
-        try expect(@trunc(a) == 2);
-    }
-    {
-        var a: f32 = 2.1;
-        try expect(@trunc(a) == 2);
-    }
-    {
-        var a: f64 = -3.5;
-        try expect(@trunc(a) == -3);
-    }
-    // {
-    //     var a: f80 = -3.5;
-    //     try expect(@trunc(a) == -3);
-    // }
-    {
-        var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
-        var result = @trunc(v);
-        try expect(math.approxEqAbs(f32, @trunc(@as(f32, 1.1)), result[0], epsilon));
-        try expect(math.approxEqAbs(f32, @trunc(@as(f32, -2.2)), result[1], epsilon));
-        try expect(math.approxEqAbs(f32, @trunc(@as(f32, 0.3)), result[2], epsilon));
-        try expect(math.approxEqAbs(f32, @trunc(@as(f32, -0.4)), result[3], epsilon));
-    }
-}
-
-test "floating point comparisons" {
-    if (has_f80_rt) try testFloatComparisons();
-    comptime try testFloatComparisons();
-}
-
-fn testFloatComparisons() !void {
-    inline for ([_]type{ f16, f32, f64, f80, f128 }) |ty| {
-        // No decimal part
-        {
-            const x: ty = 1.0;
-            try expect(x == 1);
-            try expect(x != 0);
-            try expect(x > 0);
-            try expect(x < 2);
-            try expect(x >= 1);
-            try expect(x <= 1);
-        }
-        // Non-zero decimal part
-        {
-            const x: ty = 1.5;
-            try expect(x != 1);
-            try expect(x != 2);
-            try expect(x > 1);
-            try expect(x < 2);
-            try expect(x >= 1);
-            try expect(x <= 2);
-        }
-    }
-}
test/behavior.zig
@@ -150,7 +150,6 @@ test {
                     _ = @import("behavior/const_slice_child.zig");
                     _ = @import("behavior/export_self_referential_type_info.zig");
                     _ = @import("behavior/field_parent_ptr.zig");
-                    _ = @import("behavior/floatop_stage1.zig");
                     _ = @import("behavior/fn_delegation.zig");
                     _ = @import("behavior/ir_block_deps.zig");
                     _ = @import("behavior/misc.zig");