authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-04-27 16:45:23-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-04-27 16:45:23-07:00
log09f1d62bdfb5794534b21d1cd9dafc4822697d60
tree437f6c19a6f0f16ef29fb91513176bb8aa0c91f0
parentc4eaff6665132287d05272bef8890e4607ff017c

add new builtin function `@tan`

The reason for having `@tan` is that we already have `@sin` and `@cos` because some targets have machine code instructions for them, but in the case that the implementation needs to go into compiler-rt, sin, cos, and tan all share a common dependency which includes a table of data. To avoid duplicating this table of data, we promote tan to become a builtin alongside sin and cos. ZIR: The tag enum is at capacity so this commit moves `field_call_bind_named` to be `extended`. I measured this as one of the least used tags in the zig codebase. Fix libc math suffix for `f32` being wrong in both stage1 and stage2. stage1: add missing libc prefix for float functions.

25 files changed, 203 insertions(+), 69 deletions(-)

doc/langref.html.in+15-1
......@@ -8026,7 +8026,7 @@ fn func(y: *i32) void {
80268026 only rounds once, and is thus more accurate.
80278027 </p>
80288028 <p>
8029 Supports Floats and Vectors of floats.
8029 Supports {#link|Floats#} and {#link|Vectors#} of floats.
80308030 </p>
80318031 {#header_close#}
80328032
......@@ -9440,6 +9440,7 @@ fn doTheTest() !void {
94409440 <a href="https://github.com/ziglang/zig/issues/4026">some float operations are not yet implemented for all float types</a>.
94419441 </p>
94429442 {#header_close#}
9443
94439444 {#header_open|@cos#}
94449445 <pre>{#syntax#}@cos(value: anytype) @TypeOf(value){#endsyntax#}</pre>
94459446 <p>
......@@ -9451,6 +9452,19 @@ fn doTheTest() !void {
94519452 <a href="https://github.com/ziglang/zig/issues/4026">some float operations are not yet implemented for all float types</a>.
94529453 </p>
94539454 {#header_close#}
9455
9456 {#header_open|@tan#}
9457 <pre>{#syntax#}@tan(value: anytype) @TypeOf(value){#endsyntax#}</pre>
9458 <p>
9459 Tangent trigonometric function on a floating point number.
9460 Uses a dedicated hardware instruction when available.
9461 </p>
9462 <p>
9463 Supports {#link|Floats#} and {#link|Vectors#} of floats, with the caveat that
9464 <a href="https://github.com/ziglang/zig/issues/4026">some float operations are not yet implemented for all float types</a>.
9465 </p>
9466 {#header_close#}
9467
94549468 {#header_open|@exp#}
94559469 <pre>{#syntax#}@exp(value: anytype) @TypeOf(value){#endsyntax#}</pre>
94569470 <p>
lib/std/math/complex/tanh.zig+2-2
......@@ -49,7 +49,7 @@ fn tanh32(z: Complex(f32)) Complex(f32) {
4949 }
5050
5151 // Kahan's algorithm
52 const t = math.tan(y);
52 const t = @tan(y);
5353 const beta = 1.0 + t * t;
5454 const s = math.sinh(x);
5555 const rho = @sqrt(1 + s * s);
......@@ -92,7 +92,7 @@ fn tanh64(z: Complex(f64)) Complex(f64) {
9292 }
9393
9494 // Kahan's algorithm
95 const t = math.tan(y);
95 const t = @tan(y);
9696 const beta = 1.0 + t * t;
9797 const s = math.sinh(x);
9898 const rho = @sqrt(1 + s * s);
src/Air.zig+6-2
......@@ -249,12 +249,15 @@ pub const Inst = struct {
249249 /// Square root of a floating point number.
250250 /// Uses the `un_op` field.
251251 sqrt,
252 /// Sine a floating point number.
252 /// Sine function on a floating point number.
253253 /// Uses the `un_op` field.
254254 sin,
255 /// Cosine a floating point number.
255 /// Cosine function on a floating point number.
256256 /// Uses the `un_op` field.
257257 cos,
258 /// Tangent function on a floating point number.
259 /// Uses the `un_op` field.
260 tan,
258261 /// Base e exponential of a floating point number.
259262 /// Uses the `un_op` field.
260263 exp,
......@@ -921,6 +924,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
921924 .sqrt,
922925 .sin,
923926 .cos,
927 .tan,
924928 .exp,
925929 .exp2,
926930 .log,
src/AstGen.zig+4-2
......@@ -2237,7 +2237,6 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
22372237 .field_call_bind,
22382238 .field_ptr_named,
22392239 .field_val_named,
2240 .field_call_bind_named,
22412240 .func,
22422241 .func_inferred,
22432242 .int,
......@@ -2329,6 +2328,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
23292328 .sqrt,
23302329 .sin,
23312330 .cos,
2331 .tan,
23322332 .exp,
23332333 .exp2,
23342334 .log,
......@@ -7259,6 +7259,7 @@ fn builtinCall(
72597259 .sqrt => return simpleUnOp(gz, scope, rl, node, .none, params[0], .sqrt),
72607260 .sin => return simpleUnOp(gz, scope, rl, node, .none, params[0], .sin),
72617261 .cos => return simpleUnOp(gz, scope, rl, node, .none, params[0], .cos),
7262 .tan => return simpleUnOp(gz, scope, rl, node, .none, params[0], .tan),
72627263 .exp => return simpleUnOp(gz, scope, rl, node, .none, params[0], .exp),
72637264 .exp2 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .exp2),
72647265 .log => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log),
......@@ -7947,7 +7948,8 @@ fn calleeExpr(
79477948 if (std.mem.eql(u8, builtin_name, "@field") and params.len == 2) {
79487949 const lhs = try expr(gz, scope, .ref, params[0]);
79497950 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
7950 return gz.addPlNode(.field_call_bind_named, node, Zir.Inst.FieldNamed{
7951 return gz.addExtendedPayload(.field_call_bind_named, Zir.Inst.FieldNamedNode{
7952 .node = gz.nodeIndexToRelative(node),
79517953 .lhs = lhs,
79527954 .field_name = field_name,
79537955 });
src/BuiltinFn.zig+8
......@@ -89,6 +89,7 @@ pub const Tag = enum {
8989 sqrt,
9090 sin,
9191 cos,
92 tan,
9293 exp,
9394 exp2,
9495 log,
......@@ -771,6 +772,13 @@ pub const list = list: {
771772 .param_count = 1,
772773 },
773774 },
775 .{
776 "@tan",
777 .{
778 .tag = .tan,
779 .param_count = 1,
780 },
781 },
774782 .{
775783 "@exp",
776784 .{
src/Liveness.zig+1
......@@ -422,6 +422,7 @@ fn analyzeInst(
422422 .sqrt,
423423 .sin,
424424 .cos,
425 .tan,
425426 .exp,
426427 .exp2,
427428 .log,
src/Sema.zig+35-35
......@@ -743,7 +743,6 @@ fn analyzeBodyInner(
743743 .field_val => try sema.zirFieldVal(block, inst),
744744 .field_val_named => try sema.zirFieldValNamed(block, inst),
745745 .field_call_bind => try sema.zirFieldCallBind(block, inst),
746 .field_call_bind_named => try sema.zirFieldCallBindNamed(block, inst),
747746 .func => try sema.zirFunc(block, inst, false),
748747 .func_inferred => try sema.zirFunc(block, inst, true),
749748 .import => try sema.zirImport(block, inst),
......@@ -855,6 +854,7 @@ fn analyzeBodyInner(
855854 .sqrt => try sema.zirUnaryMath(block, inst, .sqrt, Value.sqrt),
856855 .sin => try sema.zirUnaryMath(block, inst, .sin, Value.sin),
857856 .cos => try sema.zirUnaryMath(block, inst, .cos, Value.cos),
857 .tan => try sema.zirUnaryMath(block, inst, .tan, Value.tan),
858858 .exp => try sema.zirUnaryMath(block, inst, .exp, Value.exp),
859859 .exp2 => try sema.zirUnaryMath(block, inst, .exp2, Value.exp2),
860860 .log => try sema.zirUnaryMath(block, inst, .log, Value.log),
......@@ -910,35 +910,36 @@ fn analyzeBodyInner(
910910 const extended = datas[inst].extended;
911911 break :ext switch (extended.opcode) {
912912 // zig fmt: off
913 .func => try sema.zirFuncExtended( block, extended, inst),
914 .variable => try sema.zirVarExtended( block, extended),
915 .struct_decl => try sema.zirStructDecl( block, extended, inst),
916 .enum_decl => try sema.zirEnumDecl( block, extended),
917 .union_decl => try sema.zirUnionDecl( block, extended, inst),
918 .opaque_decl => try sema.zirOpaqueDecl( block, extended),
919 .ret_ptr => try sema.zirRetPtr( block, extended),
920 .ret_type => try sema.zirRetType( block, extended),
921 .this => try sema.zirThis( block, extended),
922 .ret_addr => try sema.zirRetAddr( block, extended),
923 .builtin_src => try sema.zirBuiltinSrc( block, extended),
924 .error_return_trace => try sema.zirErrorReturnTrace( block, extended),
925 .frame => try sema.zirFrame( block, extended),
926 .frame_address => try sema.zirFrameAddress( block, extended),
927 .alloc => try sema.zirAllocExtended( block, extended),
928 .builtin_extern => try sema.zirBuiltinExtern( block, extended),
929 .@"asm" => try sema.zirAsm( block, extended),
930 .typeof_peer => try sema.zirTypeofPeer( block, extended),
931 .compile_log => try sema.zirCompileLog( block, extended),
932 .add_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
933 .sub_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
934 .mul_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
935 .shl_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
936 .c_undef => try sema.zirCUndef( block, extended),
937 .c_include => try sema.zirCInclude( block, extended),
938 .c_define => try sema.zirCDefine( block, extended),
939 .wasm_memory_size => try sema.zirWasmMemorySize( block, extended),
940 .wasm_memory_grow => try sema.zirWasmMemoryGrow( block, extended),
941 .prefetch => try sema.zirPrefetch( block, extended),
913 .func => try sema.zirFuncExtended( block, extended, inst),
914 .variable => try sema.zirVarExtended( block, extended),
915 .struct_decl => try sema.zirStructDecl( block, extended, inst),
916 .enum_decl => try sema.zirEnumDecl( block, extended),
917 .union_decl => try sema.zirUnionDecl( block, extended, inst),
918 .opaque_decl => try sema.zirOpaqueDecl( block, extended),
919 .ret_ptr => try sema.zirRetPtr( block, extended),
920 .ret_type => try sema.zirRetType( block, extended),
921 .this => try sema.zirThis( block, extended),
922 .ret_addr => try sema.zirRetAddr( block, extended),
923 .builtin_src => try sema.zirBuiltinSrc( block, extended),
924 .error_return_trace => try sema.zirErrorReturnTrace( block, extended),
925 .frame => try sema.zirFrame( block, extended),
926 .frame_address => try sema.zirFrameAddress( block, extended),
927 .alloc => try sema.zirAllocExtended( block, extended),
928 .builtin_extern => try sema.zirBuiltinExtern( block, extended),
929 .@"asm" => try sema.zirAsm( block, extended),
930 .typeof_peer => try sema.zirTypeofPeer( block, extended),
931 .compile_log => try sema.zirCompileLog( block, extended),
932 .add_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
933 .sub_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
934 .mul_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
935 .shl_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
936 .c_undef => try sema.zirCUndef( block, extended),
937 .c_include => try sema.zirCInclude( block, extended),
938 .c_define => try sema.zirCDefine( block, extended),
939 .wasm_memory_size => try sema.zirWasmMemorySize( block, extended),
940 .wasm_memory_grow => try sema.zirWasmMemoryGrow( block, extended),
941 .prefetch => try sema.zirPrefetch( block, extended),
942 .field_call_bind_named => try sema.zirFieldCallBindNamed(block, extended),
942943 // zig fmt: on
943944 .dbg_block_begin => {
944945 dbg_block_begins += 1;
......@@ -6938,14 +6939,13 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
69386939 return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src);
69396940}
69406941
6941fn zirFieldCallBindNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
6942fn zirFieldCallBindNamed(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
69426943 const tracy = trace(@src());
69436944 defer tracy.end();
69446945
6945 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
6946 const src = inst_data.src();
6947 const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
6948 const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
6946 const extra = sema.code.extraData(Zir.Inst.FieldNamedNode, extended.operand).data;
6947 const src: LazySrcLoc = .{ .node_offset = extra.node };
6948 const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
69496949 const object_ptr = sema.resolveInst(extra.lhs);
69506950 const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name);
69516951 return sema.fieldCallBind(block, src, object_ptr, field_name, field_name_src);
src/Zir.zig+21-12
......@@ -407,15 +407,6 @@ pub const Inst = struct {
407407 /// The field name is a comptime instruction. Used by @field.
408408 /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed.
409409 field_val_named,
410 /// Given a pointer to a struct or object that contains virtual fields, returns the
411 /// named field. If there is no named field, searches in the type for a decl that
412 /// matches the field name. The decl is resolved and we ensure that it's a function
413 /// which can accept the object as the first parameter, with one pointer fixup. If
414 /// all of that works, this instruction produces a special "bound function" value
415 /// which contains both the function and the saved first parameter value.
416 /// Bound functions may only be used as the function parameter to a `call` or
417 /// `builtin_call` instruction. Any other use is invalid zir and may crash the compiler.
418 field_call_bind_named,
419410 /// Returns a function type, or a function instance, depending on whether
420411 /// the body_len is 0. Calling convention is auto.
421412 /// Uses the `pl_node` union field. `payload_index` points to a `Func`.
......@@ -797,6 +788,8 @@ pub const Inst = struct {
797788 sin,
798789 /// Implement builtin `@cos`. Uses `un_node`.
799790 cos,
791 /// Implement builtin `@tan`. Uses `un_node`.
792 tan,
800793 /// Implement builtin `@exp`. Uses `un_node`.
801794 exp,
802795 /// Implement builtin `@exp2`. Uses `un_node`.
......@@ -1069,7 +1062,6 @@ pub const Inst = struct {
10691062 .field_call_bind,
10701063 .field_ptr_named,
10711064 .field_val_named,
1072 .field_call_bind_named,
10731065 .func,
10741066 .func_inferred,
10751067 .has_decl,
......@@ -1179,6 +1171,7 @@ pub const Inst = struct {
11791171 .sqrt,
11801172 .sin,
11811173 .cos,
1174 .tan,
11821175 .exp,
11831176 .exp2,
11841177 .log,
......@@ -1358,7 +1351,6 @@ pub const Inst = struct {
13581351 .field_call_bind,
13591352 .field_ptr_named,
13601353 .field_val_named,
1361 .field_call_bind_named,
13621354 .func,
13631355 .func_inferred,
13641356 .has_decl,
......@@ -1451,6 +1443,7 @@ pub const Inst = struct {
14511443 .sqrt,
14521444 .sin,
14531445 .cos,
1446 .tan,
14541447 .exp,
14551448 .exp2,
14561449 .log,
......@@ -1607,7 +1600,6 @@ pub const Inst = struct {
16071600 .field_ptr_named = .pl_node,
16081601 .field_val_named = .pl_node,
16091602 .field_call_bind = .pl_node,
1610 .field_call_bind_named = .pl_node,
16111603 .func = .pl_node,
16121604 .func_inferred = .pl_node,
16131605 .import = .str_tok,
......@@ -1713,6 +1705,7 @@ pub const Inst = struct {
17131705 .sqrt = .un_node,
17141706 .sin = .un_node,
17151707 .cos = .un_node,
1708 .tan = .un_node,
17161709 .exp = .un_node,
17171710 .exp2 = .un_node,
17181711 .log = .un_node,
......@@ -1928,6 +1921,16 @@ pub const Inst = struct {
19281921 dbg_block_begin,
19291922 /// Marks the end of a semantic scope for debug info variables.
19301923 dbg_block_end,
1924 /// Given a pointer to a struct or object that contains virtual fields, returns the
1925 /// named field. If there is no named field, searches in the type for a decl that
1926 /// matches the field name. The decl is resolved and we ensure that it's a function
1927 /// which can accept the object as the first parameter, with one pointer fixup. If
1928 /// all of that works, this instruction produces a special "bound function" value
1929 /// which contains both the function and the saved first parameter value.
1930 /// Bound functions may only be used as the function parameter to a `call` or
1931 /// `builtin_call` instruction. Any other use is invalid zir and may crash the compiler.
1932 /// Uses `pl_node` field. The AST node is the `@field` builtin. Payload is FieldNamedNode.
1933 field_call_bind_named,
19311934
19321935 pub const InstData = struct {
19331936 opcode: Extended,
......@@ -2963,6 +2966,12 @@ pub const Inst = struct {
29632966 field_name: Ref,
29642967 };
29652968
2969 pub const FieldNamedNode = struct {
2970 node: i32,
2971 lhs: Ref,
2972 field_name: Ref,
2973 };
2974
29662975 pub const As = struct {
29672976 dest_type: Ref,
29682977 operand: Ref,
src/arch/aarch64/CodeGen.zig+1
......@@ -533,6 +533,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
533533 .sqrt,
534534 .sin,
535535 .cos,
536 .tan,
536537 .exp,
537538 .exp2,
538539 .log,
src/arch/arm/CodeGen.zig+1
......@@ -571,6 +571,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
571571 .sqrt,
572572 .sin,
573573 .cos,
574 .tan,
574575 .exp,
575576 .exp2,
576577 .log,
src/arch/riscv64/CodeGen.zig+1
......@@ -500,6 +500,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
500500 .sqrt,
501501 .sin,
502502 .cos,
503 .tan,
503504 .exp,
504505 .exp2,
505506 .log,
src/arch/sparcv9/CodeGen.zig+1
......@@ -451,6 +451,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
451451 .sqrt,
452452 .sin,
453453 .cos,
454 .tan,
454455 .exp,
455456 .exp2,
456457 .log,
src/arch/wasm/CodeGen.zig+1
......@@ -1559,6 +1559,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
15591559 .sqrt,
15601560 .sin,
15611561 .cos,
1562 .tan,
15621563 .exp,
15631564 .exp2,
15641565 .log,
src/arch/x86_64/CodeGen.zig+1
......@@ -656,6 +656,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
656656 .sqrt,
657657 .sin,
658658 .cos,
659 .tan,
659660 .exp,
660661 .exp2,
661662 .log,
src/codegen/c.zig+1
......@@ -1749,6 +1749,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
17491749 .sqrt,
17501750 .sin,
17511751 .cos,
1752 .tan,
17521753 .exp,
17531754 .exp2,
17541755 .log,
src/codegen/llvm.zig+5-2
......@@ -3521,6 +3521,7 @@ pub const FuncGen = struct {
35213521 .sqrt => try self.airUnaryOp(inst, .sqrt),
35223522 .sin => try self.airUnaryOp(inst, .sin),
35233523 .cos => try self.airUnaryOp(inst, .cos),
3524 .tan => try self.airUnaryOp(inst, .tan),
35243525 .exp => try self.airUnaryOp(inst, .exp),
35253526 .exp2 => try self.airUnaryOp(inst, .exp2),
35263527 .log => try self.airUnaryOp(inst, .log),
......@@ -5553,7 +5554,7 @@ pub const FuncGen = struct {
55535554 fn libcFloatSuffix(float_bits: u16) []const u8 {
55545555 return switch (float_bits) {
55555556 16 => "h", // Non-standard
5556 32 => "s",
5557 32 => "f",
55575558 64 => "",
55585559 80 => "x", // Non-standard
55595560 128 => "q", // Non-standard (mimics convention in GCC libquadmath)
......@@ -5661,6 +5662,7 @@ pub const FuncGen = struct {
56615662 sin,
56625663 sqrt,
56635664 sub,
5665 tan,
56645666 trunc,
56655667 };
56665668
......@@ -5684,7 +5686,7 @@ pub const FuncGen = struct {
56845686 const llvm_ty = try self.dg.llvmType(ty);
56855687 const scalar_llvm_ty = try self.dg.llvmType(scalar_ty);
56865688
5687 const intrinsics_allowed = intrinsicsAllowed(scalar_ty, target);
5689 const intrinsics_allowed = op != .tan and intrinsicsAllowed(scalar_ty, target);
56885690 var fn_name_buf: [64]u8 = undefined;
56895691 const strat: FloatOpStrat = if (intrinsics_allowed) switch (op) {
56905692 // Some operations are dedicated LLVM instructions, not available as intrinsics
......@@ -5720,6 +5722,7 @@ pub const FuncGen = struct {
57205722 .round,
57215723 .sin,
57225724 .sqrt,
5725 .tan,
57235726 .trunc,
57245727 => FloatOpStrat{
57255728 .libc = std.fmt.bufPrintZ(&fn_name_buf, "{s}{s}{s}", .{
src/print_air.zig+1
......@@ -158,6 +158,7 @@ const Writer = struct {
158158 .sqrt,
159159 .sin,
160160 .cos,
161 .tan,
161162 .exp,
162163 .exp2,
163164 .log,
src/print_zir.zig+11-1
......@@ -207,6 +207,7 @@ const Writer = struct {
207207 .sqrt,
208208 .sin,
209209 .cos,
210 .tan,
210211 .exp,
211212 .exp2,
212213 .log,
......@@ -400,7 +401,6 @@ const Writer = struct {
400401
401402 .field_ptr_named,
402403 .field_val_named,
403 .field_call_bind_named,
404404 => try self.writePlNodeFieldNamed(stream, inst),
405405
406406 .as_node => try self.writeAs(stream, inst),
......@@ -509,6 +509,16 @@ const Writer = struct {
509509 try stream.writeAll(")) ");
510510 try self.writeSrc(stream, src);
511511 },
512
513 .field_call_bind_named => {
514 const extra = self.code.extraData(Zir.Inst.FieldNamedNode, extended.operand).data;
515 const src: LazySrcLoc = .{ .node_offset = extra.node };
516 try self.writeInstRef(stream, extra.lhs);
517 try stream.writeAll(", ");
518 try self.writeInstRef(stream, extra.field_name);
519 try stream.writeAll(") ");
520 try self.writeSrc(stream, src);
521 },
512522 }
513523 }
514524
src/stage1/all_types.hpp+1
......@@ -1768,6 +1768,7 @@ enum BuiltinFnId {
17681768 BuiltinFnIdSqrt,
17691769 BuiltinFnIdSin,
17701770 BuiltinFnIdCos,
1771 BuiltinFnIdTan,
17711772 BuiltinFnIdExp,
17721773 BuiltinFnIdExp2,
17731774 BuiltinFnIdLog,
src/stage1/analyze.cpp+2
......@@ -10383,6 +10383,8 @@ const char *float_un_op_to_name(BuiltinFnId op) {
1038310383 return "sin";
1038410384 case BuiltinFnIdCos:
1038510385 return "cos";
10386 case BuiltinFnIdTan:
10387 return "tan";
1038610388 case BuiltinFnIdExp:
1038710389 return "exp";
1038810390 case BuiltinFnIdExp2:
src/stage1/astgen.cpp+1
......@@ -4497,6 +4497,7 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast
44974497 case BuiltinFnIdSqrt:
44984498 case BuiltinFnIdSin:
44994499 case BuiltinFnIdCos:
4500 case BuiltinFnIdTan:
45004501 case BuiltinFnIdExp:
45014502 case BuiltinFnIdExp2:
45024503 case BuiltinFnIdLog:
src/stage1/codegen.cpp+32-9
......@@ -1629,11 +1629,28 @@ static const char *get_compiler_rt_type_abbrev(ZigType *type) {
16291629 }
16301630}
16311631
1632static const char *get_math_h_type_abbrev(CodeGen *g, ZigType *float_type) {
1632static const char *libc_float_prefix(CodeGen *g, ZigType *float_type) {
1633 if (float_type == g->builtin_types.entry_f16)
1634 return "__";
1635 else if (float_type == g->builtin_types.entry_f32)
1636 return "";
1637 else if (float_type == g->builtin_types.entry_f64)
1638 return "";
1639 else if (float_type == g->builtin_types.entry_f80)
1640 return "__";
1641 else if (float_type == g->builtin_types.entry_c_longdouble)
1642 return "l";
1643 else if (float_type == g->builtin_types.entry_f128)
1644 return "";
1645 else
1646 zig_unreachable();
1647}
1648
1649static const char *libc_float_suffix(CodeGen *g, ZigType *float_type) {
16331650 if (float_type == g->builtin_types.entry_f16)
16341651 return "h"; // Non-standard
16351652 else if (float_type == g->builtin_types.entry_f32)
1636 return "s";
1653 return "f";
16371654 else if (float_type == g->builtin_types.entry_f64)
16381655 return "";
16391656 else if (float_type == g->builtin_types.entry_f80)
......@@ -2992,10 +3009,12 @@ static LLVMValueRef get_soft_float_fn(CodeGen *g, const char *name, int param_co
29923009
29933010static LLVMValueRef gen_soft_float_un_op(CodeGen *g, LLVMValueRef op, ZigType *operand_type, BuiltinFnId op_id) {
29943011 uint32_t vector_len = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.len : 0;
3012 ZigType *scalar_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type;
29953013
29963014 char fn_name[64];
2997 sprintf(fn_name, "%s%s", float_un_op_to_name(op_id), get_math_h_type_abbrev(g, operand_type));
2998 LLVMValueRef func_ref = get_soft_float_fn(g, fn_name, 1, operand_type->llvm_type, operand_type->llvm_type);
3015 sprintf(fn_name, "%s%s%s", libc_float_prefix(g, scalar_type),
3016 float_un_op_to_name(op_id), libc_float_suffix(g, scalar_type));
3017 LLVMValueRef func_ref = get_soft_float_fn(g, fn_name, 1, scalar_type->llvm_type, scalar_type->llvm_type);
29993018
30003019 LLVMValueRef result;
30013020 if (vector_len == 0) {
......@@ -3018,7 +3037,9 @@ static LLVMValueRef gen_float_un_op(CodeGen *g, LLVMValueRef operand, ZigType *o
30183037 assert(operand_type->id == ZigTypeIdFloat || operand_type->id == ZigTypeIdVector);
30193038 ZigType *elem_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type;
30203039 if ((elem_type == g->builtin_types.entry_f80 && !target_has_f80(g->zig_target)) ||
3021 (elem_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target))) {
3040 (elem_type == g->builtin_types.entry_f128 && !target_long_double_is_f128(g->zig_target)) ||
3041 op == BuiltinFnIdTan)
3042 {
30223043 return gen_soft_float_un_op(g, operand, operand_type, op);
30233044 }
30243045 LLVMValueRef float_op_fn = get_float_fn(g, operand_type, ZigLLVMFnIdFloatOp, op);
......@@ -3466,7 +3487,8 @@ static LLVMValueRef gen_soft_float_bin_op(CodeGen *g, LLVMValueRef op1_value, LL
34663487 int param_count = 2;
34673488
34683489 const char *compiler_rt_type_abbrev = get_compiler_rt_type_abbrev(operand_type);
3469 const char *math_h_type_abbrev = get_math_h_type_abbrev(g, operand_type);
3490 const char *math_float_prefix = libc_float_prefix(g, operand_type);
3491 const char *math_float_suffix = libc_float_suffix(g, operand_type);
34703492
34713493 char fn_name[64];
34723494 Icmp res_icmp = NONE;
......@@ -3523,10 +3545,10 @@ static LLVMValueRef gen_soft_float_bin_op(CodeGen *g, LLVMValueRef op1_value, LL
35233545 res_icmp = EQ_ONE;
35243546 break;
35253547 case IrBinOpMaximum:
3526 sprintf(fn_name, "fmax%s", math_h_type_abbrev);
3548 sprintf(fn_name, "%sfmax%s", math_float_prefix, math_float_suffix);
35273549 break;
35283550 case IrBinOpMinimum:
3529 sprintf(fn_name, "fmin%s", math_h_type_abbrev);
3551 sprintf(fn_name, "%sfmin%s", math_float_prefix, math_float_suffix);
35303552 break;
35313553 case IrBinOpMult:
35323554 sprintf(fn_name, "__mul%sf3", compiler_rt_type_abbrev);
......@@ -3545,7 +3567,7 @@ static LLVMValueRef gen_soft_float_bin_op(CodeGen *g, LLVMValueRef op1_value, LL
35453567 break;
35463568 case IrBinOpRemRem:
35473569 case IrBinOpRemMod:
3548 sprintf(fn_name, "fmod%s", math_h_type_abbrev);
3570 sprintf(fn_name, "%sfmod%s", math_float_prefix, math_float_suffix);
35493571 break;
35503572 default:
35513573 zig_unreachable();
......@@ -9810,6 +9832,7 @@ static void define_builtin_fns(CodeGen *g) {
98109832 create_builtin_fn(g, BuiltinFnIdSqrt, "sqrt", 1);
98119833 create_builtin_fn(g, BuiltinFnIdSin, "sin", 1);
98129834 create_builtin_fn(g, BuiltinFnIdCos, "cos", 1);
9835 create_builtin_fn(g, BuiltinFnIdTan, "tan", 1);
98139836 create_builtin_fn(g, BuiltinFnIdExp, "exp", 1);
98149837 create_builtin_fn(g, BuiltinFnIdExp2, "exp2", 1);
98159838 create_builtin_fn(g, BuiltinFnIdLog, "log", 1);
src/stage1/ir.cpp+11
......@@ -24132,6 +24132,9 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, Scope *scope, AstNode *source_
2413224132 case BuiltinFnIdCos:
2413324133 out_val->data.x_f16 = zig_double_to_f16(cos(zig_f16_to_double(op->data.x_f16)));
2413424134 break;
24135 case BuiltinFnIdTan:
24136 out_val->data.x_f16 = zig_double_to_f16(tan(zig_f16_to_double(op->data.x_f16)));
24137 break;
2413524138 case BuiltinFnIdExp:
2413624139 out_val->data.x_f16 = zig_double_to_f16(exp(zig_f16_to_double(op->data.x_f16)));
2413724140 break;
......@@ -24181,6 +24184,9 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, Scope *scope, AstNode *source_
2418124184 case BuiltinFnIdCos:
2418224185 out_val->data.x_f32 = cosf(op->data.x_f32);
2418324186 break;
24187 case BuiltinFnIdTan:
24188 out_val->data.x_f32 = tanf(op->data.x_f32);
24189 break;
2418424190 case BuiltinFnIdExp:
2418524191 out_val->data.x_f32 = expf(op->data.x_f32);
2418624192 break;
......@@ -24230,6 +24236,9 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, Scope *scope, AstNode *source_
2423024236 case BuiltinFnIdCos:
2423124237 out_val->data.x_f64 = cos(op->data.x_f64);
2423224238 break;
24239 case BuiltinFnIdTan:
24240 out_val->data.x_f64 = tan(op->data.x_f64);
24241 break;
2423324242 case BuiltinFnIdExp:
2423424243 out_val->data.x_f64 = exp(op->data.x_f64);
2423524244 break;
......@@ -24293,6 +24302,7 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, Scope *scope, AstNode *source_
2429324302 case BuiltinFnIdNearbyInt:
2429424303 case BuiltinFnIdSin:
2429524304 case BuiltinFnIdCos:
24305 case BuiltinFnIdTan:
2429624306 case BuiltinFnIdExp:
2429724307 case BuiltinFnIdExp2:
2429824308 case BuiltinFnIdLog:
......@@ -24337,6 +24347,7 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, Scope *scope, AstNode *source_
2433724347 case BuiltinFnIdNearbyInt:
2433824348 case BuiltinFnIdSin:
2433924349 case BuiltinFnIdCos:
24350 case BuiltinFnIdTan:
2434024351 case BuiltinFnIdExp:
2434124352 case BuiltinFnIdExp2:
2434224353 case BuiltinFnIdLog:
src/value.zig+38
......@@ -4473,6 +4473,44 @@ pub const Value = extern union {
44734473 }
44744474 }
44754475
4476 pub fn tan(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
4477 if (float_type.zigTypeTag() == .Vector) {
4478 const result_data = try arena.alloc(Value, float_type.vectorLen());
4479 for (result_data) |*scalar, i| {
4480 scalar.* = try tanScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
4481 }
4482 return Value.Tag.aggregate.create(arena, result_data);
4483 }
4484 return tanScalar(val, float_type, arena, target);
4485 }
4486
4487 pub fn tanScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
4488 switch (float_type.floatBits(target)) {
4489 16 => {
4490 const f = val.toFloat(f16);
4491 return Value.Tag.float_16.create(arena, @tan(f));
4492 },
4493 32 => {
4494 const f = val.toFloat(f32);
4495 return Value.Tag.float_32.create(arena, @tan(f));
4496 },
4497 64 => {
4498 const f = val.toFloat(f64);
4499 return Value.Tag.float_64.create(arena, @tan(f));
4500 },
4501 80 => {
4502 const f = val.toFloat(f80);
4503 return Value.Tag.float_80.create(arena, @tan(f));
4504 },
4505 128 => {
4506 const f = val.toFloat(f128);
4507 return Value.Tag.float_128.create(arena, @tan(f));
4508 },
4509 else => unreachable,
4510 }
4511 }
4512
4513
44764514 pub fn exp(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
44774515 if (float_type.zigTypeTag() == .Vector) {
44784516 const result_data = try arena.alloc(Value, float_type.vectorLen());
test/behavior/bugs/920.zig+2-3
......@@ -1,5 +1,4 @@
11const std = @import("std");
2const math = std.math;
32const Random = std.rand.Random;
43
54const ZigTable = struct {
......@@ -40,10 +39,10 @@ const norm_r = 3.6541528853610088;
4039const norm_v = 0.00492867323399;
4140
4241fn norm_f(x: f64) f64 {
43 return math.exp(-x * x / 2.0);
42 return @exp(-x * x / 2.0);
4443}
4544fn norm_f_inv(y: f64) f64 {
46 return math.sqrt(-2.0 * math.ln(y));
45 return @sqrt(-2.0 * @log(y));
4746}
4847fn norm_zero_case(random: *Random, u: f64) f64 {
4948 _ = random;