| author | |
| committer | |
| log | 24400d5882aa2b83a4aed3e4c1503d0393e1c541 |
| tree | d06324bd3d1e58757d2843c97a2b6392dc5a3505 |
| parent | ca3660f6bf3a1f8d77692acf72eefe148802d342 |
| parent | 7f4de2dfdbeac4457e6e3170dad9ba9bf67ac9c8 |
| signature |
12 files changed, 1008 insertions(+), 128 deletions(-)
CMakeLists.txt+2| ... | @@ -389,6 +389,8 @@ set(EMBEDDED_SOFTFLOAT_SOURCES | ... | @@ -389,6 +389,8 @@ set(EMBEDDED_SOFTFLOAT_SOURCES |
| 389 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subMagsF32.c" | 389 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subMagsF32.c" |
| 390 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subMagsF64.c" | 390 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subMagsF64.c" |
| 391 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_tryPropagateNaNF128M.c" | 391 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_tryPropagateNaNF128M.c" |
| 392 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_mulAdd.c" | ||
| 393 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_mulAdd.c" | ||
| 392 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/softfloat_state.c" | 394 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/softfloat_state.c" |
| 393 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui32_to_f128M.c" | 395 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui32_to_f128M.c" |
| 394 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui64_to_f128M.c" | 396 | "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui64_to_f128M.c" |
doc/langref.html.in+90-2| ... | @@ -6259,6 +6259,13 @@ comptime { | ... | @@ -6259,6 +6259,13 @@ comptime { |
| 6259 | This function is only valid within function scope. | 6259 | This function is only valid within function scope. |
| 6260 | </p> | 6260 | </p> |
| 6261 | 6261 | ||
| 6262 | {#header_close#} | ||
| 6263 | {#header_open|@mulAdd#} | ||
| 6264 | <pre>{#syntax#}@mulAdd(comptime T: type, a: T, b: T, c: T) T{#endsyntax#}</pre> | ||
| 6265 | <p> | ||
| 6266 | Fused multiply add (for floats), similar to {#syntax#}(a * b) + c{#endsyntax#}, except | ||
| 6267 | only rounds once, and is thus more accurate. | ||
| 6268 | </p> | ||
| 6262 | {#header_close#} | 6269 | {#header_close#} |
| 6263 | 6270 | ||
| 6264 | {#header_open|@byteSwap#} | 6271 | {#header_open|@byteSwap#} |
| ... | @@ -7347,10 +7354,91 @@ test "@setRuntimeSafety" { | ... | @@ -7347,10 +7354,91 @@ test "@setRuntimeSafety" { |
| 7347 | <pre>{#syntax#}@sqrt(comptime T: type, value: T) T{#endsyntax#}</pre> | 7354 | <pre>{#syntax#}@sqrt(comptime T: type, value: T) T{#endsyntax#}</pre> |
| 7348 | <p> | 7355 | <p> |
| 7349 | 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 |
| 7350 | 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> | ||
| 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. | ||
| 7351 | </p> | 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> | ||
| 7352 | <p> | 7439 | <p> |
| 7353 | 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. | ||
| 7354 | </p> | 7442 | </p> |
| 7355 | {#header_close#} | 7443 | {#header_close#} |
| 7356 | 7444 |
src/all_types.hpp+33-6| ... | @@ -1406,6 +1406,7 @@ enum BuiltinFnId { | ... | @@ -1406,6 +1406,7 @@ enum BuiltinFnId { |
| 1406 | BuiltinFnIdSubWithOverflow, | 1406 | BuiltinFnIdSubWithOverflow, |
| 1407 | BuiltinFnIdMulWithOverflow, | 1407 | BuiltinFnIdMulWithOverflow, |
| 1408 | BuiltinFnIdShlWithOverflow, | 1408 | BuiltinFnIdShlWithOverflow, |
| 1409 | BuiltinFnIdMulAdd, | ||
| 1409 | BuiltinFnIdCInclude, | 1410 | BuiltinFnIdCInclude, |
| 1410 | BuiltinFnIdCDefine, | 1411 | BuiltinFnIdCDefine, |
| 1411 | BuiltinFnIdCUndef, | 1412 | BuiltinFnIdCUndef, |
| ... | @@ -1433,6 +1434,19 @@ enum BuiltinFnId { | ... | @@ -1433,6 +1434,19 @@ enum BuiltinFnId { |
| 1433 | BuiltinFnIdRem, | 1434 | BuiltinFnIdRem, |
| 1434 | BuiltinFnIdMod, | 1435 | BuiltinFnIdMod, |
| 1435 | 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, | ||
| 1436 | BuiltinFnIdTruncate, | 1450 | BuiltinFnIdTruncate, |
| 1437 | BuiltinFnIdIntCast, | 1451 | BuiltinFnIdIntCast, |
| 1438 | BuiltinFnIdFloatCast, | 1452 | BuiltinFnIdFloatCast, |
| ... | @@ -1554,9 +1568,8 @@ enum ZigLLVMFnId { | ... | @@ -1554,9 +1568,8 @@ enum ZigLLVMFnId { |
| 1554 | ZigLLVMFnIdClz, | 1568 | ZigLLVMFnIdClz, |
| 1555 | ZigLLVMFnIdPopCount, | 1569 | ZigLLVMFnIdPopCount, |
| 1556 | ZigLLVMFnIdOverflowArithmetic, | 1570 | ZigLLVMFnIdOverflowArithmetic, |
| 1557 | ZigLLVMFnIdFloor, | 1571 | ZigLLVMFnIdFMA, |
| 1558 | ZigLLVMFnIdCeil, | 1572 | ZigLLVMFnIdFloatOp, |
| 1559 | ZigLLVMFnIdSqrt, | ||
| 1560 | ZigLLVMFnIdBswap, | 1573 | ZigLLVMFnIdBswap, |
| 1561 | ZigLLVMFnIdBitReverse, | 1574 | ZigLLVMFnIdBitReverse, |
| 1562 | }; | 1575 | }; |
| ... | @@ -1583,7 +1596,9 @@ struct ZigLLVMFnKey { | ... | @@ -1583,7 +1596,9 @@ struct ZigLLVMFnKey { |
| 1583 | uint32_t bit_count; | 1596 | uint32_t bit_count; |
| 1584 | } pop_count; | 1597 | } pop_count; |
| 1585 | struct { | 1598 | struct { |
| 1599 | BuiltinFnId op; | ||
| 1586 | uint32_t bit_count; | 1600 | uint32_t bit_count; |
| 1601 | uint32_t vector_len; // 0 means not a vector | ||
| 1587 | } floating; | 1602 | } floating; |
| 1588 | struct { | 1603 | struct { |
| 1589 | AddSubMul add_sub_mul; | 1604 | AddSubMul add_sub_mul; |
| ... | @@ -2235,6 +2250,8 @@ enum IrInstructionId { | ... | @@ -2235,6 +2250,8 @@ enum IrInstructionId { |
| 2235 | IrInstructionIdHandle, | 2250 | IrInstructionIdHandle, |
| 2236 | IrInstructionIdAlignOf, | 2251 | IrInstructionIdAlignOf, |
| 2237 | IrInstructionIdOverflowOp, | 2252 | IrInstructionIdOverflowOp, |
| 2253 | IrInstructionIdMulAdd, | ||
| 2254 | IrInstructionIdFloatOp, | ||
| 2238 | IrInstructionIdTestErr, | 2255 | IrInstructionIdTestErr, |
| 2239 | IrInstructionIdUnwrapErrCode, | 2256 | IrInstructionIdUnwrapErrCode, |
| 2240 | IrInstructionIdUnwrapErrPayload, | 2257 | IrInstructionIdUnwrapErrPayload, |
| ... | @@ -2296,7 +2313,6 @@ enum IrInstructionId { | ... | @@ -2296,7 +2313,6 @@ enum IrInstructionId { |
| 2296 | IrInstructionIdAddImplicitReturnType, | 2313 | IrInstructionIdAddImplicitReturnType, |
| 2297 | IrInstructionIdMergeErrRetTraces, | 2314 | IrInstructionIdMergeErrRetTraces, |
| 2298 | IrInstructionIdMarkErrRetTracePtr, | 2315 | IrInstructionIdMarkErrRetTracePtr, |
| 2299 | IrInstructionIdSqrt, | ||
| 2300 | IrInstructionIdErrSetCast, | 2316 | IrInstructionIdErrSetCast, |
| 2301 | IrInstructionIdToBytes, | 2317 | IrInstructionIdToBytes, |
| 2302 | IrInstructionIdFromBytes, | 2318 | IrInstructionIdFromBytes, |
| ... | @@ -3038,6 +3054,15 @@ struct IrInstructionOverflowOp { | ... | @@ -3038,6 +3054,15 @@ struct IrInstructionOverflowOp { |
| 3038 | ZigType *result_ptr_type; | 3054 | ZigType *result_ptr_type; |
| 3039 | }; | 3055 | }; |
| 3040 | 3056 | ||
| 3057 | struct IrInstructionMulAdd { | ||
| 3058 | IrInstruction base; | ||
| 3059 | |||
| 3060 | IrInstruction *type_value; | ||
| 3061 | IrInstruction *op1; | ||
| 3062 | IrInstruction *op2; | ||
| 3063 | IrInstruction *op3; | ||
| 3064 | }; | ||
| 3065 | |||
| 3041 | struct IrInstructionAlignOf { | 3066 | struct IrInstructionAlignOf { |
| 3042 | IrInstruction base; | 3067 | IrInstruction base; |
| 3043 | 3068 | ||
| ... | @@ -3461,11 +3486,13 @@ struct IrInstructionMarkErrRetTracePtr { | ... | @@ -3461,11 +3486,13 @@ struct IrInstructionMarkErrRetTracePtr { |
| 3461 | IrInstruction *err_ret_trace_ptr; | 3486 | IrInstruction *err_ret_trace_ptr; |
| 3462 | }; | 3487 | }; |
| 3463 | 3488 | ||
| 3464 | struct IrInstructionSqrt { | 3489 | // For float ops which take a single argument |
| 3490 | struct IrInstructionFloatOp { | ||
| 3465 | IrInstruction base; | 3491 | IrInstruction base; |
| 3466 | 3492 | ||
| 3493 | BuiltinFnId op; | ||
| 3467 | IrInstruction *type; | 3494 | IrInstruction *type; |
| 3468 | IrInstruction *op; | 3495 | IrInstruction *op1; |
| 3469 | }; | 3496 | }; |
| 3470 | 3497 | ||
| 3471 | struct IrInstructionCheckRuntimeScope { | 3498 | struct IrInstructionCheckRuntimeScope { |
src/analyze.cpp+14-10| ... | @@ -5736,12 +5736,13 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { | ... | @@ -5736,12 +5736,13 @@ 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 | return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1899859168; | 5740 | return (uint32_t)(x.data.floating.bit_count) * ((uint32_t)x.id + 1025) + |
| 5741 | case ZigLLVMFnIdCeil: | 5741 | (uint32_t)(x.data.floating.vector_len) * (((uint32_t)x.id << 5) + 1025) + |
| 5742 | return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1953839089; | 5742 | (uint32_t)(x.data.floating.op) * (uint32_t)43789879; |
| 5743 | case ZigLLVMFnIdSqrt: | 5743 | case ZigLLVMFnIdFMA: |
| 5744 | return (uint32_t)(x.data.floating.bit_count) * (uint32_t)2225366385; | 5744 | return (uint32_t)(x.data.floating.bit_count) * ((uint32_t)x.id + 1025) + |
| 5745 | (uint32_t)(x.data.floating.vector_len) * (((uint32_t)x.id << 5) + 1025); | ||
| 5745 | case ZigLLVMFnIdBswap: | 5746 | case ZigLLVMFnIdBswap: |
| 5746 | return (uint32_t)(x.data.bswap.bit_count) * (uint32_t)3661994335; | 5747 | return (uint32_t)(x.data.bswap.bit_count) * (uint32_t)3661994335; |
| 5747 | case ZigLLVMFnIdBitReverse: | 5748 | case ZigLLVMFnIdBitReverse: |
| ... | @@ -5769,10 +5770,13 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { | ... | @@ -5769,10 +5770,13 @@ 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; |
| 5777 | case ZigLLVMFnIdFMA: | ||
| 5778 | return a.data.floating.bit_count == b.data.floating.bit_count && | ||
| 5779 | a.data.floating.vector_len == b.data.floating.vector_len; | ||
| 5776 | case ZigLLVMFnIdOverflowArithmetic: | 5780 | case ZigLLVMFnIdOverflowArithmetic: |
| 5777 | return (a.data.overflow_arithmetic.bit_count == b.data.overflow_arithmetic.bit_count) && | 5781 | return (a.data.overflow_arithmetic.bit_count == b.data.overflow_arithmetic.bit_count) && |
| 5778 | (a.data.overflow_arithmetic.add_sub_mul == b.data.overflow_arithmetic.add_sub_mul) && | 5782 | (a.data.overflow_arithmetic.add_sub_mul == b.data.overflow_arithmetic.add_sub_mul) && |
src/codegen.cpp+73-31| ... | @@ -806,32 +806,47 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, ZigType *operand_type, AddSu | ... | @@ -806,32 +806,47 @@ 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); | ||
| 812 | |||
| 813 | bool is_vector = (type_entry->id == ZigTypeIdVector); | ||
| 814 | ZigType *float_type = is_vector ? type_entry->data.vector.elem_type : type_entry; | ||
| 811 | 815 | ||
| 812 | ZigLLVMFnKey key = {}; | 816 | ZigLLVMFnKey key = {}; |
| 813 | key.id = fn_id; | 817 | key.id = fn_id; |
| 814 | key.data.floating.bit_count = (uint32_t)type_entry->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; | ||
| 820 | key.data.floating.op = op; | ||
| 815 | 821 | ||
| 816 | auto existing_entry = g->llvm_fn_table.maybe_get(key); | 822 | auto existing_entry = g->llvm_fn_table.maybe_get(key); |
| 817 | if (existing_entry) | 823 | if (existing_entry) |
| 818 | return existing_entry->value; | 824 | return existing_entry->value; |
| 819 | 825 | ||
| 820 | const char *name; | 826 | const char *name; |
| 821 | if (fn_id == ZigLLVMFnIdFloor) { | 827 | uint32_t num_args; |
| 822 | name = "floor"; | 828 | if (fn_id == ZigLLVMFnIdFMA) { |
| 823 | } else if (fn_id == ZigLLVMFnIdCeil) { | 829 | name = "fma"; |
| 824 | name = "ceil"; | 830 | num_args = 3; |
| 825 | } else if (fn_id == ZigLLVMFnIdSqrt) { | 831 | } else if (fn_id == ZigLLVMFnIdFloatOp) { |
| 826 | name = "sqrt"; | 832 | name = float_op_to_name(op, true); |
| 833 | num_args = 1; | ||
| 827 | } else { | 834 | } else { |
| 828 | zig_unreachable(); | 835 | zig_unreachable(); |
| 829 | } | 836 | } |
| 830 | 837 | ||
| 831 | char fn_name[64]; | 838 | char fn_name[64]; |
| 832 | sprintf(fn_name, "llvm.%s.f%" ZIG_PRI_usize "", name, type_entry->data.floating.bit_count); | 839 | if (is_vector) |
| 840 | sprintf(fn_name, "llvm.%s.v%" PRIu32 "f%" PRIu32, name, key.data.floating.vector_len, key.data.floating.bit_count); | ||
| 841 | else | ||
| 842 | sprintf(fn_name, "llvm.%s.f%" PRIu32, name, key.data.floating.bit_count); | ||
| 833 | LLVMTypeRef float_type_ref = get_llvm_type(g, type_entry); | 843 | LLVMTypeRef float_type_ref = get_llvm_type(g, type_entry); |
| 834 | LLVMTypeRef fn_type = LLVMFunctionType(float_type_ref, &float_type_ref, 1, false); | 844 | LLVMTypeRef return_elem_types[3] = { |
| 845 | float_type_ref, | ||
| 846 | float_type_ref, | ||
| 847 | float_type_ref, | ||
| 848 | }; | ||
| 849 | LLVMTypeRef fn_type = LLVMFunctionType(float_type_ref, return_elem_types, num_args, false); | ||
| 835 | LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type); | 850 | LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type); |
| 836 | assert(LLVMGetIntrinsicID(fn_val)); | 851 | assert(LLVMGetIntrinsicID(fn_val)); |
| 837 | 852 | ||
| ... | @@ -2460,22 +2475,17 @@ static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *type_entry, | ... | @@ -2460,22 +2475,17 @@ static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *type_entry, |
| 2460 | return result; | 2475 | return result; |
| 2461 | } | 2476 | } |
| 2462 | 2477 | ||
| 2463 | 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) { |
| 2464 | if (type_entry->id == ZigTypeIdInt) | 2479 | if ((op == BuiltinFnIdCeil || |
| 2480 | op == BuiltinFnIdFloor) && | ||
| 2481 | type_entry->id == ZigTypeIdInt) | ||
| 2465 | return val; | 2482 | return val; |
| 2483 | assert(type_entry->id == ZigTypeIdFloat); | ||
| 2466 | 2484 | ||
| 2467 | LLVMValueRef floor_fn = get_float_fn(g, type_entry, ZigLLVMFnIdFloor); | 2485 | LLVMValueRef floor_fn = get_float_fn(g, type_entry, ZigLLVMFnIdFloatOp, op); |
| 2468 | return LLVMBuildCall(g->builder, floor_fn, &val, 1, ""); | 2486 | return LLVMBuildCall(g->builder, floor_fn, &val, 1, ""); |
| 2469 | } | 2487 | } |
| 2470 | 2488 | ||
| 2471 | static LLVMValueRef gen_ceil(CodeGen *g, LLVMValueRef val, ZigType *type_entry) { | ||
| 2472 | if (type_entry->id == ZigTypeIdInt) | ||
| 2473 | return val; | ||
| 2474 | |||
| 2475 | LLVMValueRef ceil_fn = get_float_fn(g, type_entry, ZigLLVMFnIdCeil); | ||
| 2476 | return LLVMBuildCall(g->builder, ceil_fn, &val, 1, ""); | ||
| 2477 | } | ||
| 2478 | |||
| 2479 | enum DivKind { | 2489 | enum DivKind { |
| 2480 | DivKindFloat, | 2490 | DivKindFloat, |
| 2481 | DivKindTrunc, | 2491 | DivKindTrunc, |
| ... | @@ -2551,7 +2561,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast | ... | @@ -2551,7 +2561,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast |
| 2551 | return result; | 2561 | return result; |
| 2552 | case DivKindExact: | 2562 | case DivKindExact: |
| 2553 | if (want_runtime_safety) { | 2563 | if (want_runtime_safety) { |
| 2554 | LLVMValueRef floored = gen_floor(g, result, type_entry); | 2564 | LLVMValueRef floored = gen_float_op(g, result, type_entry, BuiltinFnIdFloor); |
| 2555 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk"); | 2565 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk"); |
| 2556 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); | 2566 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail"); |
| 2557 | LLVMValueRef ok_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, floored, result, ""); | 2567 | LLVMValueRef ok_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, floored, result, ""); |
| ... | @@ -2573,12 +2583,12 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast | ... | @@ -2573,12 +2583,12 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast |
| 2573 | LLVMBuildCondBr(g->builder, ltz, ltz_block, gez_block); | 2583 | LLVMBuildCondBr(g->builder, ltz, ltz_block, gez_block); |
| 2574 | 2584 | ||
| 2575 | LLVMPositionBuilderAtEnd(g->builder, ltz_block); | 2585 | LLVMPositionBuilderAtEnd(g->builder, ltz_block); |
| 2576 | LLVMValueRef ceiled = gen_ceil(g, result, type_entry); | 2586 | LLVMValueRef ceiled = gen_float_op(g, result, type_entry, BuiltinFnIdCeil); |
| 2577 | LLVMBasicBlockRef ceiled_end_block = LLVMGetInsertBlock(g->builder); | 2587 | LLVMBasicBlockRef ceiled_end_block = LLVMGetInsertBlock(g->builder); |
| 2578 | LLVMBuildBr(g->builder, end_block); | 2588 | LLVMBuildBr(g->builder, end_block); |
| 2579 | 2589 | ||
| 2580 | LLVMPositionBuilderAtEnd(g->builder, gez_block); | 2590 | LLVMPositionBuilderAtEnd(g->builder, gez_block); |
| 2581 | LLVMValueRef floored = gen_floor(g, result, type_entry); | 2591 | LLVMValueRef floored = gen_float_op(g, result, type_entry, BuiltinFnIdFloor); |
| 2582 | LLVMBasicBlockRef floored_end_block = LLVMGetInsertBlock(g->builder); | 2592 | LLVMBasicBlockRef floored_end_block = LLVMGetInsertBlock(g->builder); |
| 2583 | LLVMBuildBr(g->builder, end_block); | 2593 | LLVMBuildBr(g->builder, end_block); |
| 2584 | 2594 | ||
| ... | @@ -2590,7 +2600,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast | ... | @@ -2590,7 +2600,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast |
| 2590 | return phi; | 2600 | return phi; |
| 2591 | } | 2601 | } |
| 2592 | case DivKindFloor: | 2602 | case DivKindFloor: |
| 2593 | return gen_floor(g, result, type_entry); | 2603 | return gen_float_op(g, result, type_entry, BuiltinFnIdFloor); |
| 2594 | } | 2604 | } |
| 2595 | zig_unreachable(); | 2605 | zig_unreachable(); |
| 2596 | } | 2606 | } |
| ... | @@ -5430,13 +5440,28 @@ static LLVMValueRef ir_render_mark_err_ret_trace_ptr(CodeGen *g, IrExecutable *e | ... | @@ -5430,13 +5440,28 @@ static LLVMValueRef ir_render_mark_err_ret_trace_ptr(CodeGen *g, IrExecutable *e |
| 5430 | return nullptr; | 5440 | return nullptr; |
| 5431 | } | 5441 | } |
| 5432 | 5442 | ||
| 5433 | static LLVMValueRef ir_render_sqrt(CodeGen *g, IrExecutable *executable, IrInstructionSqrt *instruction) { | 5443 | static LLVMValueRef ir_render_float_op(CodeGen *g, IrExecutable *executable, IrInstructionFloatOp *instruction) { |
| 5434 | LLVMValueRef op = ir_llvm_value(g, instruction->op); | 5444 | LLVMValueRef op = ir_llvm_value(g, instruction->op1); |
| 5435 | assert(instruction->base.value.type->id == ZigTypeIdFloat); | 5445 | assert(instruction->base.value.type->id == ZigTypeIdFloat); |
| 5436 | 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); |
| 5437 | return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); | 5447 | return LLVMBuildCall(g->builder, fn_val, &op, 1, ""); |
| 5438 | } | 5448 | } |
| 5439 | 5449 | ||
| 5450 | static LLVMValueRef ir_render_mul_add(CodeGen *g, IrExecutable *executable, IrInstructionMulAdd *instruction) { | ||
| 5451 | LLVMValueRef op1 = ir_llvm_value(g, instruction->op1); | ||
| 5452 | LLVMValueRef op2 = ir_llvm_value(g, instruction->op2); | ||
| 5453 | LLVMValueRef op3 = ir_llvm_value(g, instruction->op3); | ||
| 5454 | assert(instruction->base.value.type->id == ZigTypeIdFloat || | ||
| 5455 | instruction->base.value.type->id == ZigTypeIdVector); | ||
| 5456 | LLVMValueRef fn_val = get_float_fn(g, instruction->base.value.type, ZigLLVMFnIdFMA, BuiltinFnIdMulAdd); | ||
| 5457 | LLVMValueRef args[3] = { | ||
| 5458 | op1, | ||
| 5459 | op2, | ||
| 5460 | op3, | ||
| 5461 | }; | ||
| 5462 | return LLVMBuildCall(g->builder, fn_val, args, 3, ""); | ||
| 5463 | } | ||
| 5464 | |||
| 5440 | static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInstructionBswap *instruction) { | 5465 | static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInstructionBswap *instruction) { |
| 5441 | LLVMValueRef op = ir_llvm_value(g, instruction->op); | 5466 | LLVMValueRef op = ir_llvm_value(g, instruction->op); |
| 5442 | ZigType *int_type = instruction->base.value.type; | 5467 | ZigType *int_type = instruction->base.value.type; |
| ... | @@ -5779,8 +5804,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -5779,8 +5804,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5779 | return ir_render_merge_err_ret_traces(g, executable, (IrInstructionMergeErrRetTraces *)instruction); | 5804 | return ir_render_merge_err_ret_traces(g, executable, (IrInstructionMergeErrRetTraces *)instruction); |
| 5780 | case IrInstructionIdMarkErrRetTracePtr: | 5805 | case IrInstructionIdMarkErrRetTracePtr: |
| 5781 | 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); |
| 5782 | case IrInstructionIdSqrt: | 5807 | case IrInstructionIdFloatOp: |
| 5783 | return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction); | 5808 | return ir_render_float_op(g, executable, (IrInstructionFloatOp *)instruction); |
| 5809 | case IrInstructionIdMulAdd: | ||
| 5810 | return ir_render_mul_add(g, executable, (IrInstructionMulAdd *)instruction); | ||
| 5784 | case IrInstructionIdArrayToVector: | 5811 | case IrInstructionIdArrayToVector: |
| 5785 | return ir_render_array_to_vector(g, executable, (IrInstructionArrayToVector *)instruction); | 5812 | return ir_render_array_to_vector(g, executable, (IrInstructionArrayToVector *)instruction); |
| 5786 | case IrInstructionIdVectorToArray: | 5813 | case IrInstructionIdVectorToArray: |
| ... | @@ -7398,6 +7425,21 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -7398,6 +7425,21 @@ static void define_builtin_fns(CodeGen *g) { |
| 7398 | create_builtin_fn(g, BuiltinFnIdRem, "rem", 2); | 7425 | create_builtin_fn(g, BuiltinFnIdRem, "rem", 2); |
| 7399 | create_builtin_fn(g, BuiltinFnIdMod, "mod", 2); | 7426 | create_builtin_fn(g, BuiltinFnIdMod, "mod", 2); |
| 7400 | 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); | ||
| 7442 | create_builtin_fn(g, BuiltinFnIdMulAdd, "mulAdd", 4); | ||
| 7401 | create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX); | 7443 | create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX); |
| 7402 | create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX); | 7444 | create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX); |
| 7403 | create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX); | 7445 | create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX); |
src/ir.cpp+465-61| ... | @@ -747,6 +747,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestErr *) { | ... | @@ -747,6 +747,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestErr *) { |
| 747 | return IrInstructionIdTestErr; | 747 | return IrInstructionIdTestErr; |
| 748 | } | 748 | } |
| 749 | 749 | ||
| 750 | static constexpr IrInstructionId ir_instruction_id(IrInstructionMulAdd *) { | ||
| 751 | return IrInstructionIdMulAdd; | ||
| 752 | } | ||
| 753 | |||
| 750 | static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapErrCode *) { | 754 | static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapErrCode *) { |
| 751 | return IrInstructionIdUnwrapErrCode; | 755 | return IrInstructionIdUnwrapErrCode; |
| 752 | } | 756 | } |
| ... | @@ -987,8 +991,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionMarkErrRetTraceP | ... | @@ -987,8 +991,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionMarkErrRetTraceP |
| 987 | return IrInstructionIdMarkErrRetTracePtr; | 991 | return IrInstructionIdMarkErrRetTracePtr; |
| 988 | } | 992 | } |
| 989 | 993 | ||
| 990 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSqrt *) { | 994 | static constexpr IrInstructionId ir_instruction_id(IrInstructionFloatOp *) { |
| 991 | return IrInstructionIdSqrt; | 995 | return IrInstructionIdFloatOp; |
| 992 | } | 996 | } |
| 993 | 997 | ||
| 994 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) { | 998 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) { |
| ... | @@ -2308,6 +2312,75 @@ static IrInstruction *ir_build_overflow_op(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -2308,6 +2312,75 @@ static IrInstruction *ir_build_overflow_op(IrBuilder *irb, Scope *scope, AstNode |
| 2308 | return &instruction->base; | 2312 | return &instruction->base; |
| 2309 | } | 2313 | } |
| 2310 | 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 | |||
| 2368 | static IrInstruction *ir_build_mul_add(IrBuilder *irb, Scope *scope, AstNode *source_node, | ||
| 2369 | IrInstruction *type_value, IrInstruction *op1, IrInstruction *op2, IrInstruction *op3) { | ||
| 2370 | IrInstructionMulAdd *instruction = ir_build_instruction<IrInstructionMulAdd>(irb, scope, source_node); | ||
| 2371 | instruction->type_value = type_value; | ||
| 2372 | instruction->op1 = op1; | ||
| 2373 | instruction->op2 = op2; | ||
| 2374 | instruction->op3 = op3; | ||
| 2375 | |||
| 2376 | ir_ref_instruction(type_value, irb->current_basic_block); | ||
| 2377 | ir_ref_instruction(op1, irb->current_basic_block); | ||
| 2378 | ir_ref_instruction(op2, irb->current_basic_block); | ||
| 2379 | ir_ref_instruction(op3, irb->current_basic_block); | ||
| 2380 | |||
| 2381 | return &instruction->base; | ||
| 2382 | } | ||
| 2383 | |||
| 2311 | static IrInstruction *ir_build_align_of(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value) { | 2384 | static IrInstruction *ir_build_align_of(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value) { |
| 2312 | IrInstructionAlignOf *instruction = ir_build_instruction<IrInstructionAlignOf>(irb, scope, source_node); | 2385 | IrInstructionAlignOf *instruction = ir_build_instruction<IrInstructionAlignOf>(irb, scope, source_node); |
| 2313 | instruction->type_value = type_value; | 2386 | instruction->type_value = type_value; |
| ... | @@ -3013,17 +3086,6 @@ static IrInstruction *ir_build_mark_err_ret_trace_ptr(IrBuilder *irb, Scope *sco | ... | @@ -3013,17 +3086,6 @@ static IrInstruction *ir_build_mark_err_ret_trace_ptr(IrBuilder *irb, Scope *sco |
| 3013 | return &instruction->base; | 3086 | return &instruction->base; |
| 3014 | } | 3087 | } |
| 3015 | 3088 | ||
| 3016 | static IrInstruction *ir_build_sqrt(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type, IrInstruction *op) { | ||
| 3017 | IrInstructionSqrt *instruction = ir_build_instruction<IrInstructionSqrt>(irb, scope, source_node); | ||
| 3018 | instruction->type = type; | ||
| 3019 | instruction->op = op; | ||
| 3020 | |||
| 3021 | if (type != nullptr) ir_ref_instruction(type, irb->current_basic_block); | ||
| 3022 | ir_ref_instruction(op, irb->current_basic_block); | ||
| 3023 | |||
| 3024 | return &instruction->base; | ||
| 3025 | } | ||
| 3026 | |||
| 3027 | 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, |
| 3028 | IrInstruction *container, IrInstruction *name) | 3090 | IrInstruction *container, IrInstruction *name) |
| 3029 | { | 3091 | { |
| ... | @@ -4028,6 +4090,33 @@ static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode * | ... | @@ -4028,6 +4090,33 @@ static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode * |
| 4028 | return ir_build_overflow_op(irb, scope, node, op, type_value, op1, op2, result_ptr, nullptr); | 4090 | return ir_build_overflow_op(irb, scope, node, op, type_value, op1, op2, result_ptr, nullptr); |
| 4029 | } | 4091 | } |
| 4030 | 4092 | ||
| 4093 | static IrInstruction *ir_gen_mul_add(IrBuilder *irb, Scope *scope, AstNode *node) { | ||
| 4094 | assert(node->type == NodeTypeFnCallExpr); | ||
| 4095 | |||
| 4096 | AstNode *type_node = node->data.fn_call_expr.params.at(0); | ||
| 4097 | AstNode *op1_node = node->data.fn_call_expr.params.at(1); | ||
| 4098 | AstNode *op2_node = node->data.fn_call_expr.params.at(2); | ||
| 4099 | AstNode *op3_node = node->data.fn_call_expr.params.at(3); | ||
| 4100 | |||
| 4101 | IrInstruction *type_value = ir_gen_node(irb, type_node, scope); | ||
| 4102 | if (type_value == irb->codegen->invalid_instruction) | ||
| 4103 | return irb->codegen->invalid_instruction; | ||
| 4104 | |||
| 4105 | IrInstruction *op1 = ir_gen_node(irb, op1_node, scope); | ||
| 4106 | if (op1 == irb->codegen->invalid_instruction) | ||
| 4107 | return irb->codegen->invalid_instruction; | ||
| 4108 | |||
| 4109 | IrInstruction *op2 = ir_gen_node(irb, op2_node, scope); | ||
| 4110 | if (op2 == irb->codegen->invalid_instruction) | ||
| 4111 | return irb->codegen->invalid_instruction; | ||
| 4112 | |||
| 4113 | IrInstruction *op3 = ir_gen_node(irb, op3_node, scope); | ||
| 4114 | if (op3 == irb->codegen->invalid_instruction) | ||
| 4115 | return irb->codegen->invalid_instruction; | ||
| 4116 | |||
| 4117 | return ir_build_mul_add(irb, scope, node, type_value, op1, op2, op3); | ||
| 4118 | } | ||
| 4119 | |||
| 4031 | static IrInstruction *ir_gen_this(IrBuilder *irb, Scope *orig_scope, AstNode *node) { | 4120 | static IrInstruction *ir_gen_this(IrBuilder *irb, Scope *orig_scope, AstNode *node) { |
| 4032 | for (Scope *it_scope = orig_scope; it_scope != nullptr; it_scope = it_scope->parent) { | 4121 | for (Scope *it_scope = orig_scope; it_scope != nullptr; it_scope = it_scope->parent) { |
| 4033 | if (it_scope->id == ScopeIdDecls) { | 4122 | if (it_scope->id == ScopeIdDecls) { |
| ... | @@ -4353,6 +4442,19 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4353,6 +4442,19 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4353 | return ir_lval_wrap(irb, scope, bin_op, lval); | 4442 | return ir_lval_wrap(irb, scope, bin_op, lval); |
| 4354 | } | 4443 | } |
| 4355 | 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: | ||
| 4356 | { | 4458 | { |
| 4357 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | 4459 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| 4358 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | 4460 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); |
| ... | @@ -4364,7 +4466,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4364,7 +4466,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4364 | if (arg1_value == irb->codegen->invalid_instruction) | 4466 | if (arg1_value == irb->codegen->invalid_instruction) |
| 4365 | return arg1_value; | 4467 | return arg1_value; |
| 4366 | 4468 | ||
| 4367 | 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); |
| 4368 | return ir_lval_wrap(irb, scope, ir_sqrt, lval); | 4470 | return ir_lval_wrap(irb, scope, ir_sqrt, lval); |
| 4369 | } | 4471 | } |
| 4370 | case BuiltinFnIdTruncate: | 4472 | case BuiltinFnIdTruncate: |
| ... | @@ -4687,6 +4789,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4687,6 +4789,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4687 | return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul), lval); | 4789 | return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul), lval); |
| 4688 | case BuiltinFnIdShlWithOverflow: | 4790 | case BuiltinFnIdShlWithOverflow: |
| 4689 | return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl), lval); | 4791 | return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl), lval); |
| 4792 | case BuiltinFnIdMulAdd: | ||
| 4793 | return ir_lval_wrap(irb, scope, ir_gen_mul_add(irb, scope, node), lval); | ||
| 4690 | case BuiltinFnIdTypeName: | 4794 | case BuiltinFnIdTypeName: |
| 4691 | { | 4795 | { |
| 4692 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | 4796 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| ... | @@ -21187,6 +21291,125 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr | ... | @@ -21187,6 +21291,125 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr |
| 21187 | return result; | 21291 | return result; |
| 21188 | } | 21292 | } |
| 21189 | 21293 | ||
| 21294 | static void ir_eval_mul_add(IrAnalyze *ira, IrInstructionMulAdd *source_instr, ZigType *float_type, | ||
| 21295 | ConstExprValue *op1, ConstExprValue *op2, ConstExprValue *op3, ConstExprValue *out_val) { | ||
| 21296 | if (float_type->id == ZigTypeIdComptimeFloat) { | ||
| 21297 | f128M_mulAdd(&out_val->data.x_bigfloat.value, &op1->data.x_bigfloat.value, &op2->data.x_bigfloat.value, | ||
| 21298 | &op3->data.x_bigfloat.value); | ||
| 21299 | } else if (float_type->id == ZigTypeIdFloat) { | ||
| 21300 | switch (float_type->data.floating.bit_count) { | ||
| 21301 | case 16: | ||
| 21302 | out_val->data.x_f16 = f16_mulAdd(op1->data.x_f16, op2->data.x_f16, op3->data.x_f16); | ||
| 21303 | break; | ||
| 21304 | case 32: | ||
| 21305 | out_val->data.x_f32 = fmaf(op1->data.x_f32, op2->data.x_f32, op3->data.x_f32); | ||
| 21306 | break; | ||
| 21307 | case 64: | ||
| 21308 | out_val->data.x_f64 = fma(op1->data.x_f64, op2->data.x_f64, op3->data.x_f64); | ||
| 21309 | break; | ||
| 21310 | case 128: | ||
| 21311 | f128M_mulAdd(&op1->data.x_f128, &op2->data.x_f128, &op3->data.x_f128, &out_val->data.x_f128); | ||
| 21312 | break; | ||
| 21313 | default: | ||
| 21314 | zig_unreachable(); | ||
| 21315 | } | ||
| 21316 | } else { | ||
| 21317 | zig_unreachable(); | ||
| 21318 | } | ||
| 21319 | } | ||
| 21320 | |||
| 21321 | static IrInstruction *ir_analyze_instruction_mul_add(IrAnalyze *ira, IrInstructionMulAdd *instruction) { | ||
| 21322 | IrInstruction *type_value = instruction->type_value->child; | ||
| 21323 | if (type_is_invalid(type_value->value.type)) | ||
| 21324 | return ira->codegen->invalid_instruction; | ||
| 21325 | |||
| 21326 | ZigType *expr_type = ir_resolve_type(ira, type_value); | ||
| 21327 | if (type_is_invalid(expr_type)) | ||
| 21328 | return ira->codegen->invalid_instruction; | ||
| 21329 | |||
| 21330 | // Only allow float types, and vectors of floats. | ||
| 21331 | ZigType *float_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type; | ||
| 21332 | if (float_type->id != ZigTypeIdFloat) { | ||
| 21333 | ir_add_error(ira, type_value, | ||
| 21334 | buf_sprintf("expected float or vector of float type, found '%s'", buf_ptr(&float_type->name))); | ||
| 21335 | return ira->codegen->invalid_instruction; | ||
| 21336 | } | ||
| 21337 | |||
| 21338 | IrInstruction *op1 = instruction->op1->child; | ||
| 21339 | if (type_is_invalid(op1->value.type)) | ||
| 21340 | return ira->codegen->invalid_instruction; | ||
| 21341 | |||
| 21342 | IrInstruction *casted_op1 = ir_implicit_cast(ira, op1, expr_type); | ||
| 21343 | if (type_is_invalid(casted_op1->value.type)) | ||
| 21344 | return ira->codegen->invalid_instruction; | ||
| 21345 | |||
| 21346 | IrInstruction *op2 = instruction->op2->child; | ||
| 21347 | if (type_is_invalid(op2->value.type)) | ||
| 21348 | return ira->codegen->invalid_instruction; | ||
| 21349 | |||
| 21350 | IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, expr_type); | ||
| 21351 | if (type_is_invalid(casted_op2->value.type)) | ||
| 21352 | return ira->codegen->invalid_instruction; | ||
| 21353 | |||
| 21354 | IrInstruction *op3 = instruction->op3->child; | ||
| 21355 | if (type_is_invalid(op3->value.type)) | ||
| 21356 | return ira->codegen->invalid_instruction; | ||
| 21357 | |||
| 21358 | IrInstruction *casted_op3 = ir_implicit_cast(ira, op3, expr_type); | ||
| 21359 | if (type_is_invalid(casted_op3->value.type)) | ||
| 21360 | return ira->codegen->invalid_instruction; | ||
| 21361 | |||
| 21362 | if (instr_is_comptime(casted_op1) && | ||
| 21363 | instr_is_comptime(casted_op2) && | ||
| 21364 | instr_is_comptime(casted_op3)) { | ||
| 21365 | ConstExprValue *op1_const = ir_resolve_const(ira, casted_op1, UndefBad); | ||
| 21366 | if (!op1_const) | ||
| 21367 | return ira->codegen->invalid_instruction; | ||
| 21368 | ConstExprValue *op2_const = ir_resolve_const(ira, casted_op2, UndefBad); | ||
| 21369 | if (!op2_const) | ||
| 21370 | return ira->codegen->invalid_instruction; | ||
| 21371 | ConstExprValue *op3_const = ir_resolve_const(ira, casted_op3, UndefBad); | ||
| 21372 | if (!op3_const) | ||
| 21373 | return ira->codegen->invalid_instruction; | ||
| 21374 | |||
| 21375 | IrInstruction *result = ir_const(ira, &instruction->base, expr_type); | ||
| 21376 | ConstExprValue *out_val = &result->value; | ||
| 21377 | |||
| 21378 | if (expr_type->id == ZigTypeIdVector) { | ||
| 21379 | expand_undef_array(ira->codegen, op1_const); | ||
| 21380 | expand_undef_array(ira->codegen, op2_const); | ||
| 21381 | expand_undef_array(ira->codegen, op3_const); | ||
| 21382 | out_val->special = ConstValSpecialUndef; | ||
| 21383 | expand_undef_array(ira->codegen, out_val); | ||
| 21384 | size_t len = expr_type->data.vector.len; | ||
| 21385 | for (size_t i = 0; i < len; i += 1) { | ||
| 21386 | ConstExprValue *float_operand_op1 = &op1_const->data.x_array.data.s_none.elements[i]; | ||
| 21387 | ConstExprValue *float_operand_op2 = &op2_const->data.x_array.data.s_none.elements[i]; | ||
| 21388 | ConstExprValue *float_operand_op3 = &op3_const->data.x_array.data.s_none.elements[i]; | ||
| 21389 | ConstExprValue *float_out_val = &out_val->data.x_array.data.s_none.elements[i]; | ||
| 21390 | assert(float_operand_op1->type == float_type); | ||
| 21391 | assert(float_operand_op2->type == float_type); | ||
| 21392 | assert(float_operand_op3->type == float_type); | ||
| 21393 | assert(float_out_val->type == float_type); | ||
| 21394 | ir_eval_mul_add(ira, instruction, float_type, | ||
| 21395 | op1_const, op2_const, op3_const, float_out_val); | ||
| 21396 | float_out_val->type = float_type; | ||
| 21397 | } | ||
| 21398 | out_val->type = expr_type; | ||
| 21399 | out_val->special = ConstValSpecialStatic; | ||
| 21400 | } else { | ||
| 21401 | ir_eval_mul_add(ira, instruction, float_type, op1_const, op2_const, op3_const, out_val); | ||
| 21402 | } | ||
| 21403 | return result; | ||
| 21404 | } | ||
| 21405 | |||
| 21406 | IrInstruction *result = ir_build_mul_add(&ira->new_irb, | ||
| 21407 | instruction->base.scope, instruction->base.source_node, | ||
| 21408 | type_value, casted_op1, casted_op2, casted_op3); | ||
| 21409 | result->value.type = expr_type; | ||
| 21410 | return result; | ||
| 21411 | } | ||
| 21412 | |||
| 21190 | static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstructionTestErr *instruction) { | 21413 | static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstructionTestErr *instruction) { |
| 21191 | IrInstruction *value = instruction->value->child; | 21414 | IrInstruction *value = instruction->value->child; |
| 21192 | if (type_is_invalid(value->value.type)) | 21415 | if (type_is_invalid(value->value.type)) |
| ... | @@ -23048,70 +23271,248 @@ static IrInstruction *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *i | ... | @@ -23048,70 +23271,248 @@ static IrInstruction *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *i |
| 23048 | return result; | 23271 | return result; |
| 23049 | } | 23272 | } |
| 23050 | 23273 | ||
| 23051 | static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionSqrt *instruction) { | 23274 | static void ir_eval_float_op(IrAnalyze *ira, IrInstructionFloatOp *source_instr, ZigType *float_type, |
| 23052 | ZigType *float_type = ir_resolve_type(ira, instruction->type->child); | 23275 | ConstExprValue *op, ConstExprValue *out_val) { |
| 23053 | if (type_is_invalid(float_type)) | 23276 | assert(ira && source_instr && float_type && out_val && op); |
| 23054 | return ira->codegen->invalid_instruction; | 23277 | assert(float_type->id == ZigTypeIdFloat || |
| 23278 | float_type->id == ZigTypeIdComptimeFloat); | ||
| 23055 | 23279 | ||
| 23056 | IrInstruction *op = instruction->op->child; | 23280 | BuiltinFnId fop = source_instr->op; |
| 23057 | if (type_is_invalid(op->value.type)) | 23281 | unsigned bits; |
| 23282 | |||
| 23283 | if (float_type->id == ZigTypeIdComptimeFloat) { | ||
| 23284 | bits = 128; | ||
| 23285 | } else if (float_type->id == ZigTypeIdFloat) | ||
| 23286 | bits = float_type->data.floating.bit_count; | ||
| 23287 | |||
| 23288 | switch (bits) { | ||
| 23289 | case 16: { | ||
| 23290 | switch (fop) { | ||
| 23291 | case BuiltinFnIdSqrt: | ||
| 23292 | out_val->data.x_f16 = f16_sqrt(op->data.x_f16); | ||
| 23293 | break; | ||
| 23294 | case BuiltinFnIdSin: | ||
| 23295 | case BuiltinFnIdCos: | ||
| 23296 | case BuiltinFnIdExp: | ||
| 23297 | case BuiltinFnIdExp2: | ||
| 23298 | case BuiltinFnIdLn: | ||
| 23299 | case BuiltinFnIdLog10: | ||
| 23300 | case BuiltinFnIdLog2: | ||
| 23301 | case BuiltinFnIdFabs: | ||
| 23302 | case BuiltinFnIdFloor: | ||
| 23303 | case BuiltinFnIdCeil: | ||
| 23304 | case BuiltinFnIdTrunc: | ||
| 23305 | case BuiltinFnIdNearbyInt: | ||
| 23306 | case BuiltinFnIdRound: | ||
| 23307 | zig_panic("unimplemented f16 builtin"); | ||
| 23308 | default: | ||
| 23309 | zig_unreachable(); | ||
| 23310 | }; | ||
| 23311 | break; | ||
| 23312 | }; | ||
| 23313 | case 32: { | ||
| 23314 | switch (fop) { | ||
| 23315 | case BuiltinFnIdSqrt: | ||
| 23316 | out_val->data.x_f32 = sqrtf(op->data.x_f32); | ||
| 23317 | break; | ||
| 23318 | case BuiltinFnIdSin: | ||
| 23319 | out_val->data.x_f32 = sinf(op->data.x_f32); | ||
| 23320 | break; | ||
| 23321 | case BuiltinFnIdCos: | ||
| 23322 | out_val->data.x_f32 = cosf(op->data.x_f32); | ||
| 23323 | break; | ||
| 23324 | case BuiltinFnIdExp: | ||
| 23325 | out_val->data.x_f32 = expf(op->data.x_f32); | ||
| 23326 | break; | ||
| 23327 | case BuiltinFnIdExp2: | ||
| 23328 | out_val->data.x_f32 = exp2f(op->data.x_f32); | ||
| 23329 | break; | ||
| 23330 | case BuiltinFnIdLn: | ||
| 23331 | out_val->data.x_f32 = logf(op->data.x_f32); | ||
| 23332 | break; | ||
| 23333 | case BuiltinFnIdLog10: | ||
| 23334 | out_val->data.x_f32 = log10f(op->data.x_f32); | ||
| 23335 | break; | ||
| 23336 | case BuiltinFnIdLog2: | ||
| 23337 | out_val->data.x_f32 = log2f(op->data.x_f32); | ||
| 23338 | break; | ||
| 23339 | case BuiltinFnIdFabs: | ||
| 23340 | out_val->data.x_f32 = fabsf(op->data.x_f32); | ||
| 23341 | break; | ||
| 23342 | case BuiltinFnIdFloor: | ||
| 23343 | out_val->data.x_f32 = floorf(op->data.x_f32); | ||
| 23344 | break; | ||
| 23345 | case BuiltinFnIdCeil: | ||
| 23346 | out_val->data.x_f32 = ceilf(op->data.x_f32); | ||
| 23347 | break; | ||
| 23348 | case BuiltinFnIdTrunc: | ||
| 23349 | out_val->data.x_f32 = truncf(op->data.x_f32); | ||
| 23350 | break; | ||
| 23351 | case BuiltinFnIdNearbyInt: | ||
| 23352 | out_val->data.x_f32 = nearbyintf(op->data.x_f32); | ||
| 23353 | break; | ||
| 23354 | case BuiltinFnIdRound: | ||
| 23355 | out_val->data.x_f32 = roundf(op->data.x_f32); | ||
| 23356 | break; | ||
| 23357 | default: | ||
| 23358 | zig_unreachable(); | ||
| 23359 | }; | ||
| 23360 | break; | ||
| 23361 | }; | ||
| 23362 | case 64: { | ||
| 23363 | switch (fop) { | ||
| 23364 | case BuiltinFnIdSqrt: | ||
| 23365 | out_val->data.x_f64 = sqrt(op->data.x_f64); | ||
| 23366 | break; | ||
| 23367 | case BuiltinFnIdSin: | ||
| 23368 | out_val->data.x_f64 = sin(op->data.x_f64); | ||
| 23369 | break; | ||
| 23370 | case BuiltinFnIdCos: | ||
| 23371 | out_val->data.x_f64 = cos(op->data.x_f64); | ||
| 23372 | break; | ||
| 23373 | case BuiltinFnIdExp: | ||
| 23374 | out_val->data.x_f64 = exp(op->data.x_f64); | ||
| 23375 | break; | ||
| 23376 | case BuiltinFnIdExp2: | ||
| 23377 | out_val->data.x_f64 = exp2(op->data.x_f64); | ||
| 23378 | break; | ||
| 23379 | case BuiltinFnIdLn: | ||
| 23380 | out_val->data.x_f64 = log(op->data.x_f64); | ||
| 23381 | break; | ||
| 23382 | case BuiltinFnIdLog10: | ||
| 23383 | out_val->data.x_f64 = log10(op->data.x_f64); | ||
| 23384 | break; | ||
| 23385 | case BuiltinFnIdLog2: | ||
| 23386 | out_val->data.x_f64 = log2(op->data.x_f64); | ||
| 23387 | break; | ||
| 23388 | case BuiltinFnIdFabs: | ||
| 23389 | out_val->data.x_f64 = fabs(op->data.x_f64); | ||
| 23390 | break; | ||
| 23391 | case BuiltinFnIdFloor: | ||
| 23392 | out_val->data.x_f64 = floor(op->data.x_f64); | ||
| 23393 | break; | ||
| 23394 | case BuiltinFnIdCeil: | ||
| 23395 | out_val->data.x_f64 = ceil(op->data.x_f64); | ||
| 23396 | break; | ||
| 23397 | case BuiltinFnIdTrunc: | ||
| 23398 | out_val->data.x_f64 = trunc(op->data.x_f64); | ||
| 23399 | break; | ||
| 23400 | case BuiltinFnIdNearbyInt: | ||
| 23401 | out_val->data.x_f64 = nearbyint(op->data.x_f64); | ||
| 23402 | break; | ||
| 23403 | case BuiltinFnIdRound: | ||
| 23404 | out_val->data.x_f64 = round(op->data.x_f64); | ||
| 23405 | break; | ||
| 23406 | default: | ||
| 23407 | zig_unreachable(); | ||
| 23408 | } | ||
| 23409 | break; | ||
| 23410 | }; | ||
| 23411 | case 128: { | ||
| 23412 | float128_t *out, *in; | ||
| 23413 | if (float_type->id == ZigTypeIdComptimeFloat) { | ||
| 23414 | out = &out_val->data.x_bigfloat.value; | ||
| 23415 | in = &op->data.x_bigfloat.value; | ||
| 23416 | } else { | ||
| 23417 | out = &out_val->data.x_f128; | ||
| 23418 | in = &op->data.x_f128; | ||
| 23419 | } | ||
| 23420 | switch (fop) { | ||
| 23421 | case BuiltinFnIdSqrt: | ||
| 23422 | f128M_sqrt(in, out); | ||
| 23423 | break; | ||
| 23424 | case BuiltinFnIdNearbyInt: | ||
| 23425 | case BuiltinFnIdSin: | ||
| 23426 | case BuiltinFnIdCos: | ||
| 23427 | case BuiltinFnIdExp: | ||
| 23428 | case BuiltinFnIdExp2: | ||
| 23429 | case BuiltinFnIdLn: | ||
| 23430 | case BuiltinFnIdLog10: | ||
| 23431 | case BuiltinFnIdLog2: | ||
| 23432 | case BuiltinFnIdFabs: | ||
| 23433 | case BuiltinFnIdFloor: | ||
| 23434 | case BuiltinFnIdCeil: | ||
| 23435 | case BuiltinFnIdTrunc: | ||
| 23436 | case BuiltinFnIdRound: | ||
| 23437 | zig_panic("unimplemented f128 builtin"); | ||
| 23438 | default: | ||
| 23439 | zig_unreachable(); | ||
| 23440 | } | ||
| 23441 | break; | ||
| 23442 | }; | ||
| 23443 | default: | ||
| 23444 | zig_unreachable(); | ||
| 23445 | } | ||
| 23446 | } | ||
| 23447 | |||
| 23448 | static IrInstruction *ir_analyze_instruction_float_op(IrAnalyze *ira, IrInstructionFloatOp *instruction) { | ||
| 23449 | IrInstruction *type = instruction->type->child; | ||
| 23450 | if (type_is_invalid(type->value.type)) | ||
| 23451 | return ira->codegen->invalid_instruction; | ||
| 23452 | |||
| 23453 | ZigType *expr_type = ir_resolve_type(ira, type); | ||
| 23454 | if (type_is_invalid(expr_type)) | ||
| 23058 | return ira->codegen->invalid_instruction; | 23455 | return ira->codegen->invalid_instruction; |
| 23059 | 23456 | ||
| 23060 | bool ok_type = float_type->id == ZigTypeIdComptimeFloat || float_type->id == ZigTypeIdFloat; | 23457 | // Only allow float types, and vectors of floats. |
| 23061 | if (!ok_type) { | 23458 | ZigType *float_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type; |
| 23062 | ir_add_error(ira, instruction->type, buf_sprintf("@sqrt does not support type '%s'", buf_ptr(&float_type->name))); | 23459 | if (float_type->id != ZigTypeIdFloat && float_type->id != ZigTypeIdComptimeFloat) { |
| 23460 | 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))); | ||
| 23063 | return ira->codegen->invalid_instruction; | 23461 | return ira->codegen->invalid_instruction; |
| 23064 | } | 23462 | } |
| 23065 | 23463 | ||
| 23066 | IrInstruction *casted_op = ir_implicit_cast(ira, op, float_type); | 23464 | IrInstruction *op1 = instruction->op1->child; |
| 23067 | if (type_is_invalid(casted_op->value.type)) | 23465 | if (type_is_invalid(op1->value.type)) |
| 23068 | return ira->codegen->invalid_instruction; | 23466 | return ira->codegen->invalid_instruction; |
| 23069 | 23467 | ||
| 23070 | if (instr_is_comptime(casted_op)) { | 23468 | IrInstruction *casted_op1 = ir_implicit_cast(ira, op1, float_type); |
| 23071 | ConstExprValue *val = ir_resolve_const(ira, casted_op, UndefBad); | 23469 | if (type_is_invalid(casted_op1->value.type)) |
| 23072 | if (!val) | 23470 | return ira->codegen->invalid_instruction; |
| 23471 | |||
| 23472 | if (instr_is_comptime(casted_op1)) { | ||
| 23473 | // Our comptime 16-bit and 128-bit support is quite limited. | ||
| 23474 | if ((float_type->id == ZigTypeIdComptimeFloat || | ||
| 23475 | float_type->data.floating.bit_count == 16 || | ||
| 23476 | float_type->data.floating.bit_count == 128) && | ||
| 23477 | instruction->op != BuiltinFnIdSqrt) { | ||
| 23478 | 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))); | ||
| 23479 | return ira->codegen->invalid_instruction; | ||
| 23480 | } | ||
| 23481 | |||
| 23482 | ConstExprValue *op1_const = ir_resolve_const(ira, casted_op1, UndefBad); | ||
| 23483 | if (!op1_const) | ||
| 23073 | return ira->codegen->invalid_instruction; | 23484 | return ira->codegen->invalid_instruction; |
| 23074 | 23485 | ||
| 23075 | IrInstruction *result = ir_const(ira, &instruction->base, float_type); | 23486 | IrInstruction *result = ir_const(ira, &instruction->base, expr_type); |
| 23076 | ConstExprValue *out_val = &result->value; | 23487 | ConstExprValue *out_val = &result->value; |
| 23077 | 23488 | ||
| 23078 | if (float_type->id == ZigTypeIdComptimeFloat) { | 23489 | if (expr_type->id == ZigTypeIdVector) { |
| 23079 | bigfloat_sqrt(&out_val->data.x_bigfloat, &val->data.x_bigfloat); | 23490 | expand_undef_array(ira->codegen, op1_const); |
| 23080 | } else if (float_type->id == ZigTypeIdFloat) { | 23491 | out_val->special = ConstValSpecialUndef; |
| 23081 | switch (float_type->data.floating.bit_count) { | 23492 | expand_undef_array(ira->codegen, out_val); |
| 23082 | case 16: | 23493 | size_t len = expr_type->data.vector.len; |
| 23083 | out_val->data.x_f16 = f16_sqrt(val->data.x_f16); | 23494 | for (size_t i = 0; i < len; i += 1) { |
| 23084 | break; | 23495 | ConstExprValue *float_operand_op1 = &op1_const->data.x_array.data.s_none.elements[i]; |
| 23085 | case 32: | 23496 | ConstExprValue *float_out_val = &out_val->data.x_array.data.s_none.elements[i]; |
| 23086 | out_val->data.x_f32 = sqrtf(val->data.x_f32); | 23497 | assert(float_operand_op1->type == float_type); |
| 23087 | break; | 23498 | assert(float_out_val->type == float_type); |
| 23088 | case 64: | 23499 | ir_eval_float_op(ira, instruction, float_type, |
| 23089 | out_val->data.x_f64 = sqrt(val->data.x_f64); | 23500 | op1_const, float_out_val); |
| 23090 | break; | 23501 | float_out_val->type = float_type; |
| 23091 | case 128: | ||
| 23092 | f128M_sqrt(&val->data.x_f128, &out_val->data.x_f128); | ||
| 23093 | break; | ||
| 23094 | default: | ||
| 23095 | zig_unreachable(); | ||
| 23096 | } | 23502 | } |
| 23503 | out_val->type = expr_type; | ||
| 23504 | out_val->special = ConstValSpecialStatic; | ||
| 23097 | } else { | 23505 | } else { |
| 23098 | zig_unreachable(); | 23506 | ir_eval_float_op(ira, instruction, float_type, op1_const, out_val); |
| 23099 | } | 23507 | } |
| 23100 | |||
| 23101 | return result; | 23508 | return result; |
| 23102 | } | 23509 | } |
| 23103 | 23510 | ||
| 23104 | ir_assert(float_type->id == ZigTypeIdFloat, &instruction->base); | 23511 | ir_assert(float_type->id == ZigTypeIdFloat, &instruction->base); |
| 23105 | if (float_type->data.floating.bit_count != 16 && | ||
| 23106 | float_type->data.floating.bit_count != 32 && | ||
| 23107 | float_type->data.floating.bit_count != 64) { | ||
| 23108 | ir_add_error(ira, instruction->type, buf_sprintf("compiler TODO: add implementation of sqrt for '%s'", buf_ptr(&float_type->name))); | ||
| 23109 | return ira->codegen->invalid_instruction; | ||
| 23110 | } | ||
| 23111 | 23512 | ||
| 23112 | IrInstruction *result = ir_build_sqrt(&ira->new_irb, instruction->base.scope, | 23513 | IrInstruction *result = ir_build_float_op(&ira->new_irb, instruction->base.scope, |
| 23113 | instruction->base.source_node, nullptr, casted_op); | 23514 | instruction->base.source_node, nullptr, casted_op1, instruction->op); |
| 23114 | result->value.type = float_type; | 23515 | result->value.type = expr_type; |
| 23115 | return result; | 23516 | return result; |
| 23116 | } | 23517 | } |
| 23117 | 23518 | ||
| ... | @@ -23596,8 +23997,10 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio | ... | @@ -23596,8 +23997,10 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio |
| 23596 | return ir_analyze_instruction_merge_err_ret_traces(ira, (IrInstructionMergeErrRetTraces *)instruction); | 23997 | return ir_analyze_instruction_merge_err_ret_traces(ira, (IrInstructionMergeErrRetTraces *)instruction); |
| 23597 | case IrInstructionIdMarkErrRetTracePtr: | 23998 | case IrInstructionIdMarkErrRetTracePtr: |
| 23598 | return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction); | 23999 | return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction); |
| 23599 | case IrInstructionIdSqrt: | 24000 | case IrInstructionIdFloatOp: |
| 23600 | return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction); | 24001 | return ir_analyze_instruction_float_op(ira, (IrInstructionFloatOp *)instruction); |
| 24002 | case IrInstructionIdMulAdd: | ||
| 24003 | return ir_analyze_instruction_mul_add(ira, (IrInstructionMulAdd *)instruction); | ||
| 23601 | case IrInstructionIdIntToErr: | 24004 | case IrInstructionIdIntToErr: |
| 23602 | return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction); | 24005 | return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction); |
| 23603 | case IrInstructionIdErrToInt: | 24006 | case IrInstructionIdErrToInt: |
| ... | @@ -23836,7 +24239,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -23836,7 +24239,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 23836 | case IrInstructionIdCoroFree: | 24239 | case IrInstructionIdCoroFree: |
| 23837 | case IrInstructionIdCoroPromise: | 24240 | case IrInstructionIdCoroPromise: |
| 23838 | case IrInstructionIdPromiseResultType: | 24241 | case IrInstructionIdPromiseResultType: |
| 23839 | case IrInstructionIdSqrt: | 24242 | case IrInstructionIdFloatOp: |
| 24243 | case IrInstructionIdMulAdd: | ||
| 23840 | case IrInstructionIdAtomicLoad: | 24244 | case IrInstructionIdAtomicLoad: |
| 23841 | case IrInstructionIdIntCast: | 24245 | case IrInstructionIdIntCast: |
| 23842 | case IrInstructionIdFloatCast: | 24246 | case IrInstructionIdFloatCast: |
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+25-5| ... | @@ -1427,15 +1427,32 @@ static void ir_print_mark_err_ret_trace_ptr(IrPrint *irp, IrInstructionMarkErrRe | ... | @@ -1427,15 +1427,32 @@ 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); |
| 1440 | fprintf(irp->f, ")"); | ||
| 1441 | } | ||
| 1442 | |||
| 1443 | static void ir_print_mul_add(IrPrint *irp, IrInstructionMulAdd *instruction) { | ||
| 1444 | fprintf(irp->f, "@mulAdd("); | ||
| 1445 | if (instruction->type_value != nullptr) { | ||
| 1446 | ir_print_other_instruction(irp, instruction->type_value); | ||
| 1447 | } else { | ||
| 1448 | fprintf(irp->f, "null"); | ||
| 1449 | } | ||
| 1450 | fprintf(irp->f, ","); | ||
| 1451 | ir_print_other_instruction(irp, instruction->op1); | ||
| 1452 | fprintf(irp->f, ","); | ||
| 1453 | ir_print_other_instruction(irp, instruction->op2); | ||
| 1454 | fprintf(irp->f, ","); | ||
| 1455 | ir_print_other_instruction(irp, instruction->op3); | ||
| 1439 | fprintf(irp->f, ")"); | 1456 | fprintf(irp->f, ")"); |
| 1440 | } | 1457 | } |
| 1441 | 1458 | ||
| ... | @@ -1902,8 +1919,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1902,8 +1919,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1902 | case IrInstructionIdMarkErrRetTracePtr: | 1919 | case IrInstructionIdMarkErrRetTracePtr: |
| 1903 | ir_print_mark_err_ret_trace_ptr(irp, (IrInstructionMarkErrRetTracePtr *)instruction); | 1920 | ir_print_mark_err_ret_trace_ptr(irp, (IrInstructionMarkErrRetTracePtr *)instruction); |
| 1904 | break; | 1921 | break; |
| 1905 | case IrInstructionIdSqrt: | 1922 | case IrInstructionIdFloatOp: |
| 1906 | ir_print_sqrt(irp, (IrInstructionSqrt *)instruction); | 1923 | ir_print_float_op(irp, (IrInstructionFloatOp *)instruction); |
| 1924 | break; | ||
| 1925 | case IrInstructionIdMulAdd: | ||
| 1926 | ir_print_mul_add(irp, (IrInstructionMulAdd *)instruction); | ||
| 1907 | break; | 1927 | break; |
| 1908 | case IrInstructionIdAtomicLoad: | 1928 | case IrInstructionIdAtomicLoad: |
| 1909 | ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction); | 1929 | ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction); |
std/special/c.zig+26-13| ... | @@ -254,19 +254,32 @@ export fn fmod(x: f64, y: f64) f64 { | ... | @@ -254,19 +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 | 269 | export fn exp2(a: f64) f64 {return math.exp2(a);} | |
| 270 | export fn exp2f(a: f32) f32 {return math.exp2(a);} | ||
| 271 | export fn log(a: f64) f64 {return math.ln(a);} | ||
| 272 | export fn logf(a: f32) f32 {return math.ln(a);} | ||
| 273 | export fn log2(a: f64) f64 {return math.log2(a);} | ||
| 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);} | ||
| 270 | fn generic_fmod(comptime T: type, x: T, y: T) T { | 283 | fn generic_fmod(comptime T: type, x: T, y: T) T { |
| 271 | @setRuntimeSafety(false); | 284 | @setRuntimeSafety(false); |
| 272 | 285 |
test/stage1/behavior.zig+2| ... | @@ -69,6 +69,8 @@ comptime { | ... | @@ -69,6 +69,8 @@ comptime { |
| 69 | _ = @import("behavior/optional.zig"); | 69 | _ = @import("behavior/optional.zig"); |
| 70 | _ = @import("behavior/pointers.zig"); | 70 | _ = @import("behavior/pointers.zig"); |
| 71 | _ = @import("behavior/popcount.zig"); | 71 | _ = @import("behavior/popcount.zig"); |
| 72 | _ = @import("behavior/muladd.zig"); | ||
| 73 | _ = @import("behavior/floatop.zig"); | ||
| 72 | _ = @import("behavior/ptrcast.zig"); | 74 | _ = @import("behavior/ptrcast.zig"); |
| 73 | _ = @import("behavior/pub_enum.zig"); | 75 | _ = @import("behavior/pub_enum.zig"); |
| 74 | _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); | 76 | _ = @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 | //} | ||
test/stage1/behavior/muladd.zig created+34| ... | @@ -0,0 +1,34 @@ | ||
| 1 | const expect = @import("std").testing.expect; | ||
| 2 | |||
| 3 | test "@mulAdd" { | ||
| 4 | comptime testMulAdd(); | ||
| 5 | testMulAdd(); | ||
| 6 | } | ||
| 7 | |||
| 8 | fn testMulAdd() void { | ||
| 9 | { | ||
| 10 | var a: f16 = 5.5; | ||
| 11 | var b: f16 = 2.5; | ||
| 12 | var c: f16 = 6.25; | ||
| 13 | expect(@mulAdd(f16, a, b, c) == 20); | ||
| 14 | } | ||
| 15 | { | ||
| 16 | var a: f32 = 5.5; | ||
| 17 | var b: f32 = 2.5; | ||
| 18 | var c: f32 = 6.25; | ||
| 19 | expect(@mulAdd(f32, a, b, c) == 20); | ||
| 20 | } | ||
| 21 | { | ||
| 22 | var a: f64 = 5.5; | ||
| 23 | var b: f64 = 2.5; | ||
| 24 | var c: f64 = 6.25; | ||
| 25 | expect(@mulAdd(f64, a, b, c) == 20); | ||
| 26 | } | ||
| 27 | // Awaits implementation in libm.zig | ||
| 28 | //{ | ||
| 29 | // var a: f16 = 5.5; | ||
| 30 | // var b: f128 = 2.5; | ||
| 31 | // var c: f128 = 6.25; | ||
| 32 | // expect(@mulAdd(f128, a, b, c) == 20); | ||
| 33 | //} | ||
| 34 | } | ||
| \ No newline at end of file | |||