authorgravatar for shawn@git.icuShawn Landden <shawn@git.icu> 2019-06-21 16:18:59-05:00
committergravatar for shawn@git.icuShawn Landden <shawn@git.icu> 2019-06-22 14:34:34-05:00
log71e014caecaa54fdd8a0516710d2d9597da41398
tree4cfc85ed66ba9aec49e3f672a80c39b98e598177
parentebde2ff899c16612c7ff58df61f3946be47c51c8

stage1: add @sin @cos @exp @exp2 @ln @log2 @log10 @fabs @floor @ceil @trunc @round

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 instruction7356 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#}
73637444
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 vector1601 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};
34763488
3477struct IrInstructionSqrt {3489// For float ops which take a single argument
3490struct IrInstructionFloatOp {
3478 IrInstruction base;3491 IrInstruction base;
34793492
3493 BuiltinFnId op;
3480 IrInstruction *type;3494 IrInstruction *type;
3481 IrInstruction *op;3495 IrInstruction *op1;
3482};3496};
34833497
3484struct IrInstructionCheckRuntimeScope {3498struct 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}
808808
809static LLVMValueRef get_float_fn(CodeGen *g, ZigType *type_entry, ZigLLVMFnId fn_id) {809static 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);
812812
...@@ -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;
820821
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
824825
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}
24822477
2483static LLVMValueRef gen_floor(CodeGen *g, LLVMValueRef val, ZigType *type_entry) {2478static 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);
24862484
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}
24902488
2491static 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
2499enum DivKind {2489enum 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);
25942584
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);
25992589
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);
26042594
...@@ -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}
54525442
5453static LLVMValueRef ir_render_sqrt(CodeGen *g, IrExecutable *executable, IrInstructionSqrt *instruction) {5443static 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}
54595449
...@@ -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}
993993
994static constexpr IrInstructionId ir_instruction_id(IrInstructionSqrt *) {994static constexpr IrInstructionId ir_instruction_id(IrInstructionFloatOp *) {
995 return IrInstructionIdSqrt;995 return IrInstructionIdFloatOp;
996}996}
997997
998static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) {998static 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}
23142314
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.
2319const 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
2356static 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
2315static IrInstruction *ir_build_mul_add(IrBuilder *irb, Scope *scope, AstNode *source_node,2368static 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}
30353088
3036static 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
3047static IrInstruction *ir_build_has_decl(IrBuilder *irb, Scope *scope, AstNode *source_node,3089static 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;
44134468
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}
2321623271
23217static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionSqrt *instruction) {23272static 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);
2322123277
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
23446static 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;
2322523454
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 }
2323123461
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;
2323523465
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 }
2324023479
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;
2324323486
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 }
2326923508
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 }
2327723510
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}
2328323516
...@@ -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);
26struct IrAnalyze;26struct IrAnalyze;
27ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprValue *const_val,27ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprValue *const_val,
28 AstNode *source_node);28 AstNode *source_node);
29const char *float_op_to_name(BuiltinFnId op, bool llvm_name);
2930
30#endif31#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}
14291429
1430static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) {1430static 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}
14411442
...@@ -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"
1414
15void zig_panic(const char *format, ...) {15void 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 {
254254
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 @rem256// and have the math stuff use the intrinsic. same as @mod and @rem
257export fn floorf(x: f32) f32 {257export fn floorf(x: f32) f32 {return math.floor(x);}
258 return math.floor(x);258export fn ceilf(x: f32) f32 {return math.ceil(x);}
259}259export fn floor(x: f64) f64 {return math.floor(x);}
260export fn ceilf(x: f32) f32 {260export fn ceil(x: f64) f64 {return math.ceil(x);}
261 return math.ceil(x);261export fn fma(a: f64, b: f64, c: f64) f64 {return math.fma(f64, a, b, c);}
262}262export fn fmaf(a: f32, b: f32, c: f32) f32 {return math.fma(f32, a, b, c);}
263export fn floor(x: f64) f64 {263export fn sin(a: f64) f64 {return math.sin(a);}
264 return math.floor(x);264export fn sinf(a: f32) f32 {return math.sin(a);}
265}265export fn cos(a: f64) f64 {return math.cos(a);}
266export fn ceil(x: f64) f64 {266export fn cosf(a: f32) f32 {return math.cos(a);}
267 return math.ceil(x);267export fn exp(a: f64) f64 {return math.exp(a);}
268}268export fn expf(a: f32) f32 {return math.exp(a);}
269export fn fma(a: f64, b: f64, c: f64) f64 {269export fn exp2(a: f64) f64 {return math.exp2(a);}
270 return math.fma(f64, a, b, c);270export fn exp2f(a: f32) f32 {return math.exp2(a);}
271}271export fn log(a: f64) f64 {return math.ln(a);}
272export fn fmaf(a: f32, b: f32, c: f32) f32 {272export fn logf(a: f32) f32 {return math.ln(a);}
273 return math.fma(f32, a, b, c);273export fn log2(a: f64) f64 {return math.log2(a);}
274}274export fn log2f(a: f32) f32 {return math.log2(a);}
275export fn log10(a: f64) f64 {return math.log10(a);}
276export fn log10f(a: f32) f32 {return math.log10(a);}
277export fn fabs(a: f64) f64 {return math.fabs(a);}
278export fn fabsf(a: f32) f32 {return math.fabs(a);}
279export fn trunc(a: f64) f64 {return math.trunc(a);}
280export fn truncf(a: f32) f32 {return math.trunc(a);}
281export fn round(a: f64) f64 {return math.round(a);}
282export fn roundf(a: f32) f32 {return math.round(a);}
275fn generic_fmod(comptime T: type, x: T, y: T) T {283fn generic_fmod(comptime T: type, x: T, y: T) T {
276 @setRuntimeSafety(false);284 @setRuntimeSafety(false);
277285
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 @@
1const expect = @import("std").testing.expect;
2const pi = @import("std").math.pi;
3const e = @import("std").math.e;
4
5test "@sqrt" {
6 comptime testSqrt();
7 testSqrt();
8}
9
10fn 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
34test "@sin" {
35 comptime testSin();
36 testSin();
37}
38
39fn 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
62test "@cos" {
63 comptime testCos();
64 testCos();
65}
66
67fn 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
78test "@exp" {
79 comptime testExp();
80 testExp();
81}
82
83fn 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
94test "@exp2" {
95 comptime testExp2();
96 testExp2();
97}
98
99fn 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
110test "@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
117fn 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
128test "@log2" {
129 comptime testLog2();
130 testLog2();
131}
132
133fn 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
144test "@log10" {
145 comptime testLog10();
146 testLog10();
147}
148
149fn 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
160test "@fabs" {
161 comptime testFabs();
162 testFabs();
163}
164
165fn 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
180test "@floor" {
181 comptime testFloor();
182 testFloor();
183}
184
185fn 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
196test "@ceil" {
197 comptime testCeil();
198 testCeil();
199}
200
201fn 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
212test "@trunc" {
213 comptime testTrunc();
214 testTrunc();
215}
216
217fn 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//}