authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-06-26 14:44:01-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-06-26 14:44:01-04:00
log3085d29af83d07769582f751b3c2f5f36634e34b
treeab5e72656369bccb19857277707b90ce1fc78ec3
parent5cd4753bea9e8e79bf30217b9d0b7a4485271588
parent07c0d484eec327ca3bd1e3ce081c1ced230536a9
signaturelock-open Commit is signed but in an unrecognized format.

Merge remote-tracking branch 'origin/master' into copy-elision-3


21 files changed, 1475 insertions(+), 507 deletions(-)

CMakeLists.txt+8-3
...@@ -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"
...@@ -6653,15 +6655,18 @@ set(OPTIMIZED_C_FLAGS "-std=c99 -O3")...@@ -6653,15 +6655,18 @@ set(OPTIMIZED_C_FLAGS "-std=c99 -O3")
6653set(EXE_LDFLAGS " ")6655set(EXE_LDFLAGS " ")
6654if(MSVC)6656if(MSVC)
6655 set(EXE_LDFLAGS "/STACK:16777216")6657 set(EXE_LDFLAGS "/STACK:16777216")
6656elseif(ZIG_STATIC)6658elseif(MINGW)
6659 set(EXE_LDFLAGS "${EXE_LDFLAGS} -Wl,--stack,16777216")
6660endif()
6661
6662if(ZIG_STATIC)
6657 if(APPLE)6663 if(APPLE)
6658 set(EXE_LDFLAGS "-static-libgcc -static-libstdc++")6664 set(EXE_LDFLAGS "-static-libgcc -static-libstdc++")
6659 else()6665 else()
6660 set(EXE_LDFLAGS "-static")6666 set(EXE_LDFLAGS "-static")
6661 endif()6667 endif()
6662else()
6663 set(EXE_LDFLAGS " ")
6664endif()6668endif()
6669
6665if(ZIG_TEST_COVERAGE)6670if(ZIG_TEST_COVERAGE)
6666 set(EXE_CFLAGS "${EXE_CFLAGS} -fprofile-arcs -ftest-coverage")6671 set(EXE_CFLAGS "${EXE_CFLAGS} -fprofile-arcs -ftest-coverage")
6667 set(EXE_LDFLAGS "${EXE_LDFLAGS} -fprofile-arcs -ftest-coverage")6672 set(EXE_LDFLAGS "${EXE_LDFLAGS} -fprofile-arcs -ftest-coverage")
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-self-hosted/dep_tokenizer.zig+1-1
...@@ -998,7 +998,7 @@ fn printCharValues(out: var, bytes: []const u8) !void {...@@ -998,7 +998,7 @@ fn printCharValues(out: var, bytes: []const u8) !void {
998998
999fn printUnderstandableChar(out: var, char: u8) !void {999fn printUnderstandableChar(out: var, char: u8) !void {
1000 if (!std.ascii.isPrint(char) or char == ' ') {1000 if (!std.ascii.isPrint(char) or char == ' ') {
1001 std.fmt.format(out.context, anyerror, out.output, "\\x{X2}", char) catch {};1001 std.fmt.format(out.context, anyerror, out.output, "\\x{X:2}", char) catch {};
1002 } else {1002 } else {
1003 try out.write("'");1003 try out.write("'");
1004 try out.write([_]u8{printable_char_tab[char]});1004 try out.write([_]u8{printable_char_tab[char]});
src/all_types.hpp+33-6
...@@ -1419,6 +1419,7 @@ enum BuiltinFnId {...@@ -1419,6 +1419,7 @@ enum BuiltinFnId {
1419 BuiltinFnIdSubWithOverflow,1419 BuiltinFnIdSubWithOverflow,
1420 BuiltinFnIdMulWithOverflow,1420 BuiltinFnIdMulWithOverflow,
1421 BuiltinFnIdShlWithOverflow,1421 BuiltinFnIdShlWithOverflow,
1422 BuiltinFnIdMulAdd,
1422 BuiltinFnIdCInclude,1423 BuiltinFnIdCInclude,
1423 BuiltinFnIdCDefine,1424 BuiltinFnIdCDefine,
1424 BuiltinFnIdCUndef,1425 BuiltinFnIdCUndef,
...@@ -1446,6 +1447,19 @@ enum BuiltinFnId {...@@ -1446,6 +1447,19 @@ enum BuiltinFnId {
1446 BuiltinFnIdRem,1447 BuiltinFnIdRem,
1447 BuiltinFnIdMod,1448 BuiltinFnIdMod,
1448 BuiltinFnIdSqrt,1449 BuiltinFnIdSqrt,
1450 BuiltinFnIdSin,
1451 BuiltinFnIdCos,
1452 BuiltinFnIdExp,
1453 BuiltinFnIdExp2,
1454 BuiltinFnIdLn,
1455 BuiltinFnIdLog2,
1456 BuiltinFnIdLog10,
1457 BuiltinFnIdFabs,
1458 BuiltinFnIdFloor,
1459 BuiltinFnIdCeil,
1460 BuiltinFnIdTrunc,
1461 BuiltinFnIdNearbyInt,
1462 BuiltinFnIdRound,
1449 BuiltinFnIdTruncate,1463 BuiltinFnIdTruncate,
1450 BuiltinFnIdIntCast,1464 BuiltinFnIdIntCast,
1451 BuiltinFnIdFloatCast,1465 BuiltinFnIdFloatCast,
...@@ -1567,9 +1581,8 @@ enum ZigLLVMFnId {...@@ -1567,9 +1581,8 @@ enum ZigLLVMFnId {
1567 ZigLLVMFnIdClz,1581 ZigLLVMFnIdClz,
1568 ZigLLVMFnIdPopCount,1582 ZigLLVMFnIdPopCount,
1569 ZigLLVMFnIdOverflowArithmetic,1583 ZigLLVMFnIdOverflowArithmetic,
1570 ZigLLVMFnIdFloor,1584 ZigLLVMFnIdFMA,
1571 ZigLLVMFnIdCeil,1585 ZigLLVMFnIdFloatOp,
1572 ZigLLVMFnIdSqrt,
1573 ZigLLVMFnIdBswap,1586 ZigLLVMFnIdBswap,
1574 ZigLLVMFnIdBitReverse,1587 ZigLLVMFnIdBitReverse,
1575};1588};
...@@ -1596,7 +1609,9 @@ struct ZigLLVMFnKey {...@@ -1596,7 +1609,9 @@ struct ZigLLVMFnKey {
1596 uint32_t bit_count;1609 uint32_t bit_count;
1597 } pop_count;1610 } pop_count;
1598 struct {1611 struct {
1612 BuiltinFnId op;
1599 uint32_t bit_count;1613 uint32_t bit_count;
1614 uint32_t vector_len; // 0 means not a vector
1600 } floating;1615 } floating;
1601 struct {1616 struct {
1602 AddSubMul add_sub_mul;1617 AddSubMul add_sub_mul;
...@@ -2260,6 +2275,8 @@ enum IrInstructionId {...@@ -2260,6 +2275,8 @@ enum IrInstructionId {
2260 IrInstructionIdOverflowOp,2275 IrInstructionIdOverflowOp,
2261 IrInstructionIdTestErrSrc,2276 IrInstructionIdTestErrSrc,
2262 IrInstructionIdTestErrGen,2277 IrInstructionIdTestErrGen,
2278 IrInstructionIdMulAdd,
2279 IrInstructionIdFloatOp,
2263 IrInstructionIdUnwrapErrCode,2280 IrInstructionIdUnwrapErrCode,
2264 IrInstructionIdUnwrapErrPayload,2281 IrInstructionIdUnwrapErrPayload,
2265 IrInstructionIdErrWrapCode,2282 IrInstructionIdErrWrapCode,
...@@ -2324,7 +2341,6 @@ enum IrInstructionId {...@@ -2324,7 +2341,6 @@ enum IrInstructionId {
2324 IrInstructionIdAddImplicitReturnType,2341 IrInstructionIdAddImplicitReturnType,
2325 IrInstructionIdMergeErrRetTraces,2342 IrInstructionIdMergeErrRetTraces,
2326 IrInstructionIdMarkErrRetTracePtr,2343 IrInstructionIdMarkErrRetTracePtr,
2327 IrInstructionIdSqrt,
2328 IrInstructionIdErrSetCast,2344 IrInstructionIdErrSetCast,
2329 IrInstructionIdToBytes,2345 IrInstructionIdToBytes,
2330 IrInstructionIdFromBytes,2346 IrInstructionIdFromBytes,
...@@ -3080,6 +3096,15 @@ struct IrInstructionOverflowOp {...@@ -3080,6 +3096,15 @@ struct IrInstructionOverflowOp {
3080 ZigType *result_ptr_type;3096 ZigType *result_ptr_type;
3081};3097};
30823098
3099struct IrInstructionMulAdd {
3100 IrInstruction base;
3101
3102 IrInstruction *type_value;
3103 IrInstruction *op1;
3104 IrInstruction *op2;
3105 IrInstruction *op3;
3106};
3107
3083struct IrInstructionAlignOf {3108struct IrInstructionAlignOf {
3084 IrInstruction base;3109 IrInstruction base;
30853110
...@@ -3512,11 +3537,13 @@ struct IrInstructionMarkErrRetTracePtr {...@@ -3512,11 +3537,13 @@ struct IrInstructionMarkErrRetTracePtr {
3512 IrInstruction *err_ret_trace_ptr;3537 IrInstruction *err_ret_trace_ptr;
3513};3538};
35143539
3515struct IrInstructionSqrt {3540// For float ops which take a single argument
3541struct IrInstructionFloatOp {
3516 IrInstruction base;3542 IrInstruction base;
35173543
3544 BuiltinFnId op;
3518 IrInstruction *type;3545 IrInstruction *type;
3519 IrInstruction *op;3546 IrInstruction *op1;
3520};3547};
35213548
3522struct IrInstructionCheckRuntimeScope {3549struct 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
...@@ -808,32 +808,47 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, ZigType *operand_type, AddSu...@@ -808,32 +808,47 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, ZigType *operand_type, AddSu
808 return fn_val;808 return fn_val;
809}809}
810810
811static LLVMValueRef get_float_fn(CodeGen *g, ZigType *type_entry, ZigLLVMFnId fn_id) {811static LLVMValueRef get_float_fn(CodeGen *g, ZigType *type_entry, ZigLLVMFnId fn_id, BuiltinFnId op) {
812 assert(type_entry->id == ZigTypeIdFloat);812 assert(type_entry->id == ZigTypeIdFloat ||
813 type_entry->id == ZigTypeIdVector);
814
815 bool is_vector = (type_entry->id == ZigTypeIdVector);
816 ZigType *float_type = is_vector ? type_entry->data.vector.elem_type : type_entry;
813817
814 ZigLLVMFnKey key = {};818 ZigLLVMFnKey key = {};
815 key.id = fn_id;819 key.id = fn_id;
816 key.data.floating.bit_count = (uint32_t)type_entry->data.floating.bit_count;820 key.data.floating.bit_count = (uint32_t)float_type->data.floating.bit_count;
821 key.data.floating.vector_len = is_vector ? (uint32_t)type_entry->data.vector.len : 0;
822 key.data.floating.op = op;
817823
818 auto existing_entry = g->llvm_fn_table.maybe_get(key);824 auto existing_entry = g->llvm_fn_table.maybe_get(key);
819 if (existing_entry)825 if (existing_entry)
820 return existing_entry->value;826 return existing_entry->value;
821827
822 const char *name;828 const char *name;
823 if (fn_id == ZigLLVMFnIdFloor) {829 uint32_t num_args;
824 name = "floor";830 if (fn_id == ZigLLVMFnIdFMA) {
825 } else if (fn_id == ZigLLVMFnIdCeil) {831 name = "fma";
826 name = "ceil";832 num_args = 3;
827 } else if (fn_id == ZigLLVMFnIdSqrt) {833 } else if (fn_id == ZigLLVMFnIdFloatOp) {
828 name = "sqrt";834 name = float_op_to_name(op, true);
835 num_args = 1;
829 } else {836 } else {
830 zig_unreachable();837 zig_unreachable();
831 }838 }
832839
833 char fn_name[64];840 char fn_name[64];
834 sprintf(fn_name, "llvm.%s.f%" ZIG_PRI_usize "", name, type_entry->data.floating.bit_count);841 if (is_vector)
842 sprintf(fn_name, "llvm.%s.v%" PRIu32 "f%" PRIu32, name, key.data.floating.vector_len, key.data.floating.bit_count);
843 else
844 sprintf(fn_name, "llvm.%s.f%" PRIu32, name, key.data.floating.bit_count);
835 LLVMTypeRef float_type_ref = get_llvm_type(g, type_entry);845 LLVMTypeRef float_type_ref = get_llvm_type(g, type_entry);
836 LLVMTypeRef fn_type = LLVMFunctionType(float_type_ref, &float_type_ref, 1, false);846 LLVMTypeRef return_elem_types[3] = {
847 float_type_ref,
848 float_type_ref,
849 float_type_ref,
850 };
851 LLVMTypeRef fn_type = LLVMFunctionType(float_type_ref, return_elem_types, num_args, false);
837 LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type);852 LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type);
838 assert(LLVMGetIntrinsicID(fn_val));853 assert(LLVMGetIntrinsicID(fn_val));
839854
...@@ -2483,22 +2498,17 @@ static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *type_entry,...@@ -2483,22 +2498,17 @@ static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *type_entry,
2483 return result;2498 return result;
2484}2499}
24852500
2486static LLVMValueRef gen_floor(CodeGen *g, LLVMValueRef val, ZigType *type_entry) {2501static LLVMValueRef gen_float_op(CodeGen *g, LLVMValueRef val, ZigType *type_entry, BuiltinFnId op) {
2487 if (type_entry->id == ZigTypeIdInt)2502 if ((op == BuiltinFnIdCeil ||
2503 op == BuiltinFnIdFloor) &&
2504 type_entry->id == ZigTypeIdInt)
2488 return val;2505 return val;
2506 assert(type_entry->id == ZigTypeIdFloat);
24892507
2490 LLVMValueRef floor_fn = get_float_fn(g, type_entry, ZigLLVMFnIdFloor);2508 LLVMValueRef floor_fn = get_float_fn(g, type_entry, ZigLLVMFnIdFloatOp, op);
2491 return LLVMBuildCall(g->builder, floor_fn, &val, 1, "");2509 return LLVMBuildCall(g->builder, floor_fn, &val, 1, "");
2492}2510}
24932511
2494static LLVMValueRef gen_ceil(CodeGen *g, LLVMValueRef val, ZigType *type_entry) {
2495 if (type_entry->id == ZigTypeIdInt)
2496 return val;
2497
2498 LLVMValueRef ceil_fn = get_float_fn(g, type_entry, ZigLLVMFnIdCeil);
2499 return LLVMBuildCall(g->builder, ceil_fn, &val, 1, "");
2500}
2501
2502enum DivKind {2512enum DivKind {
2503 DivKindFloat,2513 DivKindFloat,
2504 DivKindTrunc,2514 DivKindTrunc,
...@@ -2574,7 +2584,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast...@@ -2574,7 +2584,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast
2574 return result;2584 return result;
2575 case DivKindExact:2585 case DivKindExact:
2576 if (want_runtime_safety) {2586 if (want_runtime_safety) {
2577 LLVMValueRef floored = gen_floor(g, result, type_entry);2587 LLVMValueRef floored = gen_float_op(g, result, type_entry, BuiltinFnIdFloor);
2578 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk");2588 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk");
2579 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail");2589 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail");
2580 LLVMValueRef ok_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, floored, result, "");2590 LLVMValueRef ok_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, floored, result, "");
...@@ -2596,12 +2606,12 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast...@@ -2596,12 +2606,12 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast
2596 LLVMBuildCondBr(g->builder, ltz, ltz_block, gez_block);2606 LLVMBuildCondBr(g->builder, ltz, ltz_block, gez_block);
25972607
2598 LLVMPositionBuilderAtEnd(g->builder, ltz_block);2608 LLVMPositionBuilderAtEnd(g->builder, ltz_block);
2599 LLVMValueRef ceiled = gen_ceil(g, result, type_entry);2609 LLVMValueRef ceiled = gen_float_op(g, result, type_entry, BuiltinFnIdCeil);
2600 LLVMBasicBlockRef ceiled_end_block = LLVMGetInsertBlock(g->builder);2610 LLVMBasicBlockRef ceiled_end_block = LLVMGetInsertBlock(g->builder);
2601 LLVMBuildBr(g->builder, end_block);2611 LLVMBuildBr(g->builder, end_block);
26022612
2603 LLVMPositionBuilderAtEnd(g->builder, gez_block);2613 LLVMPositionBuilderAtEnd(g->builder, gez_block);
2604 LLVMValueRef floored = gen_floor(g, result, type_entry);2614 LLVMValueRef floored = gen_float_op(g, result, type_entry, BuiltinFnIdFloor);
2605 LLVMBasicBlockRef floored_end_block = LLVMGetInsertBlock(g->builder);2615 LLVMBasicBlockRef floored_end_block = LLVMGetInsertBlock(g->builder);
2606 LLVMBuildBr(g->builder, end_block);2616 LLVMBuildBr(g->builder, end_block);
26072617
...@@ -2613,7 +2623,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast...@@ -2613,7 +2623,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast
2613 return phi;2623 return phi;
2614 }2624 }
2615 case DivKindFloor:2625 case DivKindFloor:
2616 return gen_floor(g, result, type_entry);2626 return gen_float_op(g, result, type_entry, BuiltinFnIdFloor);
2617 }2627 }
2618 zig_unreachable();2628 zig_unreachable();
2619 }2629 }
...@@ -5417,13 +5427,28 @@ static LLVMValueRef ir_render_mark_err_ret_trace_ptr(CodeGen *g, IrExecutable *e...@@ -5417,13 +5427,28 @@ static LLVMValueRef ir_render_mark_err_ret_trace_ptr(CodeGen *g, IrExecutable *e
5417 return nullptr;5427 return nullptr;
5418}5428}
54195429
5420static LLVMValueRef ir_render_sqrt(CodeGen *g, IrExecutable *executable, IrInstructionSqrt *instruction) {5430static LLVMValueRef ir_render_float_op(CodeGen *g, IrExecutable *executable, IrInstructionFloatOp *instruction) {
5421 LLVMValueRef op = ir_llvm_value(g, instruction->op);5431 LLVMValueRef op = ir_llvm_value(g, instruction->op1);
5422 assert(instruction->base.value.type->id == ZigTypeIdFloat);5432 assert(instruction->base.value.type->id == ZigTypeIdFloat);
5423 LLVMValueRef fn_val = get_float_fn(g, instruction->base.value.type, ZigLLVMFnIdSqrt);5433 LLVMValueRef fn_val = get_float_fn(g, instruction->base.value.type, ZigLLVMFnIdFloatOp, instruction->op);
5424 return LLVMBuildCall(g->builder, fn_val, &op, 1, "");5434 return LLVMBuildCall(g->builder, fn_val, &op, 1, "");
5425}5435}
54265436
5437static LLVMValueRef ir_render_mul_add(CodeGen *g, IrExecutable *executable, IrInstructionMulAdd *instruction) {
5438 LLVMValueRef op1 = ir_llvm_value(g, instruction->op1);
5439 LLVMValueRef op2 = ir_llvm_value(g, instruction->op2);
5440 LLVMValueRef op3 = ir_llvm_value(g, instruction->op3);
5441 assert(instruction->base.value.type->id == ZigTypeIdFloat ||
5442 instruction->base.value.type->id == ZigTypeIdVector);
5443 LLVMValueRef fn_val = get_float_fn(g, instruction->base.value.type, ZigLLVMFnIdFMA, BuiltinFnIdMulAdd);
5444 LLVMValueRef args[3] = {
5445 op1,
5446 op2,
5447 op3,
5448 };
5449 return LLVMBuildCall(g->builder, fn_val, args, 3, "");
5450}
5451
5427static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInstructionBswap *instruction) {5452static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInstructionBswap *instruction) {
5428 LLVMValueRef op = ir_llvm_value(g, instruction->op);5453 LLVMValueRef op = ir_llvm_value(g, instruction->op);
5429 ZigType *int_type = instruction->base.value.type;5454 ZigType *int_type = instruction->base.value.type;
...@@ -5770,8 +5795,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5770,8 +5795,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5770 return ir_render_merge_err_ret_traces(g, executable, (IrInstructionMergeErrRetTraces *)instruction);5795 return ir_render_merge_err_ret_traces(g, executable, (IrInstructionMergeErrRetTraces *)instruction);
5771 case IrInstructionIdMarkErrRetTracePtr:5796 case IrInstructionIdMarkErrRetTracePtr:
5772 return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction);5797 return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction);
5773 case IrInstructionIdSqrt:5798 case IrInstructionIdFloatOp:
5774 return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction);5799 return ir_render_float_op(g, executable, (IrInstructionFloatOp *)instruction);
5800 case IrInstructionIdMulAdd:
5801 return ir_render_mul_add(g, executable, (IrInstructionMulAdd *)instruction);
5775 case IrInstructionIdArrayToVector:5802 case IrInstructionIdArrayToVector:
5776 return ir_render_array_to_vector(g, executable, (IrInstructionArrayToVector *)instruction);5803 return ir_render_array_to_vector(g, executable, (IrInstructionArrayToVector *)instruction);
5777 case IrInstructionIdVectorToArray:5804 case IrInstructionIdVectorToArray:
...@@ -7356,6 +7383,21 @@ static void define_builtin_fns(CodeGen *g) {...@@ -7356,6 +7383,21 @@ static void define_builtin_fns(CodeGen *g) {
7356 create_builtin_fn(g, BuiltinFnIdRem, "rem", 2);7383 create_builtin_fn(g, BuiltinFnIdRem, "rem", 2);
7357 create_builtin_fn(g, BuiltinFnIdMod, "mod", 2);7384 create_builtin_fn(g, BuiltinFnIdMod, "mod", 2);
7358 create_builtin_fn(g, BuiltinFnIdSqrt, "sqrt", 2);7385 create_builtin_fn(g, BuiltinFnIdSqrt, "sqrt", 2);
7386 create_builtin_fn(g, BuiltinFnIdSin, "sin", 2);
7387 create_builtin_fn(g, BuiltinFnIdCos, "cos", 2);
7388 create_builtin_fn(g, BuiltinFnIdExp, "exp", 2);
7389 create_builtin_fn(g, BuiltinFnIdExp2, "exp2", 2);
7390 create_builtin_fn(g, BuiltinFnIdLn, "ln", 2);
7391 create_builtin_fn(g, BuiltinFnIdLog2, "log2", 2);
7392 create_builtin_fn(g, BuiltinFnIdLog10, "log10", 2);
7393 create_builtin_fn(g, BuiltinFnIdFabs, "fabs", 2);
7394 create_builtin_fn(g, BuiltinFnIdFloor, "floor", 2);
7395 create_builtin_fn(g, BuiltinFnIdCeil, "ceil", 2);
7396 create_builtin_fn(g, BuiltinFnIdTrunc, "trunc", 2);
7397 //Needs library support on Windows
7398 //create_builtin_fn(g, BuiltinFnIdNearbyInt, "nearbyInt", 2);
7399 create_builtin_fn(g, BuiltinFnIdRound, "round", 2);
7400 create_builtin_fn(g, BuiltinFnIdMulAdd, "mulAdd", 4);
7359 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);7401 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
7360 create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);7402 create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);
7361 create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX);7403 create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX);
src/ir.cpp+471-61
...@@ -777,6 +777,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestErrGen *) {...@@ -777,6 +777,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestErrGen *) {
777 return IrInstructionIdTestErrGen;777 return IrInstructionIdTestErrGen;
778}778}
779779
780static constexpr IrInstructionId ir_instruction_id(IrInstructionMulAdd *) {
781 return IrInstructionIdMulAdd;
782}
783
780static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapErrCode *) {784static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapErrCode *) {
781 return IrInstructionIdUnwrapErrCode;785 return IrInstructionIdUnwrapErrCode;
782}786}
...@@ -1037,8 +1041,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionMarkErrRetTraceP...@@ -1037,8 +1041,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionMarkErrRetTraceP
1037 return IrInstructionIdMarkErrRetTracePtr;1041 return IrInstructionIdMarkErrRetTracePtr;
1038}1042}
10391043
1040static constexpr IrInstructionId ir_instruction_id(IrInstructionSqrt *) {1044static constexpr IrInstructionId ir_instruction_id(IrInstructionFloatOp *) {
1041 return IrInstructionIdSqrt;1045 return IrInstructionIdFloatOp;
1042}1046}
10431047
1044static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) {1048static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) {
...@@ -2437,6 +2441,75 @@ static IrInstruction *ir_build_overflow_op(IrBuilder *irb, Scope *scope, AstNode...@@ -2437,6 +2441,75 @@ static IrInstruction *ir_build_overflow_op(IrBuilder *irb, Scope *scope, AstNode
2437 return &instruction->base;2441 return &instruction->base;
2438}2442}
24392443
2444
2445//TODO Powi, Pow, minnum, maxnum, maximum, minimum, copysign,
2446// lround, llround, lrint, llrint
2447// So far this is only non-complicated type functions.
2448const char *float_op_to_name(BuiltinFnId op, bool llvm_name) {
2449 const bool b = llvm_name;
2450
2451 switch (op) {
2452 case BuiltinFnIdSqrt:
2453 return "sqrt";
2454 case BuiltinFnIdSin:
2455 return "sin";
2456 case BuiltinFnIdCos:
2457 return "cos";
2458 case BuiltinFnIdExp:
2459 return "exp";
2460 case BuiltinFnIdExp2:
2461 return "exp2";
2462 case BuiltinFnIdLn:
2463 return b ? "log" : "ln";
2464 case BuiltinFnIdLog10:
2465 return "log10";
2466 case BuiltinFnIdLog2:
2467 return "log2";
2468 case BuiltinFnIdFabs:
2469 return "fabs";
2470 case BuiltinFnIdFloor:
2471 return "floor";
2472 case BuiltinFnIdCeil:
2473 return "ceil";
2474 case BuiltinFnIdTrunc:
2475 return "trunc";
2476 case BuiltinFnIdNearbyInt:
2477 return b ? "nearbyint" : "nearbyInt";
2478 case BuiltinFnIdRound:
2479 return "round";
2480 default:
2481 zig_unreachable();
2482 }
2483}
2484
2485static IrInstruction *ir_build_float_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type, IrInstruction *op1, BuiltinFnId op) {
2486 IrInstructionFloatOp *instruction = ir_build_instruction<IrInstructionFloatOp>(irb, scope, source_node);
2487 instruction->type = type;
2488 instruction->op1 = op1;
2489 instruction->op = op;
2490
2491 if (type != nullptr) ir_ref_instruction(type, irb->current_basic_block);
2492 ir_ref_instruction(op1, irb->current_basic_block);
2493
2494 return &instruction->base;
2495}
2496
2497static IrInstruction *ir_build_mul_add(IrBuilder *irb, Scope *scope, AstNode *source_node,
2498 IrInstruction *type_value, IrInstruction *op1, IrInstruction *op2, IrInstruction *op3) {
2499 IrInstructionMulAdd *instruction = ir_build_instruction<IrInstructionMulAdd>(irb, scope, source_node);
2500 instruction->type_value = type_value;
2501 instruction->op1 = op1;
2502 instruction->op2 = op2;
2503 instruction->op3 = op3;
2504
2505 ir_ref_instruction(type_value, irb->current_basic_block);
2506 ir_ref_instruction(op1, irb->current_basic_block);
2507 ir_ref_instruction(op2, irb->current_basic_block);
2508 ir_ref_instruction(op3, irb->current_basic_block);
2509
2510 return &instruction->base;
2511}
2512
2440static IrInstruction *ir_build_align_of(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value) {2513static IrInstruction *ir_build_align_of(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value) {
2441 IrInstructionAlignOf *instruction = ir_build_instruction<IrInstructionAlignOf>(irb, scope, source_node);2514 IrInstructionAlignOf *instruction = ir_build_instruction<IrInstructionAlignOf>(irb, scope, source_node);
2442 instruction->type_value = type_value;2515 instruction->type_value = type_value;
...@@ -3201,17 +3274,6 @@ static IrInstruction *ir_build_mark_err_ret_trace_ptr(IrBuilder *irb, Scope *sco...@@ -3201,17 +3274,6 @@ static IrInstruction *ir_build_mark_err_ret_trace_ptr(IrBuilder *irb, Scope *sco
3201 return &instruction->base;3274 return &instruction->base;
3202}3275}
32033276
3204static IrInstruction *ir_build_sqrt(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type, IrInstruction *op) {
3205 IrInstructionSqrt *instruction = ir_build_instruction<IrInstructionSqrt>(irb, scope, source_node);
3206 instruction->type = type;
3207 instruction->op = op;
3208
3209 if (type != nullptr) ir_ref_instruction(type, irb->current_basic_block);
3210 ir_ref_instruction(op, irb->current_basic_block);
3211
3212 return &instruction->base;
3213}
3214
3215static IrInstruction *ir_build_has_decl(IrBuilder *irb, Scope *scope, AstNode *source_node,3277static IrInstruction *ir_build_has_decl(IrBuilder *irb, Scope *scope, AstNode *source_node,
3216 IrInstruction *container, IrInstruction *name)3278 IrInstruction *container, IrInstruction *name)
3217{3279{
...@@ -4380,6 +4442,33 @@ static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *...@@ -4380,6 +4442,33 @@ static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *
4380 return ir_build_overflow_op(irb, scope, node, op, type_value, op1, op2, result_ptr, nullptr);4442 return ir_build_overflow_op(irb, scope, node, op, type_value, op1, op2, result_ptr, nullptr);
4381}4443}
43824444
4445static IrInstruction *ir_gen_mul_add(IrBuilder *irb, Scope *scope, AstNode *node) {
4446 assert(node->type == NodeTypeFnCallExpr);
4447
4448 AstNode *type_node = node->data.fn_call_expr.params.at(0);
4449 AstNode *op1_node = node->data.fn_call_expr.params.at(1);
4450 AstNode *op2_node = node->data.fn_call_expr.params.at(2);
4451 AstNode *op3_node = node->data.fn_call_expr.params.at(3);
4452
4453 IrInstruction *type_value = ir_gen_node(irb, type_node, scope);
4454 if (type_value == irb->codegen->invalid_instruction)
4455 return irb->codegen->invalid_instruction;
4456
4457 IrInstruction *op1 = ir_gen_node(irb, op1_node, scope);
4458 if (op1 == irb->codegen->invalid_instruction)
4459 return irb->codegen->invalid_instruction;
4460
4461 IrInstruction *op2 = ir_gen_node(irb, op2_node, scope);
4462 if (op2 == irb->codegen->invalid_instruction)
4463 return irb->codegen->invalid_instruction;
4464
4465 IrInstruction *op3 = ir_gen_node(irb, op3_node, scope);
4466 if (op3 == irb->codegen->invalid_instruction)
4467 return irb->codegen->invalid_instruction;
4468
4469 return ir_build_mul_add(irb, scope, node, type_value, op1, op2, op3);
4470}
4471
4383static IrInstruction *ir_gen_this(IrBuilder *irb, Scope *orig_scope, AstNode *node) {4472static IrInstruction *ir_gen_this(IrBuilder *irb, Scope *orig_scope, AstNode *node) {
4384 for (Scope *it_scope = orig_scope; it_scope != nullptr; it_scope = it_scope->parent) {4473 for (Scope *it_scope = orig_scope; it_scope != nullptr; it_scope = it_scope->parent) {
4385 if (it_scope->id == ScopeIdDecls) {4474 if (it_scope->id == ScopeIdDecls) {
...@@ -4708,6 +4797,19 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -4708,6 +4797,19 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
4708 return ir_lval_wrap(irb, scope, bin_op, lval, result_loc);4797 return ir_lval_wrap(irb, scope, bin_op, lval, result_loc);
4709 }4798 }
4710 case BuiltinFnIdSqrt:4799 case BuiltinFnIdSqrt:
4800 case BuiltinFnIdSin:
4801 case BuiltinFnIdCos:
4802 case BuiltinFnIdExp:
4803 case BuiltinFnIdExp2:
4804 case BuiltinFnIdLn:
4805 case BuiltinFnIdLog2:
4806 case BuiltinFnIdLog10:
4807 case BuiltinFnIdFabs:
4808 case BuiltinFnIdFloor:
4809 case BuiltinFnIdCeil:
4810 case BuiltinFnIdTrunc:
4811 case BuiltinFnIdNearbyInt:
4812 case BuiltinFnIdRound:
4711 {4813 {
4712 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);4814 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4713 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);4815 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
...@@ -4719,7 +4821,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -4719,7 +4821,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
4719 if (arg1_value == irb->codegen->invalid_instruction)4821 if (arg1_value == irb->codegen->invalid_instruction)
4720 return arg1_value;4822 return arg1_value;
47214823
4722 IrInstruction *ir_sqrt = ir_build_sqrt(irb, scope, node, arg0_value, arg1_value);4824 IrInstruction *ir_sqrt = ir_build_float_op(irb, scope, node, arg0_value, arg1_value, builtin_fn->id);
4723 return ir_lval_wrap(irb, scope, ir_sqrt, lval, result_loc);4825 return ir_lval_wrap(irb, scope, ir_sqrt, lval, result_loc);
4724 }4826 }
4725 case BuiltinFnIdTruncate:4827 case BuiltinFnIdTruncate:
...@@ -5043,6 +5145,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -5043,6 +5145,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
5043 return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul), lval, result_loc);5145 return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul), lval, result_loc);
5044 case BuiltinFnIdShlWithOverflow:5146 case BuiltinFnIdShlWithOverflow:
5045 return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl), lval, result_loc);5147 return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl), lval, result_loc);
5148 case BuiltinFnIdMulAdd:
5149 return ir_lval_wrap(irb, scope, ir_gen_mul_add(irb, scope, node), lval, result_loc);
5046 case BuiltinFnIdTypeName:5150 case BuiltinFnIdTypeName:
5047 {5151 {
5048 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);5152 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
...@@ -22709,6 +22813,125 @@ static IrInstruction *ir_analyze_instruction_result_ptr(IrAnalyze *ira, IrInstru...@@ -22709,6 +22813,125 @@ static IrInstruction *ir_analyze_instruction_result_ptr(IrAnalyze *ira, IrInstru
22709 return ir_get_ref(ira, &instruction->base, result, true, false);22813 return ir_get_ref(ira, &instruction->base, result, true, false);
22710}22814}
2271122815
22816static void ir_eval_mul_add(IrAnalyze *ira, IrInstructionMulAdd *source_instr, ZigType *float_type,
22817 ConstExprValue *op1, ConstExprValue *op2, ConstExprValue *op3, ConstExprValue *out_val) {
22818 if (float_type->id == ZigTypeIdComptimeFloat) {
22819 f128M_mulAdd(&out_val->data.x_bigfloat.value, &op1->data.x_bigfloat.value, &op2->data.x_bigfloat.value,
22820 &op3->data.x_bigfloat.value);
22821 } else if (float_type->id == ZigTypeIdFloat) {
22822 switch (float_type->data.floating.bit_count) {
22823 case 16:
22824 out_val->data.x_f16 = f16_mulAdd(op1->data.x_f16, op2->data.x_f16, op3->data.x_f16);
22825 break;
22826 case 32:
22827 out_val->data.x_f32 = fmaf(op1->data.x_f32, op2->data.x_f32, op3->data.x_f32);
22828 break;
22829 case 64:
22830 out_val->data.x_f64 = fma(op1->data.x_f64, op2->data.x_f64, op3->data.x_f64);
22831 break;
22832 case 128:
22833 f128M_mulAdd(&op1->data.x_f128, &op2->data.x_f128, &op3->data.x_f128, &out_val->data.x_f128);
22834 break;
22835 default:
22836 zig_unreachable();
22837 }
22838 } else {
22839 zig_unreachable();
22840 }
22841}
22842
22843static IrInstruction *ir_analyze_instruction_mul_add(IrAnalyze *ira, IrInstructionMulAdd *instruction) {
22844 IrInstruction *type_value = instruction->type_value->child;
22845 if (type_is_invalid(type_value->value.type))
22846 return ira->codegen->invalid_instruction;
22847
22848 ZigType *expr_type = ir_resolve_type(ira, type_value);
22849 if (type_is_invalid(expr_type))
22850 return ira->codegen->invalid_instruction;
22851
22852 // Only allow float types, and vectors of floats.
22853 ZigType *float_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type;
22854 if (float_type->id != ZigTypeIdFloat) {
22855 ir_add_error(ira, type_value,
22856 buf_sprintf("expected float or vector of float type, found '%s'", buf_ptr(&float_type->name)));
22857 return ira->codegen->invalid_instruction;
22858 }
22859
22860 IrInstruction *op1 = instruction->op1->child;
22861 if (type_is_invalid(op1->value.type))
22862 return ira->codegen->invalid_instruction;
22863
22864 IrInstruction *casted_op1 = ir_implicit_cast(ira, op1, expr_type);
22865 if (type_is_invalid(casted_op1->value.type))
22866 return ira->codegen->invalid_instruction;
22867
22868 IrInstruction *op2 = instruction->op2->child;
22869 if (type_is_invalid(op2->value.type))
22870 return ira->codegen->invalid_instruction;
22871
22872 IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, expr_type);
22873 if (type_is_invalid(casted_op2->value.type))
22874 return ira->codegen->invalid_instruction;
22875
22876 IrInstruction *op3 = instruction->op3->child;
22877 if (type_is_invalid(op3->value.type))
22878 return ira->codegen->invalid_instruction;
22879
22880 IrInstruction *casted_op3 = ir_implicit_cast(ira, op3, expr_type);
22881 if (type_is_invalid(casted_op3->value.type))
22882 return ira->codegen->invalid_instruction;
22883
22884 if (instr_is_comptime(casted_op1) &&
22885 instr_is_comptime(casted_op2) &&
22886 instr_is_comptime(casted_op3)) {
22887 ConstExprValue *op1_const = ir_resolve_const(ira, casted_op1, UndefBad);
22888 if (!op1_const)
22889 return ira->codegen->invalid_instruction;
22890 ConstExprValue *op2_const = ir_resolve_const(ira, casted_op2, UndefBad);
22891 if (!op2_const)
22892 return ira->codegen->invalid_instruction;
22893 ConstExprValue *op3_const = ir_resolve_const(ira, casted_op3, UndefBad);
22894 if (!op3_const)
22895 return ira->codegen->invalid_instruction;
22896
22897 IrInstruction *result = ir_const(ira, &instruction->base, expr_type);
22898 ConstExprValue *out_val = &result->value;
22899
22900 if (expr_type->id == ZigTypeIdVector) {
22901 expand_undef_array(ira->codegen, op1_const);
22902 expand_undef_array(ira->codegen, op2_const);
22903 expand_undef_array(ira->codegen, op3_const);
22904 out_val->special = ConstValSpecialUndef;
22905 expand_undef_array(ira->codegen, out_val);
22906 size_t len = expr_type->data.vector.len;
22907 for (size_t i = 0; i < len; i += 1) {
22908 ConstExprValue *float_operand_op1 = &op1_const->data.x_array.data.s_none.elements[i];
22909 ConstExprValue *float_operand_op2 = &op2_const->data.x_array.data.s_none.elements[i];
22910 ConstExprValue *float_operand_op3 = &op3_const->data.x_array.data.s_none.elements[i];
22911 ConstExprValue *float_out_val = &out_val->data.x_array.data.s_none.elements[i];
22912 assert(float_operand_op1->type == float_type);
22913 assert(float_operand_op2->type == float_type);
22914 assert(float_operand_op3->type == float_type);
22915 assert(float_out_val->type == float_type);
22916 ir_eval_mul_add(ira, instruction, float_type,
22917 op1_const, op2_const, op3_const, float_out_val);
22918 float_out_val->type = float_type;
22919 }
22920 out_val->type = expr_type;
22921 out_val->special = ConstValSpecialStatic;
22922 } else {
22923 ir_eval_mul_add(ira, instruction, float_type, op1_const, op2_const, op3_const, out_val);
22924 }
22925 return result;
22926 }
22927
22928 IrInstruction *result = ir_build_mul_add(&ira->new_irb,
22929 instruction->base.scope, instruction->base.source_node,
22930 type_value, casted_op1, casted_op2, casted_op3);
22931 result->value.type = expr_type;
22932 return result;
22933}
22934
22712static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstructionTestErrSrc *instruction) {22935static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstructionTestErrSrc *instruction) {
22713 IrInstruction *base_ptr = instruction->base_ptr->child;22936 IrInstruction *base_ptr = instruction->base_ptr->child;
22714 if (type_is_invalid(base_ptr->value.type))22937 if (type_is_invalid(base_ptr->value.type))
...@@ -24542,70 +24765,254 @@ static IrInstruction *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *i...@@ -24542,70 +24765,254 @@ static IrInstruction *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *i
24542 return result;24765 return result;
24543}24766}
2454424767
24545static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionSqrt *instruction) {24768static void ir_eval_float_op(IrAnalyze *ira, IrInstructionFloatOp *source_instr, ZigType *float_type,
24546 ZigType *float_type = ir_resolve_type(ira, instruction->type->child);24769 ConstExprValue *op, ConstExprValue *out_val) {
24547 if (type_is_invalid(float_type))24770 assert(ira && source_instr && float_type && out_val && op);
24548 return ira->codegen->invalid_instruction;24771 assert(float_type->id == ZigTypeIdFloat ||
24772 float_type->id == ZigTypeIdComptimeFloat);
2454924773
24550 IrInstruction *op = instruction->op->child;24774 BuiltinFnId fop = source_instr->op;
24551 if (type_is_invalid(op->value.type))24775 unsigned bits;
24776
24777 switch (float_type->id) {
24778 case ZigTypeIdComptimeFloat:
24779 bits = 128;
24780 break;
24781 case ZigTypeIdFloat:
24782 bits = float_type->data.floating.bit_count;
24783 break;
24784 default:
24785 zig_unreachable();
24786 }
24787
24788 switch (bits) {
24789 case 16: {
24790 switch (fop) {
24791 case BuiltinFnIdSqrt:
24792 out_val->data.x_f16 = f16_sqrt(op->data.x_f16);
24793 break;
24794 case BuiltinFnIdSin:
24795 case BuiltinFnIdCos:
24796 case BuiltinFnIdExp:
24797 case BuiltinFnIdExp2:
24798 case BuiltinFnIdLn:
24799 case BuiltinFnIdLog10:
24800 case BuiltinFnIdLog2:
24801 case BuiltinFnIdFabs:
24802 case BuiltinFnIdFloor:
24803 case BuiltinFnIdCeil:
24804 case BuiltinFnIdTrunc:
24805 case BuiltinFnIdNearbyInt:
24806 case BuiltinFnIdRound:
24807 zig_panic("unimplemented f16 builtin");
24808 default:
24809 zig_unreachable();
24810 };
24811 break;
24812 };
24813 case 32: {
24814 switch (fop) {
24815 case BuiltinFnIdSqrt:
24816 out_val->data.x_f32 = sqrtf(op->data.x_f32);
24817 break;
24818 case BuiltinFnIdSin:
24819 out_val->data.x_f32 = sinf(op->data.x_f32);
24820 break;
24821 case BuiltinFnIdCos:
24822 out_val->data.x_f32 = cosf(op->data.x_f32);
24823 break;
24824 case BuiltinFnIdExp:
24825 out_val->data.x_f32 = expf(op->data.x_f32);
24826 break;
24827 case BuiltinFnIdExp2:
24828 out_val->data.x_f32 = exp2f(op->data.x_f32);
24829 break;
24830 case BuiltinFnIdLn:
24831 out_val->data.x_f32 = logf(op->data.x_f32);
24832 break;
24833 case BuiltinFnIdLog10:
24834 out_val->data.x_f32 = log10f(op->data.x_f32);
24835 break;
24836 case BuiltinFnIdLog2:
24837 out_val->data.x_f32 = log2f(op->data.x_f32);
24838 break;
24839 case BuiltinFnIdFabs:
24840 out_val->data.x_f32 = fabsf(op->data.x_f32);
24841 break;
24842 case BuiltinFnIdFloor:
24843 out_val->data.x_f32 = floorf(op->data.x_f32);
24844 break;
24845 case BuiltinFnIdCeil:
24846 out_val->data.x_f32 = ceilf(op->data.x_f32);
24847 break;
24848 case BuiltinFnIdTrunc:
24849 out_val->data.x_f32 = truncf(op->data.x_f32);
24850 break;
24851 case BuiltinFnIdNearbyInt:
24852 out_val->data.x_f32 = nearbyintf(op->data.x_f32);
24853 break;
24854 case BuiltinFnIdRound:
24855 out_val->data.x_f32 = roundf(op->data.x_f32);
24856 break;
24857 default:
24858 zig_unreachable();
24859 };
24860 break;
24861 };
24862 case 64: {
24863 switch (fop) {
24864 case BuiltinFnIdSqrt:
24865 out_val->data.x_f64 = sqrt(op->data.x_f64);
24866 break;
24867 case BuiltinFnIdSin:
24868 out_val->data.x_f64 = sin(op->data.x_f64);
24869 break;
24870 case BuiltinFnIdCos:
24871 out_val->data.x_f64 = cos(op->data.x_f64);
24872 break;
24873 case BuiltinFnIdExp:
24874 out_val->data.x_f64 = exp(op->data.x_f64);
24875 break;
24876 case BuiltinFnIdExp2:
24877 out_val->data.x_f64 = exp2(op->data.x_f64);
24878 break;
24879 case BuiltinFnIdLn:
24880 out_val->data.x_f64 = log(op->data.x_f64);
24881 break;
24882 case BuiltinFnIdLog10:
24883 out_val->data.x_f64 = log10(op->data.x_f64);
24884 break;
24885 case BuiltinFnIdLog2:
24886 out_val->data.x_f64 = log2(op->data.x_f64);
24887 break;
24888 case BuiltinFnIdFabs:
24889 out_val->data.x_f64 = fabs(op->data.x_f64);
24890 break;
24891 case BuiltinFnIdFloor:
24892 out_val->data.x_f64 = floor(op->data.x_f64);
24893 break;
24894 case BuiltinFnIdCeil:
24895 out_val->data.x_f64 = ceil(op->data.x_f64);
24896 break;
24897 case BuiltinFnIdTrunc:
24898 out_val->data.x_f64 = trunc(op->data.x_f64);
24899 break;
24900 case BuiltinFnIdNearbyInt:
24901 out_val->data.x_f64 = nearbyint(op->data.x_f64);
24902 break;
24903 case BuiltinFnIdRound:
24904 out_val->data.x_f64 = round(op->data.x_f64);
24905 break;
24906 default:
24907 zig_unreachable();
24908 }
24909 break;
24910 };
24911 case 128: {
24912 float128_t *out, *in;
24913 if (float_type->id == ZigTypeIdComptimeFloat) {
24914 out = &out_val->data.x_bigfloat.value;
24915 in = &op->data.x_bigfloat.value;
24916 } else {
24917 out = &out_val->data.x_f128;
24918 in = &op->data.x_f128;
24919 }
24920 switch (fop) {
24921 case BuiltinFnIdSqrt:
24922 f128M_sqrt(in, out);
24923 break;
24924 case BuiltinFnIdNearbyInt:
24925 case BuiltinFnIdSin:
24926 case BuiltinFnIdCos:
24927 case BuiltinFnIdExp:
24928 case BuiltinFnIdExp2:
24929 case BuiltinFnIdLn:
24930 case BuiltinFnIdLog10:
24931 case BuiltinFnIdLog2:
24932 case BuiltinFnIdFabs:
24933 case BuiltinFnIdFloor:
24934 case BuiltinFnIdCeil:
24935 case BuiltinFnIdTrunc:
24936 case BuiltinFnIdRound:
24937 zig_panic("unimplemented f128 builtin");
24938 default:
24939 zig_unreachable();
24940 }
24941 break;
24942 };
24943 default:
24944 zig_unreachable();
24945 }
24946}
24947
24948static IrInstruction *ir_analyze_instruction_float_op(IrAnalyze *ira, IrInstructionFloatOp *instruction) {
24949 IrInstruction *type = instruction->type->child;
24950 if (type_is_invalid(type->value.type))
24951 return ira->codegen->invalid_instruction;
24952
24953 ZigType *expr_type = ir_resolve_type(ira, type);
24954 if (type_is_invalid(expr_type))
24552 return ira->codegen->invalid_instruction;24955 return ira->codegen->invalid_instruction;
2455324956
24554 bool ok_type = float_type->id == ZigTypeIdComptimeFloat || float_type->id == ZigTypeIdFloat;24957 // Only allow float types, and vectors of floats.
24555 if (!ok_type) {24958 ZigType *float_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type;
24556 ir_add_error(ira, instruction->type, buf_sprintf("@sqrt does not support type '%s'", buf_ptr(&float_type->name)));24959 if (float_type->id != ZigTypeIdFloat && float_type->id != ZigTypeIdComptimeFloat) {
24960 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)));
24557 return ira->codegen->invalid_instruction;24961 return ira->codegen->invalid_instruction;
24558 }24962 }
2455924963
24560 IrInstruction *casted_op = ir_implicit_cast(ira, op, float_type);24964 IrInstruction *op1 = instruction->op1->child;
24561 if (type_is_invalid(casted_op->value.type))24965 if (type_is_invalid(op1->value.type))
24562 return ira->codegen->invalid_instruction;24966 return ira->codegen->invalid_instruction;
2456324967
24564 if (instr_is_comptime(casted_op)) {24968 IrInstruction *casted_op1 = ir_implicit_cast(ira, op1, float_type);
24565 ConstExprValue *val = ir_resolve_const(ira, casted_op, UndefBad);24969 if (type_is_invalid(casted_op1->value.type))
24566 if (!val)24970 return ira->codegen->invalid_instruction;
24971
24972 if (instr_is_comptime(casted_op1)) {
24973 // Our comptime 16-bit and 128-bit support is quite limited.
24974 if ((float_type->id == ZigTypeIdComptimeFloat ||
24975 float_type->data.floating.bit_count == 16 ||
24976 float_type->data.floating.bit_count == 128) &&
24977 instruction->op != BuiltinFnIdSqrt) {
24978 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)));
24979 return ira->codegen->invalid_instruction;
24980 }
24981
24982 ConstExprValue *op1_const = ir_resolve_const(ira, casted_op1, UndefBad);
24983 if (!op1_const)
24567 return ira->codegen->invalid_instruction;24984 return ira->codegen->invalid_instruction;
2456824985
24569 IrInstruction *result = ir_const(ira, &instruction->base, float_type);24986 IrInstruction *result = ir_const(ira, &instruction->base, expr_type);
24570 ConstExprValue *out_val = &result->value;24987 ConstExprValue *out_val = &result->value;
2457124988
24572 if (float_type->id == ZigTypeIdComptimeFloat) {24989 if (expr_type->id == ZigTypeIdVector) {
24573 bigfloat_sqrt(&out_val->data.x_bigfloat, &val->data.x_bigfloat);24990 expand_undef_array(ira->codegen, op1_const);
24574 } else if (float_type->id == ZigTypeIdFloat) {24991 out_val->special = ConstValSpecialUndef;
24575 switch (float_type->data.floating.bit_count) {24992 expand_undef_array(ira->codegen, out_val);
24576 case 16:24993 size_t len = expr_type->data.vector.len;
24577 out_val->data.x_f16 = f16_sqrt(val->data.x_f16);24994 for (size_t i = 0; i < len; i += 1) {
24578 break;24995 ConstExprValue *float_operand_op1 = &op1_const->data.x_array.data.s_none.elements[i];
24579 case 32:24996 ConstExprValue *float_out_val = &out_val->data.x_array.data.s_none.elements[i];
24580 out_val->data.x_f32 = sqrtf(val->data.x_f32);24997 assert(float_operand_op1->type == float_type);
24581 break;24998 assert(float_out_val->type == float_type);
24582 case 64:24999 ir_eval_float_op(ira, instruction, float_type,
24583 out_val->data.x_f64 = sqrt(val->data.x_f64);25000 op1_const, float_out_val);
24584 break;25001 float_out_val->type = float_type;
24585 case 128:
24586 f128M_sqrt(&val->data.x_f128, &out_val->data.x_f128);
24587 break;
24588 default:
24589 zig_unreachable();
24590 }25002 }
25003 out_val->type = expr_type;
25004 out_val->special = ConstValSpecialStatic;
24591 } else {25005 } else {
24592 zig_unreachable();25006 ir_eval_float_op(ira, instruction, float_type, op1_const, out_val);
24593 }25007 }
24594
24595 return result;25008 return result;
24596 }25009 }
2459725010
24598 ir_assert(float_type->id == ZigTypeIdFloat, &instruction->base);25011 ir_assert(float_type->id == ZigTypeIdFloat, &instruction->base);
24599 if (float_type->data.floating.bit_count != 16 &&
24600 float_type->data.floating.bit_count != 32 &&
24601 float_type->data.floating.bit_count != 64) {
24602 ir_add_error(ira, instruction->type, buf_sprintf("compiler TODO: add implementation of sqrt for '%s'", buf_ptr(&float_type->name)));
24603 return ira->codegen->invalid_instruction;
24604 }
2460525012
24606 IrInstruction *result = ir_build_sqrt(&ira->new_irb, instruction->base.scope,25013 IrInstruction *result = ir_build_float_op(&ira->new_irb, instruction->base.scope,
24607 instruction->base.source_node, nullptr, casted_op);25014 instruction->base.source_node, nullptr, casted_op1, instruction->op);
24608 result->value.type = float_type;25015 result->value.type = expr_type;
24609 return result;25016 return result;
24610}25017}
2461125018
...@@ -25143,8 +25550,10 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction...@@ -25143,8 +25550,10 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
25143 return ir_analyze_instruction_merge_err_ret_traces(ira, (IrInstructionMergeErrRetTraces *)instruction);25550 return ir_analyze_instruction_merge_err_ret_traces(ira, (IrInstructionMergeErrRetTraces *)instruction);
25144 case IrInstructionIdMarkErrRetTracePtr:25551 case IrInstructionIdMarkErrRetTracePtr:
25145 return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction);25552 return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction);
25146 case IrInstructionIdSqrt:25553 case IrInstructionIdFloatOp:
25147 return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction);25554 return ir_analyze_instruction_float_op(ira, (IrInstructionFloatOp *)instruction);
25555 case IrInstructionIdMulAdd:
25556 return ir_analyze_instruction_mul_add(ira, (IrInstructionMulAdd *)instruction);
25148 case IrInstructionIdIntToErr:25557 case IrInstructionIdIntToErr:
25149 return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction);25558 return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction);
25150 case IrInstructionIdErrToInt:25559 case IrInstructionIdErrToInt:
...@@ -25391,7 +25800,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -25391,7 +25800,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
25391 case IrInstructionIdCoroFree:25800 case IrInstructionIdCoroFree:
25392 case IrInstructionIdCoroPromise:25801 case IrInstructionIdCoroPromise:
25393 case IrInstructionIdPromiseResultType:25802 case IrInstructionIdPromiseResultType:
25394 case IrInstructionIdSqrt:25803 case IrInstructionIdFloatOp:
25804 case IrInstructionIdMulAdd:
25395 case IrInstructionIdAtomicLoad:25805 case IrInstructionIdAtomicLoad:
25396 case IrInstructionIdIntCast:25806 case IrInstructionIdIntCast:
25397 case IrInstructionIdFloatCast:25807 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
...@@ -1563,15 +1563,32 @@ static void ir_print_mark_err_ret_trace_ptr(IrPrint *irp, IrInstructionMarkErrRe...@@ -1563,15 +1563,32 @@ static void ir_print_mark_err_ret_trace_ptr(IrPrint *irp, IrInstructionMarkErrRe
1563 fprintf(irp->f, ")");1563 fprintf(irp->f, ")");
1564}1564}
15651565
1566static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) {1566static void ir_print_float_op(IrPrint *irp, IrInstructionFloatOp *instruction) {
1567 fprintf(irp->f, "@sqrt(");1567
1568 fprintf(irp->f, "@%s(", float_op_to_name(instruction->op, false));
1568 if (instruction->type != nullptr) {1569 if (instruction->type != nullptr) {
1569 ir_print_other_instruction(irp, instruction->type);1570 ir_print_other_instruction(irp, instruction->type);
1570 } else {1571 } else {
1571 fprintf(irp->f, "null");1572 fprintf(irp->f, "null");
1572 }1573 }
1573 fprintf(irp->f, ",");1574 fprintf(irp->f, ",");
1574 ir_print_other_instruction(irp, instruction->op);1575 ir_print_other_instruction(irp, instruction->op1);
1576 fprintf(irp->f, ")");
1577}
1578
1579static void ir_print_mul_add(IrPrint *irp, IrInstructionMulAdd *instruction) {
1580 fprintf(irp->f, "@mulAdd(");
1581 if (instruction->type_value != nullptr) {
1582 ir_print_other_instruction(irp, instruction->type_value);
1583 } else {
1584 fprintf(irp->f, "null");
1585 }
1586 fprintf(irp->f, ",");
1587 ir_print_other_instruction(irp, instruction->op1);
1588 fprintf(irp->f, ",");
1589 ir_print_other_instruction(irp, instruction->op2);
1590 fprintf(irp->f, ",");
1591 ir_print_other_instruction(irp, instruction->op3);
1575 fprintf(irp->f, ")");1592 fprintf(irp->f, ")");
1576}1593}
15771594
...@@ -2053,8 +2070,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -2053,8 +2070,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
2053 case IrInstructionIdMarkErrRetTracePtr:2070 case IrInstructionIdMarkErrRetTracePtr:
2054 ir_print_mark_err_ret_trace_ptr(irp, (IrInstructionMarkErrRetTracePtr *)instruction);2071 ir_print_mark_err_ret_trace_ptr(irp, (IrInstructionMarkErrRetTracePtr *)instruction);
2055 break;2072 break;
2056 case IrInstructionIdSqrt:2073 case IrInstructionIdFloatOp:
2057 ir_print_sqrt(irp, (IrInstructionSqrt *)instruction);2074 ir_print_float_op(irp, (IrInstructionFloatOp *)instruction);
2075 break;
2076 case IrInstructionIdMulAdd:
2077 ir_print_mul_add(irp, (IrInstructionMulAdd *)instruction);
2058 break;2078 break;
2059 case IrInstructionIdAtomicLoad:2079 case IrInstructionIdAtomicLoad:
2060 ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction);2080 ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction);
std/fmt.zig+397-363
...@@ -10,6 +10,42 @@ const lossyCast = std.math.lossyCast;...@@ -10,6 +10,42 @@ const lossyCast = std.math.lossyCast;
1010
11pub const default_max_depth = 3;11pub const default_max_depth = 3;
1212
13pub const Alignment = enum {
14 Left,
15 Center,
16 Right,
17};
18
19pub const FormatOptions = struct {
20 precision: ?usize = null,
21 width: ?usize = null,
22 alignment: ?Alignment = null,
23 fill: u8 = ' ',
24};
25
26fn nextArg(comptime used_pos_args: *u32, comptime maybe_pos_arg: ?comptime_int, comptime next_arg: *comptime_int) comptime_int {
27 if (maybe_pos_arg) |pos_arg| {
28 used_pos_args.* |= 1 << pos_arg;
29 return pos_arg;
30 } else {
31 const arg = next_arg.*;
32 next_arg.* += 1;
33 return arg;
34 }
35}
36
37fn peekIsAlign(comptime fmt: []const u8) bool {
38 // Should only be called during a state transition to the format segment.
39 std.debug.assert(fmt[0] == ':');
40
41 inline for (([_]u8{ 1, 2 })[0..]) |i| {
42 if (fmt.len > i and (fmt[i] == '<' or fmt[i] == '^' or fmt[i] == '>')) {
43 return true;
44 }
45 }
46 return false;
47}
48
13/// Renders fmt string with args, calling output with slices of bytes.49/// Renders fmt string with args, calling output with slices of bytes.
14/// If `output` returns an error, the error is returned from `format` and50/// If `output` returns an error, the error is returned from `format` and
15/// `output` is not called again.51/// `output` is not called again.
...@@ -20,17 +56,30 @@ pub fn format(...@@ -20,17 +56,30 @@ pub fn format(
20 comptime fmt: []const u8,56 comptime fmt: []const u8,
21 args: ...,57 args: ...,
22) Errors!void {58) Errors!void {
59 const ArgSetType = @IntType(false, 32);
60 if (args.len > ArgSetType.bit_count) {
61 @compileError("32 arguments max are supported per format call");
62 }
63
23 const State = enum {64 const State = enum {
24 Start,65 Start,
25 OpenBrace,66 Positional,
26 CloseBrace,67 CloseBrace,
27 FormatString,68 Specifier,
69 FormatFillAndAlign,
70 FormatWidth,
71 FormatPrecision,
28 Pointer,72 Pointer,
29 };73 };
3074
31 comptime var start_index = 0;75 comptime var start_index = 0;
32 comptime var state = State.Start;76 comptime var state = State.Start;
33 comptime var next_arg = 0;77 comptime var next_arg = 0;
78 comptime var maybe_pos_arg: ?comptime_int = null;
79 comptime var used_pos_args: ArgSetType = 0;
80 comptime var specifier_start = 0;
81 comptime var specifier_end = 0;
82 comptime var options = FormatOptions{};
3483
35 inline for (fmt) |c, i| {84 inline for (fmt) |c, i| {
36 switch (state) {85 switch (state) {
...@@ -39,58 +88,183 @@ pub fn format(...@@ -39,58 +88,183 @@ pub fn format(
39 if (start_index < i) {88 if (start_index < i) {
40 try output(context, fmt[start_index..i]);89 try output(context, fmt[start_index..i]);
41 }90 }
91
42 start_index = i;92 start_index = i;
43 state = State.OpenBrace;93 specifier_start = i + 1;
94 specifier_end = i + 1;
95 maybe_pos_arg = null;
96 state = .Positional;
97 options = FormatOptions{};
44 },98 },
45
46 '}' => {99 '}' => {
47 if (start_index < i) {100 if (start_index < i) {
48 try output(context, fmt[start_index..i]);101 try output(context, fmt[start_index..i]);
49 }102 }
50 state = State.CloseBrace;103 state = .CloseBrace;
51 },104 },
52 else => {},105 else => {},
53 },106 },
54 .OpenBrace => switch (c) {107 .Positional => switch (c) {
55 '{' => {108 '{' => {
56 state = State.Start;109 state = .Start;
57 start_index = i;110 start_index = i;
58 },111 },
112 '*' => {
113 state = .Pointer;
114 },
115 ':' => {
116 state = if (comptime peekIsAlign(fmt[i..])) State.FormatFillAndAlign else State.FormatWidth;
117 specifier_end = i;
118 },
119 '0'...'9' => {
120 if (maybe_pos_arg == null) {
121 maybe_pos_arg = 0;
122 }
123
124 maybe_pos_arg.? *= 10;
125 maybe_pos_arg.? += c - '0';
126 specifier_start = i + 1;
127
128 if (maybe_pos_arg.? >= args.len) {
129 @compileError("Positional value refers to non-existent argument");
130 }
131 },
59 '}' => {132 '}' => {
60 try formatType(args[next_arg], fmt[0..0], context, Errors, output, default_max_depth);133 const arg_to_print = comptime nextArg(&used_pos_args, maybe_pos_arg, &next_arg);
61 next_arg += 1;134
62 state = State.Start;135 try formatType(
136 args[arg_to_print],
137 fmt[0..0],
138 options,
139 context,
140 Errors,
141 output,
142 default_max_depth,
143 );
144
145 state = .Start;
63 start_index = i + 1;146 start_index = i + 1;
64 },147 },
65 '*' => state = State.Pointer,
66 else => {148 else => {
67 state = State.FormatString;149 state = .Specifier;
150 specifier_start = i;
68 },151 },
69 },152 },
70 .CloseBrace => switch (c) {153 .CloseBrace => switch (c) {
71 '}' => {154 '}' => {
72 state = State.Start;155 state = .Start;
73 start_index = i;156 start_index = i;
74 },157 },
75 else => @compileError("Single '}' encountered in format string"),158 else => @compileError("Single '}' encountered in format string"),
76 },159 },
77 .FormatString => switch (c) {160 .Specifier => switch (c) {
161 ':' => {
162 specifier_end = i;
163 state = if (comptime peekIsAlign(fmt[i..])) State.FormatFillAndAlign else State.FormatWidth;
164 },
78 '}' => {165 '}' => {
79 const s = start_index + 1;166 const arg_to_print = comptime nextArg(&used_pos_args, maybe_pos_arg, &next_arg);
80 try formatType(args[next_arg], fmt[s..i], context, Errors, output, default_max_depth);167
81 next_arg += 1;168 try formatType(
82 state = State.Start;169 args[arg_to_print],
170 fmt[specifier_start..i],
171 options,
172 context,
173 Errors,
174 output,
175 default_max_depth,
176 );
177 state = .Start;
83 start_index = i + 1;178 start_index = i + 1;
84 },179 },
85 else => {},180 else => {},
86 },181 },
182 // Only entered if the format string contains a fill/align segment.
183 .FormatFillAndAlign => switch (c) {
184 '<' => {
185 options.alignment = Alignment.Left;
186 state = .FormatWidth;
187 },
188 '^' => {
189 options.alignment = Alignment.Center;
190 state = .FormatWidth;
191 },
192 '>' => {
193 options.alignment = Alignment.Right;
194 state = .FormatWidth;
195 },
196 else => {
197 options.fill = c;
198 },
199 },
200 .FormatWidth => switch (c) {
201 '0'...'9' => {
202 if (options.width == null) {
203 options.width = 0;
204 }
205
206 options.width.? *= 10;
207 options.width.? += c - '0';
208 },
209 '.' => {
210 state = .FormatPrecision;
211 },
212 '}' => {
213 const arg_to_print = comptime nextArg(&used_pos_args, maybe_pos_arg, &next_arg);
214
215 try formatType(
216 args[arg_to_print],
217 fmt[specifier_start..specifier_end],
218 options,
219 context,
220 Errors,
221 output,
222 default_max_depth,
223 );
224 state = .Start;
225 start_index = i + 1;
226 },
227 else => {
228 @compileError("Unexpected character in width value: " ++ [_]u8{c});
229 },
230 },
231 .FormatPrecision => switch (c) {
232 '0'...'9' => {
233 if (options.precision == null) {
234 options.precision = 0;
235 }
236
237 options.precision.? *= 10;
238 options.precision.? += c - '0';
239 },
240 '}' => {
241 const arg_to_print = comptime nextArg(&used_pos_args, maybe_pos_arg, &next_arg);
242
243 try formatType(
244 args[arg_to_print],
245 fmt[specifier_start..specifier_end],
246 options,
247 context,
248 Errors,
249 output,
250 default_max_depth,
251 );
252 state = .Start;
253 start_index = i + 1;
254 },
255 else => {
256 @compileError("Unexpected character in precision value: " ++ [_]u8{c});
257 },
258 },
87 .Pointer => switch (c) {259 .Pointer => switch (c) {
88 '}' => {260 '}' => {
89 try output(context, @typeName(@typeOf(args[next_arg]).Child));261 const arg_to_print = comptime nextArg(&used_pos_args, maybe_pos_arg, &next_arg);
262
263 try output(context, @typeName(@typeOf(args[arg_to_print]).Child));
90 try output(context, "@");264 try output(context, "@");
91 try formatInt(@ptrToInt(args[next_arg]), 16, false, 0, context, Errors, output);265 try formatInt(@ptrToInt(args[arg_to_print]), 16, false, 0, context, Errors, output);
92 next_arg += 1;266
93 state = State.Start;267 state = .Start;
94 start_index = i + 1;268 start_index = i + 1;
95 },269 },
96 else => @compileError("Unexpected format character after '*'"),270 else => @compileError("Unexpected format character after '*'"),
...@@ -98,7 +272,13 @@ pub fn format(...@@ -98,7 +272,13 @@ pub fn format(
98 }272 }
99 }273 }
100 comptime {274 comptime {
101 if (args.len != next_arg) {275 // All arguments must have been printed but we allow mixing positional and fixed to achieve this.
276 var i: usize = 0;
277 inline while (i < next_arg) : (i += 1) {
278 used_pos_args |= 1 << i;
279 }
280
281 if (@popCount(ArgSetType, used_pos_args) != args.len) {
102 @compileError("Unused arguments");282 @compileError("Unused arguments");
103 }283 }
104 if (state != State.Start) {284 if (state != State.Start) {
...@@ -113,6 +293,7 @@ pub fn format(...@@ -113,6 +293,7 @@ pub fn format(
113pub fn formatType(293pub fn formatType(
114 value: var,294 value: var,
115 comptime fmt: []const u8,295 comptime fmt: []const u8,
296 comptime options: FormatOptions,
116 context: var,297 context: var,
117 comptime Errors: type,298 comptime Errors: type,
118 output: fn (@typeOf(context), []const u8) Errors!void,299 output: fn (@typeOf(context), []const u8) Errors!void,
...@@ -121,7 +302,7 @@ pub fn formatType(...@@ -121,7 +302,7 @@ pub fn formatType(
121 const T = @typeOf(value);302 const T = @typeOf(value);
122 switch (@typeInfo(T)) {303 switch (@typeInfo(T)) {
123 .ComptimeInt, .Int, .Float => {304 .ComptimeInt, .Int, .Float => {
124 return formatValue(value, fmt, context, Errors, output);305 return formatValue(value, fmt, options, context, Errors, output);
125 },306 },
126 .Void => {307 .Void => {
127 return output(context, "void");308 return output(context, "void");
...@@ -131,16 +312,16 @@ pub fn formatType(...@@ -131,16 +312,16 @@ pub fn formatType(
131 },312 },
132 .Optional => {313 .Optional => {
133 if (value) |payload| {314 if (value) |payload| {
134 return formatType(payload, fmt, context, Errors, output, max_depth);315 return formatType(payload, fmt, options, context, Errors, output, max_depth);
135 } else {316 } else {
136 return output(context, "null");317 return output(context, "null");
137 }318 }
138 },319 },
139 .ErrorUnion => {320 .ErrorUnion => {
140 if (value) |payload| {321 if (value) |payload| {
141 return formatType(payload, fmt, context, Errors, output, max_depth);322 return formatType(payload, fmt, options, context, Errors, output, max_depth);
142 } else |err| {323 } else |err| {
143 return formatType(err, fmt, context, Errors, output, max_depth);324 return formatType(err, fmt, options, context, Errors, output, max_depth);
144 }325 }
145 },326 },
146 .ErrorSet => {327 .ErrorSet => {
...@@ -152,16 +333,16 @@ pub fn formatType(...@@ -152,16 +333,16 @@ pub fn formatType(
152 },333 },
153 .Enum => {334 .Enum => {
154 if (comptime std.meta.trait.hasFn("format")(T)) {335 if (comptime std.meta.trait.hasFn("format")(T)) {
155 return value.format(fmt, context, Errors, output);336 return value.format(fmt, options, context, Errors, output);
156 }337 }
157338
158 try output(context, @typeName(T));339 try output(context, @typeName(T));
159 try output(context, ".");340 try output(context, ".");
160 return formatType(@tagName(value), "", context, Errors, output, max_depth);341 return formatType(@tagName(value), "", options, context, Errors, output, max_depth);
161 },342 },
162 .Union => {343 .Union => {
163 if (comptime std.meta.trait.hasFn("format")(T)) {344 if (comptime std.meta.trait.hasFn("format")(T)) {
164 return value.format(fmt, context, Errors, output);345 return value.format(fmt, options, context, Errors, output);
165 }346 }
166347
167 try output(context, @typeName(T));348 try output(context, @typeName(T));
...@@ -175,7 +356,7 @@ pub fn formatType(...@@ -175,7 +356,7 @@ pub fn formatType(
175 try output(context, " = ");356 try output(context, " = ");
176 inline for (info.fields) |u_field| {357 inline for (info.fields) |u_field| {
177 if (@enumToInt(UnionTagType(value)) == u_field.enum_field.?.value) {358 if (@enumToInt(UnionTagType(value)) == u_field.enum_field.?.value) {
178 try formatType(@field(value, u_field.name), "", context, Errors, output, max_depth - 1);359 try formatType(@field(value, u_field.name), "", options, context, Errors, output, max_depth - 1);
179 }360 }
180 }361 }
181 try output(context, " }");362 try output(context, " }");
...@@ -185,7 +366,7 @@ pub fn formatType(...@@ -185,7 +366,7 @@ pub fn formatType(
185 },366 },
186 .Struct => {367 .Struct => {
187 if (comptime std.meta.trait.hasFn("format")(T)) {368 if (comptime std.meta.trait.hasFn("format")(T)) {
188 return value.format(fmt, context, Errors, output);369 return value.format(fmt, options, context, Errors, output);
189 }370 }
190371
191 try output(context, @typeName(T));372 try output(context, @typeName(T));
...@@ -201,7 +382,7 @@ pub fn formatType(...@@ -201,7 +382,7 @@ pub fn formatType(
201 }382 }
202 try output(context, @memberName(T, field_i));383 try output(context, @memberName(T, field_i));
203 try output(context, " = ");384 try output(context, " = ");
204 try formatType(@field(value, @memberName(T, field_i)), "", context, Errors, output, max_depth - 1);385 try formatType(@field(value, @memberName(T, field_i)), "", options, context, Errors, output, max_depth - 1);
205 }386 }
206 try output(context, " }");387 try output(context, " }");
207 },388 },
...@@ -209,12 +390,12 @@ pub fn formatType(...@@ -209,12 +390,12 @@ pub fn formatType(
209 .One => switch (@typeInfo(ptr_info.child)) {390 .One => switch (@typeInfo(ptr_info.child)) {
210 builtin.TypeId.Array => |info| {391 builtin.TypeId.Array => |info| {
211 if (info.child == u8) {392 if (info.child == u8) {
212 return formatText(value, fmt, context, Errors, output);393 return formatText(value, fmt, options, context, Errors, output);
213 }394 }
214 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));395 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
215 },396 },
216 builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {397 builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => {
217 return formatType(value.*, fmt, context, Errors, output, max_depth);398 return formatType(value.*, fmt, options, context, Errors, output, max_depth);
218 },399 },
219 else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)),400 else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)),
220 },401 },
...@@ -222,17 +403,17 @@ pub fn formatType(...@@ -222,17 +403,17 @@ pub fn formatType(
222 if (ptr_info.child == u8) {403 if (ptr_info.child == u8) {
223 if (fmt.len > 0 and fmt[0] == 's') {404 if (fmt.len > 0 and fmt[0] == 's') {
224 const len = mem.len(u8, value);405 const len = mem.len(u8, value);
225 return formatText(value[0..len], fmt, context, Errors, output);406 return formatText(value[0..len], fmt, options, context, Errors, output);
226 }407 }
227 }408 }
228 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));409 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
229 },410 },
230 .Slice => {411 .Slice => {
231 if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {412 if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) {
232 return formatText(value, fmt, context, Errors, output);413 return formatText(value, fmt, options, context, Errors, output);
233 }414 }
234 if (ptr_info.child == u8) {415 if (ptr_info.child == u8) {
235 return formatText(value, fmt, context, Errors, output);416 return formatText(value, fmt, options, context, Errors, output);
236 }417 }
237 return format(context, Errors, output, "{}@{x}", @typeName(ptr_info.child), @ptrToInt(value.ptr));418 return format(context, Errors, output, "{}@{x}", @typeName(ptr_info.child), @ptrToInt(value.ptr));
238 },419 },
...@@ -242,7 +423,7 @@ pub fn formatType(...@@ -242,7 +423,7 @@ pub fn formatType(
242 },423 },
243 .Array => |info| {424 .Array => |info| {
244 if (info.child == u8) {425 if (info.child == u8) {
245 return formatText(value, fmt, context, Errors, output);426 return formatText(value, fmt, options, context, Errors, output);
246 }427 }
247 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));428 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
248 },429 },
...@@ -256,28 +437,25 @@ pub fn formatType(...@@ -256,28 +437,25 @@ pub fn formatType(
256fn formatValue(437fn formatValue(
257 value: var,438 value: var,
258 comptime fmt: []const u8,439 comptime fmt: []const u8,
440 comptime options: FormatOptions,
259 context: var,441 context: var,
260 comptime Errors: type,442 comptime Errors: type,
261 output: fn (@typeOf(context), []const u8) Errors!void,443 output: fn (@typeOf(context), []const u8) Errors!void,
262) Errors!void {444) Errors!void {
263 if (fmt.len > 0 and fmt[0] == 'B') {445 if (comptime std.mem.eql(u8, fmt, "B")) {
264 comptime var width: ?usize = null;446 // TODO https://github.com/ziglang/zig/issues/2725
265 if (fmt.len > 1) {447 if (options.width) |w| return formatBytes(value, w, 1000, context, Errors, output);
266 if (fmt[1] == 'i') {448 return formatBytes(value, null, 1000, context, Errors, output);
267 if (fmt.len > 2) {449 } else if (comptime std.mem.eql(u8, fmt, "Bi")) {
268 width = comptime (parseUnsigned(usize, fmt[2..], 10) catch unreachable);450 // TODO https://github.com/ziglang/zig/issues/2725
269 }451 if (options.width) |w| return formatBytes(value, w, 1024, context, Errors, output);
270 return formatBytes(value, width, 1024, context, Errors, output);452 return formatBytes(value, null, 1024, context, Errors, output);
271 }
272 width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
273 }
274 return formatBytes(value, width, 1000, context, Errors, output);
275 }453 }
276454
277 const T = @typeOf(value);455 const T = @typeOf(value);
278 switch (@typeId(T)) {456 switch (@typeId(T)) {
279 .Float => return formatFloatValue(value, fmt, context, Errors, output),457 .Float => return formatFloatValue(value, fmt, options, context, Errors, output),
280 .Int, .ComptimeInt => return formatIntValue(value, fmt, context, Errors, output),458 .Int, .ComptimeInt => return formatIntValue(value, fmt, options, context, Errors, output),
281 else => comptime unreachable,459 else => comptime unreachable,
282 }460 }
283}461}
...@@ -285,13 +463,13 @@ fn formatValue(...@@ -285,13 +463,13 @@ fn formatValue(
285pub fn formatIntValue(463pub fn formatIntValue(
286 value: var,464 value: var,
287 comptime fmt: []const u8,465 comptime fmt: []const u8,
466 comptime options: FormatOptions,
288 context: var,467 context: var,
289 comptime Errors: type,468 comptime Errors: type,
290 output: fn (@typeOf(context), []const u8) Errors!void,469 output: fn (@typeOf(context), []const u8) Errors!void,
291) Errors!void {470) Errors!void {
292 comptime var radix = 10;471 comptime var radix = 10;
293 comptime var uppercase = false;472 comptime var uppercase = false;
294 comptime var width = 0;
295473
296 const int_value = if (@typeOf(value) == comptime_int) blk: {474 const int_value = if (@typeOf(value) == comptime_int) blk: {
297 const Int = math.IntFittingRange(value, value);475 const Int = math.IntFittingRange(value, value);
...@@ -299,83 +477,75 @@ pub fn formatIntValue(...@@ -299,83 +477,75 @@ pub fn formatIntValue(
299 } else477 } else
300 value;478 value;
301479
302 if (fmt.len > 0) {480 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "d")) {
303 switch (fmt[0]) {481 radix = 10;
304 'c' => {482 uppercase = false;
305 if (@typeOf(int_value).bit_count <= 8) {483 } else if (comptime std.mem.eql(u8, fmt, "c")) {
306 if (fmt.len > 1)484 if (@typeOf(int_value).bit_count <= 8) {
307 @compileError("Unknown format character: " ++ [_]u8{fmt[1]});485 return formatAsciiChar(u8(int_value), context, Errors, output);
308 return formatAsciiChar(u8(int_value), context, Errors, output);486 } else {
309 }487 @compileError("Cannot print integer that is larger than 8 bits as a ascii");
310 },
311 'b' => {
312 radix = 2;
313 uppercase = false;
314 width = 0;
315 },
316 'd' => {
317 radix = 10;
318 uppercase = false;
319 width = 0;
320 },
321 'x' => {
322 radix = 16;
323 uppercase = false;
324 width = 0;
325 },
326 'X' => {
327 radix = 16;
328 uppercase = true;
329 width = 0;
330 },
331 else => @compileError("Unknown format character: " ++ [_]u8{fmt[0]}),
332 }488 }
333 if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);489 } else if (comptime std.mem.eql(u8, fmt, "b")) {
490 radix = 2;
491 uppercase = false;
492 } else if (comptime std.mem.eql(u8, fmt, "x")) {
493 radix = 16;
494 uppercase = false;
495 } else if (comptime std.mem.eql(u8, fmt, "X")) {
496 radix = 16;
497 uppercase = true;
498 } else {
499 @compileError("Unknown format string: '" ++ fmt ++ "'");
334 }500 }
335 return formatInt(int_value, radix, uppercase, width, context, Errors, output);501
502 // TODO https://github.com/ziglang/zig/issues/2725
503 if (options.width) |w| return formatInt(int_value, radix, uppercase, w, context, Errors, output);
504 return formatInt(int_value, radix, uppercase, 0, context, Errors, output);
336}505}
337506
338fn formatFloatValue(507fn formatFloatValue(
339 value: var,508 value: var,
340 comptime fmt: []const u8,509 comptime fmt: []const u8,
510 comptime options: FormatOptions,
341 context: var,511 context: var,
342 comptime Errors: type,512 comptime Errors: type,
343 output: fn (@typeOf(context), []const u8) Errors!void,513 output: fn (@typeOf(context), []const u8) Errors!void,
344) Errors!void {514) Errors!void {
345 comptime var width: ?usize = null;515 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) {
346 comptime var float_fmt = 'e';516 // TODO https://github.com/ziglang/zig/issues/2725
347 if (fmt.len > 0) {517 if (options.precision) |p| return formatFloatScientific(value, p, context, Errors, output);
348 float_fmt = fmt[0];518 return formatFloatScientific(value, null, context, Errors, output);
349 if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);519 } else if (comptime std.mem.eql(u8, fmt, "d")) {
350 }520 // TODO https://github.com/ziglang/zig/issues/2725
351521 if (options.precision) |p| return formatFloatDecimal(value, p, context, Errors, output);
352 switch (float_fmt) {522 return formatFloatDecimal(value, null, context, Errors, output);
353 'e' => try formatFloatScientific(value, width, context, Errors, output),523 } else {
354 '.' => try formatFloatDecimal(value, width, context, Errors, output),524 @compileError("Unknown format string: '" ++ fmt ++ "'");
355 else => @compileError("Unknown format character: " ++ [_]u8{float_fmt}),
356 }525 }
357}526}
358527
359pub fn formatText(528pub fn formatText(
360 bytes: []const u8,529 bytes: []const u8,
361 comptime fmt: []const u8,530 comptime fmt: []const u8,
531 comptime options: FormatOptions,
362 context: var,532 context: var,
363 comptime Errors: type,533 comptime Errors: type,
364 output: fn (@typeOf(context), []const u8) Errors!void,534 output: fn (@typeOf(context), []const u8) Errors!void,
365) Errors!void {535) Errors!void {
366 if (fmt.len > 0) {536 if (fmt.len == 0) {
367 if (fmt[0] == 's') {537 return output(context, bytes);
368 comptime var width = 0;538 } else if (comptime std.mem.eql(u8, fmt, "s")) {
369 if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);539 if (options.width) |w| return formatBuf(bytes, w, context, Errors, output);
370 return formatBuf(bytes, width, context, Errors, output);540 return formatBuf(bytes, 0, context, Errors, output);
371 } else if ((fmt[0] == 'x') or (fmt[0] == 'X')) {541 } else if (comptime (std.mem.eql(u8, fmt, "x") or std.mem.eql(u8, fmt, "X"))) {
372 for (bytes) |c| {542 for (bytes) |c| {
373 try formatInt(c, 16, fmt[0] == 'X', 2, context, Errors, output);543 try formatInt(c, 16, fmt[0] == 'X', 2, context, Errors, output);
374 }544 }
375 return;545 return;
376 } else @compileError("Unknown format character: " ++ [_]u8{fmt[0]});546 } else {
547 @compileError("Unknown format string: '" ++ fmt ++ "'");
377 }548 }
378 return output(context, bytes);
379}549}
380550
381pub fn formatAsciiChar(551pub fn formatAsciiChar(
...@@ -868,7 +1038,7 @@ test "parseUnsigned" {...@@ -868,7 +1038,7 @@ test "parseUnsigned" {
8681038
869pub const parseFloat = @import("fmt/parse_float.zig").parseFloat;1039pub const parseFloat = @import("fmt/parse_float.zig").parseFloat;
8701040
871test "fmt.parseFloat" {1041test "parseFloat" {
872 _ = @import("fmt/parse_float.zig");1042 _ = @import("fmt/parse_float.zig");
873}1043}
8741044
...@@ -960,7 +1130,7 @@ test "parse unsigned comptime" {...@@ -960,7 +1130,7 @@ test "parse unsigned comptime" {
960 }1130 }
961}1131}
9621132
963test "fmt.optional" {1133test "optional" {
964 {1134 {
965 const value: ?i32 = 1234;1135 const value: ?i32 = 1234;
966 try testFmt("optional: 1234\n", "optional: {}\n", value);1136 try testFmt("optional: 1234\n", "optional: {}\n", value);
...@@ -971,7 +1141,7 @@ test "fmt.optional" {...@@ -971,7 +1141,7 @@ test "fmt.optional" {
971 }1141 }
972}1142}
9731143
974test "fmt.error" {1144test "error" {
975 {1145 {
976 const value: anyerror!i32 = 1234;1146 const value: anyerror!i32 = 1234;
977 try testFmt("error union: 1234\n", "error union: {}\n", value);1147 try testFmt("error union: 1234\n", "error union: {}\n", value);
...@@ -982,14 +1152,14 @@ test "fmt.error" {...@@ -982,14 +1152,14 @@ test "fmt.error" {
982 }1152 }
983}1153}
9841154
985test "fmt.int.small" {1155test "int.small" {
986 {1156 {
987 const value: u3 = 0b101;1157 const value: u3 = 0b101;
988 try testFmt("u3: 5\n", "u3: {}\n", value);1158 try testFmt("u3: 5\n", "u3: {}\n", value);
989 }1159 }
990}1160}
9911161
992test "fmt.int.specifier" {1162test "int.specifier" {
993 {1163 {
994 const value: u8 = 'a';1164 const value: u8 = 'a';
995 try testFmt("u8: a\n", "u8: {c}\n", value);1165 try testFmt("u8: a\n", "u8: {c}\n", value);
...@@ -1000,27 +1170,31 @@ test "fmt.int.specifier" {...@@ -1000,27 +1170,31 @@ test "fmt.int.specifier" {
1000 }1170 }
1001}1171}
10021172
1003test "fmt.buffer" {1173test "int.padded" {
1174 try testFmt("u8: '0001'", "u8: '{:4}'", u8(1));
1175}
1176
1177test "buffer" {
1004 {1178 {
1005 var buf1: [32]u8 = undefined;1179 var buf1: [32]u8 = undefined;
1006 var context = BufPrintContext{ .remaining = buf1[0..] };1180 var context = BufPrintContext{ .remaining = buf1[0..] };
1007 try formatType(1234, "", &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);1181 try formatType(1234, "", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
1008 var res = buf1[0 .. buf1.len - context.remaining.len];1182 var res = buf1[0 .. buf1.len - context.remaining.len];
1009 testing.expect(mem.eql(u8, res, "1234"));1183 testing.expect(mem.eql(u8, res, "1234"));
10101184
1011 context = BufPrintContext{ .remaining = buf1[0..] };1185 context = BufPrintContext{ .remaining = buf1[0..] };
1012 try formatType('a', "c", &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);1186 try formatType('a', "c", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
1013 res = buf1[0 .. buf1.len - context.remaining.len];1187 res = buf1[0 .. buf1.len - context.remaining.len];
1014 testing.expect(mem.eql(u8, res, "a"));1188 testing.expect(mem.eql(u8, res, "a"));
10151189
1016 context = BufPrintContext{ .remaining = buf1[0..] };1190 context = BufPrintContext{ .remaining = buf1[0..] };
1017 try formatType(0b1100, "b", &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);1191 try formatType(0b1100, "b", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth);
1018 res = buf1[0 .. buf1.len - context.remaining.len];1192 res = buf1[0 .. buf1.len - context.remaining.len];
1019 testing.expect(mem.eql(u8, res, "1100"));1193 testing.expect(mem.eql(u8, res, "1100"));
1020 }1194 }
1021}1195}
10221196
1023test "fmt.array" {1197test "array" {
1024 {1198 {
1025 const value: [3]u8 = "abc";1199 const value: [3]u8 = "abc";
1026 try testFmt("array: abc\n", "array: {}\n", value);1200 try testFmt("array: abc\n", "array: {}\n", value);
...@@ -1035,7 +1209,7 @@ test "fmt.array" {...@@ -1035,7 +1209,7 @@ test "fmt.array" {
1035 }1209 }
1036}1210}
10371211
1038test "fmt.slice" {1212test "slice" {
1039 {1213 {
1040 const value: []const u8 = "abc";1214 const value: []const u8 = "abc";
1041 try testFmt("slice: abc\n", "slice: {}\n", value);1215 try testFmt("slice: abc\n", "slice: {}\n", value);
...@@ -1045,11 +1219,11 @@ test "fmt.slice" {...@@ -1045,11 +1219,11 @@ test "fmt.slice" {
1045 try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", value);1219 try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", value);
1046 }1220 }
10471221
1048 try testFmt("buf: Test \n", "buf: {s5}\n", "Test");1222 try testFmt("buf: Test \n", "buf: {s:5}\n", "Test");
1049 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");1223 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");
1050}1224}
10511225
1052test "fmt.pointer" {1226test "pointer" {
1053 {1227 {
1054 const value = @intToPtr(*i32, 0xdeadbeef);1228 const value = @intToPtr(*i32, 0xdeadbeef);
1055 try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value);1229 try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value);
...@@ -1065,17 +1239,17 @@ test "fmt.pointer" {...@@ -1065,17 +1239,17 @@ test "fmt.pointer" {
1065 }1239 }
1066}1240}
10671241
1068test "fmt.cstr" {1242test "cstr" {
1069 try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");1243 try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");
1070 try testFmt("cstr: Test C \n", "cstr: {s10}\n", c"Test C");1244 try testFmt("cstr: Test C \n", "cstr: {s:10}\n", c"Test C");
1071}1245}
10721246
1073test "fmt.filesize" {1247test "filesize" {
1074 try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));1248 try testFmt("file size: 63MiB\n", "file size: {Bi}\n", usize(63 * 1024 * 1024));
1075 try testFmt("file size: 66.06MB\n", "file size: {B2}\n", usize(63 * 1024 * 1024));1249 try testFmt("file size: 66.06MB\n", "file size: {B:2}\n", usize(63 * 1024 * 1024));
1076}1250}
10771251
1078test "fmt.struct" {1252test "struct" {
1079 {1253 {
1080 const Struct = struct {1254 const Struct = struct {
1081 field: u8,1255 field: u8,
...@@ -1094,7 +1268,7 @@ test "fmt.struct" {...@@ -1094,7 +1268,7 @@ test "fmt.struct" {
1094 }1268 }
1095}1269}
10961270
1097test "fmt.enum" {1271test "enum" {
1098 const Enum = enum {1272 const Enum = enum {
1099 One,1273 One,
1100 Two,1274 Two,
...@@ -1104,229 +1278,71 @@ test "fmt.enum" {...@@ -1104,229 +1278,71 @@ test "fmt.enum" {
1104 try testFmt("enum: Enum.Two\n", "enum: {}\n", &value);1278 try testFmt("enum: Enum.Two\n", "enum: {}\n", &value);
1105}1279}
11061280
1107test "fmt.float.scientific" {1281test "float.scientific" {
1108 {1282 try testFmt("f32: 1.34000003e+00", "f32: {e}", f32(1.34));
1109 var buf1: [32]u8 = undefined;1283 try testFmt("f32: 1.23400001e+01", "f32: {e}", f32(12.34));
1110 const value: f32 = 1.34;1284 try testFmt("f64: -1.234e+11", "f64: {e}", f64(-12.34e10));
1111 const result = try bufPrint(buf1[0..], "f32: {e}\n", value);1285 try testFmt("f64: 9.99996e-40", "f64: {e}", f64(9.999960e-40));
1112 testing.expect(mem.eql(u8, result, "f32: 1.34000003e+00\n"));
1113 }
1114 {
1115 var buf1: [32]u8 = undefined;
1116 const value: f32 = 12.34;
1117 const result = try bufPrint(buf1[0..], "f32: {e}\n", value);
1118 testing.expect(mem.eql(u8, result, "f32: 1.23400001e+01\n"));
1119 }
1120 {
1121 var buf1: [32]u8 = undefined;
1122 const value: f64 = -12.34e10;
1123 const result = try bufPrint(buf1[0..], "f64: {e}\n", value);
1124 testing.expect(mem.eql(u8, result, "f64: -1.234e+11\n"));
1125 }
1126 {
1127 // This fails on release due to a minor rounding difference.
1128 // --release-fast outputs 9.999960000000001e-40 vs. the expected.
1129 // TODO fix this, it should be the same in Debug and ReleaseFast
1130 if (builtin.mode == builtin.Mode.Debug) {
1131 var buf1: [32]u8 = undefined;
1132 const value: f64 = 9.999960e-40;
1133 const result = try bufPrint(buf1[0..], "f64: {e}\n", value);
1134 testing.expect(mem.eql(u8, result, "f64: 9.99996e-40\n"));
1135 }
1136 }
1137}1286}
11381287
1139test "fmt.float.scientific.precision" {1288test "float.scientific.precision" {
1140 {1289 try testFmt("f64: 1.40971e-42", "f64: {e:.5}", f64(1.409706e-42));
1141 var buf1: [32]u8 = undefined;1290 try testFmt("f64: 1.00000e-09", "f64: {e:.5}", f64(@bitCast(f32, u32(814313563))));
1142 const value: f64 = 1.409706e-42;1291 try testFmt("f64: 7.81250e-03", "f64: {e:.5}", f64(@bitCast(f32, u32(1006632960))));
1143 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);1292 // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
1144 testing.expect(mem.eql(u8, result, "f64: 1.40971e-42\n"));1293 // In fact, libc doesn't round a lot of 5 cases up when one past the precision point.
1145 }1294 try testFmt("f64: 1.00001e+05", "f64: {e:.5}", f64(@bitCast(f32, u32(1203982400))));
1146 {
1147 var buf1: [32]u8 = undefined;
1148 const value: f64 = @bitCast(f32, u32(814313563));
1149 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
1150 testing.expect(mem.eql(u8, result, "f64: 1.00000e-09\n"));
1151 }
1152 {
1153 var buf1: [32]u8 = undefined;
1154 const value: f64 = @bitCast(f32, u32(1006632960));
1155 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
1156 testing.expect(mem.eql(u8, result, "f64: 7.81250e-03\n"));
1157 }
1158 {
1159 // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
1160 // In fact, libc doesn't round a lot of 5 cases up when one past the precision point.
1161 var buf1: [32]u8 = undefined;
1162 const value: f64 = @bitCast(f32, u32(1203982400));
1163 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
1164 testing.expect(mem.eql(u8, result, "f64: 1.00001e+05\n"));
1165 }
1166}1295}
11671296
1168test "fmt.float.special" {1297test "float.special" {
1169 {1298 try testFmt("f64: nan", "f64: {}", math.nan_f64);
1170 var buf1: [32]u8 = undefined;1299 // negative nan is not defined by IEE 754,
1171 const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);1300 // and ARM thus normalizes it to positive nan
1172 testing.expect(mem.eql(u8, result, "f64: nan\n"));
1173 }
1174 if (builtin.arch != builtin.Arch.arm) {1301 if (builtin.arch != builtin.Arch.arm) {
1175 // negative nan is not defined by IEE 754,1302 try testFmt("f64: -nan", "f64: {}", -math.nan_f64);
1176 // and ARM thus normalizes it to positive nan
1177 var buf1: [32]u8 = undefined;
1178 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.nan_f64);
1179 testing.expect(mem.eql(u8, result, "f64: -nan\n"));
1180 }
1181 {
1182 var buf1: [32]u8 = undefined;
1183 const result = try bufPrint(buf1[0..], "f64: {}\n", math.inf_f64);
1184 testing.expect(mem.eql(u8, result, "f64: inf\n"));
1185 }
1186 {
1187 var buf1: [32]u8 = undefined;
1188 const result = try bufPrint(buf1[0..], "f64: {}\n", -math.inf_f64);
1189 testing.expect(mem.eql(u8, result, "f64: -inf\n"));
1190 }1303 }
1304 try testFmt("f64: inf", "f64: {}", math.inf_f64);
1305 try testFmt("f64: -inf", "f64: {}", -math.inf_f64);
1191}1306}
11921307
1193test "fmt.float.decimal" {1308test "float.decimal" {
1194 {1309 try testFmt("f64: 152314000000000000000000000000", "f64: {d}", f64(1.52314e+29));
1195 var buf1: [64]u8 = undefined;1310 try testFmt("f32: 1.1", "f32: {d:.1}", f32(1.1234));
1196 const value: f64 = 1.52314e+29;1311 try testFmt("f32: 1234.57", "f32: {d:.2}", f32(1234.567));
1197 const result = try bufPrint(buf1[0..], "f64: {.}\n", value);1312 // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
1198 testing.expect(mem.eql(u8, result, "f64: 152314000000000000000000000000\n"));1313 // -11.12339... is rounded back up to -11.1234
1199 }1314 try testFmt("f32: -11.1234", "f32: {d:.4}", f32(-11.1234));
1200 {1315 try testFmt("f32: 91.12345", "f32: {d:.5}", f32(91.12345));
1201 var buf1: [32]u8 = undefined;1316 try testFmt("f64: 91.1234567890", "f64: {d:.10}", f64(91.12345678901235));
1202 const value: f32 = 1.1234;1317 try testFmt("f64: 0.00000", "f64: {d:.5}", f64(0.0));
1203 const result = try bufPrint(buf1[0..], "f32: {.1}\n", value);1318 try testFmt("f64: 6", "f64: {d:.0}", f64(5.700));
1204 testing.expect(mem.eql(u8, result, "f32: 1.1\n"));1319 try testFmt("f64: 10.0", "f64: {d:.1}", f64(9.999));
1205 }1320 try testFmt("f64: 1.000", "f64: {d:.3}", f64(1.0));
1206 {1321 try testFmt("f64: 0.00030000", "f64: {d:.8}", f64(0.0003));
1207 var buf1: [32]u8 = undefined;1322 try testFmt("f64: 0.00000", "f64: {d:.5}", f64(1.40130e-45));
1208 const value: f32 = 1234.567;1323 try testFmt("f64: 0.00000", "f64: {d:.5}", f64(9.999960e-40));
1209 const result = try bufPrint(buf1[0..], "f32: {.2}\n", value);
1210 testing.expect(mem.eql(u8, result, "f32: 1234.57\n"));
1211 }
1212 {
1213 var buf1: [32]u8 = undefined;
1214 const value: f32 = -11.1234;
1215 const result = try bufPrint(buf1[0..], "f32: {.4}\n", value);
1216 // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
1217 // -11.12339... is rounded back up to -11.1234
1218 testing.expect(mem.eql(u8, result, "f32: -11.1234\n"));
1219 }
1220 {
1221 var buf1: [32]u8 = undefined;
1222 const value: f32 = 91.12345;
1223 const result = try bufPrint(buf1[0..], "f32: {.5}\n", value);
1224 testing.expect(mem.eql(u8, result, "f32: 91.12345\n"));
1225 }
1226 {
1227 var buf1: [32]u8 = undefined;
1228 const value: f64 = 91.12345678901235;
1229 const result = try bufPrint(buf1[0..], "f64: {.10}\n", value);
1230 testing.expect(mem.eql(u8, result, "f64: 91.1234567890\n"));
1231 }
1232 {
1233 var buf1: [32]u8 = undefined;
1234 const value: f64 = 0.0;
1235 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1236 testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
1237 }
1238 {
1239 var buf1: [32]u8 = undefined;
1240 const value: f64 = 5.700;
1241 const result = try bufPrint(buf1[0..], "f64: {.0}\n", value);
1242 testing.expect(mem.eql(u8, result, "f64: 6\n"));
1243 }
1244 {
1245 var buf1: [32]u8 = undefined;
1246 const value: f64 = 9.999;
1247 const result = try bufPrint(buf1[0..], "f64: {.1}\n", value);
1248 testing.expect(mem.eql(u8, result, "f64: 10.0\n"));
1249 }
1250 {
1251 var buf1: [32]u8 = undefined;
1252 const value: f64 = 1.0;
1253 const result = try bufPrint(buf1[0..], "f64: {.3}\n", value);
1254 testing.expect(mem.eql(u8, result, "f64: 1.000\n"));
1255 }
1256 {
1257 var buf1: [32]u8 = undefined;
1258 const value: f64 = 0.0003;
1259 const result = try bufPrint(buf1[0..], "f64: {.8}\n", value);
1260 testing.expect(mem.eql(u8, result, "f64: 0.00030000\n"));
1261 }
1262 {
1263 var buf1: [32]u8 = undefined;
1264 const value: f64 = 1.40130e-45;
1265 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1266 testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
1267 }
1268 {
1269 var buf1: [32]u8 = undefined;
1270 const value: f64 = 9.999960e-40;
1271 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1272 testing.expect(mem.eql(u8, result, "f64: 0.00000\n"));
1273 }
1274}1324}
12751325
1276test "fmt.float.libc.sanity" {1326test "float.libc.sanity" {
1277 {1327 try testFmt("f64: 0.00001", "f64: {d:.5}", f64(@bitCast(f32, u32(916964781))));
1278 var buf1: [32]u8 = undefined;1328 try testFmt("f64: 0.00001", "f64: {d:.5}", f64(@bitCast(f32, u32(925353389))));
1279 const value: f64 = f64(@bitCast(f32, u32(916964781)));1329 try testFmt("f64: 0.10000", "f64: {d:.5}", f64(@bitCast(f32, u32(1036831278))));
1280 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);1330 try testFmt("f64: 1.00000", "f64: {d:.5}", f64(@bitCast(f32, u32(1065353133))));
1281 testing.expect(mem.eql(u8, result, "f64: 0.00001\n"));1331 try testFmt("f64: 10.00000", "f64: {d:.5}", f64(@bitCast(f32, u32(1092616192))));
1282 }1332
1283 {
1284 var buf1: [32]u8 = undefined;
1285 const value: f64 = f64(@bitCast(f32, u32(925353389)));
1286 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1287 testing.expect(mem.eql(u8, result, "f64: 0.00001\n"));
1288 }
1289 {
1290 var buf1: [32]u8 = undefined;
1291 const value: f64 = f64(@bitCast(f32, u32(1036831278)));
1292 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1293 testing.expect(mem.eql(u8, result, "f64: 0.10000\n"));
1294 }
1295 {
1296 var buf1: [32]u8 = undefined;
1297 const value: f64 = f64(@bitCast(f32, u32(1065353133)));
1298 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1299 testing.expect(mem.eql(u8, result, "f64: 1.00000\n"));
1300 }
1301 {
1302 var buf1: [32]u8 = undefined;
1303 const value: f64 = f64(@bitCast(f32, u32(1092616192)));
1304 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1305 testing.expect(mem.eql(u8, result, "f64: 10.00000\n"));
1306 }
1307 // libc differences1333 // libc differences
1308 {1334 //
1309 var buf1: [32]u8 = undefined;1335 // This is 0.015625 exactly according to gdb. We thus round down,
1310 // This is 0.015625 exactly according to gdb. We thus round down,1336 // however glibc rounds up for some reason. This occurs for all
1311 // however glibc rounds up for some reason. This occurs for all1337 // floats of the form x.yyyy25 on a precision point.
1312 // floats of the form x.yyyy25 on a precision point.1338 try testFmt("f64: 0.01563", "f64: {d:.5}", f64(@bitCast(f32, u32(1015021568))));
1313 const value: f64 = f64(@bitCast(f32, u32(1015021568)));1339 // errol3 rounds to ... 630 but libc rounds to ...632. Grisu3
1314 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);1340 // also rounds to 630 so I'm inclined to believe libc is not
1315 testing.expect(mem.eql(u8, result, "f64: 0.01563\n"));1341 // optimal here.
1316 }1342 try testFmt("f64: 18014400656965630.00000", "f64: {d:.5}", f64(@bitCast(f32, u32(1518338049))));
1317 // std-windows-x86_64-Debug-bare test case fails
1318 {
1319 // errol3 rounds to ... 630 but libc rounds to ...632. Grisu3
1320 // also rounds to 630 so I'm inclined to believe libc is not
1321 // optimal here.
1322 var buf1: [32]u8 = undefined;
1323 const value: f64 = f64(@bitCast(f32, u32(1518338049)));
1324 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1325 testing.expect(mem.eql(u8, result, "f64: 18014400656965630.00000\n"));
1326 }
1327}1343}
13281344
1329test "fmt.custom" {1345test "custom" {
1330 const Vec2 = struct {1346 const Vec2 = struct {
1331 const SelfType = @This();1347 const SelfType = @This();
1332 x: f32,1348 x: f32,
...@@ -1335,20 +1351,17 @@ test "fmt.custom" {...@@ -1335,20 +1351,17 @@ test "fmt.custom" {
1335 pub fn format(1351 pub fn format(
1336 self: SelfType,1352 self: SelfType,
1337 comptime fmt: []const u8,1353 comptime fmt: []const u8,
1354 comptime options: FormatOptions,
1338 context: var,1355 context: var,
1339 comptime Errors: type,1356 comptime Errors: type,
1340 output: fn (@typeOf(context), []const u8) Errors!void,1357 output: fn (@typeOf(context), []const u8) Errors!void,
1341 ) Errors!void {1358 ) Errors!void {
1342 switch (fmt.len) {1359 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {
1343 0 => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),1360 return std.fmt.format(context, Errors, output, "({d:.3},{d:.3})", self.x, self.y);
1344 1 => switch (fmt[0]) {1361 } else if (comptime std.mem.eql(u8, fmt, "d")) {
1345 //point format1362 return std.fmt.format(context, Errors, output, "{d:.3}x{d:.3}", self.x, self.y);
1346 'p' => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),1363 } else {
1347 //dimension format1364 @compileError("Unknown format character: '" ++ fmt ++ "'");
1348 'd' => return std.fmt.format(context, Errors, output, "{.3}x{.3}", self.x, self.y),
1349 else => unreachable,
1350 },
1351 else => unreachable,
1352 }1365 }
1353 }1366 }
1354 };1367 };
...@@ -1366,7 +1379,7 @@ test "fmt.custom" {...@@ -1366,7 +1379,7 @@ test "fmt.custom" {
1366 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", value);1379 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", value);
1367}1380}
13681381
1369test "fmt.struct" {1382test "struct" {
1370 const S = struct {1383 const S = struct {
1371 a: u32,1384 a: u32,
1372 b: anyerror,1385 b: anyerror,
...@@ -1380,7 +1393,7 @@ test "fmt.struct" {...@@ -1380,7 +1393,7 @@ test "fmt.struct" {
1380 try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst);1393 try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst);
1381}1394}
13821395
1383test "fmt.union" {1396test "union" {
1384 const TU = union(enum) {1397 const TU = union(enum) {
1385 float: f32,1398 float: f32,
1386 int: u32,1399 int: u32,
...@@ -1410,7 +1423,7 @@ test "fmt.union" {...@@ -1410,7 +1423,7 @@ test "fmt.union" {
1410 testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));1423 testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
1411}1424}
14121425
1413test "fmt.enum" {1426test "enum" {
1414 const E = enum {1427 const E = enum {
1415 One,1428 One,
1416 Two,1429 Two,
...@@ -1422,7 +1435,7 @@ test "fmt.enum" {...@@ -1422,7 +1435,7 @@ test "fmt.enum" {
1422 try testFmt("E.Two", "{}", inst);1435 try testFmt("E.Two", "{}", inst);
1423}1436}
14241437
1425test "fmt.struct.self-referential" {1438test "struct.self-referential" {
1426 const S = struct {1439 const S = struct {
1427 const SelfType = @This();1440 const SelfType = @This();
1428 a: ?*SelfType,1441 a: ?*SelfType,
...@@ -1436,7 +1449,7 @@ test "fmt.struct.self-referential" {...@@ -1436,7 +1449,7 @@ test "fmt.struct.self-referential" {
1436 try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", inst);1449 try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", inst);
1437}1450}
14381451
1439test "fmt.bytes.hex" {1452test "bytes.hex" {
1440 const some_bytes = "\xCA\xFE\xBA\xBE";1453 const some_bytes = "\xCA\xFE\xBA\xBE";
1441 try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", some_bytes);1454 try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", some_bytes);
1442 try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", some_bytes);1455 try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", some_bytes);
...@@ -1478,7 +1491,7 @@ pub fn trim(buf: []const u8) []const u8 {...@@ -1478,7 +1491,7 @@ pub fn trim(buf: []const u8) []const u8 {
1478 return buf[start..end];1491 return buf[start..end];
1479}1492}
14801493
1481test "fmt.trim" {1494test "trim" {
1482 testing.expect(mem.eql(u8, "abc", trim("\n abc \t")));1495 testing.expect(mem.eql(u8, "abc", trim("\n abc \t")));
1483 testing.expect(mem.eql(u8, "", trim(" ")));1496 testing.expect(mem.eql(u8, "", trim(" ")));
1484 testing.expect(mem.eql(u8, "", trim("")));1497 testing.expect(mem.eql(u8, "", trim("")));
...@@ -1505,22 +1518,22 @@ pub fn hexToBytes(out: []u8, input: []const u8) !void {...@@ -1505,22 +1518,22 @@ pub fn hexToBytes(out: []u8, input: []const u8) !void {
1505 }1518 }
1506}1519}
15071520
1508test "fmt.hexToBytes" {1521test "hexToBytes" {
1509 const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";1522 const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";
1510 var pb: [32]u8 = undefined;1523 var pb: [32]u8 = undefined;
1511 try hexToBytes(pb[0..], test_hex_str);1524 try hexToBytes(pb[0..], test_hex_str);
1512 try testFmt(test_hex_str, "{X}", pb);1525 try testFmt(test_hex_str, "{X}", pb);
1513}1526}
15141527
1515test "fmt.formatIntValue with comptime_int" {1528test "formatIntValue with comptime_int" {
1516 const value: comptime_int = 123456789123456789;1529 const value: comptime_int = 123456789123456789;
15171530
1518 var buf = try std.Buffer.init(std.debug.global_allocator, "");1531 var buf = try std.Buffer.init(std.debug.global_allocator, "");
1519 try formatIntValue(value, "", &buf, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append);1532 try formatIntValue(value, "", FormatOptions{}, &buf, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append);
1520 assert(mem.eql(u8, buf.toSlice(), "123456789123456789"));1533 assert(mem.eql(u8, buf.toSlice(), "123456789123456789"));
1521}1534}
15221535
1523test "fmt.formatType max_depth" {1536test "formatType max_depth" {
1524 const Vec2 = struct {1537 const Vec2 = struct {
1525 const SelfType = @This();1538 const SelfType = @This();
1526 x: f32,1539 x: f32,
...@@ -1529,11 +1542,16 @@ test "fmt.formatType max_depth" {...@@ -1529,11 +1542,16 @@ test "fmt.formatType max_depth" {
1529 pub fn format(1542 pub fn format(
1530 self: SelfType,1543 self: SelfType,
1531 comptime fmt: []const u8,1544 comptime fmt: []const u8,
1545 comptime options: FormatOptions,
1532 context: var,1546 context: var,
1533 comptime Errors: type,1547 comptime Errors: type,
1534 output: fn (@typeOf(context), []const u8) Errors!void,1548 output: fn (@typeOf(context), []const u8) Errors!void,
1535 ) Errors!void {1549 ) Errors!void {
1536 return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y);1550 if (fmt.len == 0) {
1551 return std.fmt.format(context, Errors, output, "({d:.3},{d:.3})", self.x, self.y);
1552 } else {
1553 @compileError("Unknown format string: '" ++ fmt ++ "'");
1554 }
1537 }1555 }
1538 };1556 };
1539 const E = enum {1557 const E = enum {
...@@ -1565,18 +1583,34 @@ test "fmt.formatType max_depth" {...@@ -1565,18 +1583,34 @@ test "fmt.formatType max_depth" {
1565 inst.tu.ptr = &inst.tu;1583 inst.tu.ptr = &inst.tu;
15661584
1567 var buf0 = try std.Buffer.init(std.debug.global_allocator, "");1585 var buf0 = try std.Buffer.init(std.debug.global_allocator, "");
1568 try formatType(inst, "", &buf0, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 0);1586 try formatType(inst, "", FormatOptions{}, &buf0, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 0);
1569 assert(mem.eql(u8, buf0.toSlice(), "S{ ... }"));1587 assert(mem.eql(u8, buf0.toSlice(), "S{ ... }"));
15701588
1571 var buf1 = try std.Buffer.init(std.debug.global_allocator, "");1589 var buf1 = try std.Buffer.init(std.debug.global_allocator, "");
1572 try formatType(inst, "", &buf1, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 1);1590 try formatType(inst, "", FormatOptions{}, &buf1, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 1);
1573 assert(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));1591 assert(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
15741592
1575 var buf2 = try std.Buffer.init(std.debug.global_allocator, "");1593 var buf2 = try std.Buffer.init(std.debug.global_allocator, "");
1576 try formatType(inst, "", &buf2, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 2);1594 try formatType(inst, "", FormatOptions{}, &buf2, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 2);
1577 assert(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));1595 assert(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }"));
15781596
1579 var buf3 = try std.Buffer.init(std.debug.global_allocator, "");1597 var buf3 = try std.Buffer.init(std.debug.global_allocator, "");
1580 try formatType(inst, "", &buf3, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 3);1598 try formatType(inst, "", FormatOptions{}, &buf3, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 3);
1581 assert(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));1599 assert(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }"));
1582}1600}
1601
1602test "positional" {
1603 try testFmt("2 1 0", "{2} {1} {0}", usize(0), usize(1), usize(2));
1604 try testFmt("2 1 0", "{2} {1} {}", usize(0), usize(1), usize(2));
1605 try testFmt("0 0", "{0} {0}", usize(0));
1606 try testFmt("0 1", "{} {1}", usize(0), usize(1));
1607 try testFmt("1 0 0 1", "{1} {} {0} {}", usize(0), usize(1));
1608}
1609
1610test "positional with specifier" {
1611 try testFmt("10.0", "{0d:.1}", f64(9.999));
1612}
1613
1614test "positional/alignment/width/precision" {
1615 try testFmt("10.0", "{0d: >3.1}", f64(9.999));
1616}
std/math/big/int.zig+1
...@@ -519,6 +519,7 @@ pub const Int = struct {...@@ -519,6 +519,7 @@ pub const Int = struct {
519 pub fn format(519 pub fn format(
520 self: Int,520 self: Int,
521 comptime fmt: []const u8,521 comptime fmt: []const u8,
522 comptime options: std.fmt.FormatOptions,
522 context: var,523 context: var,
523 comptime FmtError: type,524 comptime FmtError: type,
524 output: fn (@typeOf(context), []const u8) FmtError!void,525 output: fn (@typeOf(context), []const u8) FmtError!void,
std/net.zig-1
...@@ -33,7 +33,6 @@ pub const Address = struct {...@@ -33,7 +33,6 @@ pub const Address = struct {
3333
34 pub fn initIp6(ip6: *const Ip6Addr, _port: u16) Address {34 pub fn initIp6(ip6: *const Ip6Addr, _port: u16) Address {
35 return Address{35 return Address{
36 .family = os.AF_INET6,
37 .os_addr = os.sockaddr{36 .os_addr = os.sockaddr{
38 .in6 = os.sockaddr_in6{37 .in6 = os.sockaddr_in6{
39 .family = os.AF_INET6,38 .family = os.AF_INET6,
std/special/build_runner.zig+2-2
...@@ -167,7 +167,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {...@@ -167,7 +167,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {
167167
168 const allocator = builder.allocator;168 const allocator = builder.allocator;
169 for (builder.top_level_steps.toSliceConst()) |top_level_step| {169 for (builder.top_level_steps.toSliceConst()) |top_level_step| {
170 try out_stream.print(" {s22} {}\n", top_level_step.step.name, top_level_step.description);170 try out_stream.print(" {s:22} {}\n", top_level_step.step.name, top_level_step.description);
171 }171 }
172172
173 try out_stream.write(173 try out_stream.write(
...@@ -188,7 +188,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {...@@ -188,7 +188,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {
188 for (builder.available_options_list.toSliceConst()) |option| {188 for (builder.available_options_list.toSliceConst()) |option| {
189 const name = try fmt.allocPrint(allocator, " -D{}=[{}]", option.name, Builder.typeIdName(option.type_id));189 const name = try fmt.allocPrint(allocator, " -D{}=[{}]", option.name, Builder.typeIdName(option.type_id));
190 defer allocator.free(name);190 defer allocator.free(name);
191 try out_stream.print("{s24} {}\n", name, option.description);191 try out_stream.print("{s:24} {}\n", name, option.description);
192 }192 }
193 }193 }
194194
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
std/special/compiler_rt.zig+39-6
...@@ -405,15 +405,15 @@ const use_thumb_1 = usesThumb1(builtin.arch);...@@ -405,15 +405,15 @@ const use_thumb_1 = usesThumb1(builtin.arch);
405405
406fn usesThumb1(arch: builtin.Arch) bool {406fn usesThumb1(arch: builtin.Arch) bool {
407 return switch (arch) {407 return switch (arch) {
408 .arm => switch (arch.arm) {408 .arm => |sub_arch| switch (sub_arch) {
409 .v6m => true,409 .v6m => true,
410 else => false,410 else => false,
411 },411 },
412 .armeb => switch (arch.armeb) {412 .armeb => |sub_arch| switch (sub_arch) {
413 .v6m => true,413 .v6m => true,
414 else => false,414 else => false,
415 },415 },
416 .thumb => switch (arch.thumb) {416 .thumb => |sub_arch| switch (sub_arch) {
417 .v5,417 .v5,
418 .v5te,418 .v5te,
419 .v4t,419 .v4t,
...@@ -423,7 +423,7 @@ fn usesThumb1(arch: builtin.Arch) bool {...@@ -423,7 +423,7 @@ fn usesThumb1(arch: builtin.Arch) bool {
423 => true,423 => true,
424 else => false,424 else => false,
425 },425 },
426 .thumbeb => switch (arch.thumbeb) {426 .thumbeb => |sub_arch| switch (sub_arch) {
427 .v5,427 .v5,
428 .v5te,428 .v5te,
429 .v4t,429 .v4t,
...@@ -471,6 +471,22 @@ test "usesThumb1" {...@@ -471,6 +471,22 @@ test "usesThumb1" {
471 //etc.471 //etc.
472}472}
473473
474const use_thumb_1_pre_armv6 = usesThumb1PreArmv6(builtin.arch);
475
476fn usesThumb1PreArmv6(arch: builtin.Arch) bool {
477 return switch (arch) {
478 .thumb => |sub_arch| switch (sub_arch) {
479 .v5, .v5te, .v4t => true,
480 else => false,
481 },
482 .thumbeb => |sub_arch| switch (sub_arch) {
483 .v5, .v5te, .v4t => true,
484 else => false,
485 },
486 else => false,
487 };
488}
489
474nakedcc fn __aeabi_memcpy() noreturn {490nakedcc fn __aeabi_memcpy() noreturn {
475 @setRuntimeSafety(false);491 @setRuntimeSafety(false);
476 if (use_thumb_1) {492 if (use_thumb_1) {
...@@ -505,7 +521,16 @@ nakedcc fn __aeabi_memmove() noreturn {...@@ -505,7 +521,16 @@ nakedcc fn __aeabi_memmove() noreturn {
505521
506nakedcc fn __aeabi_memset() noreturn {522nakedcc fn __aeabi_memset() noreturn {
507 @setRuntimeSafety(false);523 @setRuntimeSafety(false);
508 if (use_thumb_1) {524 if (use_thumb_1_pre_armv6) {
525 asm volatile (
526 \\ eors r1, r2
527 \\ eors r2, r1
528 \\ eors r1, r2
529 \\ push {r7, lr}
530 \\ b memset
531 \\ pop {r7, pc}
532 );
533 } else if (use_thumb_1) {
509 asm volatile (534 asm volatile (
510 \\ mov r3, r1535 \\ mov r3, r1
511 \\ mov r1, r2536 \\ mov r1, r2
...@@ -527,7 +552,15 @@ nakedcc fn __aeabi_memset() noreturn {...@@ -527,7 +552,15 @@ nakedcc fn __aeabi_memset() noreturn {
527552
528nakedcc fn __aeabi_memclr() noreturn {553nakedcc fn __aeabi_memclr() noreturn {
529 @setRuntimeSafety(false);554 @setRuntimeSafety(false);
530 if (use_thumb_1) {555 if (use_thumb_1_pre_armv6) {
556 asm volatile (
557 \\ adds r2, r1, #0
558 \\ movs r1, #0
559 \\ push {r7, lr}
560 \\ bl memset
561 \\ pop {r7, pc}
562 );
563 } else if (use_thumb_1) {
531 asm volatile (564 asm volatile (
532 \\ mov r2, r1565 \\ mov r2, r1
533 \\ movs r1, #0566 \\ movs r1, #0
std/zig/parse.zig+2-2
...@@ -2833,8 +2833,8 @@ fn parseIf(arena: *Allocator, it: *TokenIterator, tree: *Tree, bodyParseFn: Node...@@ -2833,8 +2833,8 @@ fn parseIf(arena: *Allocator, it: *TokenIterator, tree: *Tree, bodyParseFn: Node
28332833
2834 const else_token = eatToken(it, .Keyword_else) orelse return node;2834 const else_token = eatToken(it, .Keyword_else) orelse return node;
2835 const payload = try parsePayload(arena, it, tree);2835 const payload = try parsePayload(arena, it, tree);
2836 const else_expr = try expectNode(arena, it, tree, parseExpr, AstError{2836 const else_expr = try expectNode(arena, it, tree, bodyParseFn, AstError{
2837 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },2837 .InvalidToken = AstError.InvalidToken{ .token = it.index },
2838 });2838 });
2839 const else_node = try arena.create(Node.Else);2839 const else_node = try arena.create(Node.Else);
2840 else_node.* = Node.Else{2840 else_node.* = Node.Else{
std/zig/parser_test.zig+12
...@@ -2234,6 +2234,18 @@ test "zig fmt: multiline string in array" {...@@ -2234,6 +2234,18 @@ test "zig fmt: multiline string in array" {
2234 );2234 );
2235}2235}
22362236
2237test "zig fmt: if type expr" {
2238 try testCanonical(
2239 \\const mycond = true;
2240 \\pub fn foo() if (mycond) i32 else void {
2241 \\ if (mycond) {
2242 \\ return 42;
2243 \\ }
2244 \\}
2245 \\
2246 );
2247}
2248
2237const std = @import("std");2249const std = @import("std");
2238const mem = std.mem;2250const mem = std.mem;
2239const warn = std.debug.warn;2251const warn = std.debug.warn;
test/compare_output.zig+1-1
...@@ -122,7 +122,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -122,7 +122,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
122 \\122 \\
123 \\pub fn main() void {123 \\pub fn main() void {
124 \\ const stdout = &(io.getStdOut() catch unreachable).outStream().stream;124 \\ const stdout = &(io.getStdOut() catch unreachable).outStream().stream;
125 \\ stdout.print("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')) catch unreachable;125 \\ stdout.print("Hello, world!\n{d:4} {x:3} {c}\n", u32(12), u16(0x12), u8('a')) catch unreachable;
126 \\}126 \\}
127 , "Hello, world!\n0012 012 a\n");127 , "Hello, world!\n0012 012 a\n");
128128
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