Commit e2ad95c088

John Schmidt <john.schmidt.h@gmail.com>
2022-02-13 18:15:13
stage2: implement vector floatops
1 parent 755d116
Changed files (2)
src
test
behavior
src/Sema.zig
@@ -11086,17 +11086,57 @@ fn zirUnaryMath(
     const operand = sema.resolveInst(inst_data.operand);
     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
     const operand_ty = sema.typeOf(operand);
-    try sema.checkFloatType(block, operand_src, operand_ty);
 
-    if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |operand_val| {
-        if (operand_val.isUndef()) return sema.addConstUndef(operand_ty);
-        const target = sema.mod.getTarget();
-        const result_val = try eval(operand_val, operand_ty, sema.arena, target);
-        return sema.addConstant(operand_ty, result_val);
+    switch (operand_ty.zigTypeTag()) {
+        .ComptimeFloat, .Float => {},
+        .Vector => {
+            const scalar_ty = operand_ty.scalarType();
+            switch (scalar_ty.zigTypeTag()) {
+                .ComptimeFloat, .Float => {},
+                else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{scalar_ty}),
+            }
+        },
+        else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{operand_ty}),
     }
 
-    try sema.requireRuntimeBlock(block, operand_src);
-    return block.addUnOp(air_tag, operand);
+    const target = sema.mod.getTarget();
+    switch (operand_ty.zigTypeTag()) {
+        .Vector => {
+            const scalar_ty = operand_ty.scalarType();
+            const vec_len = operand_ty.vectorLen();
+            const result_ty = try Type.vector(sema.arena, vec_len, scalar_ty);
+            if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
+                if (val.isUndef())
+                    return sema.addConstUndef(result_ty);
+
+                var elem_buf: Value.ElemValueBuffer = undefined;
+                const elems = try sema.arena.alloc(Value, vec_len);
+                for (elems) |*elem, i| {
+                    const elem_val = val.elemValueBuffer(i, &elem_buf);
+                    elem.* = try eval(elem_val, scalar_ty, sema.arena, target);
+                }
+                return sema.addConstant(
+                    result_ty,
+                    try Value.Tag.array.create(sema.arena, elems),
+                );
+            }
+
+            try sema.requireRuntimeBlock(block, operand_src);
+            return block.addUnOp(air_tag, operand);
+        },
+        .ComptimeFloat, .Float => {
+            if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |operand_val| {
+                if (operand_val.isUndef())
+                    return sema.addConstUndef(operand_ty);
+                const result_val = try eval(operand_val, operand_ty, sema.arena, target);
+                return sema.addConstant(operand_ty, result_val);
+            }
+
+            try sema.requireRuntimeBlock(block, operand_src);
+            return block.addUnOp(air_tag, operand);
+        },
+        else => unreachable,
+    }
 }
 
 fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
test/behavior/floatop.zig
@@ -98,6 +98,15 @@ fn testSqrt() !void {
     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));
 
+    {
+        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));
+    }
+
     if (builtin.zig_backend == .stage1) {
         if (has_f80_rt) {
             // TODO https://github.com/ziglang/zig/issues/10875
@@ -116,16 +125,6 @@ fn testSqrt() !void {
         //    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));
-        }
     }
 }
 
@@ -155,26 +154,25 @@ test "@sin" {
 }
 
 fn testSin() !void {
-    // TODO: Implement Vector support for other backends
-    if (builtin.zig_backend == .stage1) {
+    // stage1 emits an incorrect compile error for `@as(ty, std.math.pi / 2)`
+    // so skip the rest of the tests.
+    if (builtin.zig_backend != .stage1) {
+        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));
+        }
+    }
+
+    {
         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));
     }
 }
 
@@ -184,26 +182,25 @@ test "@cos" {
 }
 
 fn testCos() !void {
-    // TODO: Implement Vector support for other backends
-    if (builtin.zig_backend == .stage1) {
+    // stage1 emits an incorrect compile error for `@as(ty, std.math.pi / 2)`
+    // so skip the rest of the tests.
+    if (builtin.zig_backend != .stage1) {
+        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));
+        }
+    }
+
+    {
         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));
     }
 }
 
@@ -220,8 +217,7 @@ fn testExp() !void {
         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));
@@ -244,8 +240,7 @@ fn testExp2() !void {
         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));
@@ -281,8 +276,7 @@ fn testLog() !void {
         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));
@@ -305,8 +299,7 @@ fn testLog2() !void {
         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));
@@ -329,8 +322,7 @@ fn testLog10() !void {
         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));
@@ -362,8 +354,7 @@ fn testFabs() !void {
     //     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));
@@ -390,8 +381,7 @@ fn testFloor() !void {
     //     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));
@@ -418,8 +408,7 @@ fn testCeil() !void {
     //     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));
@@ -446,8 +435,7 @@ fn testTrunc() !void {
     //     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));