authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-06-23 17:14:28-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-06-23 17:14:28-04:00
log24400d5882aa2b83a4aed3e4c1503d0393e1c541
treed06324bd3d1e58757d2843c97a2b6392dc5a3505
parentca3660f6bf3a1f8d77692acf72eefe148802d342
parent7f4de2dfdbeac4457e6e3170dad9ba9bf67ac9c8
signaturelock-open Commit is signed but in an unrecognized format.

Merge branch 'shawnl-simd2'


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>
62616261
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#}
62636270
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 instruction7356 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#}
73567444
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};
30403056
3057struct IrInstructionMulAdd {
3058 IrInstruction base;
3059
3060 IrInstruction *type_value;
3061 IrInstruction *op1;
3062 IrInstruction *op2;
3063 IrInstruction *op3;
3064};
3065
3041struct IrInstructionAlignOf {3066struct IrInstructionAlignOf {
3042 IrInstruction base;3067 IrInstruction base;
30433068
...@@ -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};
34633488
3464struct IrInstructionSqrt {3489// For float ops which take a single argument
3490struct IrInstructionFloatOp {
3465 IrInstruction base;3491 IrInstruction base;
34663492
3493 BuiltinFnId op;
3467 IrInstruction *type;3494 IrInstruction *type;
3468 IrInstruction *op;3495 IrInstruction *op1;
3469};3496};
34703497
3471struct IrInstructionCheckRuntimeScope {3498struct 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}
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);
812
813 bool is_vector = (type_entry->id == ZigTypeIdVector);
814 ZigType *float_type = is_vector ? type_entry->data.vector.elem_type : type_entry;
811815
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;
815821
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;
819825
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 }
830837
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));
837852
...@@ -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}
24622477
2463static LLVMValueRef gen_floor(CodeGen *g, LLVMValueRef val, ZigType *type_entry) {2478static 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);
24662484
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}
24702488
2471static 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
2479enum DivKind {2489enum 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);
25742584
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);
25792589
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);
25842594
...@@ -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}
54325442
5433static LLVMValueRef ir_render_sqrt(CodeGen *g, IrExecutable *executable, IrInstructionSqrt *instruction) {5443static 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}
54395449
5450static 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
5440static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInstructionBswap *instruction) {5465static 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}
749749
750static constexpr IrInstructionId ir_instruction_id(IrInstructionMulAdd *) {
751 return IrInstructionIdMulAdd;
752}
753
750static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapErrCode *) {754static 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}
989993
990static constexpr IrInstructionId ir_instruction_id(IrInstructionSqrt *) {994static constexpr IrInstructionId ir_instruction_id(IrInstructionFloatOp *) {
991 return IrInstructionIdSqrt;995 return IrInstructionIdFloatOp;
992}996}
993997
994static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) {998static 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}
23102314
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
2368static 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
2311static IrInstruction *ir_build_align_of(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value) {2384static 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}
30153088
3016static 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
3027static 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,
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}
40304092
4093static 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
4031static IrInstruction *ir_gen_this(IrBuilder *irb, Scope *orig_scope, AstNode *node) {4120static 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;
43664468
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}
2118921293
21294static 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
21321static 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
21190static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstructionTestErr *instruction) {21413static 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}
2305023273
23051static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionSqrt *instruction) {23274static 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);
2305523279
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
23448static 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;
2305923456
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 }
2306523463
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;
2306923467
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;
2307423485
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;
2307723488
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 }
2310323510
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 }
2311123512
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}
2311723518
...@@ -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);
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+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}
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);
1440 fprintf(irp->f, ")");
1441}
1442
1443static 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}
14411458
...@@ -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 {
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);}
269269export fn exp2(a: f64) f64 {return math.exp2(a);}
270export fn exp2f(a: f32) f32 {return math.exp2(a);}
271export fn log(a: f64) f64 {return math.ln(a);}
272export fn logf(a: f32) f32 {return math.ln(a);}
273export fn log2(a: f64) f64 {return math.log2(a);}
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);}
270fn generic_fmod(comptime T: type, x: T, y: T) T {283fn generic_fmod(comptime T: type, x: T, y: T) T {
271 @setRuntimeSafety(false);284 @setRuntimeSafety(false);
272285
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 @@
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//}
test/stage1/behavior/muladd.zig created+34
...@@ -0,0 +1,34 @@
1const expect = @import("std").testing.expect;
2
3test "@mulAdd" {
4 comptime testMulAdd();
5 testMulAdd();
6}
7
8fn 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