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
389389 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subMagsF32.c"
390390 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subMagsF64.c"
391391 "${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"
392394 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/softfloat_state.c"
393395 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui32_to_f128M.c"
394396 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui64_to_f128M.c"
......@@ -6653,15 +6655,18 @@ set(OPTIMIZED_C_FLAGS "-std=c99 -O3")
66536655set(EXE_LDFLAGS " ")
66546656if(MSVC)
66556657 set(EXE_LDFLAGS "/STACK:16777216")
6656elseif(ZIG_STATIC)
6658elseif(MINGW)
6659 set(EXE_LDFLAGS "${EXE_LDFLAGS} -Wl,--stack,16777216")
6660endif()
6661
6662if(ZIG_STATIC)
66576663 if(APPLE)
66586664 set(EXE_LDFLAGS "-static-libgcc -static-libstdc++")
66596665 else()
66606666 set(EXE_LDFLAGS "-static")
66616667 endif()
6662else()
6663 set(EXE_LDFLAGS " ")
66646668endif()
6669
66656670if(ZIG_TEST_COVERAGE)
66666671 set(EXE_CFLAGS "${EXE_CFLAGS} -fprofile-arcs -ftest-coverage")
66676672 set(EXE_LDFLAGS "${EXE_LDFLAGS} -fprofile-arcs -ftest-coverage")
doc/langref.html.in+90-2
......@@ -6259,6 +6259,13 @@ comptime {
62596259 This function is only valid within function scope.
62606260 </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>
62626269 {#header_close#}
62636270
62646271 {#header_open|@byteSwap#}
......@@ -7347,10 +7354,91 @@ test "@setRuntimeSafety" {
73477354 <pre>{#syntax#}@sqrt(comptime T: type, value: T) T{#endsyntax#}</pre>
73487355 <p>
73497356 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.
73517365 </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>
73527439 <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.
73547442 </p>
73557443 {#header_close#}
73567444
src-self-hosted/dep_tokenizer.zig+1-1
......@@ -998,7 +998,7 @@ fn printCharValues(out: var, bytes: []const u8) !void {
998998
999999fn printUnderstandableChar(out: var, char: u8) !void {
10001000 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 {};
10021002 } else {
10031003 try out.write("'");
10041004 try out.write([_]u8{printable_char_tab[char]});
src/all_types.hpp+33-6
......@@ -1419,6 +1419,7 @@ enum BuiltinFnId {
14191419 BuiltinFnIdSubWithOverflow,
14201420 BuiltinFnIdMulWithOverflow,
14211421 BuiltinFnIdShlWithOverflow,
1422 BuiltinFnIdMulAdd,
14221423 BuiltinFnIdCInclude,
14231424 BuiltinFnIdCDefine,
14241425 BuiltinFnIdCUndef,
......@@ -1446,6 +1447,19 @@ enum BuiltinFnId {
14461447 BuiltinFnIdRem,
14471448 BuiltinFnIdMod,
14481449 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,
14491463 BuiltinFnIdTruncate,
14501464 BuiltinFnIdIntCast,
14511465 BuiltinFnIdFloatCast,
......@@ -1567,9 +1581,8 @@ enum ZigLLVMFnId {
15671581 ZigLLVMFnIdClz,
15681582 ZigLLVMFnIdPopCount,
15691583 ZigLLVMFnIdOverflowArithmetic,
1570 ZigLLVMFnIdFloor,
1571 ZigLLVMFnIdCeil,
1572 ZigLLVMFnIdSqrt,
1584 ZigLLVMFnIdFMA,
1585 ZigLLVMFnIdFloatOp,
15731586 ZigLLVMFnIdBswap,
15741587 ZigLLVMFnIdBitReverse,
15751588};
......@@ -1596,7 +1609,9 @@ struct ZigLLVMFnKey {
15961609 uint32_t bit_count;
15971610 } pop_count;
15981611 struct {
1612 BuiltinFnId op;
15991613 uint32_t bit_count;
1614 uint32_t vector_len; // 0 means not a vector
16001615 } floating;
16011616 struct {
16021617 AddSubMul add_sub_mul;
......@@ -2260,6 +2275,8 @@ enum IrInstructionId {
22602275 IrInstructionIdOverflowOp,
22612276 IrInstructionIdTestErrSrc,
22622277 IrInstructionIdTestErrGen,
2278 IrInstructionIdMulAdd,
2279 IrInstructionIdFloatOp,
22632280 IrInstructionIdUnwrapErrCode,
22642281 IrInstructionIdUnwrapErrPayload,
22652282 IrInstructionIdErrWrapCode,
......@@ -2324,7 +2341,6 @@ enum IrInstructionId {
23242341 IrInstructionIdAddImplicitReturnType,
23252342 IrInstructionIdMergeErrRetTraces,
23262343 IrInstructionIdMarkErrRetTracePtr,
2327 IrInstructionIdSqrt,
23282344 IrInstructionIdErrSetCast,
23292345 IrInstructionIdToBytes,
23302346 IrInstructionIdFromBytes,
......@@ -3080,6 +3096,15 @@ struct IrInstructionOverflowOp {
30803096 ZigType *result_ptr_type;
30813097};
30823098
3099struct IrInstructionMulAdd {
3100 IrInstruction base;
3101
3102 IrInstruction *type_value;
3103 IrInstruction *op1;
3104 IrInstruction *op2;
3105 IrInstruction *op3;
3106};
3107
30833108struct IrInstructionAlignOf {
30843109 IrInstruction base;
30853110
......@@ -3512,11 +3537,13 @@ struct IrInstructionMarkErrRetTracePtr {
35123537 IrInstruction *err_ret_trace_ptr;
35133538};
35143539
3515struct IrInstructionSqrt {
3540// For float ops which take a single argument
3541struct IrInstructionFloatOp {
35163542 IrInstruction base;
35173543
3544 BuiltinFnId op;
35183545 IrInstruction *type;
3519 IrInstruction *op;
3546 IrInstruction *op1;
35203547};
35213548
35223549struct IrInstructionCheckRuntimeScope {
src/analyze.cpp+14-10
......@@ -5736,12 +5736,13 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) {
57365736 return (uint32_t)(x.data.clz.bit_count) * (uint32_t)2428952817;
57375737 case ZigLLVMFnIdPopCount:
57385738 return (uint32_t)(x.data.clz.bit_count) * (uint32_t)101195049;
5739 case ZigLLVMFnIdFloor:
5740 return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1899859168;
5741 case ZigLLVMFnIdCeil:
5742 return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1953839089;
5743 case ZigLLVMFnIdSqrt:
5744 return (uint32_t)(x.data.floating.bit_count) * (uint32_t)2225366385;
5739 case ZigLLVMFnIdFloatOp:
5740 return (uint32_t)(x.data.floating.bit_count) * ((uint32_t)x.id + 1025) +
5741 (uint32_t)(x.data.floating.vector_len) * (((uint32_t)x.id << 5) + 1025) +
5742 (uint32_t)(x.data.floating.op) * (uint32_t)43789879;
5743 case ZigLLVMFnIdFMA:
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);
57455746 case ZigLLVMFnIdBswap:
57465747 return (uint32_t)(x.data.bswap.bit_count) * (uint32_t)3661994335;
57475748 case ZigLLVMFnIdBitReverse:
......@@ -5769,10 +5770,13 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {
57695770 return a.data.bswap.bit_count == b.data.bswap.bit_count;
57705771 case ZigLLVMFnIdBitReverse:
57715772 return a.data.bit_reverse.bit_count == b.data.bit_reverse.bit_count;
5772 case ZigLLVMFnIdFloor:
5773 case ZigLLVMFnIdCeil:
5774 case ZigLLVMFnIdSqrt:
5775 return a.data.floating.bit_count == b.data.floating.bit_count;
5773 case ZigLLVMFnIdFloatOp:
5774 return a.data.floating.bit_count == b.data.floating.bit_count &&
5775 a.data.floating.vector_len == b.data.floating.vector_len &&
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;
57765780 case ZigLLVMFnIdOverflowArithmetic:
57775781 return (a.data.overflow_arithmetic.bit_count == b.data.overflow_arithmetic.bit_count) &&
57785782 (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
808808 return fn_val;
809809}
810810
811static LLVMValueRef get_float_fn(CodeGen *g, ZigType *type_entry, ZigLLVMFnId fn_id) {
812 assert(type_entry->id == ZigTypeIdFloat);
811static LLVMValueRef get_float_fn(CodeGen *g, ZigType *type_entry, ZigLLVMFnId fn_id, BuiltinFnId op) {
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
814818 ZigLLVMFnKey key = {};
815819 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
818824 auto existing_entry = g->llvm_fn_table.maybe_get(key);
819825 if (existing_entry)
820826 return existing_entry->value;
821827
822828 const char *name;
823 if (fn_id == ZigLLVMFnIdFloor) {
824 name = "floor";
825 } else if (fn_id == ZigLLVMFnIdCeil) {
826 name = "ceil";
827 } else if (fn_id == ZigLLVMFnIdSqrt) {
828 name = "sqrt";
829 uint32_t num_args;
830 if (fn_id == ZigLLVMFnIdFMA) {
831 name = "fma";
832 num_args = 3;
833 } else if (fn_id == ZigLLVMFnIdFloatOp) {
834 name = float_op_to_name(op, true);
835 num_args = 1;
829836 } else {
830837 zig_unreachable();
831838 }
832839
833840 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);
835845 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);
837852 LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type);
838853 assert(LLVMGetIntrinsicID(fn_val));
839854
......@@ -2483,22 +2498,17 @@ static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *type_entry,
24832498 return result;
24842499}
24852500
2486static LLVMValueRef gen_floor(CodeGen *g, LLVMValueRef val, ZigType *type_entry) {
2487 if (type_entry->id == ZigTypeIdInt)
2501static LLVMValueRef gen_float_op(CodeGen *g, LLVMValueRef val, ZigType *type_entry, BuiltinFnId op) {
2502 if ((op == BuiltinFnIdCeil ||
2503 op == BuiltinFnIdFloor) &&
2504 type_entry->id == ZigTypeIdInt)
24882505 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);
24912509 return LLVMBuildCall(g->builder, floor_fn, &val, 1, "");
24922510}
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
25022512enum DivKind {
25032513 DivKindFloat,
25042514 DivKindTrunc,
......@@ -2574,7 +2584,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast
25742584 return result;
25752585 case DivKindExact:
25762586 if (want_runtime_safety) {
2577 LLVMValueRef floored = gen_floor(g, result, type_entry);
2587 LLVMValueRef floored = gen_float_op(g, result, type_entry, BuiltinFnIdFloor);
25782588 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactOk");
25792589 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail");
25802590 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
25962606 LLVMBuildCondBr(g->builder, ltz, ltz_block, gez_block);
25972607
25982608 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);
26002610 LLVMBasicBlockRef ceiled_end_block = LLVMGetInsertBlock(g->builder);
26012611 LLVMBuildBr(g->builder, end_block);
26022612
26032613 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);
26052615 LLVMBasicBlockRef floored_end_block = LLVMGetInsertBlock(g->builder);
26062616 LLVMBuildBr(g->builder, end_block);
26072617
......@@ -2613,7 +2623,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast
26132623 return phi;
26142624 }
26152625 case DivKindFloor:
2616 return gen_floor(g, result, type_entry);
2626 return gen_float_op(g, result, type_entry, BuiltinFnIdFloor);
26172627 }
26182628 zig_unreachable();
26192629 }
......@@ -5417,13 +5427,28 @@ static LLVMValueRef ir_render_mark_err_ret_trace_ptr(CodeGen *g, IrExecutable *e
54175427 return nullptr;
54185428}
54195429
5420static LLVMValueRef ir_render_sqrt(CodeGen *g, IrExecutable *executable, IrInstructionSqrt *instruction) {
5421 LLVMValueRef op = ir_llvm_value(g, instruction->op);
5430static LLVMValueRef ir_render_float_op(CodeGen *g, IrExecutable *executable, IrInstructionFloatOp *instruction) {
5431 LLVMValueRef op = ir_llvm_value(g, instruction->op1);
54225432 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);
54245434 return LLVMBuildCall(g->builder, fn_val, &op, 1, "");
54255435}
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
54275452static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInstructionBswap *instruction) {
54285453 LLVMValueRef op = ir_llvm_value(g, instruction->op);
54295454 ZigType *int_type = instruction->base.value.type;
......@@ -5770,8 +5795,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
57705795 return ir_render_merge_err_ret_traces(g, executable, (IrInstructionMergeErrRetTraces *)instruction);
57715796 case IrInstructionIdMarkErrRetTracePtr:
57725797 return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction);
5773 case IrInstructionIdSqrt:
5774 return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction);
5798 case IrInstructionIdFloatOp:
5799 return ir_render_float_op(g, executable, (IrInstructionFloatOp *)instruction);
5800 case IrInstructionIdMulAdd:
5801 return ir_render_mul_add(g, executable, (IrInstructionMulAdd *)instruction);
57755802 case IrInstructionIdArrayToVector:
57765803 return ir_render_array_to_vector(g, executable, (IrInstructionArrayToVector *)instruction);
57775804 case IrInstructionIdVectorToArray:
......@@ -7356,6 +7383,21 @@ static void define_builtin_fns(CodeGen *g) {
73567383 create_builtin_fn(g, BuiltinFnIdRem, "rem", 2);
73577384 create_builtin_fn(g, BuiltinFnIdMod, "mod", 2);
73587385 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);
73597401 create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX);
73607402 create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX);
73617403 create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX);
src/ir.cpp+471-61
......@@ -777,6 +777,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestErrGen *) {
777777 return IrInstructionIdTestErrGen;
778778}
779779
780static constexpr IrInstructionId ir_instruction_id(IrInstructionMulAdd *) {
781 return IrInstructionIdMulAdd;
782}
783
780784static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapErrCode *) {
781785 return IrInstructionIdUnwrapErrCode;
782786}
......@@ -1037,8 +1041,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionMarkErrRetTraceP
10371041 return IrInstructionIdMarkErrRetTracePtr;
10381042}
10391043
1040static constexpr IrInstructionId ir_instruction_id(IrInstructionSqrt *) {
1041 return IrInstructionIdSqrt;
1044static constexpr IrInstructionId ir_instruction_id(IrInstructionFloatOp *) {
1045 return IrInstructionIdFloatOp;
10421046}
10431047
10441048static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) {
......@@ -2437,6 +2441,75 @@ static IrInstruction *ir_build_overflow_op(IrBuilder *irb, Scope *scope, AstNode
24372441 return &instruction->base;
24382442}
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
24402513static IrInstruction *ir_build_align_of(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value) {
24412514 IrInstructionAlignOf *instruction = ir_build_instruction<IrInstructionAlignOf>(irb, scope, source_node);
24422515 instruction->type_value = type_value;
......@@ -3201,17 +3274,6 @@ static IrInstruction *ir_build_mark_err_ret_trace_ptr(IrBuilder *irb, Scope *sco
32013274 return &instruction->base;
32023275}
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
32153277static IrInstruction *ir_build_has_decl(IrBuilder *irb, Scope *scope, AstNode *source_node,
32163278 IrInstruction *container, IrInstruction *name)
32173279{
......@@ -4380,6 +4442,33 @@ static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *
43804442 return ir_build_overflow_op(irb, scope, node, op, type_value, op1, op2, result_ptr, nullptr);
43814443}
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
43834472static IrInstruction *ir_gen_this(IrBuilder *irb, Scope *orig_scope, AstNode *node) {
43844473 for (Scope *it_scope = orig_scope; it_scope != nullptr; it_scope = it_scope->parent) {
43854474 if (it_scope->id == ScopeIdDecls) {
......@@ -4708,6 +4797,19 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
47084797 return ir_lval_wrap(irb, scope, bin_op, lval, result_loc);
47094798 }
47104799 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:
47114813 {
47124814 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
47134815 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
47194821 if (arg1_value == irb->codegen->invalid_instruction)
47204822 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);
47234825 return ir_lval_wrap(irb, scope, ir_sqrt, lval, result_loc);
47244826 }
47254827 case BuiltinFnIdTruncate:
......@@ -5043,6 +5145,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
50435145 return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul), lval, result_loc);
50445146 case BuiltinFnIdShlWithOverflow:
50455147 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);
50465150 case BuiltinFnIdTypeName:
50475151 {
50485152 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
2270922813 return ir_get_ref(ira, &instruction->base, result, true, false);
2271022814}
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
2271222935static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstructionTestErrSrc *instruction) {
2271322936 IrInstruction *base_ptr = instruction->base_ptr->child;
2271422937 if (type_is_invalid(base_ptr->value.type))
......@@ -24542,70 +24765,254 @@ static IrInstruction *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *i
2454224765 return result;
2454324766}
2454424767
24545static IrInstruction *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstructionSqrt *instruction) {
24546 ZigType *float_type = ir_resolve_type(ira, instruction->type->child);
24547 if (type_is_invalid(float_type))
24548 return ira->codegen->invalid_instruction;
24768static void ir_eval_float_op(IrAnalyze *ira, IrInstructionFloatOp *source_instr, ZigType *float_type,
24769 ConstExprValue *op, ConstExprValue *out_val) {
24770 assert(ira && source_instr && float_type && out_val && op);
24771 assert(float_type->id == ZigTypeIdFloat ||
24772 float_type->id == ZigTypeIdComptimeFloat);
2454924773
24550 IrInstruction *op = instruction->op->child;
24551 if (type_is_invalid(op->value.type))
24774 BuiltinFnId fop = source_instr->op;
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))
2455224955 return ira->codegen->invalid_instruction;
2455324956
24554 bool ok_type = float_type->id == ZigTypeIdComptimeFloat || float_type->id == ZigTypeIdFloat;
24555 if (!ok_type) {
24556 ir_add_error(ira, instruction->type, buf_sprintf("@sqrt does not support type '%s'", buf_ptr(&float_type->name)));
24957 // Only allow float types, and vectors of floats.
24958 ZigType *float_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type;
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)));
2455724961 return ira->codegen->invalid_instruction;
2455824962 }
2455924963
24560 IrInstruction *casted_op = ir_implicit_cast(ira, op, float_type);
24561 if (type_is_invalid(casted_op->value.type))
24964 IrInstruction *op1 = instruction->op1->child;
24965 if (type_is_invalid(op1->value.type))
2456224966 return ira->codegen->invalid_instruction;
2456324967
24564 if (instr_is_comptime(casted_op)) {
24565 ConstExprValue *val = ir_resolve_const(ira, casted_op, UndefBad);
24566 if (!val)
24968 IrInstruction *casted_op1 = ir_implicit_cast(ira, op1, float_type);
24969 if (type_is_invalid(casted_op1->value.type))
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)
2456724984 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);
2457024987 ConstExprValue *out_val = &result->value;
2457124988
24572 if (float_type->id == ZigTypeIdComptimeFloat) {
24573 bigfloat_sqrt(&out_val->data.x_bigfloat, &val->data.x_bigfloat);
24574 } else if (float_type->id == ZigTypeIdFloat) {
24575 switch (float_type->data.floating.bit_count) {
24576 case 16:
24577 out_val->data.x_f16 = f16_sqrt(val->data.x_f16);
24578 break;
24579 case 32:
24580 out_val->data.x_f32 = sqrtf(val->data.x_f32);
24581 break;
24582 case 64:
24583 out_val->data.x_f64 = sqrt(val->data.x_f64);
24584 break;
24585 case 128:
24586 f128M_sqrt(&val->data.x_f128, &out_val->data.x_f128);
24587 break;
24588 default:
24589 zig_unreachable();
24989 if (expr_type->id == ZigTypeIdVector) {
24990 expand_undef_array(ira->codegen, op1_const);
24991 out_val->special = ConstValSpecialUndef;
24992 expand_undef_array(ira->codegen, out_val);
24993 size_t len = expr_type->data.vector.len;
24994 for (size_t i = 0; i < len; i += 1) {
24995 ConstExprValue *float_operand_op1 = &op1_const->data.x_array.data.s_none.elements[i];
24996 ConstExprValue *float_out_val = &out_val->data.x_array.data.s_none.elements[i];
24997 assert(float_operand_op1->type == float_type);
24998 assert(float_out_val->type == float_type);
24999 ir_eval_float_op(ira, instruction, float_type,
25000 op1_const, float_out_val);
25001 float_out_val->type = float_type;
2459025002 }
25003 out_val->type = expr_type;
25004 out_val->special = ConstValSpecialStatic;
2459125005 } else {
24592 zig_unreachable();
25006 ir_eval_float_op(ira, instruction, float_type, op1_const, out_val);
2459325007 }
24594
2459525008 return result;
2459625009 }
2459725010
2459825011 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,
24607 instruction->base.source_node, nullptr, casted_op);
24608 result->value.type = float_type;
25013 IrInstruction *result = ir_build_float_op(&ira->new_irb, instruction->base.scope,
25014 instruction->base.source_node, nullptr, casted_op1, instruction->op);
25015 result->value.type = expr_type;
2460925016 return result;
2461025017}
2461125018
......@@ -25143,8 +25550,10 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
2514325550 return ir_analyze_instruction_merge_err_ret_traces(ira, (IrInstructionMergeErrRetTraces *)instruction);
2514425551 case IrInstructionIdMarkErrRetTracePtr:
2514525552 return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction);
25146 case IrInstructionIdSqrt:
25147 return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction);
25553 case IrInstructionIdFloatOp:
25554 return ir_analyze_instruction_float_op(ira, (IrInstructionFloatOp *)instruction);
25555 case IrInstructionIdMulAdd:
25556 return ir_analyze_instruction_mul_add(ira, (IrInstructionMulAdd *)instruction);
2514825557 case IrInstructionIdIntToErr:
2514925558 return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction);
2515025559 case IrInstructionIdErrToInt:
......@@ -25391,7 +25800,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2539125800 case IrInstructionIdCoroFree:
2539225801 case IrInstructionIdCoroPromise:
2539325802 case IrInstructionIdPromiseResultType:
25394 case IrInstructionIdSqrt:
25803 case IrInstructionIdFloatOp:
25804 case IrInstructionIdMulAdd:
2539525805 case IrInstructionIdAtomicLoad:
2539625806 case IrInstructionIdIntCast:
2539725807 case IrInstructionIdFloatCast:
src/ir.hpp+1
......@@ -26,5 +26,6 @@ bool ir_has_side_effects(IrInstruction *instruction);
2626struct IrAnalyze;
2727ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprValue *const_val,
2828 AstNode *source_node);
29const char *float_op_to_name(BuiltinFnId op, bool llvm_name);
2930
3031#endif
src/ir_print.cpp+25-5
......@@ -1563,15 +1563,32 @@ static void ir_print_mark_err_ret_trace_ptr(IrPrint *irp, IrInstructionMarkErrRe
15631563 fprintf(irp->f, ")");
15641564}
15651565
1566static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) {
1567 fprintf(irp->f, "@sqrt(");
1566static void ir_print_float_op(IrPrint *irp, IrInstructionFloatOp *instruction) {
1567
1568 fprintf(irp->f, "@%s(", float_op_to_name(instruction->op, false));
15681569 if (instruction->type != nullptr) {
15691570 ir_print_other_instruction(irp, instruction->type);
15701571 } else {
15711572 fprintf(irp->f, "null");
15721573 }
15731574 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);
15751592 fprintf(irp->f, ")");
15761593}
15771594
......@@ -2053,8 +2070,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
20532070 case IrInstructionIdMarkErrRetTracePtr:
20542071 ir_print_mark_err_ret_trace_ptr(irp, (IrInstructionMarkErrRetTracePtr *)instruction);
20552072 break;
2056 case IrInstructionIdSqrt:
2057 ir_print_sqrt(irp, (IrInstructionSqrt *)instruction);
2073 case IrInstructionIdFloatOp:
2074 ir_print_float_op(irp, (IrInstructionFloatOp *)instruction);
2075 break;
2076 case IrInstructionIdMulAdd:
2077 ir_print_mul_add(irp, (IrInstructionMulAdd *)instruction);
20582078 break;
20592079 case IrInstructionIdAtomicLoad:
20602080 ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction);
std/fmt.zig+397-363
......@@ -10,6 +10,42 @@ const lossyCast = std.math.lossyCast;
1010
1111pub 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
1349/// Renders fmt string with args, calling output with slices of bytes.
1450/// If `output` returns an error, the error is returned from `format` and
1551/// `output` is not called again.
......@@ -20,17 +56,30 @@ pub fn format(
2056 comptime fmt: []const u8,
2157 args: ...,
2258) 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
2364 const State = enum {
2465 Start,
25 OpenBrace,
66 Positional,
2667 CloseBrace,
27 FormatString,
68 Specifier,
69 FormatFillAndAlign,
70 FormatWidth,
71 FormatPrecision,
2872 Pointer,
2973 };
3074
3175 comptime var start_index = 0;
3276 comptime var state = State.Start;
3377 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
3584 inline for (fmt) |c, i| {
3685 switch (state) {
......@@ -39,58 +88,183 @@ pub fn format(
3988 if (start_index < i) {
4089 try output(context, fmt[start_index..i]);
4190 }
91
4292 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{};
4498 },
45
4699 '}' => {
47100 if (start_index < i) {
48101 try output(context, fmt[start_index..i]);
49102 }
50 state = State.CloseBrace;
103 state = .CloseBrace;
51104 },
52105 else => {},
53106 },
54 .OpenBrace => switch (c) {
107 .Positional => switch (c) {
55108 '{' => {
56 state = State.Start;
109 state = .Start;
57110 start_index = i;
58111 },
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 },
59132 '}' => {
60 try formatType(args[next_arg], fmt[0..0], context, Errors, output, default_max_depth);
61 next_arg += 1;
62 state = State.Start;
133 const arg_to_print = comptime nextArg(&used_pos_args, maybe_pos_arg, &next_arg);
134
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;
63146 start_index = i + 1;
64147 },
65 '*' => state = State.Pointer,
66148 else => {
67 state = State.FormatString;
149 state = .Specifier;
150 specifier_start = i;
68151 },
69152 },
70153 .CloseBrace => switch (c) {
71154 '}' => {
72 state = State.Start;
155 state = .Start;
73156 start_index = i;
74157 },
75158 else => @compileError("Single '}' encountered in format string"),
76159 },
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 },
78165 '}' => {
79 const s = start_index + 1;
80 try formatType(args[next_arg], fmt[s..i], context, Errors, output, default_max_depth);
81 next_arg += 1;
82 state = State.Start;
166 const arg_to_print = comptime nextArg(&used_pos_args, maybe_pos_arg, &next_arg);
167
168 try formatType(
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;
83178 start_index = i + 1;
84179 },
85180 else => {},
86181 },
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 },
87259 .Pointer => switch (c) {
88260 '}' => {
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));
90264 try output(context, "@");
91 try formatInt(@ptrToInt(args[next_arg]), 16, false, 0, context, Errors, output);
92 next_arg += 1;
93 state = State.Start;
265 try formatInt(@ptrToInt(args[arg_to_print]), 16, false, 0, context, Errors, output);
266
267 state = .Start;
94268 start_index = i + 1;
95269 },
96270 else => @compileError("Unexpected format character after '*'"),
......@@ -98,7 +272,13 @@ pub fn format(
98272 }
99273 }
100274 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) {
102282 @compileError("Unused arguments");
103283 }
104284 if (state != State.Start) {
......@@ -113,6 +293,7 @@ pub fn format(
113293pub fn formatType(
114294 value: var,
115295 comptime fmt: []const u8,
296 comptime options: FormatOptions,
116297 context: var,
117298 comptime Errors: type,
118299 output: fn (@typeOf(context), []const u8) Errors!void,
......@@ -121,7 +302,7 @@ pub fn formatType(
121302 const T = @typeOf(value);
122303 switch (@typeInfo(T)) {
123304 .ComptimeInt, .Int, .Float => {
124 return formatValue(value, fmt, context, Errors, output);
305 return formatValue(value, fmt, options, context, Errors, output);
125306 },
126307 .Void => {
127308 return output(context, "void");
......@@ -131,16 +312,16 @@ pub fn formatType(
131312 },
132313 .Optional => {
133314 if (value) |payload| {
134 return formatType(payload, fmt, context, Errors, output, max_depth);
315 return formatType(payload, fmt, options, context, Errors, output, max_depth);
135316 } else {
136317 return output(context, "null");
137318 }
138319 },
139320 .ErrorUnion => {
140321 if (value) |payload| {
141 return formatType(payload, fmt, context, Errors, output, max_depth);
322 return formatType(payload, fmt, options, context, Errors, output, max_depth);
142323 } else |err| {
143 return formatType(err, fmt, context, Errors, output, max_depth);
324 return formatType(err, fmt, options, context, Errors, output, max_depth);
144325 }
145326 },
146327 .ErrorSet => {
......@@ -152,16 +333,16 @@ pub fn formatType(
152333 },
153334 .Enum => {
154335 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);
156337 }
157338
158339 try output(context, @typeName(T));
159340 try output(context, ".");
160 return formatType(@tagName(value), "", context, Errors, output, max_depth);
341 return formatType(@tagName(value), "", options, context, Errors, output, max_depth);
161342 },
162343 .Union => {
163344 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);
165346 }
166347
167348 try output(context, @typeName(T));
......@@ -175,7 +356,7 @@ pub fn formatType(
175356 try output(context, " = ");
176357 inline for (info.fields) |u_field| {
177358 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);
179360 }
180361 }
181362 try output(context, " }");
......@@ -185,7 +366,7 @@ pub fn formatType(
185366 },
186367 .Struct => {
187368 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);
189370 }
190371
191372 try output(context, @typeName(T));
......@@ -201,7 +382,7 @@ pub fn formatType(
201382 }
202383 try output(context, @memberName(T, field_i));
203384 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);
205386 }
206387 try output(context, " }");
207388 },
......@@ -209,12 +390,12 @@ pub fn formatType(
209390 .One => switch (@typeInfo(ptr_info.child)) {
210391 builtin.TypeId.Array => |info| {
211392 if (info.child == u8) {
212 return formatText(value, fmt, context, Errors, output);
393 return formatText(value, fmt, options, context, Errors, output);
213394 }
214395 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
215396 },
216397 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);
218399 },
219400 else => return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value)),
220401 },
......@@ -222,17 +403,17 @@ pub fn formatType(
222403 if (ptr_info.child == u8) {
223404 if (fmt.len > 0 and fmt[0] == 's') {
224405 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);
226407 }
227408 }
228409 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
229410 },
230411 .Slice => {
231412 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);
233414 }
234415 if (ptr_info.child == u8) {
235 return formatText(value, fmt, context, Errors, output);
416 return formatText(value, fmt, options, context, Errors, output);
236417 }
237418 return format(context, Errors, output, "{}@{x}", @typeName(ptr_info.child), @ptrToInt(value.ptr));
238419 },
......@@ -242,7 +423,7 @@ pub fn formatType(
242423 },
243424 .Array => |info| {
244425 if (info.child == u8) {
245 return formatText(value, fmt, context, Errors, output);
426 return formatText(value, fmt, options, context, Errors, output);
246427 }
247428 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
248429 },
......@@ -256,28 +437,25 @@ pub fn formatType(
256437fn formatValue(
257438 value: var,
258439 comptime fmt: []const u8,
440 comptime options: FormatOptions,
259441 context: var,
260442 comptime Errors: type,
261443 output: fn (@typeOf(context), []const u8) Errors!void,
262444) Errors!void {
263 if (fmt.len > 0 and fmt[0] == 'B') {
264 comptime var width: ?usize = null;
265 if (fmt.len > 1) {
266 if (fmt[1] == 'i') {
267 if (fmt.len > 2) {
268 width = comptime (parseUnsigned(usize, fmt[2..], 10) catch unreachable);
269 }
270 return formatBytes(value, width, 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);
445 if (comptime std.mem.eql(u8, fmt, "B")) {
446 // TODO https://github.com/ziglang/zig/issues/2725
447 if (options.width) |w| return formatBytes(value, w, 1000, context, Errors, output);
448 return formatBytes(value, null, 1000, context, Errors, output);
449 } else if (comptime std.mem.eql(u8, fmt, "Bi")) {
450 // TODO https://github.com/ziglang/zig/issues/2725
451 if (options.width) |w| return formatBytes(value, w, 1024, context, Errors, output);
452 return formatBytes(value, null, 1024, context, Errors, output);
275453 }
276454
277455 const T = @typeOf(value);
278456 switch (@typeId(T)) {
279 .Float => return formatFloatValue(value, fmt, context, Errors, output),
280 .Int, .ComptimeInt => return formatIntValue(value, fmt, context, Errors, output),
457 .Float => return formatFloatValue(value, fmt, options, context, Errors, output),
458 .Int, .ComptimeInt => return formatIntValue(value, fmt, options, context, Errors, output),
281459 else => comptime unreachable,
282460 }
283461}
......@@ -285,13 +463,13 @@ fn formatValue(
285463pub fn formatIntValue(
286464 value: var,
287465 comptime fmt: []const u8,
466 comptime options: FormatOptions,
288467 context: var,
289468 comptime Errors: type,
290469 output: fn (@typeOf(context), []const u8) Errors!void,
291470) Errors!void {
292471 comptime var radix = 10;
293472 comptime var uppercase = false;
294 comptime var width = 0;
295473
296474 const int_value = if (@typeOf(value) == comptime_int) blk: {
297475 const Int = math.IntFittingRange(value, value);
......@@ -299,83 +477,75 @@ pub fn formatIntValue(
299477 } else
300478 value;
301479
302 if (fmt.len > 0) {
303 switch (fmt[0]) {
304 'c' => {
305 if (@typeOf(int_value).bit_count <= 8) {
306 if (fmt.len > 1)
307 @compileError("Unknown format character: " ++ [_]u8{fmt[1]});
308 return formatAsciiChar(u8(int_value), context, Errors, output);
309 }
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]}),
480 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "d")) {
481 radix = 10;
482 uppercase = false;
483 } else if (comptime std.mem.eql(u8, fmt, "c")) {
484 if (@typeOf(int_value).bit_count <= 8) {
485 return formatAsciiChar(u8(int_value), context, Errors, output);
486 } else {
487 @compileError("Cannot print integer that is larger than 8 bits as a ascii");
332488 }
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 ++ "'");
334500 }
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);
336505}
337506
338507fn formatFloatValue(
339508 value: var,
340509 comptime fmt: []const u8,
510 comptime options: FormatOptions,
341511 context: var,
342512 comptime Errors: type,
343513 output: fn (@typeOf(context), []const u8) Errors!void,
344514) Errors!void {
345 comptime var width: ?usize = null;
346 comptime var float_fmt = 'e';
347 if (fmt.len > 0) {
348 float_fmt = fmt[0];
349 if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
350 }
351
352 switch (float_fmt) {
353 'e' => try formatFloatScientific(value, width, context, Errors, output),
354 '.' => try formatFloatDecimal(value, width, context, Errors, output),
355 else => @compileError("Unknown format character: " ++ [_]u8{float_fmt}),
515 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "e")) {
516 // TODO https://github.com/ziglang/zig/issues/2725
517 if (options.precision) |p| return formatFloatScientific(value, p, context, Errors, output);
518 return formatFloatScientific(value, null, context, Errors, output);
519 } else if (comptime std.mem.eql(u8, fmt, "d")) {
520 // TODO https://github.com/ziglang/zig/issues/2725
521 if (options.precision) |p| return formatFloatDecimal(value, p, context, Errors, output);
522 return formatFloatDecimal(value, null, context, Errors, output);
523 } else {
524 @compileError("Unknown format string: '" ++ fmt ++ "'");
356525 }
357526}
358527
359528pub fn formatText(
360529 bytes: []const u8,
361530 comptime fmt: []const u8,
531 comptime options: FormatOptions,
362532 context: var,
363533 comptime Errors: type,
364534 output: fn (@typeOf(context), []const u8) Errors!void,
365535) Errors!void {
366 if (fmt.len > 0) {
367 if (fmt[0] == 's') {
368 comptime var width = 0;
369 if (fmt.len > 1) width = comptime (parseUnsigned(usize, fmt[1..], 10) catch unreachable);
370 return formatBuf(bytes, width, context, Errors, output);
371 } else if ((fmt[0] == 'x') or (fmt[0] == 'X')) {
372 for (bytes) |c| {
373 try formatInt(c, 16, fmt[0] == 'X', 2, context, Errors, output);
374 }
375 return;
376 } else @compileError("Unknown format character: " ++ [_]u8{fmt[0]});
536 if (fmt.len == 0) {
537 return output(context, bytes);
538 } else if (comptime std.mem.eql(u8, fmt, "s")) {
539 if (options.width) |w| return formatBuf(bytes, w, context, Errors, output);
540 return formatBuf(bytes, 0, context, Errors, output);
541 } else if (comptime (std.mem.eql(u8, fmt, "x") or std.mem.eql(u8, fmt, "X"))) {
542 for (bytes) |c| {
543 try formatInt(c, 16, fmt[0] == 'X', 2, context, Errors, output);
544 }
545 return;
546 } else {
547 @compileError("Unknown format string: '" ++ fmt ++ "'");
377548 }
378 return output(context, bytes);
379549}
380550
381551pub fn formatAsciiChar(
......@@ -868,7 +1038,7 @@ test "parseUnsigned" {
8681038
8691039pub const parseFloat = @import("fmt/parse_float.zig").parseFloat;
8701040
871test "fmt.parseFloat" {
1041test "parseFloat" {
8721042 _ = @import("fmt/parse_float.zig");
8731043}
8741044
......@@ -960,7 +1130,7 @@ test "parse unsigned comptime" {
9601130 }
9611131}
9621132
963test "fmt.optional" {
1133test "optional" {
9641134 {
9651135 const value: ?i32 = 1234;
9661136 try testFmt("optional: 1234\n", "optional: {}\n", value);
......@@ -971,7 +1141,7 @@ test "fmt.optional" {
9711141 }
9721142}
9731143
974test "fmt.error" {
1144test "error" {
9751145 {
9761146 const value: anyerror!i32 = 1234;
9771147 try testFmt("error union: 1234\n", "error union: {}\n", value);
......@@ -982,14 +1152,14 @@ test "fmt.error" {
9821152 }
9831153}
9841154
985test "fmt.int.small" {
1155test "int.small" {
9861156 {
9871157 const value: u3 = 0b101;
9881158 try testFmt("u3: 5\n", "u3: {}\n", value);
9891159 }
9901160}
9911161
992test "fmt.int.specifier" {
1162test "int.specifier" {
9931163 {
9941164 const value: u8 = 'a';
9951165 try testFmt("u8: a\n", "u8: {c}\n", value);
......@@ -1000,27 +1170,31 @@ test "fmt.int.specifier" {
10001170 }
10011171}
10021172
1003test "fmt.buffer" {
1173test "int.padded" {
1174 try testFmt("u8: '0001'", "u8: '{:4}'", u8(1));
1175}
1176
1177test "buffer" {
10041178 {
10051179 var buf1: [32]u8 = undefined;
10061180 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);
10081182 var res = buf1[0 .. buf1.len - context.remaining.len];
10091183 testing.expect(mem.eql(u8, res, "1234"));
10101184
10111185 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);
10131187 res = buf1[0 .. buf1.len - context.remaining.len];
10141188 testing.expect(mem.eql(u8, res, "a"));
10151189
10161190 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);
10181192 res = buf1[0 .. buf1.len - context.remaining.len];
10191193 testing.expect(mem.eql(u8, res, "1100"));
10201194 }
10211195}
10221196
1023test "fmt.array" {
1197test "array" {
10241198 {
10251199 const value: [3]u8 = "abc";
10261200 try testFmt("array: abc\n", "array: {}\n", value);
......@@ -1035,7 +1209,7 @@ test "fmt.array" {
10351209 }
10361210}
10371211
1038test "fmt.slice" {
1212test "slice" {
10391213 {
10401214 const value: []const u8 = "abc";
10411215 try testFmt("slice: abc\n", "slice: {}\n", value);
......@@ -1045,11 +1219,11 @@ test "fmt.slice" {
10451219 try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", value);
10461220 }
10471221
1048 try testFmt("buf: Test \n", "buf: {s5}\n", "Test");
1222 try testFmt("buf: Test \n", "buf: {s:5}\n", "Test");
10491223 try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");
10501224}
10511225
1052test "fmt.pointer" {
1226test "pointer" {
10531227 {
10541228 const value = @intToPtr(*i32, 0xdeadbeef);
10551229 try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value);
......@@ -1065,17 +1239,17 @@ test "fmt.pointer" {
10651239 }
10661240}
10671241
1068test "fmt.cstr" {
1242test "cstr" {
10691243 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");
10711245}
10721246
1073test "fmt.filesize" {
1247test "filesize" {
10741248 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));
10761250}
10771251
1078test "fmt.struct" {
1252test "struct" {
10791253 {
10801254 const Struct = struct {
10811255 field: u8,
......@@ -1094,7 +1268,7 @@ test "fmt.struct" {
10941268 }
10951269}
10961270
1097test "fmt.enum" {
1271test "enum" {
10981272 const Enum = enum {
10991273 One,
11001274 Two,
......@@ -1104,229 +1278,71 @@ test "fmt.enum" {
11041278 try testFmt("enum: Enum.Two\n", "enum: {}\n", &value);
11051279}
11061280
1107test "fmt.float.scientific" {
1108 {
1109 var buf1: [32]u8 = undefined;
1110 const value: f32 = 1.34;
1111 const result = try bufPrint(buf1[0..], "f32: {e}\n", value);
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 }
1281test "float.scientific" {
1282 try testFmt("f32: 1.34000003e+00", "f32: {e}", f32(1.34));
1283 try testFmt("f32: 1.23400001e+01", "f32: {e}", f32(12.34));
1284 try testFmt("f64: -1.234e+11", "f64: {e}", f64(-12.34e10));
1285 try testFmt("f64: 9.99996e-40", "f64: {e}", f64(9.999960e-40));
11371286}
11381287
1139test "fmt.float.scientific.precision" {
1140 {
1141 var buf1: [32]u8 = undefined;
1142 const value: f64 = 1.409706e-42;
1143 const result = try bufPrint(buf1[0..], "f64: {e5}\n", value);
1144 testing.expect(mem.eql(u8, result, "f64: 1.40971e-42\n"));
1145 }
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 }
1288test "float.scientific.precision" {
1289 try testFmt("f64: 1.40971e-42", "f64: {e:.5}", f64(1.409706e-42));
1290 try testFmt("f64: 1.00000e-09", "f64: {e:.5}", f64(@bitCast(f32, u32(814313563))));
1291 try testFmt("f64: 7.81250e-03", "f64: {e:.5}", f64(@bitCast(f32, u32(1006632960))));
1292 // libc rounds 1.000005e+05 to 1.00000e+05 but zig does 1.00001e+05.
1293 // In fact, libc doesn't round a lot of 5 cases up when one past the precision point.
1294 try testFmt("f64: 1.00001e+05", "f64: {e:.5}", f64(@bitCast(f32, u32(1203982400))));
11661295}
11671296
1168test "fmt.float.special" {
1169 {
1170 var buf1: [32]u8 = undefined;
1171 const result = try bufPrint(buf1[0..], "f64: {}\n", math.nan_f64);
1172 testing.expect(mem.eql(u8, result, "f64: nan\n"));
1173 }
1297test "float.special" {
1298 try testFmt("f64: nan", "f64: {}", math.nan_f64);
1299 // negative nan is not defined by IEE 754,
1300 // and ARM thus normalizes it to positive nan
11741301 if (builtin.arch != builtin.Arch.arm) {
1175 // negative nan is not defined by IEE 754,
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"));
1302 try testFmt("f64: -nan", "f64: {}", -math.nan_f64);
11901303 }
1304 try testFmt("f64: inf", "f64: {}", math.inf_f64);
1305 try testFmt("f64: -inf", "f64: {}", -math.inf_f64);
11911306}
11921307
1193test "fmt.float.decimal" {
1194 {
1195 var buf1: [64]u8 = undefined;
1196 const value: f64 = 1.52314e+29;
1197 const result = try bufPrint(buf1[0..], "f64: {.}\n", value);
1198 testing.expect(mem.eql(u8, result, "f64: 152314000000000000000000000000\n"));
1199 }
1200 {
1201 var buf1: [32]u8 = undefined;
1202 const value: f32 = 1.1234;
1203 const result = try bufPrint(buf1[0..], "f32: {.1}\n", value);
1204 testing.expect(mem.eql(u8, result, "f32: 1.1\n"));
1205 }
1206 {
1207 var buf1: [32]u8 = undefined;
1208 const value: f32 = 1234.567;
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 }
1308test "float.decimal" {
1309 try testFmt("f64: 152314000000000000000000000000", "f64: {d}", f64(1.52314e+29));
1310 try testFmt("f32: 1.1", "f32: {d:.1}", f32(1.1234));
1311 try testFmt("f32: 1234.57", "f32: {d:.2}", f32(1234.567));
1312 // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64).
1313 // -11.12339... is rounded back up to -11.1234
1314 try testFmt("f32: -11.1234", "f32: {d:.4}", f32(-11.1234));
1315 try testFmt("f32: 91.12345", "f32: {d:.5}", f32(91.12345));
1316 try testFmt("f64: 91.1234567890", "f64: {d:.10}", f64(91.12345678901235));
1317 try testFmt("f64: 0.00000", "f64: {d:.5}", f64(0.0));
1318 try testFmt("f64: 6", "f64: {d:.0}", f64(5.700));
1319 try testFmt("f64: 10.0", "f64: {d:.1}", f64(9.999));
1320 try testFmt("f64: 1.000", "f64: {d:.3}", f64(1.0));
1321 try testFmt("f64: 0.00030000", "f64: {d:.8}", f64(0.0003));
1322 try testFmt("f64: 0.00000", "f64: {d:.5}", f64(1.40130e-45));
1323 try testFmt("f64: 0.00000", "f64: {d:.5}", f64(9.999960e-40));
12741324}
12751325
1276test "fmt.float.libc.sanity" {
1277 {
1278 var buf1: [32]u8 = undefined;
1279 const value: f64 = f64(@bitCast(f32, u32(916964781)));
1280 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1281 testing.expect(mem.eql(u8, result, "f64: 0.00001\n"));
1282 }
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 }
1326test "float.libc.sanity" {
1327 try testFmt("f64: 0.00001", "f64: {d:.5}", f64(@bitCast(f32, u32(916964781))));
1328 try testFmt("f64: 0.00001", "f64: {d:.5}", f64(@bitCast(f32, u32(925353389))));
1329 try testFmt("f64: 0.10000", "f64: {d:.5}", f64(@bitCast(f32, u32(1036831278))));
1330 try testFmt("f64: 1.00000", "f64: {d:.5}", f64(@bitCast(f32, u32(1065353133))));
1331 try testFmt("f64: 10.00000", "f64: {d:.5}", f64(@bitCast(f32, u32(1092616192))));
1332
13071333 // libc differences
1308 {
1309 var buf1: [32]u8 = undefined;
1310 // This is 0.015625 exactly according to gdb. We thus round down,
1311 // however glibc rounds up for some reason. This occurs for all
1312 // floats of the form x.yyyy25 on a precision point.
1313 const value: f64 = f64(@bitCast(f32, u32(1015021568)));
1314 const result = try bufPrint(buf1[0..], "f64: {.5}\n", value);
1315 testing.expect(mem.eql(u8, result, "f64: 0.01563\n"));
1316 }
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 }
1334 //
1335 // This is 0.015625 exactly according to gdb. We thus round down,
1336 // however glibc rounds up for some reason. This occurs for all
1337 // floats of the form x.yyyy25 on a precision point.
1338 try testFmt("f64: 0.01563", "f64: {d:.5}", f64(@bitCast(f32, u32(1015021568))));
1339 // errol3 rounds to ... 630 but libc rounds to ...632. Grisu3
1340 // also rounds to 630 so I'm inclined to believe libc is not
1341 // optimal here.
1342 try testFmt("f64: 18014400656965630.00000", "f64: {d:.5}", f64(@bitCast(f32, u32(1518338049))));
13271343}
13281344
1329test "fmt.custom" {
1345test "custom" {
13301346 const Vec2 = struct {
13311347 const SelfType = @This();
13321348 x: f32,
......@@ -1335,20 +1351,17 @@ test "fmt.custom" {
13351351 pub fn format(
13361352 self: SelfType,
13371353 comptime fmt: []const u8,
1354 comptime options: FormatOptions,
13381355 context: var,
13391356 comptime Errors: type,
13401357 output: fn (@typeOf(context), []const u8) Errors!void,
13411358 ) Errors!void {
1342 switch (fmt.len) {
1343 0 => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
1344 1 => switch (fmt[0]) {
1345 //point format
1346 'p' => return std.fmt.format(context, Errors, output, "({.3},{.3})", self.x, self.y),
1347 //dimension format
1348 'd' => return std.fmt.format(context, Errors, output, "{.3}x{.3}", self.x, self.y),
1349 else => unreachable,
1350 },
1351 else => unreachable,
1359 if (fmt.len == 0 or comptime std.mem.eql(u8, fmt, "p")) {
1360 return std.fmt.format(context, Errors, output, "({d:.3},{d:.3})", self.x, self.y);
1361 } else if (comptime std.mem.eql(u8, fmt, "d")) {
1362 return std.fmt.format(context, Errors, output, "{d:.3}x{d:.3}", self.x, self.y);
1363 } else {
1364 @compileError("Unknown format character: '" ++ fmt ++ "'");
13521365 }
13531366 }
13541367 };
......@@ -1366,7 +1379,7 @@ test "fmt.custom" {
13661379 try testFmt("dim: 10.200x2.220\n", "dim: {d}\n", value);
13671380}
13681381
1369test "fmt.struct" {
1382test "struct" {
13701383 const S = struct {
13711384 a: u32,
13721385 b: anyerror,
......@@ -1380,7 +1393,7 @@ test "fmt.struct" {
13801393 try testFmt("S{ .a = 456, .b = error.Unused }", "{}", inst);
13811394}
13821395
1383test "fmt.union" {
1396test "union" {
13841397 const TU = union(enum) {
13851398 float: f32,
13861399 int: u32,
......@@ -1410,7 +1423,7 @@ test "fmt.union" {
14101423 testing.expect(mem.eql(u8, uu_result[0..3], "EU@"));
14111424}
14121425
1413test "fmt.enum" {
1426test "enum" {
14141427 const E = enum {
14151428 One,
14161429 Two,
......@@ -1422,7 +1435,7 @@ test "fmt.enum" {
14221435 try testFmt("E.Two", "{}", inst);
14231436}
14241437
1425test "fmt.struct.self-referential" {
1438test "struct.self-referential" {
14261439 const S = struct {
14271440 const SelfType = @This();
14281441 a: ?*SelfType,
......@@ -1436,7 +1449,7 @@ test "fmt.struct.self-referential" {
14361449 try testFmt("S{ .a = S{ .a = S{ .a = S{ ... } } } }", "{}", inst);
14371450}
14381451
1439test "fmt.bytes.hex" {
1452test "bytes.hex" {
14401453 const some_bytes = "\xCA\xFE\xBA\xBE";
14411454 try testFmt("lowercase: cafebabe\n", "lowercase: {x}\n", some_bytes);
14421455 try testFmt("uppercase: CAFEBABE\n", "uppercase: {X}\n", some_bytes);
......@@ -1478,7 +1491,7 @@ pub fn trim(buf: []const u8) []const u8 {
14781491 return buf[start..end];
14791492}
14801493
1481test "fmt.trim" {
1494test "trim" {
14821495 testing.expect(mem.eql(u8, "abc", trim("\n abc \t")));
14831496 testing.expect(mem.eql(u8, "", trim(" ")));
14841497 testing.expect(mem.eql(u8, "", trim("")));
......@@ -1505,22 +1518,22 @@ pub fn hexToBytes(out: []u8, input: []const u8) !void {
15051518 }
15061519}
15071520
1508test "fmt.hexToBytes" {
1521test "hexToBytes" {
15091522 const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";
15101523 var pb: [32]u8 = undefined;
15111524 try hexToBytes(pb[0..], test_hex_str);
15121525 try testFmt(test_hex_str, "{X}", pb);
15131526}
15141527
1515test "fmt.formatIntValue with comptime_int" {
1528test "formatIntValue with comptime_int" {
15161529 const value: comptime_int = 123456789123456789;
15171530
15181531 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);
15201533 assert(mem.eql(u8, buf.toSlice(), "123456789123456789"));
15211534}
15221535
1523test "fmt.formatType max_depth" {
1536test "formatType max_depth" {
15241537 const Vec2 = struct {
15251538 const SelfType = @This();
15261539 x: f32,
......@@ -1529,11 +1542,16 @@ test "fmt.formatType max_depth" {
15291542 pub fn format(
15301543 self: SelfType,
15311544 comptime fmt: []const u8,
1545 comptime options: FormatOptions,
15321546 context: var,
15331547 comptime Errors: type,
15341548 output: fn (@typeOf(context), []const u8) Errors!void,
15351549 ) 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 }
15371555 }
15381556 };
15391557 const E = enum {
......@@ -1565,18 +1583,34 @@ test "fmt.formatType max_depth" {
15651583 inst.tu.ptr = &inst.tu;
15661584
15671585 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);
15691587 assert(mem.eql(u8, buf0.toSlice(), "S{ ... }"));
15701588
15711589 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);
15731591 assert(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }"));
15741592
15751593 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);
15771595 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
15791597 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);
15811599 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) }"));
15821600}
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 {
519519 pub fn format(
520520 self: Int,
521521 comptime fmt: []const u8,
522 comptime options: std.fmt.FormatOptions,
522523 context: var,
523524 comptime FmtError: type,
524525 output: fn (@typeOf(context), []const u8) FmtError!void,
std/net.zig-1
......@@ -33,7 +33,6 @@ pub const Address = struct {
3333
3434 pub fn initIp6(ip6: *const Ip6Addr, _port: u16) Address {
3535 return Address{
36 .family = os.AF_INET6,
3736 .os_addr = os.sockaddr{
3837 .in6 = os.sockaddr_in6{
3938 .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 {
167167
168168 const allocator = builder.allocator;
169169 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);
171171 }
172172
173173 try out_stream.write(
......@@ -188,7 +188,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {
188188 for (builder.available_options_list.toSliceConst()) |option| {
189189 const name = try fmt.allocPrint(allocator, " -D{}=[{}]", option.name, Builder.typeIdName(option.type_id));
190190 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);
192192 }
193193 }
194194
std/special/c.zig+26-13
......@@ -254,19 +254,32 @@ export fn fmod(x: f64, y: f64) f64 {
254254
255255// TODO add intrinsics for these (and probably the double version too)
256256// and have the math stuff use the intrinsic. same as @mod and @rem
257export fn floorf(x: f32) f32 {
258 return math.floor(x);
259}
260export fn ceilf(x: f32) f32 {
261 return math.ceil(x);
262}
263export fn floor(x: f64) f64 {
264 return math.floor(x);
265}
266export fn ceil(x: f64) f64 {
267 return math.ceil(x);
268}
269
257export fn floorf(x: f32) f32 {return math.floor(x);}
258export fn ceilf(x: f32) f32 {return math.ceil(x);}
259export fn floor(x: f64) f64 {return math.floor(x);}
260export fn ceil(x: f64) f64 {return math.ceil(x);}
261export fn fma(a: f64, b: f64, c: f64) f64 {return math.fma(f64, a, b, c);}
262export fn fmaf(a: f32, b: f32, c: f32) f32 {return math.fma(f32, a, b, c);}
263export fn sin(a: f64) f64 {return math.sin(a);}
264export fn sinf(a: f32) f32 {return math.sin(a);}
265export fn cos(a: f64) f64 {return math.cos(a);}
266export fn cosf(a: f32) f32 {return math.cos(a);}
267export fn exp(a: f64) f64 {return math.exp(a);}
268export fn expf(a: f32) f32 {return math.exp(a);}
269export 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);}
270283fn generic_fmod(comptime T: type, x: T, y: T) T {
271284 @setRuntimeSafety(false);
272285
std/special/compiler_rt.zig+39-6
......@@ -405,15 +405,15 @@ const use_thumb_1 = usesThumb1(builtin.arch);
405405
406406fn usesThumb1(arch: builtin.Arch) bool {
407407 return switch (arch) {
408 .arm => switch (arch.arm) {
408 .arm => |sub_arch| switch (sub_arch) {
409409 .v6m => true,
410410 else => false,
411411 },
412 .armeb => switch (arch.armeb) {
412 .armeb => |sub_arch| switch (sub_arch) {
413413 .v6m => true,
414414 else => false,
415415 },
416 .thumb => switch (arch.thumb) {
416 .thumb => |sub_arch| switch (sub_arch) {
417417 .v5,
418418 .v5te,
419419 .v4t,
......@@ -423,7 +423,7 @@ fn usesThumb1(arch: builtin.Arch) bool {
423423 => true,
424424 else => false,
425425 },
426 .thumbeb => switch (arch.thumbeb) {
426 .thumbeb => |sub_arch| switch (sub_arch) {
427427 .v5,
428428 .v5te,
429429 .v4t,
......@@ -471,6 +471,22 @@ test "usesThumb1" {
471471 //etc.
472472}
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
474490nakedcc fn __aeabi_memcpy() noreturn {
475491 @setRuntimeSafety(false);
476492 if (use_thumb_1) {
......@@ -505,7 +521,16 @@ nakedcc fn __aeabi_memmove() noreturn {
505521
506522nakedcc fn __aeabi_memset() noreturn {
507523 @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) {
509534 asm volatile (
510535 \\ mov r3, r1
511536 \\ mov r1, r2
......@@ -527,7 +552,15 @@ nakedcc fn __aeabi_memset() noreturn {
527552
528553nakedcc fn __aeabi_memclr() noreturn {
529554 @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) {
531564 asm volatile (
532565 \\ mov r2, r1
533566 \\ movs r1, #0
std/zig/parse.zig+2-2
......@@ -2833,8 +2833,8 @@ fn parseIf(arena: *Allocator, it: *TokenIterator, tree: *Tree, bodyParseFn: Node
28332833
28342834 const else_token = eatToken(it, .Keyword_else) orelse return node;
28352835 const payload = try parsePayload(arena, it, tree);
2836 const else_expr = try expectNode(arena, it, tree, parseExpr, AstError{
2837 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
2836 const else_expr = try expectNode(arena, it, tree, bodyParseFn, AstError{
2837 .InvalidToken = AstError.InvalidToken{ .token = it.index },
28382838 });
28392839 const else_node = try arena.create(Node.Else);
28402840 else_node.* = Node.Else{
std/zig/parser_test.zig+12
......@@ -2234,6 +2234,18 @@ test "zig fmt: multiline string in array" {
22342234 );
22352235}
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
22372249const std = @import("std");
22382250const mem = std.mem;
22392251const warn = std.debug.warn;
test/compare_output.zig+1-1
......@@ -122,7 +122,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
122122 \\
123123 \\pub fn main() void {
124124 \\ 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;
126126 \\}
127127 , "Hello, world!\n0012 012 a\n");
128128
test/stage1/behavior.zig+2
......@@ -69,6 +69,8 @@ comptime {
6969 _ = @import("behavior/optional.zig");
7070 _ = @import("behavior/pointers.zig");
7171 _ = @import("behavior/popcount.zig");
72 _ = @import("behavior/muladd.zig");
73 _ = @import("behavior/floatop.zig");
7274 _ = @import("behavior/ptrcast.zig");
7375 _ = @import("behavior/pub_enum.zig");
7476 _ = @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