authorgravatar for john.schmidt.h@gmail.comJohn Schmidt <john.schmidt.h@gmail.com> 2022-02-13 18:15:13+01:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-02-17 14:47:21+02:00
loge2ad95c0883bfaacba7377fdf3e037d9fecd4940
tree79ad699fd00d543bf861768a933d5f5bb3361a9f
parent755d116ecf2d221e2ad8b572c58a7d4f99163ff9

stage2: implement vector floatops


2 files changed, 92 insertions(+), 64 deletions(-)

src/Sema.zig+48-8
...@@ -11086,17 +11086,57 @@ fn zirUnaryMath(...@@ -11086,17 +11086,57 @@ fn zirUnaryMath(
11086 const operand = sema.resolveInst(inst_data.operand);11086 const operand = sema.resolveInst(inst_data.operand);
11087 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };11087 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
11088 const operand_ty = sema.typeOf(operand);11088 const operand_ty = sema.typeOf(operand);
11089 try sema.checkFloatType(block, operand_src, operand_ty);
1109011089
11091 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |operand_val| {11090 switch (operand_ty.zigTypeTag()) {
11092 if (operand_val.isUndef()) return sema.addConstUndef(operand_ty);11091 .ComptimeFloat, .Float => {},
11093 const target = sema.mod.getTarget();11092 .Vector => {
11094 const result_val = try eval(operand_val, operand_ty, sema.arena, target);11093 const scalar_ty = operand_ty.scalarType();
11095 return sema.addConstant(operand_ty, result_val);11094 switch (scalar_ty.zigTypeTag()) {
11095 .ComptimeFloat, .Float => {},
11096 else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{scalar_ty}),
11097 }
11098 },
11099 else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{operand_ty}),
11096 }11100 }
1109711101
11098 try sema.requireRuntimeBlock(block, operand_src);11102 const target = sema.mod.getTarget();
11099 return block.addUnOp(air_tag, operand);11103 switch (operand_ty.zigTypeTag()) {
11104 .Vector => {
11105 const scalar_ty = operand_ty.scalarType();
11106 const vec_len = operand_ty.vectorLen();
11107 const result_ty = try Type.vector(sema.arena, vec_len, scalar_ty);
11108 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
11109 if (val.isUndef())
11110 return sema.addConstUndef(result_ty);
11111
11112 var elem_buf: Value.ElemValueBuffer = undefined;
11113 const elems = try sema.arena.alloc(Value, vec_len);
11114 for (elems) |*elem, i| {
11115 const elem_val = val.elemValueBuffer(i, &elem_buf);
11116 elem.* = try eval(elem_val, scalar_ty, sema.arena, target);
11117 }
11118 return sema.addConstant(
11119 result_ty,
11120 try Value.Tag.array.create(sema.arena, elems),
11121 );
11122 }
11123
11124 try sema.requireRuntimeBlock(block, operand_src);
11125 return block.addUnOp(air_tag, operand);
11126 },
11127 .ComptimeFloat, .Float => {
11128 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |operand_val| {
11129 if (operand_val.isUndef())
11130 return sema.addConstUndef(operand_ty);
11131 const result_val = try eval(operand_val, operand_ty, sema.arena, target);
11132 return sema.addConstant(operand_ty, result_val);
11133 }
11134
11135 try sema.requireRuntimeBlock(block, operand_src);
11136 return block.addUnOp(air_tag, operand);
11137 },
11138 else => unreachable,
11139 }
11100}11140}
1110111141
11102fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {11142fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
test/behavior/floatop.zig+44-56
...@@ -98,6 +98,15 @@ fn testSqrt() !void {...@@ -98,6 +98,15 @@ fn testSqrt() !void {
98 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 1.1)), 1.0488088481701516, epsilon));98 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 1.1)), 1.0488088481701516, epsilon));
99 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 2.0)), 1.4142135623730950, epsilon));99 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 2.0)), 1.4142135623730950, epsilon));
100100
101 {
102 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
103 var result = @sqrt(v);
104 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 1.1)), result[0], epsilon));
105 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 2.2)), result[1], epsilon));
106 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 3.3)), result[2], epsilon));
107 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 4.4)), result[3], epsilon));
108 }
109
101 if (builtin.zig_backend == .stage1) {110 if (builtin.zig_backend == .stage1) {
102 if (has_f80_rt) {111 if (has_f80_rt) {
103 // TODO https://github.com/ziglang/zig/issues/10875112 // TODO https://github.com/ziglang/zig/issues/10875
...@@ -116,16 +125,6 @@ fn testSqrt() !void {...@@ -116,16 +125,6 @@ fn testSqrt() !void {
116 // var a: f128 = 49;125 // var a: f128 = 49;
117 //try expect(@sqrt(a) == 7);126 //try expect(@sqrt(a) == 7);
118 //}127 //}
119
120 // TODO Implement Vector support for stage2
121 {
122 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
123 var result = @sqrt(v);
124 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 1.1)), result[0], epsilon));
125 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 2.2)), result[1], epsilon));
126 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 3.3)), result[2], epsilon));
127 try expect(math.approxEqAbs(f32, @sqrt(@as(f32, 4.4)), result[3], epsilon));
128 }
129 }128 }
130}129}
131130
...@@ -155,26 +154,25 @@ test "@sin" {...@@ -155,26 +154,25 @@ test "@sin" {
155}154}
156155
157fn testSin() !void {156fn testSin() !void {
158 // TODO: Implement Vector support for other backends157 // stage1 emits an incorrect compile error for `@as(ty, std.math.pi / 2)`
159 if (builtin.zig_backend == .stage1) {158 // so skip the rest of the tests.
159 if (builtin.zig_backend != .stage1) {
160 inline for ([_]type{ f16, f32, f64 }) |ty| {
161 const eps = epsForType(ty);
162 try expect(@sin(@as(ty, 0)) == 0);
163 try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi)), 0, eps));
164 try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 2)), 1, eps));
165 try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 4)), 0.7071067811865475, eps));
166 }
167 }
168
169 {
160 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };170 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
161 var result = @sin(v);171 var result = @sin(v);
162 try expect(math.approxEqAbs(f32, @sin(@as(f32, 1.1)), result[0], epsilon));172 try expect(math.approxEqAbs(f32, @sin(@as(f32, 1.1)), result[0], epsilon));
163 try expect(math.approxEqAbs(f32, @sin(@as(f32, 2.2)), result[1], epsilon));173 try expect(math.approxEqAbs(f32, @sin(@as(f32, 2.2)), result[1], epsilon));
164 try expect(math.approxEqAbs(f32, @sin(@as(f32, 3.3)), result[2], epsilon));174 try expect(math.approxEqAbs(f32, @sin(@as(f32, 3.3)), result[2], epsilon));
165 try expect(math.approxEqAbs(f32, @sin(@as(f32, 4.4)), result[3], epsilon));175 try expect(math.approxEqAbs(f32, @sin(@as(f32, 4.4)), result[3], epsilon));
166
167 // stage1 emits an incorrect compile error for `@as(ty, std.math.pi / 2)`
168 // so skip the rest of the tests.
169 return;
170 }
171
172 inline for ([_]type{ f16, f32, f64 }) |ty| {
173 const eps = epsForType(ty);
174 try expect(@sin(@as(ty, 0)) == 0);
175 try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi)), 0, eps));
176 try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 2)), 1, eps));
177 try expect(math.approxEqAbs(ty, @sin(@as(ty, std.math.pi / 4)), 0.7071067811865475, eps));
178 }176 }
179}177}
180178
...@@ -184,26 +182,25 @@ test "@cos" {...@@ -184,26 +182,25 @@ test "@cos" {
184}182}
185183
186fn testCos() !void {184fn testCos() !void {
187 // TODO: Implement Vector support for other backends185 // stage1 emits an incorrect compile error for `@as(ty, std.math.pi / 2)`
188 if (builtin.zig_backend == .stage1) {186 // so skip the rest of the tests.
187 if (builtin.zig_backend != .stage1) {
188 inline for ([_]type{ f16, f32, f64 }) |ty| {
189 const eps = epsForType(ty);
190 try expect(@cos(@as(ty, 0)) == 1);
191 try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi)), -1, eps));
192 try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 2)), 0, eps));
193 try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 4)), 0.7071067811865475, eps));
194 }
195 }
196
197 {
189 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };198 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
190 var result = @cos(v);199 var result = @cos(v);
191 try expect(math.approxEqAbs(f32, @cos(@as(f32, 1.1)), result[0], epsilon));200 try expect(math.approxEqAbs(f32, @cos(@as(f32, 1.1)), result[0], epsilon));
192 try expect(math.approxEqAbs(f32, @cos(@as(f32, 2.2)), result[1], epsilon));201 try expect(math.approxEqAbs(f32, @cos(@as(f32, 2.2)), result[1], epsilon));
193 try expect(math.approxEqAbs(f32, @cos(@as(f32, 3.3)), result[2], epsilon));202 try expect(math.approxEqAbs(f32, @cos(@as(f32, 3.3)), result[2], epsilon));
194 try expect(math.approxEqAbs(f32, @cos(@as(f32, 4.4)), result[3], epsilon));203 try expect(math.approxEqAbs(f32, @cos(@as(f32, 4.4)), result[3], epsilon));
195
196 // stage1 emits an incorrect compile error for `@as(ty, std.math.pi / 2)`
197 // so skip the rest of the tests.
198 return;
199 }
200
201 inline for ([_]type{ f16, f32, f64 }) |ty| {
202 const eps = epsForType(ty);
203 try expect(@cos(@as(ty, 0)) == 1);
204 try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi)), -1, eps));
205 try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 2)), 0, eps));
206 try expect(math.approxEqAbs(ty, @cos(@as(ty, std.math.pi / 4)), 0.7071067811865475, eps));
207 }204 }
208}205}
209206
...@@ -220,8 +217,7 @@ fn testExp() !void {...@@ -220,8 +217,7 @@ fn testExp() !void {
220 try expect(math.approxEqAbs(ty, @exp(@as(ty, 5)), 148.4131591025766, eps));217 try expect(math.approxEqAbs(ty, @exp(@as(ty, 5)), 148.4131591025766, eps));
221 }218 }
222219
223 // TODO: Implement Vector support for other backends220 {
224 if (builtin.zig_backend == .stage1) {
225 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };221 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
226 var result = @exp(v);222 var result = @exp(v);
227 try expect(math.approxEqAbs(f32, @exp(@as(f32, 1.1)), result[0], epsilon));223 try expect(math.approxEqAbs(f32, @exp(@as(f32, 1.1)), result[0], epsilon));
...@@ -244,8 +240,7 @@ fn testExp2() !void {...@@ -244,8 +240,7 @@ fn testExp2() !void {
244 try expect(math.approxEqAbs(ty, @exp2(@as(ty, 4.5)), 22.627416997969, eps));240 try expect(math.approxEqAbs(ty, @exp2(@as(ty, 4.5)), 22.627416997969, eps));
245 }241 }
246242
247 // TODO: Implement Vector support for other backends243 {
248 if (builtin.zig_backend == .stage1) {
249 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };244 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
250 var result = @exp2(v);245 var result = @exp2(v);
251 try expect(math.approxEqAbs(f32, @exp2(@as(f32, 1.1)), result[0], epsilon));246 try expect(math.approxEqAbs(f32, @exp2(@as(f32, 1.1)), result[0], epsilon));
...@@ -281,8 +276,7 @@ fn testLog() !void {...@@ -281,8 +276,7 @@ fn testLog() !void {
281 try expect(math.approxEqAbs(ty, @log(@as(ty, 5)), 1.6094379124341, eps));276 try expect(math.approxEqAbs(ty, @log(@as(ty, 5)), 1.6094379124341, eps));
282 }277 }
283278
284 // TODO: Implement Vector support for other backends279 {
285 if (builtin.zig_backend == .stage1) {
286 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };280 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
287 var result = @log(v);281 var result = @log(v);
288 try expect(math.approxEqAbs(f32, @log(@as(f32, 1.1)), result[0], epsilon));282 try expect(math.approxEqAbs(f32, @log(@as(f32, 1.1)), result[0], epsilon));
...@@ -305,8 +299,7 @@ fn testLog2() !void {...@@ -305,8 +299,7 @@ fn testLog2() !void {
305 try expect(math.approxEqAbs(ty, @log2(@as(ty, 10)), 3.3219280948874, eps));299 try expect(math.approxEqAbs(ty, @log2(@as(ty, 10)), 3.3219280948874, eps));
306 }300 }
307301
308 // TODO: Implement Vector support for other backends302 {
309 if (builtin.zig_backend == .stage1) {
310 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };303 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
311 var result = @log2(v);304 var result = @log2(v);
312 try expect(math.approxEqAbs(f32, @log2(@as(f32, 1.1)), result[0], epsilon));305 try expect(math.approxEqAbs(f32, @log2(@as(f32, 1.1)), result[0], epsilon));
...@@ -329,8 +322,7 @@ fn testLog10() !void {...@@ -329,8 +322,7 @@ fn testLog10() !void {
329 try expect(math.approxEqAbs(ty, @log10(@as(ty, 50)), 1.698970004336, eps));322 try expect(math.approxEqAbs(ty, @log10(@as(ty, 50)), 1.698970004336, eps));
330 }323 }
331324
332 // TODO: Implement Vector support for other backends325 {
333 if (builtin.zig_backend == .stage1) {
334 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };326 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
335 var result = @log10(v);327 var result = @log10(v);
336 try expect(math.approxEqAbs(f32, @log10(@as(f32, 1.1)), result[0], epsilon));328 try expect(math.approxEqAbs(f32, @log10(@as(f32, 1.1)), result[0], epsilon));
...@@ -362,8 +354,7 @@ fn testFabs() !void {...@@ -362,8 +354,7 @@ fn testFabs() !void {
362 // try expect(@fabs(b) == 2.5);354 // try expect(@fabs(b) == 2.5);
363 // }355 // }
364356
365 // TODO: Implement Vector support for other backends357 {
366 if (builtin.zig_backend == .stage1) {
367 var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };358 var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
368 var result = @fabs(v);359 var result = @fabs(v);
369 try expect(math.approxEqAbs(f32, @fabs(@as(f32, 1.1)), result[0], epsilon));360 try expect(math.approxEqAbs(f32, @fabs(@as(f32, 1.1)), result[0], epsilon));
...@@ -390,8 +381,7 @@ fn testFloor() !void {...@@ -390,8 +381,7 @@ fn testFloor() !void {
390 // try expect(@floor(a) == 3);381 // try expect(@floor(a) == 3);
391 // }382 // }
392383
393 // TODO: Implement Vector support for other backends384 {
394 if (builtin.zig_backend == .stage1) {
395 var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };385 var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
396 var result = @floor(v);386 var result = @floor(v);
397 try expect(math.approxEqAbs(f32, @floor(@as(f32, 1.1)), result[0], epsilon));387 try expect(math.approxEqAbs(f32, @floor(@as(f32, 1.1)), result[0], epsilon));
...@@ -418,8 +408,7 @@ fn testCeil() !void {...@@ -418,8 +408,7 @@ fn testCeil() !void {
418 // try expect(@ceil(a) == 4);408 // try expect(@ceil(a) == 4);
419 // }409 // }
420410
421 // TODO: Implement Vector support for other backends411 {
422 if (builtin.zig_backend == .stage1) {
423 var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };412 var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
424 var result = @ceil(v);413 var result = @ceil(v);
425 try expect(math.approxEqAbs(f32, @ceil(@as(f32, 1.1)), result[0], epsilon));414 try expect(math.approxEqAbs(f32, @ceil(@as(f32, 1.1)), result[0], epsilon));
...@@ -446,8 +435,7 @@ fn testTrunc() !void {...@@ -446,8 +435,7 @@ fn testTrunc() !void {
446 // try expect(@trunc(a) == -3);435 // try expect(@trunc(a) == -3);
447 // }436 // }
448437
449 // TODO: Implement Vector support for other backends438 {
450 if (builtin.zig_backend == .stage1) {
451 var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };439 var v: Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
452 var result = @trunc(v);440 var result = @trunc(v);
453 try expect(math.approxEqAbs(f32, @trunc(@as(f32, 1.1)), result[0], epsilon));441 try expect(math.approxEqAbs(f32, @trunc(@as(f32, 1.1)), result[0], epsilon));