| author | |
| committer | |
| log | 71e014caecaa54fdd8a0516710d2d9597da41398 |
| tree | 4cfc85ed66ba9aec49e3f672a80c39b98e598177 |
| parent | ebde2ff899c16612c7ff58df61f3946be47c51c8 |
and expand @sqrt
This revealed that the accuracy of ln is not as good as the current algorithm in
musl and glibc, and should be ported again.
v2: actually include tests
v3: fix reversal of in and out arguments on f128M_sqrt()
add test for @sqrt on comptime_float
do not include @nearbyInt() until it works on all targets.11 files changed, 719 insertions(+), 131 deletions(-)
doc/langref.html.in+83-2| ... | @@ -7354,10 +7354,91 @@ test "@setRuntimeSafety" { | ... | @@ -7354,10 +7354,91 @@ test "@setRuntimeSafety" { |
| 7354 | <pre>{#syntax#}@sqrt(comptime T: type, value: T) T{#endsyntax#}</pre> | 7354 | <pre>{#syntax#}@sqrt(comptime T: type, value: T) T{#endsyntax#}</pre> |
| 7355 | <p> | 7355 | <p> |
| 7356 | Performs the square root of a floating point number. Uses a dedicated hardware instruction | 7356 | Performs the square root of a floating point number. Uses a dedicated hardware instruction |
| 7357 | when available. Currently only supports f32 and f64 at runtime. f128 at runtime is TODO. | 7357 | when available. Supports f16, f32, f64, and f128, as well as vectors. |
| 7358 | </p> | 7358 | </p> |
| 7359 | {#header_close#} | ||
| 7360 | {#header_open|@sin#} | ||
| 7361 | <pre>{#syntax#}@sin(comptime T: type, value: T) T{#endsyntax#}</pre> | ||
| 7362 | <p> | ||
| 7363 | Sine trigometric function on a floating point number. Uses a dedicated hardware instruction | ||
| 7364 | when available. Currently supports f32 and f64. | ||
| 7365 | </p> | ||
| 7366 | {#header_close#} | ||
| 7367 | {#header_open|@cos#} | ||
| 7368 | <pre>{#syntax#}@cos(comptime T: type, value: T) T{#endsyntax#}</pre> | ||
| 7369 | <p> | ||
| 7370 | Cosine trigometric function on a floating point number. Uses a dedicated hardware instruction | ||
| 7371 | when available. Currently supports f32 and f64. | ||
| 7372 | </p> | ||
| 7373 | {#header_close#} | ||
| 7374 | {#header_open|@exp#} | ||
| 7375 | <pre>{#syntax#}@exp(comptime T: type, value: T) T{#endsyntax#}</pre> | ||
| 7376 | <p> | ||
| 7377 | Base-e exponential function on a floating point number. Uses a dedicated hardware instruction | ||
| 7378 | when available. Currently supports f32 and f64. | ||
| 7379 | </p> | ||
| 7380 | {#header_close#} | ||
| 7381 | {#header_open|@exp2#} | ||
| 7382 | <pre>{#syntax#}@exp2(comptime T: type, value: T) T{#endsyntax#}</pre> | ||
| 7383 | <p> | ||
| 7384 | Base-2 exponential function on a floating point number. Uses a dedicated hardware instruction | ||
| 7385 | when available. Currently supports f32 and f64. | ||
| 7386 | </p> | ||
| 7387 | {#header_close#} | ||
| 7388 | {#header_open|@ln#} | ||
| 7389 | <pre>{#syntax#}@ln(comptime T: type, value: T) T{#endsyntax#}</pre> | ||
| 7390 | <p> | ||
| 7391 | Returns the natural logarithm of a floating point number. Uses a dedicated hardware instruction | ||
| 7392 | when available. Currently supports f32 and f64. | ||
| 7393 | </p> | ||
| 7394 | {#header_close#} | ||
| 7395 | {#header_open|@log2#} | ||
| 7396 | <pre>{#syntax#}@log2(comptime T: type, value: T) T{#endsyntax#}</pre> | ||
| 7397 | <p> | ||
| 7398 | Returns the logarithm to the base 2 of a floating point number. Uses a dedicated hardware instruction | ||
| 7399 | when available. Currently supports f32 and f64. | ||
| 7400 | </p> | ||
| 7401 | {#header_close#} | ||
| 7402 | {#header_open|@log10#} | ||
| 7403 | <pre>{#syntax#}@log10(comptime T: type, value: T) T{#endsyntax#}</pre> | ||
| 7404 | <p> | ||
| 7405 | Returns the logarithm to the base 10 of a floating point number. Uses a dedicated hardware instruction | ||
| 7406 | when available. Currently supports f32 and f64. | ||
| 7407 | </p> | ||
| 7408 | {#header_close#} | ||
| 7409 | {#header_open|@fabs#} | ||
| 7410 | <pre>{#syntax#}@fabs(comptime T: type, value: T) T{#endsyntax#}</pre> | ||
| 7411 | <p> | ||
| 7412 | Returns the absolute value of a floating point number. Uses a dedicated hardware instruction | ||
| 7413 | when available. Currently supports f32 and f64. | ||
| 7414 | </p> | ||
| 7415 | {#header_close#} | ||
| 7416 | {#header_open|@floor#} | ||
| 7417 | <pre>{#syntax#}@floor(comptime T: type, value: T) T{#endsyntax#}</pre> | ||
| 7418 | <p> | ||
| 7419 | Returns the largest integral value not greater than the given floating point number. Uses a dedicated hardware instruction | ||
| 7420 | when available. Currently supports f32 and f64. | ||
| 7421 | </p> | ||
| 7422 | {#header_close#} | ||
| 7423 | {#header_open|@ceil#} | ||
| 7424 | <pre>{#syntax#}@ceil(comptime T: type, value: T) T{#endsyntax#}</pre> | ||
| 7425 | <p> | ||
| 7426 | Returns the largest integral value not less than the given floating point number. Uses a dedicated hardware instruction | ||
| 7427 | when available. Currently supports f32 and f64. | ||
| 7428 | </p> | ||
| 7429 | {#header_close#} | ||
| 7430 | {#header_open|@trunc#} | ||
| 7431 | <pre>{#syntax#}@trunc(comptime T: type, value: T) T{#endsyntax#}</pre> | ||
| 7432 | <p> | ||
| 7433 | Rounds the given floating point number to an integer, towards zero. Uses a dedicated hardware instruction | ||
| 7434 | when available. Currently supports f32 and f64. | ||
| 7435 | </p> | ||
| 7436 | {#header_close#} | ||
| 7437 | {#header_open|@round#} | ||
| 7438 | <pre>{#syntax#}@round(comptime T: type, value: T) T{#endsyntax#}</pre> | ||
| 7359 | <p> | 7439 | <p> |
| 7360 | This is a low-level intrinsic. Most code can use {#syntax#}std.math.sqrt{#endsyntax#} instead. | 7440 | Rounds the given floating point number to an integer, away from zero. Uses a dedicated hardware instruction |
| 7441 | when available. Currently supports f32 and f64. | ||
| 7361 | </p> | 7442 | </p> |
| 7362 | {#header_close#} | 7443 | {#header_close#} |
| 7363 | 7444 |
src/all_types.hpp+20-6| ... | @@ -1434,6 +1434,19 @@ enum BuiltinFnId { | ... | @@ -1434,6 +1434,19 @@ enum BuiltinFnId { |
| 1434 | BuiltinFnIdRem, | 1434 | BuiltinFnIdRem, |
| 1435 | BuiltinFnIdMod, | 1435 | BuiltinFnIdMod, |
| 1436 | BuiltinFnIdSqrt, | 1436 | BuiltinFnIdSqrt, |
| 1437 | BuiltinFnIdSin, | ||
| 1438 | BuiltinFnIdCos, | ||
| 1439 | BuiltinFnIdExp, | ||
| 1440 | BuiltinFnIdExp2, | ||
| 1441 | BuiltinFnIdLn, | ||
| 1442 | BuiltinFnIdLog2, | ||
| 1443 | BuiltinFnIdLog10, | ||
| 1444 | BuiltinFnIdFabs, | ||
| 1445 | BuiltinFnIdFloor, | ||
| 1446 | BuiltinFnIdCeil, | ||
| 1447 | BuiltinFnIdTrunc, | ||
| 1448 | BuiltinFnIdNearbyInt, | ||
| 1449 | BuiltinFnIdRound, | ||
| 1437 | BuiltinFnIdTruncate, | 1450 | BuiltinFnIdTruncate, |
| 1438 | BuiltinFnIdIntCast, | 1451 | BuiltinFnIdIntCast, |
| 1439 | BuiltinFnIdFloatCast, | 1452 | BuiltinFnIdFloatCast, |
| ... | @@ -1556,9 +1569,7 @@ enum ZigLLVMFnId { | ... | @@ -1556,9 +1569,7 @@ enum ZigLLVMFnId { |
| 1556 | ZigLLVMFnIdPopCount, | 1569 | ZigLLVMFnIdPopCount, |
| 1557 | ZigLLVMFnIdOverflowArithmetic, | 1570 | ZigLLVMFnIdOverflowArithmetic, |
| 1558 | ZigLLVMFnIdFMA, | 1571 | ZigLLVMFnIdFMA, |
| 1559 | ZigLLVMFnIdFloor, | 1572 | ZigLLVMFnIdFloatOp, |
| 1560 | ZigLLVMFnIdCeil, | ||
| 1561 | ZigLLVMFnIdSqrt, | ||
| 1562 | ZigLLVMFnIdBswap, | 1573 | ZigLLVMFnIdBswap, |
| 1563 | ZigLLVMFnIdBitReverse, | 1574 | ZigLLVMFnIdBitReverse, |
| 1564 | }; | 1575 | }; |
| ... | @@ -1585,6 +1596,7 @@ struct ZigLLVMFnKey { | ... | @@ -1585,6 +1596,7 @@ struct ZigLLVMFnKey { |
| 1585 | uint32_t bit_count; | 1596 | uint32_t bit_count; |
| 1586 | } pop_count; | 1597 | } pop_count; |
| 1587 | struct { | 1598 | struct { |
| 1599 | BuiltinFnId op; | ||
| 1588 | uint32_t bit_count; | 1600 | uint32_t bit_count; |
| 1589 | uint32_t vector_len; // 0 means not a vector | 1601 | uint32_t vector_len; // 0 means not a vector |
| 1590 | } floating; | 1602 | } floating; |
| ... | @@ -2239,6 +2251,7 @@ enum IrInstructionId { | ... | @@ -2239,6 +2251,7 @@ enum IrInstructionId { |
| 2239 | IrInstructionIdAlignOf, | 2251 | IrInstructionIdAlignOf, |
| 2240 | IrInstructionIdOverflowOp, | 2252 | IrInstructionIdOverflowOp, |
| 2241 | IrInstructionIdMulAdd, | 2253 | IrInstructionIdMulAdd, |
| 2254 | IrInstructionIdFloatOp, | ||
| 2242 | IrInstructionIdTestErr, | 2255 | IrInstructionIdTestErr, |
| 2243 | IrInstructionIdUnwrapErrCode, | 2256 | IrInstructionIdUnwrapErrCode, |
| 2244 | IrInstructionIdUnwrapErrPayload, | 2257 | IrInstructionIdUnwrapErrPayload, |
| ... | @@ -2300,7 +2313,6 @@ enum IrInstructionId { | ... | @@ -2300,7 +2313,6 @@ enum IrInstructionId { |
| 2300 | IrInstructionIdAddImplicitReturnType, | 2313 | IrInstructionIdAddImplicitReturnType, |
| 2301 | IrInstructionIdMergeErrRetTraces, | 2314 | IrInstructionIdMergeErrRetTraces, |
| 2302 | IrInstructionIdMarkErrRetTracePtr, | 2315 | IrInstructionIdMarkErrRetTracePtr, |
| 2303 | IrInstructionIdSqrt, | ||
| 2304 | IrInstructionIdErrSetCast, | 2316 | IrInstructionIdErrSetCast, |
| 2305 | IrInstructionIdToBytes, | 2317 | IrInstructionIdToBytes, |
| 2306 | IrInstructionIdFromBytes, | 2318 | IrInstructionIdFromBytes, |
| ... | @@ -3474,11 +3486,13 @@ struct IrInstructionMarkErrRetTracePtr { | ... | @@ -3474,11 +3486,13 @@ struct IrInstructionMarkErrRetTracePtr { |
| 3474 | IrInstruction *err_ret_trace_ptr; | 3486 | IrInstruction *err_ret_trace_ptr; |
| 3475 | }; | 3487 | }; |
| 3476 | 3488 | ||
| 3477 | struct IrInstructionSqrt { | 3489 | // For float ops which take a single argument |
| 3490 | struct IrInstructionFloatOp { | ||
| 3478 | IrInstruction base; | 3491 | IrInstruction base; |
| 3479 | 3492 | ||
| 3493 | BuiltinFnId op; | ||
| 3480 | IrInstruction *type; | 3494 | IrInstruction *type; |
| 3481 | IrInstruction *op; | 3495 | IrInstruction *op1; |
| 3482 | }; | 3496 | }; |
| 3483 | 3497 | ||
| 3484 | struct IrInstructionCheckRuntimeScope { | 3498 | struct IrInstructionCheckRuntimeScope { |
src/analyze.cpp+8-7| ... | @@ -5736,9 +5736,10 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { | ... | @@ -5736,9 +5736,10 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { |
| 5736 | return (uint32_t)(x.data.clz.bit_count) * (uint32_t)2428952817; | 5736 | return (uint32_t)(x.data.clz.bit_count) * (uint32_t)2428952817; |
| 5737 | case ZigLLVMFnIdPopCount: | 5737 | case ZigLLVMFnIdPopCount: |
| 5738 | return (uint32_t)(x.data.clz.bit_count) * (uint32_t)101195049; | 5738 | return (uint32_t)(x.data.clz.bit_count) * (uint32_t)101195049; |
| 5739 | case ZigLLVMFnIdFloor: | 5739 | case ZigLLVMFnIdFloatOp: |
| 5740 | case ZigLLVMFnIdCeil: | 5740 | return (uint32_t)(x.data.floating.bit_count) * ((uint32_t)x.id + 1025) + |
| 5741 | case ZigLLVMFnIdSqrt: | 5741 | (uint32_t)(x.data.floating.vector_len) * (((uint32_t)x.id << 5) + 1025) + |
| 5742 | (uint32_t)(x.data.floating.op) * (uint32_t)43789879; | ||
| 5742 | case ZigLLVMFnIdFMA: | 5743 | case ZigLLVMFnIdFMA: |
| 5743 | return (uint32_t)(x.data.floating.bit_count) * ((uint32_t)x.id + 1025) + | 5744 | return (uint32_t)(x.data.floating.bit_count) * ((uint32_t)x.id + 1025) + |
| 5744 | (uint32_t)(x.data.floating.vector_len) * (((uint32_t)x.id << 5) + 1025); | 5745 | (uint32_t)(x.data.floating.vector_len) * (((uint32_t)x.id << 5) + 1025); |
| ... | @@ -5769,10 +5770,10 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { | ... | @@ -5769,10 +5770,10 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { |
| 5769 | return a.data.bswap.bit_count == b.data.bswap.bit_count; | 5770 | return a.data.bswap.bit_count == b.data.bswap.bit_count; |
| 5770 | case ZigLLVMFnIdBitReverse: | 5771 | case ZigLLVMFnIdBitReverse: |
| 5771 | return a.data.bit_reverse.bit_count == b.data.bit_reverse.bit_count; | 5772 | return a.data.bit_reverse.bit_count == b.data.bit_reverse.bit_count; |
| 5772 | case ZigLLVMFnIdFloor: | 5773 | case ZigLLVMFnIdFloatOp: |
| 5773 | case ZigLLVMFnIdCeil: | 5774 | return a.data.floating.bit_count == b.data.floating.bit_count && |
| 5774 | case ZigLLVMFnIdSqrt: | 5775 | a.data.floating.vector_len == b.data.floating.vector_len && |
| 5775 | return a.data.floating.bit_count == b.data.floating.bit_count; | 5776 | a.data.floating.op == b.data.floating.op; |
| 5776 | case ZigLLVMFnIdFMA: | 5777 | case ZigLLVMFnIdFMA: |
| 5777 | return a.data.floating.bit_count == b.data.floating.bit_count && | 5778 | return a.data.floating.bit_count == b.data.floating.bit_count && |
| 5778 | a.data.floating.vector_len == b.data.floating.vector_len; | 5779 | a.data.floating.vector_len == b.data.floating.vector_len; |
src/codegen.cpp+36-32| ... | @@ -806,7 +806,7 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, ZigType *operand_type, AddSu | ... | @@ -806,7 +806,7 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, ZigType *operand_type, AddSu |
| 806 | return fn_val; | 806 | return fn_val; |
| 807 | } | 807 | } |
| 808 | 808 | ||
| 809 | static LLVMValueRef get_float_fn(CodeGen *g, ZigType *type_entry, ZigLLVMFnId fn_id) { | 809 | static LLVMValueRef get_float_fn(CodeGen *g, ZigType *type_entry, ZigLLVMFnId fn_id, BuiltinFnId op) { |
| 810 | assert(type_entry->id == ZigTypeIdFloat || | 810 | assert(type_entry->id == ZigTypeIdFloat || |
| 811 | type_entry->id == ZigTypeIdVector); | 811 | type_entry->id == ZigTypeIdVector); |
| 812 | 812 | ||
| ... | @@ -817,6 +817,7 @@ static LLVMValueRef get_float_fn(CodeGen *g, ZigType *type_entry, ZigLLVMFnId fn | ... | @@ -817,6 +817,7 @@ static LLVMValueRef get_float_fn(CodeGen *g, ZigType *type_entry, ZigLLVMFnId fn |
| 817 | key.id = fn_id; | 817 | key.id = fn_id; |
| 818 | key.data.floating.bit_count = (uint32_t)float_type->data.floating.bit_count; | 818 | key.data.floating.bit_count = (uint32_t)float_type->data.floating.bit_count; |
| 819 | key.data.floating.vector_len = is_vector ? (uint32_t)type_entry->data.vector.len : 0; | 819 | key.data.floating.vector_len = is_vector ? (uint32_t)type_entry->data.vector.len : 0; |
| 820 | key.data.floating.op = op; | ||
| 820 | 821 | ||
| 821 | auto existing_entry = g->llvm_fn_table.maybe_get(key); | 822 | auto existing_entry = g->llvm_fn_table.maybe_get(key); |
| 822 | if (existing_entry) | 823 | if (existing_entry) |
| ... | @@ -824,18 +825,12 @@ static LLVMValueRef get_float_fn(CodeGen *g, ZigType *type_entry, ZigLLVMFnId fn | ... | @@ -824,18 +825,12 @@ static LLVMValueRef get_float_fn(CodeGen *g, ZigType *type_entry, ZigLLVMFnId fn |
| 824 | 825 | ||
| 825 | const char *name; | 826 | const char *name; |
| 826 | uint32_t num_args; | 827 | uint32_t num_args; |
| 827 | if (fn_id == ZigLLVMFnIdFloor) { | 828 | if (fn_id == ZigLLVMFnIdFMA) { |
| 828 | name = "floor"; | ||
| 829 | num_args = 1; | ||
| 830 | } else if (fn_id == ZigLLVMFnIdCeil) { | ||
| 831 | name = "ceil"; | ||
| 832 | num_args = 1; | ||
| 833 | } else if (fn_id == ZigLLVMFnIdSqrt) { | ||
| 834 | name = "sqrt"; | ||
| 835 | num_args = 1; | ||
| 836 | } else if (fn_id == ZigLLVMFnIdFMA) { | ||
| 837 | name = "fma"; | 829 | name = "fma"; |
| 838 | num_args = 3; | 830 | num_args = 3; |
| 831 | } else if (fn_id == ZigLLVMFnIdFloatOp) { | ||
| 832 | name = float_op_to_name(op, true); | ||
| 833 | num_args = 1; | ||
| 839 | } else { | 834 | } else { |
| 840 | zig_unreachable(); | 835 | zig_unreachable(); |
| 841 | } | 836 | } |
| ... | @@ -2480,22 +2475,17 @@ static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *type_entry, | ... | @@ -2480,22 +2475,17 @@ static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *type_entry, |
| 2480 | return result; | 2475 | return result; |
| 2481 | } | 2476 | } |
| 2482 | 2477 | ||
| 2483 | static LLVMValueRef gen_floor(CodeGen *g, LLVMValueRef val, ZigType *type_entry) { | 2478 | static LLVMValueRef gen_float_op(CodeGen *g, LLVMValueRef val, ZigType *type_entry, BuiltinFnId op) { |
| 2484 | if (type_entry->id == ZigTypeIdInt) | 2479 | if ((op == BuiltinFnIdCeil || |
| 2480 | op == BuiltinFnIdFloor) && | ||
| 2481 | type_entry->id == ZigTypeIdInt) | ||
| 2485 | return val; | 2482 | return val; |
| 2483 | assert(type_entry->id == ZigTypeIdFloat); | ||
| 2486 | 2484 | ||
| 2487 | LLVMValueRef floor_fn = get_float_fn(g, type_entry, ZigLLVMFnIdFloor); | 2485 | LLVMValueRef floor_fn = get_float_fn(g, type_entry, ZigLLVMFnIdFloatOp, op); |
| 2488 | return LLVMBuildCall(g->builder, floor_fn, &val, 1, ""); | 2486 | return LLVMBuildCall(g->builder, floor_fn, &val, 1, ""); |
| 2489 | } | 2487 | } |
| 2490 | 2488 | ||
| 2491 | static LLVMValueRef gen_ceil(CodeGen *g, LLVMValueRef val, ZigType *type_entry) { | ||
| 2492 | if (type_entry->id == ZigTypeIdInt) | ||
| 2493 | return val; | ||
| 2494 | |||
| 2495 | LLVMValueRef ceil_fn = get_float_fn(g, type_entry, ZigLLVMFnIdCeil); | ||
| 2496 | return LLVMBuildCall(g->builder, ceil_fn, &val, 1, ""); | ||
| 2497 | } | ||
| 2498 | |||
| 2499 | enum DivKind { | 2489 | enum DivKind { |
| 2500 | DivKindFloat, | 2490 | DivKindFloat, |
| 2501 | DivKindTrunc, | 2491 | DivKindTrunc, |
| ... | @@ -2571,7 +2561,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast | ... | @@ -2571,7 +2561,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast |
| 2571 | return result; | 2561 | return result; |
| 2572 | case DivKindExact: | 2562 | case DivKindExact: |
| 2573 | if (want_runtime_safety) { | 2563 | if (want_runtime_safety) { |
| 2574 | LLVMValueRef floored = gen_floor(g, result, type_entry); | 2564 | LLVMValueRef floored = gen_float_op(g, result, type_entry, BuiltinFnIdFloor); |
| 2575 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk"); | 2565 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk"); |
| 2576 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); | 2566 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); |
| 2577 | LLVMValueRef ok_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, floored, result, ""); | 2567 | LLVMValueRef ok_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, floored, result, ""); |
| ... | @@ -2593,12 +2583,12 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast | ... | @@ -2593,12 +2583,12 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast |
| 2593 | LLVMBuildCondBr(g->builder, ltz, ltz_block, gez_block); | 2583 | LLVMBuildCondBr(g->builder, ltz, ltz_block, gez_block); |
| 2594 | 2584 | ||
| 2595 | LLVMPositionBuilderAtEnd(g->builder, ltz_block); | 2585 | LLVMPositionBuilderAtEnd(g->builder, ltz_block); |
| 2596 | LLVMValueRef ceiled = gen_ceil(g, result, type_entry); | 2586 | LLVMValueRef ceiled = gen_float_op(g, result, type_entry, BuiltinFnIdCeil); |
| 2597 | LLVMBasicBlockRef ceiled_end_block = LLVMGetInsertBlock(g->builder); | 2587 | LLVMBasicBlockRef ceiled_end_block = LLVMGetInsertBlock(g->builder); |
| 2598 | LLVMBuildBr(g->builder, end_block); | 2588 | LLVMBuildBr(g->builder, end_block); |
| 2599 | 2589 | ||
| 2600 | LLVMPositionBuilderAtEnd(g->builder, gez_block); | 2590 | LLVMPositionBuilderAtEnd(g->builder, gez_block); |
| 2601 | LLVMValueRef floored = gen_floor(g, result, type_entry); | 2591 | LLVMValueRef floored = gen_float_op(g, result, type_entry, BuiltinFnIdFloor); |
| 2602 | LLVMBasicBlockRef floored_end_block = LLVMGetInsertBlock(g->builder); | 2592 | LLVMBasicBlockRef floored_end_block = LLVMGetInsertBlock(g->builder); |
| 2603 | LLVMBuildBr(g->builder, end_block); | 2593 | LLVMBuildBr(g->builder, end_block); |
| 2604 | 2594 | ||
| ... | @@ -2610,7 +2600,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast | ... | @@ -2610,7 +2600,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast |
| 2610 | return phi; | 2600 | return phi; |
| 2611 | } | 2601 | } |
| 2612 | case DivKindFloor: | 2602 | case DivKindFloor: |
| 2613 | return gen_floor(g, result, type_entry); | 2603 | return gen_float_op(g, result, type_entry, BuiltinFnIdFloor); |
| 2614 | } | 2604 | } |
| 2615 | zig_unreachable(); | 2605 | zig_unreachable(); |
| 2616 | } | 2606 | } |
| ... | @@ -5450,10 +5440,10 @@ static LLVMValueRef ir_render_mark_err_ret_trace_ptr(CodeGen *g, IrExecutable *e | ... | @@ -5450,10 +5440,10 @@ static LLVMValueRef ir_render_mark_err_ret_trace_ptr(CodeGen *g, IrExecutable *e |
| 5450 | return nullptr; | 5440 | return nullptr; |
| 5451 | } | 5441 | } |
| 5452 | 5442 | ||
| 5453 | static LLVMValueRef ir_render_sqrt(CodeGen *g, IrExecutable *executable, IrInstructionSqrt *instruction) { | 5443 | static LLVMValueRef ir_render_float_op(CodeGen *g, IrExecutable *executable, IrInstructionFloatOp *instruction) { |
| 5454 | LLVMValueRef op = ir_llvm_value(g, instruction->op); | 5444 | LLVMValueRef op = ir_llvm_value(g, instruction->op1); |
| 5455 | assert(instruction->base.value.type->id == ZigTypeIdFloat); | 5445 | assert(instruction->base.value.type->id == ZigTypeIdFloat); |
| 5456 | LLVMValueRef fn_val = get_float_fn(g, instruction->base.value.type, ZigLLVMFnIdSqrt); | 5446 | LLVMValueRef fn_val = get_float_fn(g, instruction->base.value.type, ZigLLVMFnIdFloatOp, instruction->op); |
| 5457 | return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); | 5447 | return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); |
| 5458 | } | 5448 | } |
| 5459 | 5449 | ||
| ... | @@ -5463,7 +5453,7 @@ static LLVMValueRef ir_render_mul_add(CodeGen *g, IrExecutable *executable, IrIn | ... | @@ -5463,7 +5453,7 @@ static LLVMValueRef ir_render_mul_add(CodeGen *g, IrExecutable *executable, IrIn |
| 5463 | LLVMValueRef op3 = ir_llvm_value(g, instruction->op3); | 5453 | LLVMValueRef op3 = ir_llvm_value(g, instruction->op3); |
| 5464 | assert(instruction->base.value.type->id == ZigTypeIdFloat || | 5454 | assert(instruction->base.value.type->id == ZigTypeIdFloat || |
| 5465 | instruction->base.value.type->id == ZigTypeIdVector); | 5455 | instruction->base.value.type->id == ZigTypeIdVector); |
| 5466 | LLVMValueRef fn_val = get_float_fn(g, instruction->base.value.type, ZigLLVMFnIdFMA); | 5456 | LLVMValueRef fn_val = get_float_fn(g, instruction->base.value.type, ZigLLVMFnIdFMA, BuiltinFnIdMulAdd); |
| 5467 | LLVMValueRef args[3] = { | 5457 | LLVMValueRef args[3] = { |
| 5468 | op1, | 5458 | op1, |
| 5469 | op2, | 5459 | op2, |
| ... | @@ -5814,8 +5804,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -5814,8 +5804,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5814 | return ir_render_merge_err_ret_traces(g, executable, (IrInstructionMergeErrRetTraces *)instruction); | 5804 | return ir_render_merge_err_ret_traces(g, executable, (IrInstructionMergeErrRetTraces *)instruction); |
| 5815 | case IrInstructionIdMarkErrRetTracePtr: | 5805 | case IrInstructionIdMarkErrRetTracePtr: |
| 5816 | return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction); | 5806 | return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction); |
| 5817 | case IrInstructionIdSqrt: | 5807 | case IrInstructionIdFloatOp: |
| 5818 | return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction); | 5808 | return ir_render_float_op(g, executable, (IrInstructionFloatOp *)instruction); |
| 5819 | case IrInstructionIdMulAdd: | 5809 | case IrInstructionIdMulAdd: |
| 5820 | return ir_render_mul_add(g, executable, (IrInstructionMulAdd *)instruction); | 5810 | return ir_render_mul_add(g, executable, (IrInstructionMulAdd *)instruction); |
| 5821 | case IrInstructionIdArrayToVector: | 5811 | case IrInstructionIdArrayToVector: |
| ... | @@ -7435,6 +7425,20 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -7435,6 +7425,20 @@ static void define_builtin_fns(CodeGen *g) { |
| 7435 | create_builtin_fn(g, BuiltinFnIdRem, "rem", 2); | 7425 | create_builtin_fn(g, BuiltinFnIdRem, "rem", 2); |
| 7436 | create_builtin_fn(g, BuiltinFnIdMod, "mod", 2); | 7426 | create_builtin_fn(g, BuiltinFnIdMod, "mod", 2); |
| 7437 | create_builtin_fn(g, BuiltinFnIdSqrt, "sqrt", 2); | 7427 | create_builtin_fn(g, BuiltinFnIdSqrt, "sqrt", 2); |
| 7428 | create_builtin_fn(g, BuiltinFnIdSin, "sin", 2); | ||
| 7429 | create_builtin_fn(g, BuiltinFnIdCos, "cos", 2); | ||
| 7430 | create_builtin_fn(g, BuiltinFnIdExp, "exp", 2); | ||
| 7431 | create_builtin_fn(g, BuiltinFnIdExp2, "exp2", 2); | ||
| 7432 | create_builtin_fn(g, BuiltinFnIdLn, "ln", 2); | ||
| 7433 | create_builtin_fn(g, BuiltinFnIdLog2, "log2", 2); | ||
| 7434 | create_builtin_fn(g, BuiltinFnIdLog10, "log10", 2); | ||
| 7435 | create_builtin_fn(g, BuiltinFnIdFabs, "fabs", 2); | ||
| 7436 | create_builtin_fn(g, BuiltinFnIdFloor, "floor", 2); | ||
| 7437 | create_builtin_fn(g, BuiltinFnIdCeil, "ceil", 2); | ||
| 7438 | create_builtin_fn(g, BuiltinFnIdTrunc, "trunc", 2); | ||
| 7439 | //Needs library support on Windows | ||
| 7440 | //create_builtin_fn(g, BuiltinFnIdNearbyInt, "nearbyInt", 2); | ||
| 7441 | create_builtin_fn(g, BuiltinFnIdRound, "round", 2); | ||
| 7438 | create_builtin_fn(g, BuiltinFnIdMulAdd, "mulAdd", 4); | 7442 | create_builtin_fn(g, BuiltinFnIdMulAdd, "mulAdd", 4); |
| 7439 | create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX); | 7443 | create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX); |
| 7440 | create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX); | 7444 | create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX); |
src/ir.cpp+294-61| ... | @@ -991,8 +991,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionMarkErrRetTraceP | ... | @@ -991,8 +991,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionMarkErrRetTraceP |
| 991 | return IrInstructionIdMarkErrRetTracePtr; | 991 | return IrInstructionIdMarkErrRetTracePtr; |
| 992 | } | 992 | } |
| 993 | 993 | ||
| 994 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSqrt *) { | 994 | static constexpr IrInstructionId ir_instruction_id(IrInstructionFloatOp *) { |
| 995 | return IrInstructionIdSqrt; | 995 | return IrInstructionIdFloatOp; |
| 996 | } | 996 | } |
| 997 | 997 | ||
| 998 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) { | 998 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) { |
| ... | @@ -2312,6 +2312,59 @@ static IrInstruction *ir_build_overflow_op(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -2312,6 +2312,59 @@ static IrInstruction *ir_build_overflow_op(IrBuilder *irb, Scope *scope, AstNode |
| 2312 | return &instruction->base; | 2312 | return &instruction->base; |
| 2313 | } | 2313 | } |
| 2314 | 2314 | ||
| 2315 | |||
| 2316 | //TODO Powi, Pow, minnum, maxnum, maximum, minimum, copysign, | ||
| 2317 | // lround, llround, lrint, llrint | ||
| 2318 | // So far this is only non-complicated type functions. | ||
| 2319 | const char *float_op_to_name(BuiltinFnId op, bool llvm_name) { | ||
| 2320 | const bool b = llvm_name; | ||
| 2321 | |||
| 2322 | switch (op) { | ||
| 2323 | case BuiltinFnIdSqrt: | ||
| 2324 | return "sqrt"; | ||
| 2325 | case BuiltinFnIdSin: | ||
| 2326 | return "sin"; | ||
| 2327 | case BuiltinFnIdCos: | ||
| 2328 | return "cos"; | ||
| 2329 | case BuiltinFnIdExp: | ||
| 2330 | return "exp"; | ||
| 2331 | case BuiltinFnIdExp2: | ||
| 2332 | return "exp2"; | ||
| 2333 | case BuiltinFnIdLn: | ||
| 2334 | return b ? "log" : "ln"; | ||
| 2335 | case BuiltinFnIdLog10: | ||
| 2336 | return "log10"; | ||
| 2337 | case BuiltinFnIdLog2: | ||
| 2338 | return "log2"; | ||
| 2339 | case BuiltinFnIdFabs: | ||
| 2340 | return "fabs"; | ||
| 2341 | case BuiltinFnIdFloor: | ||
| 2342 | return "floor"; | ||
| 2343 | case BuiltinFnIdCeil: | ||
| 2344 | return "ceil"; | ||
| 2345 | case BuiltinFnIdTrunc: | ||
| 2346 | return "trunc"; | ||
| 2347 | case BuiltinFnIdNearbyInt: | ||
| 2348 | return b ? "nearbyint" : "nearbyInt"; | ||
| 2349 | case BuiltinFnIdRound: | ||
| 2350 | return "round"; | ||
| 2351 | default: | ||
| 2352 | zig_unreachable(); | ||
| 2353 | } | ||
| 2354 | } | ||
| 2355 | |||
| 2356 | static IrInstruction *ir_build_float_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type, IrInstruction *op1, BuiltinFnId op) { | ||
| 2357 | IrInstructionFloatOp *instruction = ir_build_instruction<IrInstructionFloatOp>(irb, scope, source_node); | ||
| 2358 | instruction->type = type; | ||
| 2359 | instruction->op1 = op1; | ||
| 2360 | instruction->op = op; | ||
| 2361 | |||
| 2362 | if (type != nullptr) ir_ref_instruction(type, irb->current_basic_block); | ||
| 2363 | ir_ref_instruction(op1, irb->current_basic_block); | ||
| 2364 | |||
| 2365 | return &instruction->base; | ||
| 2366 | } | ||
| 2367 | |||
| 2315 | static IrInstruction *ir_build_mul_add(IrBuilder *irb, Scope *scope, AstNode *source_node, | 2368 | static IrInstruction *ir_build_mul_add(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2316 | IrInstruction *type_value, IrInstruction *op1, IrInstruction *op2, IrInstruction *op3) { | 2369 | IrInstruction *type_value, IrInstruction *op1, IrInstruction *op2, IrInstruction *op3) { |
| 2317 | IrInstructionMulAdd *instruction = ir_build_instruction<IrInstructionMulAdd>(irb, scope, source_node); | 2370 | IrInstructionMulAdd *instruction = ir_build_instruction<IrInstructionMulAdd>(irb, scope, source_node); |
| ... | @@ -3033,17 +3086,6 @@ static IrInstruction *ir_build_mark_err_ret_trace_ptr(IrBuilder *irb, Scope *sco | ... | @@ -3033,17 +3086,6 @@ static IrInstruction *ir_build_mark_err_ret_trace_ptr(IrBuilder *irb, Scope *sco |
| 3033 | return &instruction->base; | 3086 | return &instruction->base; |
| 3034 | } | 3087 | } |
| 3035 | 3088 | ||
| 3036 | static IrInstruction *ir_build_sqrt(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type, IrInstruction *op) { | ||
| 3037 | IrInstructionSqrt *instruction = ir_build_instruction<IrInstructionSqrt>(irb, scope, source_node); | ||
| 3038 | instruction->type = type; | ||
| 3039 | instruction->op = op; | ||
| 3040 | |||
| 3041 | if (type != nullptr) ir_ref_instruction(type, irb->current_basic_block); | ||
| 3042 | ir_ref_instruction(op, irb->current_basic_block); | ||
| 3043 | |||
| 3044 | return &instruction->base; | ||
| 3045 | } | ||
| 3046 | |||
| 3047 | static IrInstruction *ir_build_has_decl(IrBuilder *irb, Scope *scope, AstNode *source_node, | 3089 | static IrInstruction *ir_build_has_decl(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 3048 | IrInstruction *container, IrInstruction *name) | 3090 | IrInstruction *container, IrInstruction *name) |
| 3049 | { | 3091 | { |
| ... | @@ -4400,6 +4442,19 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4400,6 +4442,19 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4400 | return ir_lval_wrap(irb, scope, bin_op, lval); | 4442 | return ir_lval_wrap(irb, scope, bin_op, lval); |
| 4401 | } | 4443 | } |
| 4402 | case BuiltinFnIdSqrt: | 4444 | case BuiltinFnIdSqrt: |
| 4445 | case BuiltinFnIdSin: | ||
| 4446 | case BuiltinFnIdCos: | ||
| 4447 | case BuiltinFnIdExp: | ||
| 4448 | case BuiltinFnIdExp2: | ||
| 4449 | case BuiltinFnIdLn: | ||
| 4450 | case BuiltinFnIdLog2: | ||
| 4451 | case BuiltinFnIdLog10: | ||
| 4452 | case BuiltinFnIdFabs: | ||
| 4453 | case BuiltinFnIdFloor: | ||
| 4454 | case BuiltinFnIdCeil: | ||
| 4455 | case BuiltinFnIdTrunc: | ||
| 4456 | case BuiltinFnIdNearbyInt: | ||
| 4457 | case BuiltinFnIdRound: | ||
| 4403 | { | 4458 | { |
| 4404 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | 4459 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| 4405 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | 4460 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); |
| ... | @@ -4411,7 +4466,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4411,7 +4466,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4411 | if (arg1_value == irb->codegen->invalid_instruction) | 4466 | if (arg1_value == irb->codegen->invalid_instruction) |
| 4412 | return arg1_value; | 4467 | return arg1_value; |
| 4413 | 4468 | ||
| 4414 | IrInstruction *ir_sqrt = ir_build_sqrt(irb, scope, node, arg0_value, arg1_value); | 4469 | IrInstruction *ir_sqrt = ir_build_float_op(irb, scope, node, arg0_value, arg1_value, builtin_fn->id); |
| 4415 | return ir_lval_wrap(irb, scope, ir_sqrt, lval); | 4470 | return ir_lval_wrap(irb, scope, ir_sqrt, lval); |
| 4416 | } | 4471 | } |
| 4417 | case BuiltinFnIdTruncate: | 4472 | case BuiltinFnIdTruncate: |
| ... | @@ -23214,70 +23269,248 @@ static IrInstruction *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *i | ... | @@ -23214,70 +23269,248 @@ static IrInstruction *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *i |
| 23214 | return result; | 23269 | return result; |
| 23215 | } | 23270 | } |
| 23216 | 23271 | ||
| 23217 | static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionSqrt *instruction) { | 23272 | static void ir_eval_float_op(IrAnalyze *ira, IrInstructionFloatOp *source_instr, ZigType *float_type, |
| 23218 | ZigType *float_type = ir_resolve_type(ira, instruction->type->child); | 23273 | ConstExprValue *op, ConstExprValue *out_val) { |
| 23219 | if (type_is_invalid(float_type)) | 23274 | assert(ira && source_instr && float_type && out_val && op); |
| 23220 | return ira->codegen->invalid_instruction; | 23275 | assert(float_type->id == ZigTypeIdFloat || |
| 23276 | float_type->id == ZigTypeIdComptimeFloat); | ||
| 23221 | 23277 | ||
| 23222 | IrInstruction *op = instruction->op->child; | 23278 | BuiltinFnId fop = source_instr->op; |
| 23223 | if (type_is_invalid(op->value.type)) | 23279 | unsigned bits; |
| 23280 | |||
| 23281 | if (float_type->id == ZigTypeIdComptimeFloat) { | ||
| 23282 | bits = 128; | ||
| 23283 | } else if (float_type->id == ZigTypeIdFloat) | ||
| 23284 | bits = float_type->data.floating.bit_count; | ||
| 23285 | |||
| 23286 | switch (bits) { | ||
| 23287 | case 16: { | ||
| 23288 | switch (fop) { | ||
| 23289 | case BuiltinFnIdSqrt: | ||
| 23290 | out_val->data.x_f16 = f16_sqrt(op->data.x_f16); | ||
| 23291 | break; | ||
| 23292 | case BuiltinFnIdSin: | ||
| 23293 | case BuiltinFnIdCos: | ||
| 23294 | case BuiltinFnIdExp: | ||
| 23295 | case BuiltinFnIdExp2: | ||
| 23296 | case BuiltinFnIdLn: | ||
| 23297 | case BuiltinFnIdLog10: | ||
| 23298 | case BuiltinFnIdLog2: | ||
| 23299 | case BuiltinFnIdFabs: | ||
| 23300 | case BuiltinFnIdFloor: | ||
| 23301 | case BuiltinFnIdCeil: | ||
| 23302 | case BuiltinFnIdTrunc: | ||
| 23303 | case BuiltinFnIdNearbyInt: | ||
| 23304 | case BuiltinFnIdRound: | ||
| 23305 | zig_panic("unimplemented f16 builtin"); | ||
| 23306 | default: | ||
| 23307 | zig_unreachable(); | ||
| 23308 | }; | ||
| 23309 | break; | ||
| 23310 | }; | ||
| 23311 | case 32: { | ||
| 23312 | switch (fop) { | ||
| 23313 | case BuiltinFnIdSqrt: | ||
| 23314 | out_val->data.x_f32 = sqrtf(op->data.x_f32); | ||
| 23315 | break; | ||
| 23316 | case BuiltinFnIdSin: | ||
| 23317 | out_val->data.x_f32 = sinf(op->data.x_f32); | ||
| 23318 | break; | ||
| 23319 | case BuiltinFnIdCos: | ||
| 23320 | out_val->data.x_f32 = cosf(op->data.x_f32); | ||
| 23321 | break; | ||
| 23322 | case BuiltinFnIdExp: | ||
| 23323 | out_val->data.x_f32 = expf(op->data.x_f32); | ||
| 23324 | break; | ||
| 23325 | case BuiltinFnIdExp2: | ||
| 23326 | out_val->data.x_f32 = exp2f(op->data.x_f32); | ||
| 23327 | break; | ||
| 23328 | case BuiltinFnIdLn: | ||
| 23329 | out_val->data.x_f32 = logf(op->data.x_f32); | ||
| 23330 | break; | ||
| 23331 | case BuiltinFnIdLog10: | ||
| 23332 | out_val->data.x_f32 = log10f(op->data.x_f32); | ||
| 23333 | break; | ||
| 23334 | case BuiltinFnIdLog2: | ||
| 23335 | out_val->data.x_f32 = log2f(op->data.x_f32); | ||
| 23336 | break; | ||
| 23337 | case BuiltinFnIdFabs: | ||
| 23338 | out_val->data.x_f32 = fabsf(op->data.x_f32); | ||
| 23339 | break; | ||
| 23340 | case BuiltinFnIdFloor: | ||
| 23341 | out_val->data.x_f32 = floorf(op->data.x_f32); | ||
| 23342 | break; | ||
| 23343 | case BuiltinFnIdCeil: | ||
| 23344 | out_val->data.x_f32 = ceilf(op->data.x_f32); | ||
| 23345 | break; | ||
| 23346 | case BuiltinFnIdTrunc: | ||
| 23347 | out_val->data.x_f32 = truncf(op->data.x_f32); | ||
| 23348 | break; | ||
| 23349 | case BuiltinFnIdNearbyInt: | ||
| 23350 | out_val->data.x_f32 = nearbyintf(op->data.x_f32); | ||
| 23351 | break; | ||
| 23352 | case BuiltinFnIdRound: | ||
| 23353 | out_val->data.x_f32 = roundf(op->data.x_f32); | ||
| 23354 | break; | ||
| 23355 | default: | ||
| 23356 | zig_unreachable(); | ||
| 23357 | }; | ||
| 23358 | break; | ||
| 23359 | }; | ||
| 23360 | case 64: { | ||
| 23361 | switch (fop) { | ||
| 23362 | case BuiltinFnIdSqrt: | ||
| 23363 | out_val->data.x_f64 = sqrt(op->data.x_f64); | ||
| 23364 | break; | ||
| 23365 | case BuiltinFnIdSin: | ||
| 23366 | out_val->data.x_f64 = sin(op->data.x_f64); | ||
| 23367 | break; | ||
| 23368 | case BuiltinFnIdCos: | ||
| 23369 | out_val->data.x_f64 = cos(op->data.x_f64); | ||
| 23370 | break; | ||
| 23371 | case BuiltinFnIdExp: | ||
| 23372 | out_val->data.x_f64 = exp(op->data.x_f64); | ||
| 23373 | break; | ||
| 23374 | case BuiltinFnIdExp2: | ||
| 23375 | out_val->data.x_f64 = exp2(op->data.x_f64); | ||
| 23376 | break; | ||
| 23377 | case BuiltinFnIdLn: | ||
| 23378 | out_val->data.x_f64 = log(op->data.x_f64); | ||
| 23379 | break; | ||
| 23380 | case BuiltinFnIdLog10: | ||
| 23381 | out_val->data.x_f64 = log10(op->data.x_f64); | ||
| 23382 | break; | ||
| 23383 | case BuiltinFnIdLog2: | ||
| 23384 | out_val->data.x_f64 = log2(op->data.x_f64); | ||
| 23385 | break; | ||
| 23386 | case BuiltinFnIdFabs: | ||
| 23387 | out_val->data.x_f64 = fabs(op->data.x_f64); | ||
| 23388 | break; | ||
| 23389 | case BuiltinFnIdFloor: | ||
| 23390 | out_val->data.x_f64 = floor(op->data.x_f64); | ||
| 23391 | break; | ||
| 23392 | case BuiltinFnIdCeil: | ||
| 23393 | out_val->data.x_f64 = ceil(op->data.x_f64); | ||
| 23394 | break; | ||
| 23395 | case BuiltinFnIdTrunc: | ||
| 23396 | out_val->data.x_f64 = trunc(op->data.x_f64); | ||
| 23397 | break; | ||
| 23398 | case BuiltinFnIdNearbyInt: | ||
| 23399 | out_val->data.x_f64 = nearbyint(op->data.x_f64); | ||
| 23400 | break; | ||
| 23401 | case BuiltinFnIdRound: | ||
| 23402 | out_val->data.x_f64 = round(op->data.x_f64); | ||
| 23403 | break; | ||
| 23404 | default: | ||
| 23405 | zig_unreachable(); | ||
| 23406 | } | ||
| 23407 | break; | ||
| 23408 | }; | ||
| 23409 | case 128: { | ||
| 23410 | float128_t *out, *in; | ||
| 23411 | if (float_type->id == ZigTypeIdComptimeFloat) { | ||
| 23412 | out = &out_val->data.x_bigfloat.value; | ||
| 23413 | in = &op->data.x_bigfloat.value; | ||
| 23414 | } else { | ||
| 23415 | out = &out_val->data.x_f128; | ||
| 23416 | in = &op->data.x_f128; | ||
| 23417 | } | ||
| 23418 | switch (fop) { | ||
| 23419 | case BuiltinFnIdSqrt: | ||
| 23420 | f128M_sqrt(in, out); | ||
| 23421 | break; | ||
| 23422 | case BuiltinFnIdNearbyInt: | ||
| 23423 | case BuiltinFnIdSin: | ||
| 23424 | case BuiltinFnIdCos: | ||
| 23425 | case BuiltinFnIdExp: | ||
| 23426 | case BuiltinFnIdExp2: | ||
| 23427 | case BuiltinFnIdLn: | ||
| 23428 | case BuiltinFnIdLog10: | ||
| 23429 | case BuiltinFnIdLog2: | ||
| 23430 | case BuiltinFnIdFabs: | ||
| 23431 | case BuiltinFnIdFloor: | ||
| 23432 | case BuiltinFnIdCeil: | ||
| 23433 | case BuiltinFnIdTrunc: | ||
| 23434 | case BuiltinFnIdRound: | ||
| 23435 | zig_panic("unimplemented f128 builtin"); | ||
| 23436 | default: | ||
| 23437 | zig_unreachable(); | ||
| 23438 | } | ||
| 23439 | break; | ||
| 23440 | }; | ||
| 23441 | default: | ||
| 23442 | zig_unreachable(); | ||
| 23443 | } | ||
| 23444 | } | ||
| 23445 | |||
| 23446 | static IrInstruction *ir_analyze_instruction_float_op(IrAnalyze *ira, IrInstructionFloatOp *instruction) { | ||
| 23447 | IrInstruction *type = instruction->type->child; | ||
| 23448 | if (type_is_invalid(type->value.type)) | ||
| 23449 | return ira->codegen->invalid_instruction; | ||
| 23450 | |||
| 23451 | ZigType *expr_type = ir_resolve_type(ira, type); | ||
| 23452 | if (type_is_invalid(expr_type)) | ||
| 23224 | return ira->codegen->invalid_instruction; | 23453 | return ira->codegen->invalid_instruction; |
| 23225 | 23454 | ||
| 23226 | bool ok_type = float_type->id == ZigTypeIdComptimeFloat || float_type->id == ZigTypeIdFloat; | 23455 | // Only allow float types, and vectors of floats. |
| 23227 | if (!ok_type) { | 23456 | ZigType *float_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type; |
| 23228 | ir_add_error(ira, instruction->type, buf_sprintf("@sqrt does not support type '%s'", buf_ptr(&float_type->name))); | 23457 | if (float_type->id != ZigTypeIdFloat && float_type->id != ZigTypeIdComptimeFloat) { |
| 23458 | ir_add_error(ira, instruction->type, buf_sprintf("@%s does not support type '%s'", float_op_to_name(instruction->op, false), buf_ptr(&float_type->name))); | ||
| 23229 | return ira->codegen->invalid_instruction; | 23459 | return ira->codegen->invalid_instruction; |
| 23230 | } | 23460 | } |
| 23231 | 23461 | ||
| 23232 | IrInstruction *casted_op = ir_implicit_cast(ira, op, float_type); | 23462 | IrInstruction *op1 = instruction->op1->child; |
| 23233 | if (type_is_invalid(casted_op->value.type)) | 23463 | if (type_is_invalid(op1->value.type)) |
| 23234 | return ira->codegen->invalid_instruction; | 23464 | return ira->codegen->invalid_instruction; |
| 23235 | 23465 | ||
| 23236 | if (instr_is_comptime(casted_op)) { | 23466 | IrInstruction *casted_op1 = ir_implicit_cast(ira, op1, float_type); |
| 23237 | ConstExprValue *val = ir_resolve_const(ira, casted_op, UndefBad); | 23467 | if (type_is_invalid(casted_op1->value.type)) |
| 23238 | if (!val) | 23468 | return ira->codegen->invalid_instruction; |
| 23469 | |||
| 23470 | if (instr_is_comptime(casted_op1)) { | ||
| 23471 | // Our comptime 16-bit and 128-bit support is quite limited. | ||
| 23472 | if ((float_type->id == ZigTypeIdComptimeFloat || | ||
| 23473 | float_type->data.floating.bit_count == 16 || | ||
| 23474 | float_type->data.floating.bit_count == 128) && | ||
| 23475 | instruction->op != BuiltinFnIdSqrt) { | ||
| 23476 | ir_add_error(ira, instruction->type, buf_sprintf("@%s does not support type '%s'", float_op_to_name(instruction->op, false), buf_ptr(&float_type->name))); | ||
| 23239 | return ira->codegen->invalid_instruction; | 23477 | return ira->codegen->invalid_instruction; |
| 23478 | } | ||
| 23240 | 23479 | ||
| 23241 | IrInstruction *result = ir_const(ira, &instruction->base, float_type); | 23480 | ConstExprValue *op1_const = ir_resolve_const(ira, casted_op1, UndefBad); |
| 23481 | if (!op1_const) | ||
| 23482 | return ira->codegen->invalid_instruction; | ||
| 23483 | |||
| 23484 | IrInstruction *result = ir_const(ira, &instruction->base, expr_type); | ||
| 23242 | ConstExprValue *out_val = &result->value; | 23485 | ConstExprValue *out_val = &result->value; |
| 23243 | 23486 | ||
| 23244 | if (float_type->id == ZigTypeIdComptimeFloat) { | 23487 | if (expr_type->id == ZigTypeIdVector) { |
| 23245 | bigfloat_sqrt(&out_val->data.x_bigfloat, &val->data.x_bigfloat); | 23488 | expand_undef_array(ira->codegen, op1_const); |
| 23246 | } else if (float_type->id == ZigTypeIdFloat) { | 23489 | out_val->special = ConstValSpecialUndef; |
| 23247 | switch (float_type->data.floating.bit_count) { | 23490 | expand_undef_array(ira->codegen, out_val); |
| 23248 | case 16: | 23491 | size_t len = expr_type->data.vector.len; |
| 23249 | out_val->data.x_f16 = f16_sqrt(val->data.x_f16); | 23492 | for (size_t i = 0; i < len; i += 1) { |
| 23250 | break; | 23493 | ConstExprValue *float_operand_op1 = &op1_const->data.x_array.data.s_none.elements[i]; |
| 23251 | case 32: | 23494 | ConstExprValue *float_out_val = &out_val->data.x_array.data.s_none.elements[i]; |
| 23252 | out_val->data.x_f32 = sqrtf(val->data.x_f32); | 23495 | assert(float_operand_op1->type == float_type); |
| 23253 | break; | 23496 | assert(float_out_val->type == float_type); |
| 23254 | case 64: | 23497 | ir_eval_float_op(ira, instruction, float_type, |
| 23255 | out_val->data.x_f64 = sqrt(val->data.x_f64); | 23498 | op1_const, float_out_val); |
| 23256 | break; | 23499 | float_out_val->type = float_type; |
| 23257 | case 128: | ||
| 23258 | f128M_sqrt(&val->data.x_f128, &out_val->data.x_f128); | ||
| 23259 | break; | ||
| 23260 | default: | ||
| 23261 | zig_unreachable(); | ||
| 23262 | } | 23500 | } |
| 23501 | out_val->type = expr_type; | ||
| 23502 | out_val->special = ConstValSpecialStatic; | ||
| 23263 | } else { | 23503 | } else { |
| 23264 | zig_unreachable(); | 23504 | ir_eval_float_op(ira, instruction, float_type, op1_const, out_val); |
| 23265 | } | 23505 | } |
| 23266 | |||
| 23267 | return result; | 23506 | return result; |
| 23268 | } | 23507 | } |
| 23269 | 23508 | ||
| 23270 | ir_assert(float_type->id == ZigTypeIdFloat, &instruction->base); | 23509 | ir_assert(float_type->id == ZigTypeIdFloat, &instruction->base); |
| 23271 | if (float_type->data.floating.bit_count != 16 && | ||
| 23272 | float_type->data.floating.bit_count != 32 && | ||
| 23273 | float_type->data.floating.bit_count != 64) { | ||
| 23274 | ir_add_error(ira, instruction->type, buf_sprintf("compiler TODO: add implementation of sqrt for '%s'", buf_ptr(&float_type->name))); | ||
| 23275 | return ira->codegen->invalid_instruction; | ||
| 23276 | } | ||
| 23277 | 23510 | ||
| 23278 | IrInstruction *result = ir_build_sqrt(&ira->new_irb, instruction->base.scope, | 23511 | IrInstruction *result = ir_build_float_op(&ira->new_irb, instruction->base.scope, |
| 23279 | instruction->base.source_node, nullptr, casted_op); | 23512 | instruction->base.source_node, nullptr, casted_op1, instruction->op); |
| 23280 | result->value.type = float_type; | 23513 | result->value.type = expr_type; |
| 23281 | return result; | 23514 | return result; |
| 23282 | } | 23515 | } |
| 23283 | 23516 | ||
| ... | @@ -23762,8 +23995,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio | ... | @@ -23762,8 +23995,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio |
| 23762 | return ir_analyze_instruction_merge_err_ret_traces(ira, (IrInstructionMergeErrRetTraces *)instruction); | 23995 | return ir_analyze_instruction_merge_err_ret_traces(ira, (IrInstructionMergeErrRetTraces *)instruction); |
| 23763 | case IrInstructionIdMarkErrRetTracePtr: | 23996 | case IrInstructionIdMarkErrRetTracePtr: |
| 23764 | return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction); | 23997 | return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction); |
| 23765 | case IrInstructionIdSqrt: | 23998 | case IrInstructionIdFloatOp: |
| 23766 | return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction); | 23999 | return ir_analyze_instruction_float_op(ira, (IrInstructionFloatOp *)instruction); |
| 23767 | case IrInstructionIdMulAdd: | 24000 | case IrInstructionIdMulAdd: |
| 23768 | return ir_analyze_instruction_mul_add(ira, (IrInstructionMulAdd *)instruction); | 24001 | return ir_analyze_instruction_mul_add(ira, (IrInstructionMulAdd *)instruction); |
| 23769 | case IrInstructionIdIntToErr: | 24002 | case IrInstructionIdIntToErr: |
| ... | @@ -24004,7 +24237,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -24004,7 +24237,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 24004 | case IrInstructionIdCoroFree: | 24237 | case IrInstructionIdCoroFree: |
| 24005 | case IrInstructionIdCoroPromise: | 24238 | case IrInstructionIdCoroPromise: |
| 24006 | case IrInstructionIdPromiseResultType: | 24239 | case IrInstructionIdPromiseResultType: |
| 24007 | case IrInstructionIdSqrt: | 24240 | case IrInstructionIdFloatOp: |
| 24008 | case IrInstructionIdMulAdd: | 24241 | case IrInstructionIdMulAdd: |
| 24009 | case IrInstructionIdAtomicLoad: | 24242 | case IrInstructionIdAtomicLoad: |
| 24010 | case IrInstructionIdIntCast: | 24243 | case IrInstructionIdIntCast: |
src/ir.hpp+1| ... | @@ -26,5 +26,6 @@ bool ir_has_side_effects(IrInstruction *instruction); | ... | @@ -26,5 +26,6 @@ bool ir_has_side_effects(IrInstruction *instruction); |
| 26 | struct IrAnalyze; | 26 | struct IrAnalyze; |
| 27 | ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprValue *const_val, | 27 | ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprValue *const_val, |
| 28 | AstNode *source_node); | 28 | AstNode *source_node); |
| 29 | const char *float_op_to_name(BuiltinFnId op, bool llvm_name); | ||
| 29 | 30 | ||
| 30 | #endif | 31 | #endif |
src/ir_print.cpp+6-5| ... | @@ -1427,15 +1427,16 @@ static void ir_print_mark_err_ret_trace_ptr(IrPrint *irp, IrInstructionMarkErrRe | ... | @@ -1427,15 +1427,16 @@ static void ir_print_mark_err_ret_trace_ptr(IrPrint *irp, IrInstructionMarkErrRe |
| 1427 | fprintf(irp->f, ")"); | 1427 | fprintf(irp->f, ")"); |
| 1428 | } | 1428 | } |
| 1429 | 1429 | ||
| 1430 | static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) { | 1430 | static void ir_print_float_op(IrPrint *irp, IrInstructionFloatOp *instruction) { |
| 1431 | fprintf(irp->f, "@sqrt("); | 1431 | |
| 1432 | fprintf(irp->f, "@%s(", float_op_to_name(instruction->op, false)); | ||
| 1432 | if (instruction->type != nullptr) { | 1433 | if (instruction->type != nullptr) { |
| 1433 | ir_print_other_instruction(irp, instruction->type); | 1434 | ir_print_other_instruction(irp, instruction->type); |
| 1434 | } else { | 1435 | } else { |
| 1435 | fprintf(irp->f, "null"); | 1436 | fprintf(irp->f, "null"); |
| 1436 | } | 1437 | } |
| 1437 | fprintf(irp->f, ","); | 1438 | fprintf(irp->f, ","); |
| 1438 | ir_print_other_instruction(irp, instruction->op); | 1439 | ir_print_other_instruction(irp, instruction->op1); |
| 1439 | fprintf(irp->f, ")"); | 1440 | fprintf(irp->f, ")"); |
| 1440 | } | 1441 | } |
| 1441 | 1442 | ||
| ... | @@ -1918,8 +1919,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1918,8 +1919,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1918 | case IrInstructionIdMarkErrRetTracePtr: | 1919 | case IrInstructionIdMarkErrRetTracePtr: |
| 1919 | ir_print_mark_err_ret_trace_ptr(irp, (IrInstructionMarkErrRetTracePtr *)instruction); | 1920 | ir_print_mark_err_ret_trace_ptr(irp, (IrInstructionMarkErrRetTracePtr *)instruction); |
| 1920 | break; | 1921 | break; |
| 1921 | case IrInstructionIdSqrt: | 1922 | case IrInstructionIdFloatOp: |
| 1922 | ir_print_sqrt(irp, (IrInstructionSqrt *)instruction); | 1923 | ir_print_float_op(irp, (IrInstructionFloatOp *)instruction); |
| 1923 | break; | 1924 | break; |
| 1924 | case IrInstructionIdMulAdd: | 1925 | case IrInstructionIdMulAdd: |
| 1925 | ir_print_mul_add(irp, (IrInstructionMulAdd *)instruction); | 1926 | ir_print_mul_add(irp, (IrInstructionMulAdd *)instruction); |
src/util.cpp+1| ... | @@ -13,6 +13,7 @@ | ... | @@ -13,6 +13,7 @@ |
| 13 | #include "userland.h" | 13 | #include "userland.h" |
| 14 | 14 | ||
| 15 | void zig_panic(const char *format, ...) { | 15 | void zig_panic(const char *format, ...) { |
| 16 | abort(); | ||
| 16 | va_list ap; | 17 | va_list ap; |
| 17 | va_start(ap, format); | 18 | va_start(ap, format); |
| 18 | vfprintf(stderr, format, ap); | 19 | vfprintf(stderr, format, ap); |
std/special/c.zig+26-18| ... | @@ -254,24 +254,32 @@ export fn fmod(x: f64, y: f64) f64 { | ... | @@ -254,24 +254,32 @@ export fn fmod(x: f64, y: f64) f64 { |
| 254 | 254 | ||
| 255 | // TODO add intrinsics for these (and probably the double version too) | 255 | // TODO add intrinsics for these (and probably the double version too) |
| 256 | // and have the math stuff use the intrinsic. same as @mod and @rem | 256 | // and have the math stuff use the intrinsic. same as @mod and @rem |
| 257 | export fn floorf(x: f32) f32 { | 257 | export fn floorf(x: f32) f32 {return math.floor(x);} |
| 258 | return math.floor(x); | 258 | export fn ceilf(x: f32) f32 {return math.ceil(x);} |
| 259 | } | 259 | export fn floor(x: f64) f64 {return math.floor(x);} |
| 260 | export fn ceilf(x: f32) f32 { | 260 | export fn ceil(x: f64) f64 {return math.ceil(x);} |
| 261 | return math.ceil(x); | 261 | export fn fma(a: f64, b: f64, c: f64) f64 {return math.fma(f64, a, b, c);} |
| 262 | } | 262 | export fn fmaf(a: f32, b: f32, c: f32) f32 {return math.fma(f32, a, b, c);} |
| 263 | export fn floor(x: f64) f64 { | 263 | export fn sin(a: f64) f64 {return math.sin(a);} |
| 264 | return math.floor(x); | 264 | export fn sinf(a: f32) f32 {return math.sin(a);} |
| 265 | } | 265 | export fn cos(a: f64) f64 {return math.cos(a);} |
| 266 | export fn ceil(x: f64) f64 { | 266 | export fn cosf(a: f32) f32 {return math.cos(a);} |
| 267 | return math.ceil(x); | 267 | export fn exp(a: f64) f64 {return math.exp(a);} |
| 268 | } | 268 | export fn expf(a: f32) f32 {return math.exp(a);} |
| 269 | export fn fma(a: f64, b: f64, c: f64) f64 { | 269 | export fn exp2(a: f64) f64 {return math.exp2(a);} |
| 270 | return math.fma(f64, a, b, c); | 270 | export fn exp2f(a: f32) f32 {return math.exp2(a);} |
| 271 | } | 271 | export fn log(a: f64) f64 {return math.ln(a);} |
| 272 | export fn fmaf(a: f32, b: f32, c: f32) f32 { | 272 | export fn logf(a: f32) f32 {return math.ln(a);} |
| 273 | return math.fma(f32, a, b, c); | 273 | export fn log2(a: f64) f64 {return math.log2(a);} |
| 274 | } | 274 | export fn log2f(a: f32) f32 {return math.log2(a);} |
| 275 | export fn log10(a: f64) f64 {return math.log10(a);} | ||
| 276 | export fn log10f(a: f32) f32 {return math.log10(a);} | ||
| 277 | export fn fabs(a: f64) f64 {return math.fabs(a);} | ||
| 278 | export fn fabsf(a: f32) f32 {return math.fabs(a);} | ||
| 279 | export fn trunc(a: f64) f64 {return math.trunc(a);} | ||
| 280 | export fn truncf(a: f32) f32 {return math.trunc(a);} | ||
| 281 | export fn round(a: f64) f64 {return math.round(a);} | ||
| 282 | export fn roundf(a: f32) f32 {return math.round(a);} | ||
| 275 | fn generic_fmod(comptime T: type, x: T, y: T) T { | 283 | fn generic_fmod(comptime T: type, x: T, y: T) T { |
| 276 | @setRuntimeSafety(false); | 284 | @setRuntimeSafety(false); |
| 277 | 285 |
test/stage1/behavior.zig+1| ... | @@ -71,6 +71,7 @@ comptime { | ... | @@ -71,6 +71,7 @@ comptime { |
| 71 | _ = @import("behavior/pointers.zig"); | 71 | _ = @import("behavior/pointers.zig"); |
| 72 | _ = @import("behavior/popcount.zig"); | 72 | _ = @import("behavior/popcount.zig"); |
| 73 | _ = @import("behavior/muladd.zig"); | 73 | _ = @import("behavior/muladd.zig"); |
| 74 | _ = @import("behavior/floatop.zig"); | ||
| 74 | _ = @import("behavior/ptrcast.zig"); | 75 | _ = @import("behavior/ptrcast.zig"); |
| 75 | _ = @import("behavior/pub_enum.zig"); | 76 | _ = @import("behavior/pub_enum.zig"); |
| 76 | _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); | 77 | _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); |
test/stage1/behavior/floatop.zig created+243| ... | @@ -0,0 +1,243 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | const pi = @import("std").math.pi; | ||
| 3 | const e = @import("std").math.e; | ||
| 4 | |||
| 5 | test "@sqrt" { | ||
| 6 | comptime testSqrt(); | ||
| 7 | testSqrt(); | ||
| 8 | } | ||
| 9 | |||
| 10 | fn testSqrt() void { | ||
| 11 | { | ||
| 12 | var a: f16 = 4; | ||
| 13 | expect(@sqrt(f16, a) == 2); | ||
| 14 | } | ||
| 15 | { | ||
| 16 | var a: f32 = 9; | ||
| 17 | expect(@sqrt(f32, a) == 3); | ||
| 18 | } | ||
| 19 | { | ||
| 20 | var a: f64 = 25; | ||
| 21 | expect(@sqrt(f64, a) == 5); | ||
| 22 | } | ||
| 23 | { | ||
| 24 | const a: comptime_float = 25.0; | ||
| 25 | expect(@sqrt(comptime_float, a) == 5.0); | ||
| 26 | } | ||
| 27 | // Waiting on a c.zig implementation | ||
| 28 | //{ | ||
| 29 | // var a: f128 = 49; | ||
| 30 | // expect(@sqrt(f128, a) == 7); | ||
| 31 | //} | ||
| 32 | } | ||
| 33 | |||
| 34 | test "@sin" { | ||
| 35 | comptime testSin(); | ||
| 36 | testSin(); | ||
| 37 | } | ||
| 38 | |||
| 39 | fn testSin() void { | ||
| 40 | // TODO - this is actually useful and should be implemented | ||
| 41 | // (all the trig functions for f16) | ||
| 42 | // but will probably wait till self-hosted | ||
| 43 | //{ | ||
| 44 | // var a: f16 = pi; | ||
| 45 | // expect(@sin(f16, a/2) == 1); | ||
| 46 | //} | ||
| 47 | { | ||
| 48 | var a: f32 = 0; | ||
| 49 | expect(@sin(f32, a) == 0); | ||
| 50 | } | ||
| 51 | { | ||
| 52 | var a: f64 = 0; | ||
| 53 | expect(@sin(f64, a) == 0); | ||
| 54 | } | ||
| 55 | // TODO | ||
| 56 | //{ | ||
| 57 | // var a: f16 = pi; | ||
| 58 | // expect(@sqrt(f128, a/2) == 1); | ||
| 59 | //} | ||
| 60 | } | ||
| 61 | |||
| 62 | test "@cos" { | ||
| 63 | comptime testCos(); | ||
| 64 | testCos(); | ||
| 65 | } | ||
| 66 | |||
| 67 | fn testCos() void { | ||
| 68 | { | ||
| 69 | var a: f32 = 0; | ||
| 70 | expect(@cos(f32, a) == 1); | ||
| 71 | } | ||
| 72 | { | ||
| 73 | var a: f64 = 0; | ||
| 74 | expect(@cos(f64, a) == 1); | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | test "@exp" { | ||
| 79 | comptime testExp(); | ||
| 80 | testExp(); | ||
| 81 | } | ||
| 82 | |||
| 83 | fn testExp() void { | ||
| 84 | { | ||
| 85 | var a: f32 = 0; | ||
| 86 | expect(@exp(f32, a) == 1); | ||
| 87 | } | ||
| 88 | { | ||
| 89 | var a: f64 = 0; | ||
| 90 | expect(@exp(f64, a) == 1); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | test "@exp2" { | ||
| 95 | comptime testExp2(); | ||
| 96 | testExp2(); | ||
| 97 | } | ||
| 98 | |||
| 99 | fn testExp2() void { | ||
| 100 | { | ||
| 101 | var a: f32 = 2; | ||
| 102 | expect(@exp2(f32, a) == 4); | ||
| 103 | } | ||
| 104 | { | ||
| 105 | var a: f64 = 2; | ||
| 106 | expect(@exp2(f64, a) == 4); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | test "@ln" { | ||
| 111 | // Old musl (and glibc?), and our current math.ln implementation do not return 1 | ||
| 112 | // so also accept those values. | ||
| 113 | comptime testLn(); | ||
| 114 | testLn(); | ||
| 115 | } | ||
| 116 | |||
| 117 | fn testLn() void { | ||
| 118 | { | ||
| 119 | var a: f32 = e; | ||
| 120 | expect(@ln(f32, a) == 1 or @ln(f32, a) == @bitCast(f32, u32(0x3f7fffff))); | ||
| 121 | } | ||
| 122 | { | ||
| 123 | var a: f64 = e; | ||
| 124 | expect(@ln(f64, a) == 1 or @ln(f64, a) == @bitCast(f64, u64(0x3ff0000000000000))); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | test "@log2" { | ||
| 129 | comptime testLog2(); | ||
| 130 | testLog2(); | ||
| 131 | } | ||
| 132 | |||
| 133 | fn testLog2() void { | ||
| 134 | { | ||
| 135 | var a: f32 = 4; | ||
| 136 | expect(@log2(f32, a) == 2); | ||
| 137 | } | ||
| 138 | { | ||
| 139 | var a: f64 = 4; | ||
| 140 | expect(@log2(f64, a) == 2); | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | test "@log10" { | ||
| 145 | comptime testLog10(); | ||
| 146 | testLog10(); | ||
| 147 | } | ||
| 148 | |||
| 149 | fn testLog10() void { | ||
| 150 | { | ||
| 151 | var a: f32 = 100; | ||
| 152 | expect(@log10(f32, a) == 2); | ||
| 153 | } | ||
| 154 | { | ||
| 155 | var a: f64 = 1000; | ||
| 156 | expect(@log10(f64, a) == 3); | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | test "@fabs" { | ||
| 161 | comptime testFabs(); | ||
| 162 | testFabs(); | ||
| 163 | } | ||
| 164 | |||
| 165 | fn testFabs() void { | ||
| 166 | { | ||
| 167 | var a: f32 = -2.5; | ||
| 168 | var b: f32 = 2.5; | ||
| 169 | expect(@fabs(f32, a) == 2.5); | ||
| 170 | expect(@fabs(f32, b) == 2.5); | ||
| 171 | } | ||
| 172 | { | ||
| 173 | var a: f64 = -2.5; | ||
| 174 | var b: f64 = 2.5; | ||
| 175 | expect(@fabs(f64, a) == 2.5); | ||
| 176 | expect(@fabs(f64, b) == 2.5); | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | test "@floor" { | ||
| 181 | comptime testFloor(); | ||
| 182 | testFloor(); | ||
| 183 | } | ||
| 184 | |||
| 185 | fn testFloor() void { | ||
| 186 | { | ||
| 187 | var a: f32 = 2.1; | ||
| 188 | expect(@floor(f32, a) == 2); | ||
| 189 | } | ||
| 190 | { | ||
| 191 | var a: f64 = 3.5; | ||
| 192 | expect(@floor(f64, a) == 3); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | test "@ceil" { | ||
| 197 | comptime testCeil(); | ||
| 198 | testCeil(); | ||
| 199 | } | ||
| 200 | |||
| 201 | fn testCeil() void { | ||
| 202 | { | ||
| 203 | var a: f32 = 2.1; | ||
| 204 | expect(@ceil(f32, a) == 3); | ||
| 205 | } | ||
| 206 | { | ||
| 207 | var a: f64 = 3.5; | ||
| 208 | expect(@ceil(f64, a) == 4); | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | test "@trunc" { | ||
| 213 | comptime testTrunc(); | ||
| 214 | testTrunc(); | ||
| 215 | } | ||
| 216 | |||
| 217 | fn testTrunc() void { | ||
| 218 | { | ||
| 219 | var a: f32 = 2.1; | ||
| 220 | expect(@trunc(f32, a) == 2); | ||
| 221 | } | ||
| 222 | { | ||
| 223 | var a: f64 = -3.5; | ||
| 224 | expect(@trunc(f64, a) == -3); | ||
| 225 | } | ||
| 226 | } | ||
| 227 | |||
| 228 | // This is waiting on library support for the Windows build (not sure why the other's don't need it) | ||
| 229 | //test "@nearbyInt" { | ||
| 230 | // comptime testNearbyInt(); | ||
| 231 | // testNearbyInt(); | ||
| 232 | //} | ||
| 233 | |||
| 234 | //fn testNearbyInt() void { | ||
| 235 | // { | ||
| 236 | // var a: f32 = 2.1; | ||
| 237 | // expect(@nearbyInt(f32, a) == 2); | ||
| 238 | // } | ||
| 239 | // { | ||
| 240 | // var a: f64 = -3.75; | ||
| 241 | // expect(@nearbyInt(f64, a) == -4); | ||
| 242 | // } | ||
| 243 | //} | ||