| author | |
| committer | |
| log | 09f1d62bdfb5794534b21d1cd9dafc4822697d60 |
| tree | 437f6c19a6f0f16ef29fb91513176bb8aa0c91f0 |
| parent | c4eaff6665132287d05272bef8890e4607ff017c |
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 { |
| 8026 | 8026 | only rounds once, and is thus more accurate. |
| 8027 | 8027 | </p> |
| 8028 | 8028 | <p> |
| 8029 | Supports Floats and Vectors of floats. | |
| 8029 | Supports {#link|Floats#} and {#link|Vectors#} of floats. | |
| 8030 | 8030 | </p> |
| 8031 | 8031 | {#header_close#} |
| 8032 | 8032 | |
| ... | ... | @@ -9440,6 +9440,7 @@ fn doTheTest() !void { |
| 9440 | 9440 | <a href="https://github.com/ziglang/zig/issues/4026">some float operations are not yet implemented for all float types</a>. |
| 9441 | 9441 | </p> |
| 9442 | 9442 | {#header_close#} |
| 9443 | ||
| 9443 | 9444 | {#header_open|@cos#} |
| 9444 | 9445 | <pre>{#syntax#}@cos(value: anytype) @TypeOf(value){#endsyntax#}</pre> |
| 9445 | 9446 | <p> |
| ... | ... | @@ -9451,6 +9452,19 @@ fn doTheTest() !void { |
| 9451 | 9452 | <a href="https://github.com/ziglang/zig/issues/4026">some float operations are not yet implemented for all float types</a>. |
| 9452 | 9453 | </p> |
| 9453 | 9454 | {#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 | ||
| 9454 | 9468 | {#header_open|@exp#} |
| 9455 | 9469 | <pre>{#syntax#}@exp(value: anytype) @TypeOf(value){#endsyntax#}</pre> |
| 9456 | 9470 | <p> |
lib/std/math/complex/tanh.zig+2-2| ... | ... | @@ -49,7 +49,7 @@ fn tanh32(z: Complex(f32)) Complex(f32) { |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | 51 | // Kahan's algorithm |
| 52 | const t = math.tan(y); | |
| 52 | const t = @tan(y); | |
| 53 | 53 | const beta = 1.0 + t * t; |
| 54 | 54 | const s = math.sinh(x); |
| 55 | 55 | const rho = @sqrt(1 + s * s); |
| ... | ... | @@ -92,7 +92,7 @@ fn tanh64(z: Complex(f64)) Complex(f64) { |
| 92 | 92 | } |
| 93 | 93 | |
| 94 | 94 | // Kahan's algorithm |
| 95 | const t = math.tan(y); | |
| 95 | const t = @tan(y); | |
| 96 | 96 | const beta = 1.0 + t * t; |
| 97 | 97 | const s = math.sinh(x); |
| 98 | 98 | const rho = @sqrt(1 + s * s); |
src/Air.zig+6-2| ... | ... | @@ -249,12 +249,15 @@ pub const Inst = struct { |
| 249 | 249 | /// Square root of a floating point number. |
| 250 | 250 | /// Uses the `un_op` field. |
| 251 | 251 | sqrt, |
| 252 | /// Sine a floating point number. | |
| 252 | /// Sine function on a floating point number. | |
| 253 | 253 | /// Uses the `un_op` field. |
| 254 | 254 | sin, |
| 255 | /// Cosine a floating point number. | |
| 255 | /// Cosine function on a floating point number. | |
| 256 | 256 | /// Uses the `un_op` field. |
| 257 | 257 | cos, |
| 258 | /// Tangent function on a floating point number. | |
| 259 | /// Uses the `un_op` field. | |
| 260 | tan, | |
| 258 | 261 | /// Base e exponential of a floating point number. |
| 259 | 262 | /// Uses the `un_op` field. |
| 260 | 263 | exp, |
| ... | ... | @@ -921,6 +924,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 921 | 924 | .sqrt, |
| 922 | 925 | .sin, |
| 923 | 926 | .cos, |
| 927 | .tan, | |
| 924 | 928 | .exp, |
| 925 | 929 | .exp2, |
| 926 | 930 | .log, |
src/AstGen.zig+4-2| ... | ... | @@ -2237,7 +2237,6 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner |
| 2237 | 2237 | .field_call_bind, |
| 2238 | 2238 | .field_ptr_named, |
| 2239 | 2239 | .field_val_named, |
| 2240 | .field_call_bind_named, | |
| 2241 | 2240 | .func, |
| 2242 | 2241 | .func_inferred, |
| 2243 | 2242 | .int, |
| ... | ... | @@ -2329,6 +2328,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner |
| 2329 | 2328 | .sqrt, |
| 2330 | 2329 | .sin, |
| 2331 | 2330 | .cos, |
| 2331 | .tan, | |
| 2332 | 2332 | .exp, |
| 2333 | 2333 | .exp2, |
| 2334 | 2334 | .log, |
| ... | ... | @@ -7259,6 +7259,7 @@ fn builtinCall( |
| 7259 | 7259 | .sqrt => return simpleUnOp(gz, scope, rl, node, .none, params[0], .sqrt), |
| 7260 | 7260 | .sin => return simpleUnOp(gz, scope, rl, node, .none, params[0], .sin), |
| 7261 | 7261 | .cos => return simpleUnOp(gz, scope, rl, node, .none, params[0], .cos), |
| 7262 | .tan => return simpleUnOp(gz, scope, rl, node, .none, params[0], .tan), | |
| 7262 | 7263 | .exp => return simpleUnOp(gz, scope, rl, node, .none, params[0], .exp), |
| 7263 | 7264 | .exp2 => return simpleUnOp(gz, scope, rl, node, .none, params[0], .exp2), |
| 7264 | 7265 | .log => return simpleUnOp(gz, scope, rl, node, .none, params[0], .log), |
| ... | ... | @@ -7947,7 +7948,8 @@ fn calleeExpr( |
| 7947 | 7948 | if (std.mem.eql(u8, builtin_name, "@field") and params.len == 2) { |
| 7948 | 7949 | const lhs = try expr(gz, scope, .ref, params[0]); |
| 7949 | 7950 | 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), | |
| 7951 | 7953 | .lhs = lhs, |
| 7952 | 7954 | .field_name = field_name, |
| 7953 | 7955 | }); |
src/BuiltinFn.zig+8| ... | ... | @@ -89,6 +89,7 @@ pub const Tag = enum { |
| 89 | 89 | sqrt, |
| 90 | 90 | sin, |
| 91 | 91 | cos, |
| 92 | tan, | |
| 92 | 93 | exp, |
| 93 | 94 | exp2, |
| 94 | 95 | log, |
| ... | ... | @@ -771,6 +772,13 @@ pub const list = list: { |
| 771 | 772 | .param_count = 1, |
| 772 | 773 | }, |
| 773 | 774 | }, |
| 775 | .{ | |
| 776 | "@tan", | |
| 777 | .{ | |
| 778 | .tag = .tan, | |
| 779 | .param_count = 1, | |
| 780 | }, | |
| 781 | }, | |
| 774 | 782 | .{ |
| 775 | 783 | "@exp", |
| 776 | 784 | .{ |
src/Liveness.zig+1| ... | ... | @@ -422,6 +422,7 @@ fn analyzeInst( |
| 422 | 422 | .sqrt, |
| 423 | 423 | .sin, |
| 424 | 424 | .cos, |
| 425 | .tan, | |
| 425 | 426 | .exp, |
| 426 | 427 | .exp2, |
| 427 | 428 | .log, |
src/Sema.zig+35-35| ... | ... | @@ -743,7 +743,6 @@ fn analyzeBodyInner( |
| 743 | 743 | .field_val => try sema.zirFieldVal(block, inst), |
| 744 | 744 | .field_val_named => try sema.zirFieldValNamed(block, inst), |
| 745 | 745 | .field_call_bind => try sema.zirFieldCallBind(block, inst), |
| 746 | .field_call_bind_named => try sema.zirFieldCallBindNamed(block, inst), | |
| 747 | 746 | .func => try sema.zirFunc(block, inst, false), |
| 748 | 747 | .func_inferred => try sema.zirFunc(block, inst, true), |
| 749 | 748 | .import => try sema.zirImport(block, inst), |
| ... | ... | @@ -855,6 +854,7 @@ fn analyzeBodyInner( |
| 855 | 854 | .sqrt => try sema.zirUnaryMath(block, inst, .sqrt, Value.sqrt), |
| 856 | 855 | .sin => try sema.zirUnaryMath(block, inst, .sin, Value.sin), |
| 857 | 856 | .cos => try sema.zirUnaryMath(block, inst, .cos, Value.cos), |
| 857 | .tan => try sema.zirUnaryMath(block, inst, .tan, Value.tan), | |
| 858 | 858 | .exp => try sema.zirUnaryMath(block, inst, .exp, Value.exp), |
| 859 | 859 | .exp2 => try sema.zirUnaryMath(block, inst, .exp2, Value.exp2), |
| 860 | 860 | .log => try sema.zirUnaryMath(block, inst, .log, Value.log), |
| ... | ... | @@ -910,35 +910,36 @@ fn analyzeBodyInner( |
| 910 | 910 | const extended = datas[inst].extended; |
| 911 | 911 | break :ext switch (extended.opcode) { |
| 912 | 912 | // 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), | |
| 942 | 943 | // zig fmt: on |
| 943 | 944 | .dbg_block_begin => { |
| 944 | 945 | dbg_block_begins += 1; |
| ... | ... | @@ -6938,14 +6939,13 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 6938 | 6939 | return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src); |
| 6939 | 6940 | } |
| 6940 | 6941 | |
| 6941 | fn zirFieldCallBindNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 6942 | fn zirFieldCallBindNamed(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { | |
| 6942 | 6943 | const tracy = trace(@src()); |
| 6943 | 6944 | defer tracy.end(); |
| 6944 | 6945 | |
| 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 }; | |
| 6949 | 6949 | const object_ptr = sema.resolveInst(extra.lhs); |
| 6950 | 6950 | const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name); |
| 6951 | 6951 | 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 { |
| 407 | 407 | /// The field name is a comptime instruction. Used by @field. |
| 408 | 408 | /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed. |
| 409 | 409 | 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, | |
| 419 | 410 | /// Returns a function type, or a function instance, depending on whether |
| 420 | 411 | /// the body_len is 0. Calling convention is auto. |
| 421 | 412 | /// Uses the `pl_node` union field. `payload_index` points to a `Func`. |
| ... | ... | @@ -797,6 +788,8 @@ pub const Inst = struct { |
| 797 | 788 | sin, |
| 798 | 789 | /// Implement builtin `@cos`. Uses `un_node`. |
| 799 | 790 | cos, |
| 791 | /// Implement builtin `@tan`. Uses `un_node`. | |
| 792 | tan, | |
| 800 | 793 | /// Implement builtin `@exp`. Uses `un_node`. |
| 801 | 794 | exp, |
| 802 | 795 | /// Implement builtin `@exp2`. Uses `un_node`. |
| ... | ... | @@ -1069,7 +1062,6 @@ pub const Inst = struct { |
| 1069 | 1062 | .field_call_bind, |
| 1070 | 1063 | .field_ptr_named, |
| 1071 | 1064 | .field_val_named, |
| 1072 | .field_call_bind_named, | |
| 1073 | 1065 | .func, |
| 1074 | 1066 | .func_inferred, |
| 1075 | 1067 | .has_decl, |
| ... | ... | @@ -1179,6 +1171,7 @@ pub const Inst = struct { |
| 1179 | 1171 | .sqrt, |
| 1180 | 1172 | .sin, |
| 1181 | 1173 | .cos, |
| 1174 | .tan, | |
| 1182 | 1175 | .exp, |
| 1183 | 1176 | .exp2, |
| 1184 | 1177 | .log, |
| ... | ... | @@ -1358,7 +1351,6 @@ pub const Inst = struct { |
| 1358 | 1351 | .field_call_bind, |
| 1359 | 1352 | .field_ptr_named, |
| 1360 | 1353 | .field_val_named, |
| 1361 | .field_call_bind_named, | |
| 1362 | 1354 | .func, |
| 1363 | 1355 | .func_inferred, |
| 1364 | 1356 | .has_decl, |
| ... | ... | @@ -1451,6 +1443,7 @@ pub const Inst = struct { |
| 1451 | 1443 | .sqrt, |
| 1452 | 1444 | .sin, |
| 1453 | 1445 | .cos, |
| 1446 | .tan, | |
| 1454 | 1447 | .exp, |
| 1455 | 1448 | .exp2, |
| 1456 | 1449 | .log, |
| ... | ... | @@ -1607,7 +1600,6 @@ pub const Inst = struct { |
| 1607 | 1600 | .field_ptr_named = .pl_node, |
| 1608 | 1601 | .field_val_named = .pl_node, |
| 1609 | 1602 | .field_call_bind = .pl_node, |
| 1610 | .field_call_bind_named = .pl_node, | |
| 1611 | 1603 | .func = .pl_node, |
| 1612 | 1604 | .func_inferred = .pl_node, |
| 1613 | 1605 | .import = .str_tok, |
| ... | ... | @@ -1713,6 +1705,7 @@ pub const Inst = struct { |
| 1713 | 1705 | .sqrt = .un_node, |
| 1714 | 1706 | .sin = .un_node, |
| 1715 | 1707 | .cos = .un_node, |
| 1708 | .tan = .un_node, | |
| 1716 | 1709 | .exp = .un_node, |
| 1717 | 1710 | .exp2 = .un_node, |
| 1718 | 1711 | .log = .un_node, |
| ... | ... | @@ -1928,6 +1921,16 @@ pub const Inst = struct { |
| 1928 | 1921 | dbg_block_begin, |
| 1929 | 1922 | /// Marks the end of a semantic scope for debug info variables. |
| 1930 | 1923 | 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, | |
| 1931 | 1934 | |
| 1932 | 1935 | pub const InstData = struct { |
| 1933 | 1936 | opcode: Extended, |
| ... | ... | @@ -2963,6 +2966,12 @@ pub const Inst = struct { |
| 2963 | 2966 | field_name: Ref, |
| 2964 | 2967 | }; |
| 2965 | 2968 | |
| 2969 | pub const FieldNamedNode = struct { | |
| 2970 | node: i32, | |
| 2971 | lhs: Ref, | |
| 2972 | field_name: Ref, | |
| 2973 | }; | |
| 2974 | ||
| 2966 | 2975 | pub const As = struct { |
| 2967 | 2976 | dest_type: Ref, |
| 2968 | 2977 | operand: Ref, |
src/arch/aarch64/CodeGen.zig+1| ... | ... | @@ -533,6 +533,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 533 | 533 | .sqrt, |
| 534 | 534 | .sin, |
| 535 | 535 | .cos, |
| 536 | .tan, | |
| 536 | 537 | .exp, |
| 537 | 538 | .exp2, |
| 538 | 539 | .log, |
src/arch/arm/CodeGen.zig+1| ... | ... | @@ -571,6 +571,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 571 | 571 | .sqrt, |
| 572 | 572 | .sin, |
| 573 | 573 | .cos, |
| 574 | .tan, | |
| 574 | 575 | .exp, |
| 575 | 576 | .exp2, |
| 576 | 577 | .log, |
src/arch/riscv64/CodeGen.zig+1| ... | ... | @@ -500,6 +500,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 500 | 500 | .sqrt, |
| 501 | 501 | .sin, |
| 502 | 502 | .cos, |
| 503 | .tan, | |
| 503 | 504 | .exp, |
| 504 | 505 | .exp2, |
| 505 | 506 | .log, |
src/arch/sparcv9/CodeGen.zig+1| ... | ... | @@ -451,6 +451,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 451 | 451 | .sqrt, |
| 452 | 452 | .sin, |
| 453 | 453 | .cos, |
| 454 | .tan, | |
| 454 | 455 | .exp, |
| 455 | 456 | .exp2, |
| 456 | 457 | .log, |
src/arch/wasm/CodeGen.zig+1| ... | ... | @@ -1559,6 +1559,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1559 | 1559 | .sqrt, |
| 1560 | 1560 | .sin, |
| 1561 | 1561 | .cos, |
| 1562 | .tan, | |
| 1562 | 1563 | .exp, |
| 1563 | 1564 | .exp2, |
| 1564 | 1565 | .log, |
src/arch/x86_64/CodeGen.zig+1| ... | ... | @@ -656,6 +656,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 656 | 656 | .sqrt, |
| 657 | 657 | .sin, |
| 658 | 658 | .cos, |
| 659 | .tan, | |
| 659 | 660 | .exp, |
| 660 | 661 | .exp2, |
| 661 | 662 | .log, |
src/codegen/c.zig+1| ... | ... | @@ -1749,6 +1749,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1749 | 1749 | .sqrt, |
| 1750 | 1750 | .sin, |
| 1751 | 1751 | .cos, |
| 1752 | .tan, | |
| 1752 | 1753 | .exp, |
| 1753 | 1754 | .exp2, |
| 1754 | 1755 | .log, |
src/codegen/llvm.zig+5-2| ... | ... | @@ -3521,6 +3521,7 @@ pub const FuncGen = struct { |
| 3521 | 3521 | .sqrt => try self.airUnaryOp(inst, .sqrt), |
| 3522 | 3522 | .sin => try self.airUnaryOp(inst, .sin), |
| 3523 | 3523 | .cos => try self.airUnaryOp(inst, .cos), |
| 3524 | .tan => try self.airUnaryOp(inst, .tan), | |
| 3524 | 3525 | .exp => try self.airUnaryOp(inst, .exp), |
| 3525 | 3526 | .exp2 => try self.airUnaryOp(inst, .exp2), |
| 3526 | 3527 | .log => try self.airUnaryOp(inst, .log), |
| ... | ... | @@ -5553,7 +5554,7 @@ pub const FuncGen = struct { |
| 5553 | 5554 | fn libcFloatSuffix(float_bits: u16) []const u8 { |
| 5554 | 5555 | return switch (float_bits) { |
| 5555 | 5556 | 16 => "h", // Non-standard |
| 5556 | 32 => "s", | |
| 5557 | 32 => "f", | |
| 5557 | 5558 | 64 => "", |
| 5558 | 5559 | 80 => "x", // Non-standard |
| 5559 | 5560 | 128 => "q", // Non-standard (mimics convention in GCC libquadmath) |
| ... | ... | @@ -5661,6 +5662,7 @@ pub const FuncGen = struct { |
| 5661 | 5662 | sin, |
| 5662 | 5663 | sqrt, |
| 5663 | 5664 | sub, |
| 5665 | tan, | |
| 5664 | 5666 | trunc, |
| 5665 | 5667 | }; |
| 5666 | 5668 | |
| ... | ... | @@ -5684,7 +5686,7 @@ pub const FuncGen = struct { |
| 5684 | 5686 | const llvm_ty = try self.dg.llvmType(ty); |
| 5685 | 5687 | const scalar_llvm_ty = try self.dg.llvmType(scalar_ty); |
| 5686 | 5688 | |
| 5687 | const intrinsics_allowed = intrinsicsAllowed(scalar_ty, target); | |
| 5689 | const intrinsics_allowed = op != .tan and intrinsicsAllowed(scalar_ty, target); | |
| 5688 | 5690 | var fn_name_buf: [64]u8 = undefined; |
| 5689 | 5691 | const strat: FloatOpStrat = if (intrinsics_allowed) switch (op) { |
| 5690 | 5692 | // Some operations are dedicated LLVM instructions, not available as intrinsics |
| ... | ... | @@ -5720,6 +5722,7 @@ pub const FuncGen = struct { |
| 5720 | 5722 | .round, |
| 5721 | 5723 | .sin, |
| 5722 | 5724 | .sqrt, |
| 5725 | .tan, | |
| 5723 | 5726 | .trunc, |
| 5724 | 5727 | => FloatOpStrat{ |
| 5725 | 5728 | .libc = std.fmt.bufPrintZ(&fn_name_buf, "{s}{s}{s}", .{ |
src/print_air.zig+1| ... | ... | @@ -158,6 +158,7 @@ const Writer = struct { |
| 158 | 158 | .sqrt, |
| 159 | 159 | .sin, |
| 160 | 160 | .cos, |
| 161 | .tan, | |
| 161 | 162 | .exp, |
| 162 | 163 | .exp2, |
| 163 | 164 | .log, |
src/print_zir.zig+11-1| ... | ... | @@ -207,6 +207,7 @@ const Writer = struct { |
| 207 | 207 | .sqrt, |
| 208 | 208 | .sin, |
| 209 | 209 | .cos, |
| 210 | .tan, | |
| 210 | 211 | .exp, |
| 211 | 212 | .exp2, |
| 212 | 213 | .log, |
| ... | ... | @@ -400,7 +401,6 @@ const Writer = struct { |
| 400 | 401 | |
| 401 | 402 | .field_ptr_named, |
| 402 | 403 | .field_val_named, |
| 403 | .field_call_bind_named, | |
| 404 | 404 | => try self.writePlNodeFieldNamed(stream, inst), |
| 405 | 405 | |
| 406 | 406 | .as_node => try self.writeAs(stream, inst), |
| ... | ... | @@ -509,6 +509,16 @@ const Writer = struct { |
| 509 | 509 | try stream.writeAll(")) "); |
| 510 | 510 | try self.writeSrc(stream, src); |
| 511 | 511 | }, |
| 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 | }, | |
| 512 | 522 | } |
| 513 | 523 | } |
| 514 | 524 |
src/stage1/all_types.hpp+1| ... | ... | @@ -1768,6 +1768,7 @@ enum BuiltinFnId { |
| 1768 | 1768 | BuiltinFnIdSqrt, |
| 1769 | 1769 | BuiltinFnIdSin, |
| 1770 | 1770 | BuiltinFnIdCos, |
| 1771 | BuiltinFnIdTan, | |
| 1771 | 1772 | BuiltinFnIdExp, |
| 1772 | 1773 | BuiltinFnIdExp2, |
| 1773 | 1774 | BuiltinFnIdLog, |
src/stage1/analyze.cpp+2| ... | ... | @@ -10383,6 +10383,8 @@ const char *float_un_op_to_name(BuiltinFnId op) { |
| 10383 | 10383 | return "sin"; |
| 10384 | 10384 | case BuiltinFnIdCos: |
| 10385 | 10385 | return "cos"; |
| 10386 | case BuiltinFnIdTan: | |
| 10387 | return "tan"; | |
| 10386 | 10388 | case BuiltinFnIdExp: |
| 10387 | 10389 | return "exp"; |
| 10388 | 10390 | case BuiltinFnIdExp2: |
src/stage1/astgen.cpp+1| ... | ... | @@ -4497,6 +4497,7 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast |
| 4497 | 4497 | case BuiltinFnIdSqrt: |
| 4498 | 4498 | case BuiltinFnIdSin: |
| 4499 | 4499 | case BuiltinFnIdCos: |
| 4500 | case BuiltinFnIdTan: | |
| 4500 | 4501 | case BuiltinFnIdExp: |
| 4501 | 4502 | case BuiltinFnIdExp2: |
| 4502 | 4503 | case BuiltinFnIdLog: |
src/stage1/codegen.cpp+32-9| ... | ... | @@ -1629,11 +1629,28 @@ static const char *get_compiler_rt_type_abbrev(ZigType *type) { |
| 1629 | 1629 | } |
| 1630 | 1630 | } |
| 1631 | 1631 | |
| 1632 | static const char *get_math_h_type_abbrev(CodeGen *g, ZigType *float_type) { | |
| 1632 | static 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 | ||
| 1649 | static const char *libc_float_suffix(CodeGen *g, ZigType *float_type) { | |
| 1633 | 1650 | if (float_type == g->builtin_types.entry_f16) |
| 1634 | 1651 | return "h"; // Non-standard |
| 1635 | 1652 | else if (float_type == g->builtin_types.entry_f32) |
| 1636 | return "s"; | |
| 1653 | return "f"; | |
| 1637 | 1654 | else if (float_type == g->builtin_types.entry_f64) |
| 1638 | 1655 | return ""; |
| 1639 | 1656 | 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 |
| 2992 | 3009 | |
| 2993 | 3010 | static LLVMValueRef gen_soft_float_un_op(CodeGen *g, LLVMValueRef op, ZigType *operand_type, BuiltinFnId op_id) { |
| 2994 | 3011 | 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; | |
| 2995 | 3013 | |
| 2996 | 3014 | 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); | |
| 2999 | 3018 | |
| 3000 | 3019 | LLVMValueRef result; |
| 3001 | 3020 | if (vector_len == 0) { |
| ... | ... | @@ -3018,7 +3037,9 @@ static LLVMValueRef gen_float_un_op(CodeGen *g, LLVMValueRef operand, ZigType *o |
| 3018 | 3037 | assert(operand_type->id == ZigTypeIdFloat || operand_type->id == ZigTypeIdVector); |
| 3019 | 3038 | ZigType *elem_type = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.elem_type : operand_type; |
| 3020 | 3039 | 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 | { | |
| 3022 | 3043 | return gen_soft_float_un_op(g, operand, operand_type, op); |
| 3023 | 3044 | } |
| 3024 | 3045 | 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 |
| 3466 | 3487 | int param_count = 2; |
| 3467 | 3488 | |
| 3468 | 3489 | 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); | |
| 3470 | 3492 | |
| 3471 | 3493 | char fn_name[64]; |
| 3472 | 3494 | Icmp res_icmp = NONE; |
| ... | ... | @@ -3523,10 +3545,10 @@ static LLVMValueRef gen_soft_float_bin_op(CodeGen *g, LLVMValueRef op1_value, LL |
| 3523 | 3545 | res_icmp = EQ_ONE; |
| 3524 | 3546 | break; |
| 3525 | 3547 | case IrBinOpMaximum: |
| 3526 | sprintf(fn_name, "fmax%s", math_h_type_abbrev); | |
| 3548 | sprintf(fn_name, "%sfmax%s", math_float_prefix, math_float_suffix); | |
| 3527 | 3549 | break; |
| 3528 | 3550 | case IrBinOpMinimum: |
| 3529 | sprintf(fn_name, "fmin%s", math_h_type_abbrev); | |
| 3551 | sprintf(fn_name, "%sfmin%s", math_float_prefix, math_float_suffix); | |
| 3530 | 3552 | break; |
| 3531 | 3553 | case IrBinOpMult: |
| 3532 | 3554 | 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 |
| 3545 | 3567 | break; |
| 3546 | 3568 | case IrBinOpRemRem: |
| 3547 | 3569 | case IrBinOpRemMod: |
| 3548 | sprintf(fn_name, "fmod%s", math_h_type_abbrev); | |
| 3570 | sprintf(fn_name, "%sfmod%s", math_float_prefix, math_float_suffix); | |
| 3549 | 3571 | break; |
| 3550 | 3572 | default: |
| 3551 | 3573 | zig_unreachable(); |
| ... | ... | @@ -9810,6 +9832,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 9810 | 9832 | create_builtin_fn(g, BuiltinFnIdSqrt, "sqrt", 1); |
| 9811 | 9833 | create_builtin_fn(g, BuiltinFnIdSin, "sin", 1); |
| 9812 | 9834 | create_builtin_fn(g, BuiltinFnIdCos, "cos", 1); |
| 9835 | create_builtin_fn(g, BuiltinFnIdTan, "tan", 1); | |
| 9813 | 9836 | create_builtin_fn(g, BuiltinFnIdExp, "exp", 1); |
| 9814 | 9837 | create_builtin_fn(g, BuiltinFnIdExp2, "exp2", 1); |
| 9815 | 9838 | 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_ |
| 24132 | 24132 | case BuiltinFnIdCos: |
| 24133 | 24133 | out_val->data.x_f16 = zig_double_to_f16(cos(zig_f16_to_double(op->data.x_f16))); |
| 24134 | 24134 | 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; | |
| 24135 | 24138 | case BuiltinFnIdExp: |
| 24136 | 24139 | out_val->data.x_f16 = zig_double_to_f16(exp(zig_f16_to_double(op->data.x_f16))); |
| 24137 | 24140 | break; |
| ... | ... | @@ -24181,6 +24184,9 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, Scope *scope, AstNode *source_ |
| 24181 | 24184 | case BuiltinFnIdCos: |
| 24182 | 24185 | out_val->data.x_f32 = cosf(op->data.x_f32); |
| 24183 | 24186 | break; |
| 24187 | case BuiltinFnIdTan: | |
| 24188 | out_val->data.x_f32 = tanf(op->data.x_f32); | |
| 24189 | break; | |
| 24184 | 24190 | case BuiltinFnIdExp: |
| 24185 | 24191 | out_val->data.x_f32 = expf(op->data.x_f32); |
| 24186 | 24192 | break; |
| ... | ... | @@ -24230,6 +24236,9 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, Scope *scope, AstNode *source_ |
| 24230 | 24236 | case BuiltinFnIdCos: |
| 24231 | 24237 | out_val->data.x_f64 = cos(op->data.x_f64); |
| 24232 | 24238 | break; |
| 24239 | case BuiltinFnIdTan: | |
| 24240 | out_val->data.x_f64 = tan(op->data.x_f64); | |
| 24241 | break; | |
| 24233 | 24242 | case BuiltinFnIdExp: |
| 24234 | 24243 | out_val->data.x_f64 = exp(op->data.x_f64); |
| 24235 | 24244 | break; |
| ... | ... | @@ -24293,6 +24302,7 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, Scope *scope, AstNode *source_ |
| 24293 | 24302 | case BuiltinFnIdNearbyInt: |
| 24294 | 24303 | case BuiltinFnIdSin: |
| 24295 | 24304 | case BuiltinFnIdCos: |
| 24305 | case BuiltinFnIdTan: | |
| 24296 | 24306 | case BuiltinFnIdExp: |
| 24297 | 24307 | case BuiltinFnIdExp2: |
| 24298 | 24308 | case BuiltinFnIdLog: |
| ... | ... | @@ -24337,6 +24347,7 @@ static ErrorMsg *ir_eval_float_op(IrAnalyze *ira, Scope *scope, AstNode *source_ |
| 24337 | 24347 | case BuiltinFnIdNearbyInt: |
| 24338 | 24348 | case BuiltinFnIdSin: |
| 24339 | 24349 | case BuiltinFnIdCos: |
| 24350 | case BuiltinFnIdTan: | |
| 24340 | 24351 | case BuiltinFnIdExp: |
| 24341 | 24352 | case BuiltinFnIdExp2: |
| 24342 | 24353 | case BuiltinFnIdLog: |
src/value.zig+38| ... | ... | @@ -4473,6 +4473,44 @@ pub const Value = extern union { |
| 4473 | 4473 | } |
| 4474 | 4474 | } |
| 4475 | 4475 | |
| 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 | ||
| 4476 | 4514 | pub fn exp(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value { |
| 4477 | 4515 | if (float_type.zigTypeTag() == .Vector) { |
| 4478 | 4516 | const result_data = try arena.alloc(Value, float_type.vectorLen()); |
test/behavior/bugs/920.zig+2-3| ... | ... | @@ -1,5 +1,4 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const math = std.math; | |
| 3 | 2 | const Random = std.rand.Random; |
| 4 | 3 | |
| 5 | 4 | const ZigTable = struct { |
| ... | ... | @@ -40,10 +39,10 @@ const norm_r = 3.6541528853610088; |
| 40 | 39 | const norm_v = 0.00492867323399; |
| 41 | 40 | |
| 42 | 41 | fn norm_f(x: f64) f64 { |
| 43 | return math.exp(-x * x / 2.0); | |
| 42 | return @exp(-x * x / 2.0); | |
| 44 | 43 | } |
| 45 | 44 | fn norm_f_inv(y: f64) f64 { |
| 46 | return math.sqrt(-2.0 * math.ln(y)); | |
| 45 | return @sqrt(-2.0 * @log(y)); | |
| 47 | 46 | } |
| 48 | 47 | fn norm_zero_case(random: *Random, u: f64) f64 { |
| 49 | 48 | _ = random; |