authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-02 20:00:13-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-02 20:00:13-04:00
log6e1425e3123855422068738f0911d5cac9bb0aef
treefe9e93e40d174bafeb20b74e7da8ed79c562ac19
parentdd627372660209cc5a8ab294d5811b97cd1f56f5
parent06e8c2e5194439ce5b66f18fcf60108604449957

Merge remote-tracking branch 'origin/master' into llvm7


101 files changed, 5531 insertions(+), 1739 deletions(-)

.gitignore+1
......@@ -1,3 +1,4 @@
11zig-cache/
22build/
33build-*/
4docgen_tmp/
CMakeLists.txt+28-2
......@@ -22,7 +22,7 @@ set(ZIG_VERSION "${ZIG_VERSION_MAJOR}.${ZIG_VERSION_MINOR}.${ZIG_VERSION_PATCH}"
2222find_program(GIT_EXE NAMES git)
2323if(GIT_EXE)
2424 execute_process(
25 COMMAND ${GIT_EXE} name-rev HEAD --tags --name-only --no-undefined --always
25 COMMAND ${GIT_EXE} -C ${CMAKE_SOURCE_DIR} name-rev HEAD --tags --name-only --no-undefined --always
2626 OUTPUT_VARIABLE ZIG_GIT_REV
2727 OUTPUT_STRIP_TRAILING_WHITESPACE)
2828 if(ZIG_GIT_REV MATCHES "\\^0$")
......@@ -261,12 +261,15 @@ endif()
261261set(EMBEDDED_SOFTFLOAT_SOURCES
262262 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c"
263263 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c"
264 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF16UI.c"
264265 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c"
265266 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c"
266267 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c"
268 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f16UIToCommonNaN.c"
267269 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c"
268270 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c"
269271 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c"
272 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNF16UI.c"
270273 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c"
271274 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_add.c"
272275 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_div.c"
......@@ -293,8 +296,20 @@ set(EMBEDDED_SOFTFLOAT_SOURCES
293296 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c"
294297 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui64.c"
295298 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui64_r_minMag.c"
299 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_add.c"
300 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_div.c"
301 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_eq.c"
302 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_lt.c"
303 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_mul.c"
304 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_rem.c"
305 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_roundToInt.c"
306 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_sqrt.c"
307 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_sub.c"
308 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_to_f128M.c"
309 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_to_f64.c"
296310 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f32_to_f128M.c"
297311 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_f128M.c"
312 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_f16.c"
298313 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_add256M.c"
299314 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addCarryM.c"
300315 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addComplCarryM.c"
......@@ -416,7 +431,8 @@ set(ZIG_CPP_SOURCES
416431set(ZIG_STD_FILES
417432 "array_list.zig"
418433 "atomic/index.zig"
419 "atomic/queue.zig"
434 "atomic/queue_mpmc.zig"
435 "atomic/queue_mpsc.zig"
420436 "atomic/stack.zig"
421437 "base64.zig"
422438 "buf_map.zig"
......@@ -558,6 +574,7 @@ set(ZIG_STD_FILES
558574 "special/compiler_rt/aullrem.zig"
559575 "special/compiler_rt/comparetf2.zig"
560576 "special/compiler_rt/divti3.zig"
577 "special/compiler_rt/extendXfYf2.zig"
561578 "special/compiler_rt/fixuint.zig"
562579 "special/compiler_rt/fixunsdfdi.zig"
563580 "special/compiler_rt/fixunsdfsi.zig"
......@@ -568,8 +585,17 @@ set(ZIG_STD_FILES
568585 "special/compiler_rt/fixunstfdi.zig"
569586 "special/compiler_rt/fixunstfsi.zig"
570587 "special/compiler_rt/fixunstfti.zig"
588 "special/compiler_rt/floatunditf.zig"
589 "special/compiler_rt/floatunsitf.zig"
590 "special/compiler_rt/floatuntidf.zig"
591 "special/compiler_rt/floatuntisf.zig"
592 "special/compiler_rt/floatuntitf.zig"
593 "special/compiler_rt/floattidf.zig"
594 "special/compiler_rt/floattisf.zig"
595 "special/compiler_rt/floattitf.zig"
571596 "special/compiler_rt/muloti4.zig"
572597 "special/compiler_rt/index.zig"
598 "special/compiler_rt/truncXfYf2.zig"
573599 "special/compiler_rt/udivmod.zig"
574600 "special/compiler_rt/udivmoddi4.zig"
575601 "special/compiler_rt/udivmodti4.zig"
doc/langref.html.in+573-92
......@@ -367,6 +367,11 @@ pub fn main() void {
367367 <td>for ABI compatibility with C</td>
368368 </tr>
369369
370 <tr>
371 <td><code>f16</code></td>
372 <td><code>float</code></td>
373 <td>16-bit floating point (10-bit mantissa) IEEE-754-2008 binary16</td>
374 </tr>
370375 <tr>
371376 <td><code>f32</code></td>
372377 <td><code>float</code></td>
......@@ -654,6 +659,7 @@ fn divide(a: i32, b: i32) i32 {
654659 {#header_open|Floats#}
655660 <p>Zig has the following floating point types:</p>
656661 <ul>
662 <li><code>f16</code> - IEEE-754-2008 binary16</li>
657663 <li><code>f32</code> - IEEE-754-2008 binary32</li>
658664 <li><code>f64</code> - IEEE-754-2008 binary64</li>
659665 <li><code>f128</code> - IEEE-754-2008 binary128</li>
......@@ -1456,8 +1462,7 @@ test "pointer array access" {
14561462 // Taking an address of an individual element gives a
14571463 // pointer to a single item. This kind of pointer
14581464 // does not support pointer arithmetic.
1459
1460 var array = []u8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1465 var array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
14611466 const ptr = &array[2];
14621467 assert(@typeOf(ptr) == *u8);
14631468
......@@ -1469,7 +1474,7 @@ test "pointer array access" {
14691474test "pointer slicing" {
14701475 // In Zig, we prefer using slices over null-terminated pointers.
14711476 // You can turn an array into a slice using slice syntax:
1472 var array = []u8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1477 var array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
14731478 const slice = array[2..4];
14741479 assert(slice.len == 2);
14751480
......@@ -1541,13 +1546,13 @@ test "pointer casting" {
15411546 // To convert one pointer type to another, use @ptrCast. This is an unsafe
15421547 // operation that Zig cannot protect you against. Use @ptrCast only when other
15431548 // conversions are not possible.
1544 const bytes align(@alignOf(u32)) = []u8{0x12, 0x12, 0x12, 0x12};
1549 const bytes align(@alignOf(u32)) = []u8{ 0x12, 0x12, 0x12, 0x12 };
15451550 const u32_ptr = @ptrCast(*const u32, &bytes[0]);
15461551 assert(u32_ptr.* == 0x12121212);
15471552
15481553 // Even this example is contrived - there are better ways to do the above than
15491554 // pointer casting. For example, using a slice narrowing cast:
1550 const u32_value = ([]const u32)(bytes[0..])[0];
1555 const u32_value = @bytesToSlice(u32, bytes[0..])[0];
15511556 assert(u32_value == 0x12121212);
15521557
15531558 // And even another way, the most straightforward way to do it:
......@@ -1630,13 +1635,13 @@ test "function alignment" {
16301635const assert = @import("std").debug.assert;
16311636
16321637test "pointer alignment safety" {
1633 var array align(4) = []u32{0x11111111, 0x11111111};
1634 const bytes = ([]u8)(array[0..]);
1638 var array align(4) = []u32{ 0x11111111, 0x11111111 };
1639 const bytes = @sliceToBytes(array[0..]);
16351640 assert(foo(bytes) == 0x11111111);
16361641}
16371642fn foo(bytes: []u8) u32 {
16381643 const slice4 = bytes[1..5];
1639 const int_slice = ([]u32)(@alignCast(4, slice4));
1644 const int_slice = @bytesToSlice(u32, @alignCast(4, slice4));
16401645 return int_slice[0];
16411646}
16421647 {#code_end#}
......@@ -1728,8 +1733,8 @@ test "slice pointer" {
17281733test "slice widening" {
17291734 // Zig supports slice widening and slice narrowing. Cast a slice of u8
17301735 // to a slice of anything else, and Zig will perform the length conversion.
1731 const array align(@alignOf(u32)) = []u8{0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13};
1732 const slice = ([]const u32)(array[0..]);
1736 const array align(@alignOf(u32)) = []u8{ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13 };
1737 const slice = @bytesToSlice(u32, array[0..]);
17331738 assert(slice.len == 2);
17341739 assert(slice[0] == 0x12121212);
17351740 assert(slice[1] == 0x13131313);
......@@ -1901,9 +1906,9 @@ const Value = enum(u2) {
19011906// Now you can cast between u2 and Value.
19021907// The ordinal value starts from 0, counting up for each member.
19031908test "enum ordinal value" {
1904 assert(u2(Value.Zero) == 0);
1905 assert(u2(Value.One) == 1);
1906 assert(u2(Value.Two) == 2);
1909 assert(@enumToInt(Value.Zero) == 0);
1910 assert(@enumToInt(Value.One) == 1);
1911 assert(@enumToInt(Value.Two) == 2);
19071912}
19081913
19091914// You can override the ordinal value for an enum.
......@@ -1913,9 +1918,9 @@ const Value2 = enum(u32) {
19131918 Million = 1000000,
19141919};
19151920test "set enum ordinal value" {
1916 assert(u32(Value2.Hundred) == 100);
1917 assert(u32(Value2.Thousand) == 1000);
1918 assert(u32(Value2.Million) == 1000000);
1921 assert(@enumToInt(Value2.Hundred) == 100);
1922 assert(@enumToInt(Value2.Thousand) == 1000);
1923 assert(@enumToInt(Value2.Million) == 1000000);
19191924}
19201925
19211926// Enums can have methods, the same as structs and unions.
......@@ -2356,11 +2361,18 @@ fn eventuallyErrorSequence() error!u32 {
23562361 break :blk numbers_left;
23572362 };
23582363}
2364 {#code_end#}
2365
2366 {#header_open|inline while#}
2367 <p>
2368 While loops can be inlined. This causes the loop to be unrolled, which
2369 allows the code to do some things which only work at compile time,
2370 such as use types as first class values.
2371 </p>
2372 {#code_begin|test#}
2373const assert = @import("std").debug.assert;
23592374
23602375test "inline while loop" {
2361 // While loops can be inlined. This causes the loop to be unrolled, which
2362 // allows the code to do some things which only work at compile time,
2363 // such as use types as first class values.
23642376 comptime var i = 0;
23652377 var sum: usize = 0;
23662378 inline while (i < 3) : (i += 1) {
......@@ -2379,6 +2391,16 @@ fn typeNameLength(comptime T: type) usize {
23792391 return @typeName(T).len;
23802392}
23812393 {#code_end#}
2394 <p>
2395 It is recommended to use <code>inline</code> loops only for one of these reasons:
2396 </p>
2397 <ul>
2398 <li>You need the loop to execute at {#link|comptime#} for the semantics to work.</li>
2399 <li>
2400 You have a benchmark to prove that forcibly unrolling the loop in this way is measurably faster.
2401 </li>
2402 </ul>
2403 {#header_close#}
23822404 {#see_also|if|Optionals|Errors|comptime|unreachable#}
23832405 {#header_close#}
23842406 {#header_open|for#}
......@@ -2446,15 +2468,20 @@ test "for else" {
24462468 break :blk sum;
24472469 };
24482470}
2449
2471 {#code_end#}
2472 {#header_open|inline for#}
2473 <p>
2474 For loops can be inlined. This causes the loop to be unrolled, which
2475 allows the code to do some things which only work at compile time,
2476 such as use types as first class values.
2477 The capture value and iterator value of inlined for loops are
2478 compile-time known.
2479 </p>
2480 {#code_begin|test#}
2481const assert = @import("std").debug.assert;
24502482
24512483test "inline for loop" {
24522484 const nums = []i32{2, 4, 6};
2453 // For loops can be inlined. This causes the loop to be unrolled, which
2454 // allows the code to do some things which only work at compile time,
2455 // such as use types as first class values.
2456 // The capture value and iterator value of inlined for loops are
2457 // compile-time known.
24582485 var sum: usize = 0;
24592486 inline for (nums) |i| {
24602487 const T = switch (i) {
......@@ -2472,6 +2499,16 @@ fn typeNameLength(comptime T: type) usize {
24722499 return @typeName(T).len;
24732500}
24742501 {#code_end#}
2502 <p>
2503 It is recommended to use <code>inline</code> loops only for one of these reasons:
2504 </p>
2505 <ul>
2506 <li>You need the loop to execute at {#link|comptime#} for the semantics to work.</li>
2507 <li>
2508 You have a benchmark to prove that forcibly unrolling the loop in this way is measurably faster.
2509 </li>
2510 </ul>
2511 {#header_close#}
24752512 {#see_also|while|comptime|Arrays|Slices#}
24762513 {#header_close#}
24772514 {#header_open|if#}
......@@ -3542,14 +3579,191 @@ const optional_value: ?i32 = null;
35423579 {#header_close#}
35433580 {#header_close#}
35443581 {#header_open|Casting#}
3545 <p>TODO: explain implicit vs explicit casting</p>
3546 <p>TODO: resolve peer types builtin</p>
3547 <p>TODO: truncate builtin</p>
3548 <p>TODO: bitcast builtin</p>
3549 <p>TODO: int to ptr builtin</p>
3550 <p>TODO: ptr to int builtin</p>
3551 <p>TODO: ptrcast builtin</p>
3552 <p>TODO: explain number literals vs concrete types</p>
3582 <p>
3583 A <strong>type cast</strong> converts a value of one type to another.
3584 Zig has {#link|Implicit Casts#} for conversions that are known to be completely safe and unambiguous,
3585 and {#link|Explicit Casts#} for conversions that one would not want to happen on accident.
3586 There is also a third kind of type conversion called {#link|Peer Type Resolution#} for
3587 the case when a result type must be decided given multiple operand types.
3588 </p>
3589 {#header_open|Implicit Casts#}
3590 <p>
3591 An implicit cast occurs when one type is expected, but different type is provided:
3592 </p>
3593 {#code_begin|test#}
3594test "implicit cast - variable declaration" {
3595 var a: u8 = 1;
3596 var b: u16 = a;
3597}
3598
3599test "implicit cast - function call" {
3600 var a: u8 = 1;
3601 foo(a);
3602}
3603
3604fn foo(b: u16) void {}
3605
3606test "implicit cast - invoke a type as a function" {
3607 var a: u8 = 1;
3608 var b = u16(a);
3609}
3610 {#code_end#}
3611 <p>
3612 Implicit casts are only allowed when it is completely unambiguous how to get from one type to another,
3613 and the transformation is guaranteed to be safe.
3614 </p>
3615 {#header_open|Implicit Cast: Stricter Qualification#}
3616 <p>
3617 Values which have the same representation at runtime can be cast to increase the strictness
3618 of the qualifiers, no matter how nested the qualifiers are:
3619 </p>
3620 <ul>
3621 <li><code>const</code> - non-const to const is allowed</li>
3622 <li><code>volatile</code> - non-volatile to volatile is allowed</li>
3623 <li><code>align</code> - bigger to smaller alignment is allowed </li>
3624 <li>{#link|error sets|Error Set Type#} to supersets is allowed</li>
3625 </ul>
3626 <p>
3627 These casts are no-ops at runtime since the value representation does not change.
3628 </p>
3629 {#code_begin|test#}
3630test "implicit cast - const qualification" {
3631 var a: i32 = 1;
3632 var b: *i32 = &a;
3633 foo(b);
3634}
3635
3636fn foo(a: *const i32) void {}
3637 {#code_end#}
3638 <p>
3639 In addition, pointers implicitly cast to const optional pointers:
3640 </p>
3641 {#code_begin|test#}
3642const std = @import("std");
3643const assert = std.debug.assert;
3644const mem = std.mem;
3645
3646test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
3647 const window_name = [1][*]const u8{c"window name"};
3648 const x: [*]const ?[*]const u8 = &window_name;
3649 assert(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name"));
3650}
3651 {#code_end#}
3652 {#header_close#}
3653 {#header_open|Implicit Cast: Integer and Float Widening#}
3654 <p>
3655 {#link|Integers#} implicitly cast to integer types which can represent every value of the old type, and likewise
3656 {#link|Floats#} implicitly cast to float types which can represent every value of the old type.
3657 </p>
3658 {#code_begin|test#}
3659const std = @import("std");
3660const assert = std.debug.assert;
3661const mem = std.mem;
3662
3663test "integer widening" {
3664 var a: u8 = 250;
3665 var b: u16 = a;
3666 var c: u32 = b;
3667 var d: u64 = c;
3668 var e: u64 = d;
3669 var f: u128 = e;
3670 assert(f == a);
3671}
3672
3673test "implicit unsigned integer to signed integer" {
3674 var a: u8 = 250;
3675 var b: i16 = a;
3676 assert(b == 250);
3677}
3678
3679test "float widening" {
3680 var a: f16 = 12.34;
3681 var b: f32 = a;
3682 var c: f64 = b;
3683 var d: f128 = c;
3684 assert(d == a);
3685}
3686 {#code_end#}
3687 {#header_close#}
3688 {#header_open|Implicit Cast: Arrays#}
3689 <p>TODO: [N]T to []const T</p>
3690 <p>TODO: *const [N]T to []const T</p>
3691 <p>TODO: [N]T to *const []const T</p>
3692 <p>TODO: [N]T to ?[]const T</p>
3693 <p>TODO: *[N]T to []T</p>
3694 <p>TODO: *[N]T to [*]T</p>
3695 <p>TODO: *T to *[1]T</p>
3696 <p>TODO: [N]T to E![]const T</p>
3697 {#header_close#}
3698 {#header_open|Implicit Cast: Optionals#}
3699 <p>TODO: T to ?T</p>
3700 <p>TODO: T to E!?T</p>
3701 <p>TODO: null to ?T</p>
3702 {#header_close#}
3703 {#header_open|Implicit Cast: T to E!T#}
3704 <p>TODO</p>
3705 {#header_close#}
3706 {#header_open|Implicit Cast: E to E!T#}
3707 <p>TODO</p>
3708 {#header_close#}
3709 {#header_open|Implicit Cast: comptime_int to *const integer#}
3710 <p>TODO</p>
3711 {#header_close#}
3712 {#header_open|Implicit Cast: comptime_float to *const float#}
3713 <p>TODO</p>
3714 {#header_close#}
3715 {#header_open|Implicit Cast: compile-time known numbers#}
3716 <p>TODO</p>
3717 {#header_close#}
3718 {#header_open|Implicit Cast: union to enum#}
3719 <p>TODO</p>
3720 {#header_close#}
3721 {#header_open|Implicit Cast: enum to union#}
3722 <p>TODO</p>
3723 {#header_close#}
3724 {#header_open|Implicit Cast: T to *T when @sizeOf(T) == 0#}
3725 <p>TODO</p>
3726 {#header_close#}
3727 {#header_open|Implicit Cast: undefined#}
3728 <p>TODO</p>
3729 {#header_close#}
3730 {#header_open|Implicit Cast: T to *const T#}
3731 <p>TODO</p>
3732 {#header_close#}
3733 {#header_close#}
3734
3735 {#header_open|Explicit Casts#}
3736 <p>
3737 Explicit casts are performed via {#link|Builtin Functions#}.
3738 Some explicit casts are safe; some are not.
3739 Some explicit casts perform language-level assertions; some do not.
3740 Some explicit casts are no-ops at runtime; some are not.
3741 </p>
3742 <ul>
3743 <li>{#link|@bitCast#} - change type but maintain bit representation</li>
3744 <li>{#link|@alignCast#} - make a pointer have more alignment</li>
3745 <li>{#link|@boolToInt#} - convert true to 1 and false to 0</li>
3746 <li>{#link|@bytesToSlice#} - convert a slice of bytes to a slice of another type</li>
3747 <li>{#link|@enumToInt#} - obtain the integer tag value of an enum or tagged union</li>
3748 <li>{#link|@errSetCast#} - convert to a smaller error set</li>
3749 <li>{#link|@errorToInt#} - obtain the integer value of an error code</li>
3750 <li>{#link|@floatCast#} - convert a larger float to a smaller float</li>
3751 <li>{#link|@floatToInt#} - obtain the integer part of a float value</li>
3752 <li>{#link|@intCast#} - convert between integer types</li>
3753 <li>{#link|@intToEnum#} - obtain an enum value based on its integer tag value</li>
3754 <li>{#link|@intToError#} - obtain an error code based on its integer value</li>
3755 <li>{#link|@intToFloat#} - convert an integer to a float value</li>
3756 <li>{#link|@intToPtr#} - convert an address to a pointer</li>
3757 <li>{#link|@ptrCast#} - convert between pointer types</li>
3758 <li>{#link|@ptrToInt#} - obtain the address of a pointer</li>
3759 <li>{#link|@sliceToBytes#} - convert a slice of anything to a slice of bytes</li>
3760 <li>{#link|@truncate#} - convert between integer types, chopping off bits</li>
3761 </ul>
3762 {#header_close#}
3763
3764 {#header_open|Peer Type Resolution#}
3765 <p>TODO</p>
3766 {#header_close#}
35533767 {#header_close#}
35543768
35553769 {#header_open|void#}
......@@ -4223,13 +4437,8 @@ pub fn main() void {
42234437 task in userland. It does so without introducing another language on top of Zig, such as
42244438 a macro language or a preprocessor language. It's Zig all the way down.
42254439 </p>
4226 <p>TODO: suggestion to not use inline unless necessary</p>
4227 {#header_close#}
42284440 {#header_close#}
4229 {#header_open|inline#}
4230 <p>TODO: inline while</p>
4231 <p>TODO: inline for</p>
4232 <p>TODO: suggestion to not use inline unless necessary</p>
4441 {#see_also|inline while|inline for#}
42334442 {#header_close#}
42344443 {#header_open|Assembly#}
42354444 <p>TODO: example of inline assembly</p>
......@@ -4651,6 +4860,18 @@ comptime {
46514860 </p>
46524861 {#header_close#}
46534862
4863 {#header_open|@bytesToSlice#}
4864 <pre><code class="zig">@bytesToSlice(comptime Element: type, bytes: []u8) []Element</code></pre>
4865 <p>
4866 Converts a slice of bytes or array of bytes into a slice of <code>Element</code>.
4867 The resulting slice has the same {#link|pointer|Pointers#} properties as the parameter.
4868 </p>
4869 <p>
4870 Attempting to convert a number of bytes with a length that does not evenly divide into a slice of
4871 elements results in safety-protected {#link|Undefined Behavior#}.
4872 </p>
4873 {#header_close#}
4874
46544875 {#header_open|@cDefine#}
46554876 <pre><code class="zig">@cDefine(comptime name: []u8, value)</code></pre>
46564877 <p>
......@@ -4919,12 +5140,23 @@ test "main" {
49195140 </p>
49205141 {#see_also|@import#}
49215142 {#header_close#}
4922 {#header_open|@export#}
4923 <pre><code class="zig">@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) []const u8</code></pre>
5143
5144 {#header_open|@enumToInt#}
5145 <pre><code class="zig">@enumToInt(enum_value: var) var</code></pre>
49245146 <p>
4925 Creates a symbol in the output object file.
5147 Converts an enumeration value into its integer tag type.
49265148 </p>
5149 {#see_also|@intToEnum#}
49275150 {#header_close#}
5151
5152 {#header_open|@errSetCast#}
5153 <pre><code class="zig">@errSetCast(comptime T: DestType, value: var) DestType</code></pre>
5154 <p>
5155 Converts an error value from one error set to another error set. Attempting to convert an error
5156 which is not in the destination error set results in safety-protected {#link|Undefined Behavior#}.
5157 </p>
5158 {#header_close#}
5159
49285160 {#header_open|@errorName#}
49295161 <pre><code class="zig">@errorName(err: error) []u8</code></pre>
49305162 <p>
......@@ -4941,6 +5173,7 @@ test "main" {
49415173 error name table will be generated.
49425174 </p>
49435175 {#header_close#}
5176
49445177 {#header_open|@errorReturnTrace#}
49455178 <pre><code class="zig">@errorReturnTrace() ?*builtin.StackTrace</code></pre>
49465179 <p>
......@@ -4949,6 +5182,33 @@ test "main" {
49495182 stack trace object. Otherwise returns `null`.
49505183 </p>
49515184 {#header_close#}
5185
5186 {#header_open|@errorToInt#}
5187 <pre><code class="zig">@errorToInt(err: var) @IntType(false, @sizeOf(error) * 8)</code></pre>
5188 <p>
5189 Supports the following types:
5190 </p>
5191 <ul>
5192 <li>error unions</li>
5193 <li><code>E!void</code></li>
5194 </ul>
5195 <p>
5196 Converts an error to the integer representation of an error.
5197 </p>
5198 <p>
5199 It is generally recommended to avoid this
5200 cast, as the integer representation of an error is not stable across source code changes.
5201 </p>
5202 {#see_also|@intToError#}
5203 {#header_close#}
5204
5205 {#header_open|@export#}
5206 <pre><code class="zig">@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) []const u8</code></pre>
5207 <p>
5208 Creates a symbol in the output object file.
5209 </p>
5210 {#header_close#}
5211
49525212 {#header_open|@fence#}
49535213 <pre><code class="zig">@fence(order: AtomicOrder)</code></pre>
49545214 <p>
......@@ -4985,8 +5245,12 @@ test "main" {
49855245 <pre><code class="zig">@floatToInt(comptime DestType: type, float: var) DestType</code></pre>
49865246 <p>
49875247 Converts the integer part of a floating point number to the destination type.
4988 To convert the other way, use {#link|@intToFloat#}. This cast is always safe.
49895248 </p>
5249 <p>
5250 If the integer part of the floating point number cannot fit in the destination type,
5251 it invokes safety-checked {#link|Undefined Behavior#}.
5252 </p>
5253 {#see_also|@intToFloat#}
49905254 {#header_close#}
49915255
49925256 {#header_open|@frameAddress#}
......@@ -5049,8 +5313,36 @@ fn add(a: i32, b: i32) i32 { return a + b; }
50495313 <p>
50505314 Converts an integer to another integer while keeping the same numerical value.
50515315 Attempting to convert a number which is out of range of the destination type results in
5052 {#link|Undefined Behavior#}.
5316 safety-protected {#link|Undefined Behavior#}.
5317 </p>
5318 {#header_close#}
5319
5320 {#header_open|@intToEnum#}
5321 <pre><code class="zig">@intToEnum(comptime DestType: type, int_value: @TagType(DestType)) DestType</code></pre>
5322 <p>
5323 Converts an integer into an {#link|enum#} value.
5324 </p>
5325 <p>
5326 Attempting to convert an integer which represents no value in the chosen enum type invokes
5327 safety-checked {#link|Undefined Behavior#}.
50535328 </p>
5329 {#see_also|@enumToInt#}
5330 {#header_close#}
5331
5332 {#header_open|@intToError#}
5333 <pre><code class="zig">@intToError(value: @IntType(false, @sizeOf(error) * 8)) error</code></pre>
5334 <p>
5335 Converts from the integer representation of an error into the global error set type.
5336 </p>
5337 <p>
5338 It is generally recommended to avoid this
5339 cast, as the integer representation of an error is not stable across source code changes.
5340 </p>
5341 <p>
5342 Attempting to convert an integer that does not correspond to any error results in
5343 safety-protected {#link|Undefined Behavior#}.
5344 </p>
5345 {#see_also|@errorToInt#}
50545346 {#header_close#}
50555347
50565348 {#header_open|@intToFloat#}
......@@ -5413,12 +5705,6 @@ pub const FloatMode = enum {
54135705 </p>
54145706 {#see_also|Compile Variables#}
54155707 {#header_close#}
5416 {#header_open|@setGlobalSection#}
5417 <pre><code class="zig">@setGlobalSection(global_variable_name, comptime section_name: []const u8) bool</code></pre>
5418 <p>
5419 Puts the global variable in the specified section.
5420 </p>
5421 {#header_close#}
54225708 {#header_open|@shlExact#}
54235709 <pre><code class="zig">@shlExact(value: T, shift_amt: Log2T) T</code></pre>
54245710 <p>
......@@ -5456,8 +5742,9 @@ pub const FloatMode = enum {
54565742 </p>
54575743 {#see_also|@shlExact|@shlWithOverflow#}
54585744 {#header_close#}
5745
54595746 {#header_open|@sizeOf#}
5460 <pre><code class="zig">@sizeOf(comptime T: type) (number literal)</code></pre>
5747 <pre><code class="zig">@sizeOf(comptime T: type) comptime_int</code></pre>
54615748 <p>
54625749 This function returns the number of bytes it takes to store <code>T</code> in memory.
54635750 </p>
......@@ -5465,6 +5752,15 @@ pub const FloatMode = enum {
54655752 The result is a target-specific compile time constant.
54665753 </p>
54675754 {#header_close#}
5755
5756 {#header_open|@sliceToBytes#}
5757 <pre><code class="zig">@sliceToBytes(value: var) []u8</code></pre>
5758 <p>
5759 Converts a slice or array to a slice of <code>u8</code>. The resulting slice has the same
5760 {#link|pointer|Pointers#} properties as the parameter.
5761 </p>
5762 {#header_close#}
5763
54685764 {#header_open|@sqrt#}
54695765 <pre><code class="zig">@sqrt(comptime T: type, value: T) T</code></pre>
54705766 <p>
......@@ -5600,10 +5896,17 @@ pub const TypeInfo = union(TypeId) {
56005896 };
56015897
56025898 pub const Pointer = struct {
5899 size: Size,
56035900 is_const: bool,
56045901 is_volatile: bool,
56055902 alignment: u32,
56065903 child: type,
5904
5905 pub const Size = enum {
5906 One,
5907 Many,
5908 Slice,
5909 };
56075910 };
56085911
56095912 pub const Array = struct {
......@@ -5667,7 +5970,7 @@ pub const TypeInfo = union(TypeId) {
56675970
56685971 pub const Union = struct {
56695972 layout: ContainerLayout,
5670 tag_type: type,
5973 tag_type: ?type,
56715974 fields: []UnionField,
56725975 defs: []Definition,
56735976 };
......@@ -5684,20 +5987,20 @@ pub const TypeInfo = union(TypeId) {
56845987 pub const FnArg = struct {
56855988 is_generic: bool,
56865989 is_noalias: bool,
5687 arg_type: type,
5990 arg_type: ?type,
56885991 };
56895992
56905993 pub const Fn = struct {
56915994 calling_convention: CallingConvention,
56925995 is_generic: bool,
56935996 is_var_args: bool,
5694 return_type: type,
5695 async_allocator_type: type,
5997 return_type: ?type,
5998 async_allocator_type: ?type,
56965999 args: []FnArg,
56976000 };
56986001
56996002 pub const Promise = struct {
5700 child: type,
6003 child: ?type,
57016004 };
57026005
57036006 pub const Definition = struct {
......@@ -5764,7 +6067,7 @@ pub const TypeInfo = union(TypeId) {
57646067 {#code_begin|syntax#}
57656068const Builder = @import("std").build.Builder;
57666069
5767pub fn build(b: &Builder) void {
6070pub fn build(b: *Builder) void {
57686071 const exe = b.addExecutable("example", "example.zig");
57696072 exe.setBuildMode(b.standardReleaseOptions());
57706073 b.default_step.dependOn(&exe.step);
......@@ -5817,10 +6120,10 @@ pub fn build(b: &Builder) void {
58176120 {#header_open|Undefined Behavior#}
58186121 <p>
58196122 Zig has many instances of undefined behavior. If undefined behavior is
5820 detected at compile-time, Zig emits an error. Most undefined behavior that
5821 cannot be detected at compile-time can be detected at runtime. In these cases,
5822 Zig has safety checks. Safety checks can be disabled on a per-block basis
5823 with {#link|setRuntimeSafety#}. The {#link|ReleaseFast#}
6123 detected at compile-time, Zig emits a compile error and refuses to continue.
6124 Most undefined behavior that cannot be detected at compile-time can be detected
6125 at runtime. In these cases, Zig has safety checks. Safety checks can be disabled
6126 on a per-block basis with {#link|setRuntimeSafety#}. The {#link|ReleaseFast#}
58246127 build mode disables all safety checks in order to facilitate optimizations.
58256128 </p>
58266129 <p>
......@@ -5841,7 +6144,14 @@ fn assert(ok: bool) void {
58416144 if (!ok) unreachable; // assertion failure
58426145}
58436146 {#code_end#}
5844 <p>At runtime crashes with the message <code>reached unreachable code</code> and a stack trace.</p>
6147 <p>At runtime:</p>
6148 {#code_begin|exe_err#}
6149const std = @import("std");
6150
6151pub fn main() void {
6152 std.debug.assert(false);
6153}
6154 {#code_end#}
58456155 {#header_close#}
58466156 {#header_open|Index out of Bounds#}
58476157 <p>At compile-time:</p>
......@@ -5851,7 +6161,16 @@ comptime {
58516161 const garbage = array[5];
58526162}
58536163 {#code_end#}
5854 <p>At runtime crashes with the message <code>index out of bounds</code> and a stack trace.</p>
6164 <p>At runtime:</p>
6165 {#code_begin|exe_err#}
6166pub fn main() void {
6167 var x = foo("hello");
6168}
6169
6170fn foo(x: []const u8) u8 {
6171 return x[5];
6172}
6173 {#code_end#}
58556174 {#header_close#}
58566175 {#header_open|Cast Negative Number to Unsigned Integer#}
58576176 <p>At compile-time:</p>
......@@ -5861,10 +6180,18 @@ comptime {
58616180 const unsigned = @intCast(u32, value);
58626181}
58636182 {#code_end#}
5864 <p>At runtime crashes with the message <code>attempt to cast negative value to unsigned integer</code> and a stack trace.</p>
6183 <p>At runtime:</p>
6184 {#code_begin|exe_err#}
6185const std = @import("std");
6186
6187pub fn main() void {
6188 var value: i32 = -1;
6189 var unsigned = @intCast(u32, value);
6190 std.debug.warn("value: {}\n", unsigned);
6191}
6192 {#code_end#}
58656193 <p>
5866 If you are trying to obtain the maximum value of an unsigned integer, use <code>@maxValue(T)</code>,
5867 where <code>T</code> is the integer type, such as <code>u32</code>.
6194 To obtain the maximum value of an unsigned integer, use {#link|@maxValue#}.
58686195 </p>
58696196 {#header_close#}
58706197 {#header_open|Cast Truncates Data#}
......@@ -5875,11 +6202,18 @@ comptime {
58756202 const byte = @intCast(u8, spartan_count);
58766203}
58776204 {#code_end#}
5878 <p>At runtime crashes with the message <code>integer cast truncated bits</code> and a stack trace.</p>
6205 <p>At runtime:</p>
6206 {#code_begin|exe_err#}
6207const std = @import("std");
6208
6209pub fn main() void {
6210 var spartan_count: u16 = 300;
6211 const byte = @intCast(u8, spartan_count);
6212 std.debug.warn("value: {}\n", byte);
6213}
6214 {#code_end#}
58796215 <p>
5880 If you are trying to truncate bits, use <code>@truncate(T, value)</code>,
5881 where <code>T</code> is the integer type, such as <code>u32</code>, and <code>value</code>
5882 is the value you want to truncate.
6216 To truncate bits, use {#link|@truncate#}.
58836217 </p>
58846218 {#header_close#}
58856219 {#header_open|Integer Overflow#}
......@@ -5891,9 +6225,9 @@ comptime {
58916225 <li><code>-</code> (negation)</li>
58926226 <li><code>*</code> (multiplication)</li>
58936227 <li><code>/</code> (division)</li>
5894 <li><code>@divTrunc</code> (division)</li>
5895 <li><code>@divFloor</code> (division)</li>
5896 <li><code>@divExact</code> (division)</li>
6228 <li>{#link|@divTrunc#} (division)</li>
6229 <li>{#link|@divFloor#} (division)</li>
6230 <li>{#link|@divExact#} (division)</li>
58976231 </ul>
58986232 <p>Example with addition at compile-time:</p>
58996233 {#code_begin|test_err|operation caused overflow#}
......@@ -5902,7 +6236,16 @@ comptime {
59026236 byte += 1;
59036237}
59046238 {#code_end#}
5905 <p>At runtime crashes with the message <code>integer overflow</code> and a stack trace.</p>
6239 <p>At runtime:</p>
6240 {#code_begin|exe_err#}
6241const std = @import("std");
6242
6243pub fn main() void {
6244 var byte: u8 = 255;
6245 byte += 1;
6246 std.debug.warn("value: {}\n", byte);
6247}
6248 {#code_end#}
59066249 {#header_close#}
59076250 {#header_open|Standard Library Math Functions#}
59086251 <p>These functions provided by the standard library return possible errors.</p>
......@@ -5937,13 +6280,13 @@ pub fn main() !void {
59376280 occurred, as well as returning the overflowed bits:
59386281 </p>
59396282 <ul>
5940 <li><code>@addWithOverflow</code></li>
5941 <li><code>@subWithOverflow</code></li>
5942 <li><code>@mulWithOverflow</code></li>
5943 <li><code>@shlWithOverflow</code></li>
6283 <li>{#link|@addWithOverflow#}</li>
6284 <li>{#link|@subWithOverflow#}</li>
6285 <li>{#link|@mulWithOverflow#}</li>
6286 <li>{#link|@shlWithOverflow#}</li>
59446287 </ul>
59456288 <p>
5946 Example of <code>@addWithOverflow</code>:
6289 Example of {#link|@addWithOverflow#}:
59476290 </p>
59486291 {#code_begin|exe#}
59496292const warn = @import("std").debug.warn;
......@@ -5989,7 +6332,16 @@ comptime {
59896332 const x = @shlExact(u8(0b01010101), 2);
59906333}
59916334 {#code_end#}
5992 <p>At runtime crashes with the message <code>left shift overflowed bits</code> and a stack trace.</p>
6335 <p>At runtime:</p>
6336 {#code_begin|exe_err#}
6337const std = @import("std");
6338
6339pub fn main() void {
6340 var x: u8 = 0b01010101;
6341 var y = @shlExact(x, 2);
6342 std.debug.warn("value: {}\n", y);
6343}
6344 {#code_end#}
59936345 {#header_close#}
59946346 {#header_open|Exact Right Shift Overflow#}
59956347 <p>At compile-time:</p>
......@@ -5998,7 +6350,16 @@ comptime {
59986350 const x = @shrExact(u8(0b10101010), 2);
59996351}
60006352 {#code_end#}
6001 <p>At runtime crashes with the message <code>right shift overflowed bits</code> and a stack trace.</p>
6353 <p>At runtime:</p>
6354 {#code_begin|exe_err#}
6355const std = @import("std");
6356
6357pub fn main() void {
6358 var x: u8 = 0b10101010;
6359 var y = @shrExact(x, 2);
6360 std.debug.warn("value: {}\n", y);
6361}
6362 {#code_end#}
60026363 {#header_close#}
60036364 {#header_open|Division by Zero#}
60046365 <p>At compile-time:</p>
......@@ -6009,8 +6370,17 @@ comptime {
60096370 const c = a / b;
60106371}
60116372 {#code_end#}
6012 <p>At runtime crashes with the message <code>division by zero</code> and a stack trace.</p>
6373 <p>At runtime:</p>
6374 {#code_begin|exe_err#}
6375const std = @import("std");
60136376
6377pub fn main() void {
6378 var a: u32 = 1;
6379 var b: u32 = 0;
6380 var c = a / b;
6381 std.debug.warn("value: {}\n", c);
6382}
6383 {#code_end#}
60146384 {#header_close#}
60156385 {#header_open|Remainder Division by Zero#}
60166386 <p>At compile-time:</p>
......@@ -6021,14 +6391,57 @@ comptime {
60216391 const c = a % b;
60226392}
60236393 {#code_end#}
6024 <p>At runtime crashes with the message <code>remainder division by zero</code> and a stack trace.</p>
6394 <p>At runtime:</p>
6395 {#code_begin|exe_err#}
6396const std = @import("std");
60256397
6398pub fn main() void {
6399 var a: u32 = 10;
6400 var b: u32 = 0;
6401 var c = a % b;
6402 std.debug.warn("value: {}\n", c);
6403}
6404 {#code_end#}
60266405 {#header_close#}
60276406 {#header_open|Exact Division Remainder#}
6028 <p>TODO</p>
6407 <p>At compile-time:</p>
6408 {#code_begin|test_err|exact division had a remainder#}
6409comptime {
6410 const a: u32 = 10;
6411 const b: u32 = 3;
6412 const c = @divExact(a, b);
6413}
6414 {#code_end#}
6415 <p>At runtime:</p>
6416 {#code_begin|exe_err#}
6417const std = @import("std");
6418
6419pub fn main() void {
6420 var a: u32 = 10;
6421 var b: u32 = 3;
6422 var c = @divExact(a, b);
6423 std.debug.warn("value: {}\n", c);
6424}
6425 {#code_end#}
60296426 {#header_close#}
60306427 {#header_open|Slice Widen Remainder#}
6031 <p>TODO</p>
6428 <p>At compile-time:</p>
6429 {#code_begin|test_err|unable to convert#}
6430comptime {
6431 var bytes = [5]u8{ 1, 2, 3, 4, 5 };
6432 var slice = @bytesToSlice(u32, bytes);
6433}
6434 {#code_end#}
6435 <p>At runtime:</p>
6436 {#code_begin|exe_err#}
6437const std = @import("std");
6438
6439pub fn main() void {
6440 var bytes = [5]u8{ 1, 2, 3, 4, 5 };
6441 var slice = @bytesToSlice(u32, bytes[0..]);
6442 std.debug.warn("value: {}\n", slice[0]);
6443}
6444 {#code_end#}
60326445 {#header_close#}
60336446 {#header_open|Attempt to Unwrap Null#}
60346447 <p>At compile-time:</p>
......@@ -6038,7 +6451,16 @@ comptime {
60386451 const number = optional_number.?;
60396452}
60406453 {#code_end#}
6041 <p>At runtime crashes with the message <code>attempt to unwrap null</code> and a stack trace.</p>
6454 <p>At runtime:</p>
6455 {#code_begin|exe_err#}
6456const std = @import("std");
6457
6458pub fn main() void {
6459 var optional_number: ?i32 = null;
6460 var number = optional_number.?;
6461 std.debug.warn("value: {}\n", number);
6462}
6463 {#code_end#}
60426464 <p>One way to avoid this crash is to test for null instead of assuming non-null, with
60436465 the <code>if</code> expression:</p>
60446466 {#code_begin|exe|test#}
......@@ -6053,6 +6475,7 @@ pub fn main() void {
60536475 }
60546476}
60556477 {#code_end#}
6478 {#see_also|Optionals#}
60566479 {#header_close#}
60576480 {#header_open|Attempt to Unwrap Error#}
60586481 <p>At compile-time:</p>
......@@ -6065,7 +6488,19 @@ fn getNumberOrFail() !i32 {
60656488 return error.UnableToReturnNumber;
60666489}
60676490 {#code_end#}
6068 <p>At runtime crashes with the message <code>attempt to unwrap error: ErrorCode</code> and a stack trace.</p>
6491 <p>At runtime:</p>
6492 {#code_begin|exe_err#}
6493const std = @import("std");
6494
6495pub fn main() void {
6496 const number = getNumberOrFail() catch unreachable;
6497 std.debug.warn("value: {}\n", number);
6498}
6499
6500fn getNumberOrFail() !i32 {
6501 return error.UnableToReturnNumber;
6502}
6503 {#code_end#}
60696504 <p>One way to avoid this crash is to test for an error instead of assuming a successful result, with
60706505 the <code>if</code> expression:</p>
60716506 {#code_begin|exe#}
......@@ -6085,30 +6520,76 @@ fn getNumberOrFail() !i32 {
60856520 return error.UnableToReturnNumber;
60866521}
60876522 {#code_end#}
6523 {#see_also|Errors#}
60886524 {#header_close#}
60896525 {#header_open|Invalid Error Code#}
60906526 <p>At compile-time:</p>
60916527 {#code_begin|test_err|integer value 11 represents no error#}
60926528comptime {
60936529 const err = error.AnError;
6094 const number = u32(err) + 10;
6095 const invalid_err = error(number);
6530 const number = @errorToInt(err) + 10;
6531 const invalid_err = @intToError(number);
6532}
6533 {#code_end#}
6534 <p>At runtime:</p>
6535 {#code_begin|exe_err#}
6536const std = @import("std");
6537
6538pub fn main() void {
6539 var err = error.AnError;
6540 var number = @errorToInt(err) + 500;
6541 var invalid_err = @intToError(number);
6542 std.debug.warn("value: {}\n", number);
60966543}
60976544 {#code_end#}
6098 <p>At runtime crashes with the message <code>invalid error code</code> and a stack trace.</p>
60996545 {#header_close#}
61006546 {#header_open|Invalid Enum Cast#}
6101 <p>TODO</p>
6547 <p>At compile-time:</p>
6548 {#code_begin|test_err|has no tag matching integer value 3#}
6549const Foo = enum {
6550 A,
6551 B,
6552 C,
6553};
6554comptime {
6555 const a: u2 = 3;
6556 const b = @intToEnum(Foo, a);
6557}
6558 {#code_end#}
6559 <p>At runtime:</p>
6560 {#code_begin|exe_err#}
6561const std = @import("std");
6562
6563const Foo = enum {
6564 A,
6565 B,
6566 C,
6567};
6568
6569pub fn main() void {
6570 var a: u2 = 3;
6571 var b = @intToEnum(Foo, a);
6572 std.debug.warn("value: {}\n", @tagName(b));
6573}
6574 {#code_end#}
6575 {#header_close#}
61026576
6577 {#header_open|Invalid Error Set Cast#}
6578 <p>TODO</p>
61036579 {#header_close#}
6580
61046581 {#header_open|Incorrect Pointer Alignment#}
61056582 <p>TODO</p>
61066583
61076584 {#header_close#}
61086585 {#header_open|Wrong Union Field Access#}
61096586 <p>TODO</p>
6587 {#header_close#}
61106588
6589 {#header_open|Out of Bounds Float To Integer Cast#}
6590 <p>TODO</p>
61116591 {#header_close#}
6592
61126593 {#header_close#}
61136594 {#header_open|Memory#}
61146595 <p>TODO: explain no default allocator in zig</p>
......@@ -6793,7 +7274,7 @@ hljs.registerLanguage("zig", function(t) {
67937274 a = t.IR + "\\s*\\(",
67947275 c = {
67957276 keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong resume cancel await async orelse",
6796 built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic ptrCast intCast floatCast intToFloat floatToInt boolToInt bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo typeName newStackCall",
7277 built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage divTrunc divFloor enumTagName intToPtr ptrToInt panic ptrCast intCast floatCast intToFloat floatToInt boolToInt bytesToSlice sliceToBytes errSetCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo typeName newStackCall errorToInt intToError enumToInt intToEnum",
67977278 literal: "true false null undefined"
67987279 },
67997280 n = [e, t.CLCM, t.CBCM, s, r];
src-self-hosted/arg.zig+2-2
......@@ -168,7 +168,7 @@ pub const Args = struct {
168168 }
169169
170170 // e.g. --names value1 value2 value3
171 pub fn many(self: *Args, name: []const u8) ?[]const []const u8 {
171 pub fn many(self: *Args, name: []const u8) []const []const u8 {
172172 if (self.flags.get(name)) |entry| {
173173 switch (entry.value) {
174174 FlagArg.Many => |inner| {
......@@ -177,7 +177,7 @@ pub const Args = struct {
177177 else => @panic("attempted to retrieve flag with wrong type"),
178178 }
179179 } else {
180 return null;
180 return []const []const u8{};
181181 }
182182 }
183183};
src-self-hosted/errmsg.zig+1-1
......@@ -35,7 +35,7 @@ pub fn createFromParseError(
3535 var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;
3636 try parse_error.render(&tree.tokens, out_stream);
3737
38 const msg = try allocator.construct(Msg{
38 const msg = try allocator.create(Msg{
3939 .tree = tree,
4040 .path = path,
4141 .text = text_buf.toOwnedSlice(),
src-self-hosted/main.zig+147-430
......@@ -1,6 +1,7 @@
11const std = @import("std");
22const builtin = @import("builtin");
33
4const event = std.event;
45const os = std.os;
56const io = std.io;
67const mem = std.mem;
......@@ -26,15 +27,11 @@ const usage =
2627 \\
2728 \\Commands:
2829 \\
29 \\ build Build project from build.zig
3030 \\ build-exe [source] Create executable from source or object files
3131 \\ build-lib [source] Create library from source or object files
3232 \\ build-obj [source] Create object from source or assembly
3333 \\ fmt [source] Parse file and render in canonical zig format
34 \\ run [source] Create executable and run immediately
3534 \\ targets List available compilation targets
36 \\ test [source] Create and run a test build
37 \\ translate-c [source] Convert c code to zig code
3835 \\ version Print version number and exit
3936 \\ zen Print zen of zig and exit
4037 \\
......@@ -47,7 +44,10 @@ const Command = struct {
4744};
4845
4946pub fn main() !void {
50 var allocator = std.heap.c_allocator;
47 // This allocator needs to be thread-safe because we use it for the event.Loop
48 // which multiplexes coroutines onto kernel threads.
49 // libc allocator is guaranteed to have this property.
50 const allocator = std.heap.c_allocator;
5151
5252 var stdout_file = try std.io.getStdOut();
5353 var stdout_out_stream = std.io.FileOutStream.init(&stdout_file);
......@@ -58,18 +58,16 @@ pub fn main() !void {
5858 stderr = &stderr_out_stream.stream;
5959
6060 const args = try os.argsAlloc(allocator);
61 defer os.argsFree(allocator, args);
61 // TODO I'm getting unreachable code here, which shouldn't happen
62 //defer os.argsFree(allocator, args);
6263
6364 if (args.len <= 1) {
65 try stderr.write("expected command argument\n\n");
6466 try stderr.write(usage);
6567 os.exit(1);
6668 }
6769
6870 const commands = []Command{
69 Command{
70 .name = "build",
71 .exec = cmdBuild,
72 },
7371 Command{
7472 .name = "build-exe",
7573 .exec = cmdBuildExe,
......@@ -86,22 +84,10 @@ pub fn main() !void {
8684 .name = "fmt",
8785 .exec = cmdFmt,
8886 },
89 Command{
90 .name = "run",
91 .exec = cmdRun,
92 },
9387 Command{
9488 .name = "targets",
9589 .exec = cmdTargets,
9690 },
97 Command{
98 .name = "test",
99 .exec = cmdTest,
100 },
101 Command{
102 .name = "translate-c",
103 .exec = cmdTranslateC,
104 },
10591 Command{
10692 .name = "version",
10793 .exec = cmdVersion,
......@@ -124,177 +110,15 @@ pub fn main() !void {
124110
125111 for (commands) |command| {
126112 if (mem.eql(u8, command.name, args[1])) {
127 try command.exec(allocator, args[2..]);
128 return;
113 return command.exec(allocator, args[2..]);
129114 }
130115 }
131116
132117 try stderr.print("unknown command: {}\n\n", args[1]);
133118 try stderr.write(usage);
119 os.exit(1);
134120}
135121
136// cmd:build ///////////////////////////////////////////////////////////////////////////////////////
137
138const usage_build =
139 \\usage: zig build <options>
140 \\
141 \\General Options:
142 \\ --help Print this help and exit
143 \\ --init Generate a build.zig template
144 \\ --build-file [file] Override path to build.zig
145 \\ --cache-dir [path] Override path to cache directory
146 \\ --verbose Print commands before executing them
147 \\ --prefix [path] Override default install prefix
148 \\
149 \\Project-Specific Options:
150 \\
151 \\ Project-specific options become available when the build file is found.
152 \\
153 \\Advanced Options:
154 \\ --build-file [file] Override path to build.zig
155 \\ --cache-dir [path] Override path to cache directory
156 \\ --verbose-tokenize Enable compiler debug output for tokenization
157 \\ --verbose-ast Enable compiler debug output for parsing into an AST
158 \\ --verbose-link Enable compiler debug output for linking
159 \\ --verbose-ir Enable compiler debug output for Zig IR
160 \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR
161 \\ --verbose-cimport Enable compiler debug output for C imports
162 \\
163 \\
164;
165
166const args_build_spec = []Flag{
167 Flag.Bool("--help"),
168 Flag.Bool("--init"),
169 Flag.Arg1("--build-file"),
170 Flag.Arg1("--cache-dir"),
171 Flag.Bool("--verbose"),
172 Flag.Arg1("--prefix"),
173
174 Flag.Arg1("--build-file"),
175 Flag.Arg1("--cache-dir"),
176 Flag.Bool("--verbose-tokenize"),
177 Flag.Bool("--verbose-ast"),
178 Flag.Bool("--verbose-link"),
179 Flag.Bool("--verbose-ir"),
180 Flag.Bool("--verbose-llvm-ir"),
181 Flag.Bool("--verbose-cimport"),
182};
183
184const missing_build_file =
185 \\No 'build.zig' file found.
186 \\
187 \\Initialize a 'build.zig' template file with `zig build --init`,
188 \\or build an executable directly with `zig build-exe $FILENAME.zig`.
189 \\
190 \\See: `zig build --help` or `zig help` for more options.
191 \\
192;
193
194fn cmdBuild(allocator: *Allocator, args: []const []const u8) !void {
195 var flags = try Args.parse(allocator, args_build_spec, args);
196 defer flags.deinit();
197
198 if (flags.present("help")) {
199 try stderr.write(usage_build);
200 os.exit(0);
201 }
202
203 const zig_lib_dir = try introspect.resolveZigLibDir(allocator);
204 defer allocator.free(zig_lib_dir);
205
206 const zig_std_dir = try os.path.join(allocator, zig_lib_dir, "std");
207 defer allocator.free(zig_std_dir);
208
209 const special_dir = try os.path.join(allocator, zig_std_dir, "special");
210 defer allocator.free(special_dir);
211
212 const build_runner_path = try os.path.join(allocator, special_dir, "build_runner.zig");
213 defer allocator.free(build_runner_path);
214
215 const build_file = flags.single("build-file") orelse "build.zig";
216 const build_file_abs = try os.path.resolve(allocator, ".", build_file);
217 defer allocator.free(build_file_abs);
218
219 const build_file_exists = os.File.access(allocator, build_file_abs, os.default_file_mode) catch false;
220
221 if (flags.present("init")) {
222 if (build_file_exists) {
223 try stderr.print("build.zig already exists\n");
224 os.exit(1);
225 }
226
227 // need a new scope for proper defer scope finalization on exit
228 {
229 const build_template_path = try os.path.join(allocator, special_dir, "build_file_template.zig");
230 defer allocator.free(build_template_path);
231
232 try os.copyFile(allocator, build_template_path, build_file_abs);
233 try stderr.print("wrote build.zig template\n");
234 }
235
236 os.exit(0);
237 }
238
239 if (!build_file_exists) {
240 try stderr.write(missing_build_file);
241 os.exit(1);
242 }
243
244 // TODO: Invoke build.zig entrypoint directly?
245 var zig_exe_path = try os.selfExePath(allocator);
246 defer allocator.free(zig_exe_path);
247
248 var build_args = ArrayList([]const u8).init(allocator);
249 defer build_args.deinit();
250
251 const build_file_basename = os.path.basename(build_file_abs);
252 const build_file_dirname = os.path.dirname(build_file_abs) orelse ".";
253
254 var full_cache_dir: []u8 = undefined;
255 if (flags.single("cache-dir")) |cache_dir| {
256 full_cache_dir = try os.path.resolve(allocator, ".", cache_dir, full_cache_dir);
257 } else {
258 full_cache_dir = try os.path.join(allocator, build_file_dirname, "zig-cache");
259 }
260 defer allocator.free(full_cache_dir);
261
262 const path_to_build_exe = try os.path.join(allocator, full_cache_dir, "build");
263 defer allocator.free(path_to_build_exe);
264
265 try build_args.append(path_to_build_exe);
266 try build_args.append(zig_exe_path);
267 try build_args.append(build_file_dirname);
268 try build_args.append(full_cache_dir);
269
270 var proc = try os.ChildProcess.init(build_args.toSliceConst(), allocator);
271 defer proc.deinit();
272
273 var term = try proc.spawnAndWait();
274 switch (term) {
275 os.ChildProcess.Term.Exited => |status| {
276 if (status != 0) {
277 try stderr.print("{} exited with status {}\n", build_args.at(0), status);
278 os.exit(1);
279 }
280 },
281 os.ChildProcess.Term.Signal => |signal| {
282 try stderr.print("{} killed by signal {}\n", build_args.at(0), signal);
283 os.exit(1);
284 },
285 os.ChildProcess.Term.Stopped => |signal| {
286 try stderr.print("{} stopped by signal {}\n", build_args.at(0), signal);
287 os.exit(1);
288 },
289 os.ChildProcess.Term.Unknown => |status| {
290 try stderr.print("{} encountered unknown failure {}\n", build_args.at(0), status);
291 os.exit(1);
292 },
293 }
294}
295
296// cmd:build-exe ///////////////////////////////////////////////////////////////////////////////////
297
298122const usage_build_generic =
299123 \\usage: zig build-exe <options> [file]
300124 \\ zig build-lib <options> [file]
......@@ -315,8 +139,11 @@ const usage_build_generic =
315139 \\ --output-h [file] Override generated header file path
316140 \\ --pkg-begin [name] [path] Make package available to import and push current pkg
317141 \\ --pkg-end Pop current pkg
318 \\ --release-fast Build with optimizations on and safety off
319 \\ --release-safe Build with optimizations on and safety on
142 \\ --mode [mode] Set the build mode
143 \\ debug (default) optimizations off, safety on
144 \\ release-fast optimizations on, safety off
145 \\ release-safe optimizations on, safety on
146 \\ release-small optimize for small binary, safety off
320147 \\ --static Output will be statically linked
321148 \\ --strip Exclude debug symbols
322149 \\ --target-arch [name] Specify target architecture
......@@ -367,6 +194,12 @@ const args_build_generic = []Flag{
367194 "off",
368195 "on",
369196 }),
197 Flag.Option("--mode", []const []const u8{
198 "debug",
199 "release-fast",
200 "release-safe",
201 "release-small",
202 }),
370203
371204 Flag.ArgMergeN("--assembly", 1),
372205 Flag.Arg1("--cache-dir"),
......@@ -383,8 +216,6 @@ const args_build_generic = []Flag{
383216 // NOTE: Parsed manually after initial check
384217 Flag.ArgN("--pkg-begin", 2),
385218 Flag.Bool("--pkg-end"),
386 Flag.Bool("--release-fast"),
387 Flag.Bool("--release-safe"),
388219 Flag.Bool("--static"),
389220 Flag.Bool("--strip"),
390221 Flag.Arg1("--target-arch"),
......@@ -431,16 +262,25 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
431262 defer flags.deinit();
432263
433264 if (flags.present("help")) {
434 try stderr.write(usage_build_generic);
265 try stdout.write(usage_build_generic);
435266 os.exit(0);
436267 }
437268
438 var build_mode = builtin.Mode.Debug;
439 if (flags.present("release-fast")) {
440 build_mode = builtin.Mode.ReleaseFast;
441 } else if (flags.present("release-safe")) {
442 build_mode = builtin.Mode.ReleaseSafe;
443 }
269 const build_mode = blk: {
270 if (flags.single("mode")) |mode_flag| {
271 if (mem.eql(u8, mode_flag, "debug")) {
272 break :blk builtin.Mode.Debug;
273 } else if (mem.eql(u8, mode_flag, "release-fast")) {
274 break :blk builtin.Mode.ReleaseFast;
275 } else if (mem.eql(u8, mode_flag, "release-safe")) {
276 break :blk builtin.Mode.ReleaseSafe;
277 } else if (mem.eql(u8, mode_flag, "release-small")) {
278 break :blk builtin.Mode.ReleaseSmall;
279 } else unreachable;
280 } else {
281 break :blk builtin.Mode.Debug;
282 }
283 };
444284
445285 const color = blk: {
446286 if (flags.single("color")) |color_flag| {
......@@ -456,20 +296,21 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
456296 }
457297 };
458298
459 var emit_type = Module.Emit.Binary;
460 if (flags.single("emit")) |emit_flag| {
461 if (mem.eql(u8, emit_flag, "asm")) {
462 emit_type = Module.Emit.Assembly;
463 } else if (mem.eql(u8, emit_flag, "bin")) {
464 emit_type = Module.Emit.Binary;
465 } else if (mem.eql(u8, emit_flag, "llvm-ir")) {
466 emit_type = Module.Emit.LlvmIr;
299 const emit_type = blk: {
300 if (flags.single("emit")) |emit_flag| {
301 if (mem.eql(u8, emit_flag, "asm")) {
302 break :blk Module.Emit.Assembly;
303 } else if (mem.eql(u8, emit_flag, "bin")) {
304 break :blk Module.Emit.Binary;
305 } else if (mem.eql(u8, emit_flag, "llvm-ir")) {
306 break :blk Module.Emit.LlvmIr;
307 } else unreachable;
467308 } else {
468 unreachable;
309 break :blk Module.Emit.Binary;
469310 }
470 }
311 };
471312
472 var cur_pkg = try Module.CliPkg.init(allocator, "", "", null); // TODO: Need a path, name?
313 var cur_pkg = try CliPkg.init(allocator, "", "", null);
473314 defer cur_pkg.deinit();
474315
475316 var i: usize = 0;
......@@ -482,15 +323,16 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
482323 i += 1;
483324 const new_pkg_path = args[i];
484325
485 var new_cur_pkg = try Module.CliPkg.init(allocator, new_pkg_name, new_pkg_path, cur_pkg);
326 var new_cur_pkg = try CliPkg.init(allocator, new_pkg_name, new_pkg_path, cur_pkg);
486327 try cur_pkg.children.append(new_cur_pkg);
487328 cur_pkg = new_cur_pkg;
488329 } else if (mem.eql(u8, "--pkg-end", arg_name)) {
489 if (cur_pkg.parent == null) {
330 if (cur_pkg.parent) |parent| {
331 cur_pkg = parent;
332 } else {
490333 try stderr.print("encountered --pkg-end with no matching --pkg-begin\n");
491334 os.exit(1);
492335 }
493 cur_pkg = cur_pkg.parent.?;
494336 }
495337 }
496338
......@@ -499,43 +341,42 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
499341 os.exit(1);
500342 }
501343
502 var in_file: ?[]const u8 = undefined;
503 switch (flags.positionals.len) {
504 0 => {
505 try stderr.write("--name [name] not provided and unable to infer\n");
506 os.exit(1);
507 },
508 1 => {
509 in_file = flags.positionals.at(0);
510 },
344 const provided_name = flags.single("name");
345 const root_source_file = switch (flags.positionals.len) {
346 0 => null,
347 1 => flags.positionals.at(0),
511348 else => {
512 try stderr.write("only one zig input file is accepted during build\n");
349 try stderr.print("unexpected extra parameter: {}\n", flags.positionals.at(1));
513350 os.exit(1);
514351 },
515 }
352 };
516353
517 const basename = os.path.basename(in_file.?);
518 var it = mem.split(basename, ".");
519 const root_name = it.next() orelse {
520 try stderr.write("file name cannot be empty\n");
521 os.exit(1);
354 const root_name = if (provided_name) |n| n else blk: {
355 if (root_source_file) |file| {
356 const basename = os.path.basename(file);
357 var it = mem.split(basename, ".");
358 break :blk it.next() orelse basename;
359 } else {
360 try stderr.write("--name [name] not provided and unable to infer\n");
361 os.exit(1);
362 }
522363 };
523364
524 const asm_a = flags.many("assembly");
525 const obj_a = flags.many("object");
526 if (in_file == null and (obj_a == null or obj_a.?.len == 0) and (asm_a == null or asm_a.?.len == 0)) {
365 const assembly_files = flags.many("assembly");
366 const link_objects = flags.many("object");
367 if (root_source_file == null and link_objects.len == 0 and assembly_files.len == 0) {
527368 try stderr.write("Expected source file argument or at least one --object or --assembly argument\n");
528369 os.exit(1);
529370 }
530371
531 if (out_type == Module.Kind.Obj and (obj_a != null and obj_a.?.len != 0)) {
372 if (out_type == Module.Kind.Obj and link_objects.len != 0) {
532373 try stderr.write("When building an object file, --object arguments are invalid\n");
533374 os.exit(1);
534375 }
535376
536 const zig_root_source_file = in_file;
537
538 const full_cache_dir = os.path.resolve(allocator, ".", flags.single("cache-dir") orelse "zig-cache"[0..]) catch {
377 const rel_cache_dir = flags.single("cache-dir") orelse "zig-cache"[0..];
378 const full_cache_dir = os.path.resolve(allocator, ".", rel_cache_dir) catch {
379 try stderr.print("invalid cache dir: {}\n", rel_cache_dir);
539380 os.exit(1);
540381 };
541382 defer allocator.free(full_cache_dir);
......@@ -543,10 +384,12 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
543384 const zig_lib_dir = introspect.resolveZigLibDir(allocator) catch os.exit(1);
544385 defer allocator.free(zig_lib_dir);
545386
387 var loop = try event.Loop.init(allocator);
388
546389 var module = try Module.create(
547 allocator,
390 &loop,
548391 root_name,
549 zig_root_source_file,
392 root_source_file,
550393 Target.Native,
551394 out_type,
552395 build_mode,
......@@ -561,24 +404,21 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
561404
562405 module.is_test = false;
563406
564 if (flags.single("linker-script")) |linker_script| {
565 module.linker_script = linker_script;
566 }
567
407 module.linker_script = flags.single("linker-script");
568408 module.each_lib_rpath = flags.present("each-lib-rpath");
569409
570410 var clang_argv_buf = ArrayList([]const u8).init(allocator);
571411 defer clang_argv_buf.deinit();
572 if (flags.many("mllvm")) |mllvm_flags| {
573 for (mllvm_flags) |mllvm| {
574 try clang_argv_buf.append("-mllvm");
575 try clang_argv_buf.append(mllvm);
576 }
577412
578 module.llvm_argv = mllvm_flags;
579 module.clang_argv = clang_argv_buf.toSliceConst();
413 const mllvm_flags = flags.many("mllvm");
414 for (mllvm_flags) |mllvm| {
415 try clang_argv_buf.append("-mllvm");
416 try clang_argv_buf.append(mllvm);
580417 }
581418
419 module.llvm_argv = mllvm_flags;
420 module.clang_argv = clang_argv_buf.toSliceConst();
421
582422 module.strip = flags.present("strip");
583423 module.is_static = flags.present("static");
584424
......@@ -610,18 +450,9 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
610450 module.verbose_cimport = flags.present("verbose-cimport");
611451
612452 module.err_color = color;
613
614 if (flags.many("library-path")) |lib_dirs| {
615 module.lib_dirs = lib_dirs;
616 }
617
618 if (flags.many("framework")) |frameworks| {
619 module.darwin_frameworks = frameworks;
620 }
621
622 if (flags.many("rpath")) |rpath_list| {
623 module.rpath_list = rpath_list;
624 }
453 module.lib_dirs = flags.many("library-path");
454 module.darwin_frameworks = flags.many("framework");
455 module.rpath_list = flags.many("rpath");
625456
626457 if (flags.single("output-h")) |output_h| {
627458 module.out_h_path = output_h;
......@@ -644,41 +475,51 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
644475 }
645476
646477 module.emit_file_type = emit_type;
647 if (flags.many("object")) |objects| {
648 module.link_objects = objects;
649 }
650 if (flags.many("assembly")) |assembly_files| {
651 module.assembly_files = assembly_files;
652 }
478 module.link_objects = link_objects;
479 module.assembly_files = assembly_files;
480 module.link_out_file = flags.single("out-file");
653481
654482 try module.build();
655 try module.link(flags.single("out-file") orelse null);
483 const process_build_events_handle = try async<loop.allocator> processBuildEvents(module, true);
484 defer cancel process_build_events_handle;
485 loop.run();
486}
656487
657 if (flags.present("print-timing-info")) {
658 // codegen_print_timing_info(g, stderr);
488async fn processBuildEvents(module: *Module, watch: bool) void {
489 while (watch) {
490 // TODO directly awaiting async should guarantee memory allocation elision
491 const build_event = await (async module.events.get() catch unreachable);
492
493 switch (build_event) {
494 Module.Event.Ok => {
495 std.debug.warn("Build succeeded\n");
496 // for now we stop after 1
497 module.loop.stop();
498 return;
499 },
500 Module.Event.Error => |err| {
501 std.debug.warn("build failed: {}\n", @errorName(err));
502 @panic("TODO error return trace");
503 },
504 Module.Event.Fail => |errs| {
505 @panic("TODO print compile error messages");
506 },
507 }
659508 }
660
661 try stderr.print("building {}: {}\n", @tagName(out_type), in_file);
662509}
663510
664511fn cmdBuildExe(allocator: *Allocator, args: []const []const u8) !void {
665 try buildOutputType(allocator, args, Module.Kind.Exe);
512 return buildOutputType(allocator, args, Module.Kind.Exe);
666513}
667514
668// cmd:build-lib ///////////////////////////////////////////////////////////////////////////////////
669
670515fn cmdBuildLib(allocator: *Allocator, args: []const []const u8) !void {
671 try buildOutputType(allocator, args, Module.Kind.Lib);
516 return buildOutputType(allocator, args, Module.Kind.Lib);
672517}
673518
674// cmd:build-obj ///////////////////////////////////////////////////////////////////////////////////
675
676519fn cmdBuildObj(allocator: *Allocator, args: []const []const u8) !void {
677 try buildOutputType(allocator, args, Module.Kind.Obj);
520 return buildOutputType(allocator, args, Module.Kind.Obj);
678521}
679522
680// cmd:fmt /////////////////////////////////////////////////////////////////////////////////////////
681
682523const usage_fmt =
683524 \\usage: zig fmt [file]...
684525 \\
......@@ -707,7 +548,7 @@ const Fmt = struct {
707548
708549 // file_path must outlive Fmt
709550 fn addToQueue(self: *Fmt, file_path: []const u8) !void {
710 const new_node = try self.seen.allocator.construct(std.LinkedList([]const u8).Node{
551 const new_node = try self.seen.allocator.create(std.LinkedList([]const u8).Node{
711552 .prev = undefined,
712553 .next = undefined,
713554 .data = file_path,
......@@ -735,7 +576,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
735576 defer flags.deinit();
736577
737578 if (flags.present("help")) {
738 try stderr.write(usage_fmt);
579 try stdout.write(usage_fmt);
739580 os.exit(0);
740581 }
741582
......@@ -863,162 +704,16 @@ fn cmdTargets(allocator: *Allocator, args: []const []const u8) !void {
863704 }
864705}
865706
866// cmd:version /////////////////////////////////////////////////////////////////////////////////////
867
868707fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void {
869708 try stdout.print("{}\n", std.cstr.toSliceConst(c.ZIG_VERSION_STRING));
870709}
871710
872// cmd:test ////////////////////////////////////////////////////////////////////////////////////////
873
874const usage_test =
875 \\usage: zig test [file]...
876 \\
877 \\Options:
878 \\ --help Print this help and exit
879 \\
880 \\
881;
882
883711const args_test_spec = []Flag{Flag.Bool("--help")};
884712
885fn cmdTest(allocator: *Allocator, args: []const []const u8) !void {
886 var flags = try Args.parse(allocator, args_build_spec, args);
887 defer flags.deinit();
888
889 if (flags.present("help")) {
890 try stderr.write(usage_test);
891 os.exit(0);
892 }
893
894 if (flags.positionals.len != 1) {
895 try stderr.write("expected exactly one zig source file\n");
896 os.exit(1);
897 }
898
899 // compile the test program into the cache and run
900
901 // NOTE: May be overlap with buildOutput, take the shared part out.
902 try stderr.print("testing file {}\n", flags.positionals.at(0));
903}
904
905// cmd:run /////////////////////////////////////////////////////////////////////////////////////////
906
907// Run should be simple and not expose the full set of arguments provided by build-exe. If specific
908// build requirements are need, the user should `build-exe` then `run` manually.
909const usage_run =
910 \\usage: zig run [file] -- <runtime args>
911 \\
912 \\Options:
913 \\ --help Print this help and exit
914 \\
915 \\
916;
917
918const args_run_spec = []Flag{Flag.Bool("--help")};
919
920fn cmdRun(allocator: *Allocator, args: []const []const u8) !void {
921 var compile_args = args;
922 var runtime_args: []const []const u8 = []const []const u8{};
923
924 for (args) |argv, i| {
925 if (mem.eql(u8, argv, "--")) {
926 compile_args = args[0..i];
927 runtime_args = args[i + 1 ..];
928 break;
929 }
930 }
931 var flags = try Args.parse(allocator, args_run_spec, compile_args);
932 defer flags.deinit();
933
934 if (flags.present("help")) {
935 try stderr.write(usage_run);
936 os.exit(0);
937 }
938
939 if (flags.positionals.len != 1) {
940 try stderr.write("expected exactly one zig source file\n");
941 os.exit(1);
942 }
943
944 try stderr.print("runtime args:\n");
945 for (runtime_args) |cargs| {
946 try stderr.print("{}\n", cargs);
947 }
948}
949
950// cmd:translate-c /////////////////////////////////////////////////////////////////////////////////
951
952const usage_translate_c =
953 \\usage: zig translate-c [file]
954 \\
955 \\Options:
956 \\ --help Print this help and exit
957 \\ --enable-timing-info Print timing diagnostics
958 \\ --output [path] Output file to write generated zig file (default: stdout)
959 \\
960 \\
961;
962
963const args_translate_c_spec = []Flag{
964 Flag.Bool("--help"),
965 Flag.Bool("--enable-timing-info"),
966 Flag.Arg1("--libc-include-dir"),
967 Flag.Arg1("--output"),
968};
969
970fn cmdTranslateC(allocator: *Allocator, args: []const []const u8) !void {
971 var flags = try Args.parse(allocator, args_translate_c_spec, args);
972 defer flags.deinit();
973
974 if (flags.present("help")) {
975 try stderr.write(usage_translate_c);
976 os.exit(0);
977 }
978
979 if (flags.positionals.len != 1) {
980 try stderr.write("expected exactly one c source file\n");
981 os.exit(1);
982 }
983
984 // set up codegen
985
986 const zig_root_source_file = null;
987
988 // NOTE: translate-c shouldn't require setting up the full codegen instance as it does in
989 // the C++ compiler.
990
991 // codegen_create(g);
992 // codegen_set_out_name(g, null);
993 // codegen_translate_c(g, flags.positional.at(0))
994
995 var output_stream = stdout;
996 if (flags.single("output")) |output_file| {
997 var file = try os.File.openWrite(allocator, output_file);
998 defer file.close();
999
1000 var file_stream = io.FileOutStream.init(&file);
1001 // TODO: Not being set correctly, still stdout
1002 output_stream = &file_stream.stream;
1003 }
1004
1005 // ast_render(g, output_stream, g->root_import->root, 4);
1006 try output_stream.write("pub const example = 10;\n");
1007
1008 if (flags.present("enable-timing-info")) {
1009 // codegen_print_timing_info(g, stdout);
1010 try stderr.write("printing timing info for translate-c\n");
1011 }
1012}
1013
1014// cmd:help ////////////////////////////////////////////////////////////////////////////////////////
1015
1016713fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void {
1017 try stderr.write(usage);
714 try stdout.write(usage);
1018715}
1019716
1020// cmd:zen /////////////////////////////////////////////////////////////////////////////////////////
1021
1022717const info_zen =
1023718 \\
1024719 \\ * Communicate intent precisely.
......@@ -1040,8 +735,6 @@ fn cmdZen(allocator: *Allocator, args: []const []const u8) !void {
1040735 try stdout.write(info_zen);
1041736}
1042737
1043// cmd:internal ////////////////////////////////////////////////////////////////////////////////////
1044
1045738const usage_internal =
1046739 \\usage: zig internal [subcommand]
1047740 \\
......@@ -1095,3 +788,27 @@ fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void {
1095788 std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB),
1096789 );
1097790}
791
792const CliPkg = struct {
793 name: []const u8,
794 path: []const u8,
795 children: ArrayList(*CliPkg),
796 parent: ?*CliPkg,
797
798 pub fn init(allocator: *mem.Allocator, name: []const u8, path: []const u8, parent: ?*CliPkg) !*CliPkg {
799 var pkg = try allocator.create(CliPkg{
800 .name = name,
801 .path = path,
802 .children = ArrayList(*CliPkg).init(allocator),
803 .parent = parent,
804 });
805 return pkg;
806 }
807
808 pub fn deinit(self: *CliPkg) void {
809 for (self.children.toSliceConst()) |child| {
810 child.deinit();
811 }
812 self.children.deinit();
813 }
814};
src-self-hosted/module.zig+111-61
......@@ -11,9 +11,11 @@ const warn = std.debug.warn;
1111const Token = std.zig.Token;
1212const ArrayList = std.ArrayList;
1313const errmsg = @import("errmsg.zig");
14const ast = std.zig.ast;
15const event = std.event;
1416
1517pub const Module = struct {
16 allocator: *mem.Allocator,
18 loop: *event.Loop,
1719 name: Buffer,
1820 root_src_path: ?[]const u8,
1921 module: llvm.ModuleRef,
......@@ -76,6 +78,52 @@ pub const Module = struct {
7678
7779 kind: Kind,
7880
81 link_out_file: ?[]const u8,
82 events: *event.Channel(Event),
83
84 // TODO handle some of these earlier and report them in a way other than error codes
85 pub const BuildError = error{
86 OutOfMemory,
87 EndOfStream,
88 BadFd,
89 Io,
90 IsDir,
91 Unexpected,
92 SystemResources,
93 SharingViolation,
94 PathAlreadyExists,
95 FileNotFound,
96 AccessDenied,
97 PipeBusy,
98 FileTooBig,
99 SymLinkLoop,
100 ProcessFdQuotaExceeded,
101 NameTooLong,
102 SystemFdQuotaExceeded,
103 NoDevice,
104 PathNotFound,
105 NoSpaceLeft,
106 NotDir,
107 FileSystem,
108 OperationAborted,
109 IoPending,
110 BrokenPipe,
111 WouldBlock,
112 FileClosed,
113 DestinationAddressRequired,
114 DiskQuota,
115 InputOutput,
116 NoStdHandles,
117 Overflow,
118 NotSupported,
119 };
120
121 pub const Event = union(enum) {
122 Ok,
123 Fail: []errmsg.Msg,
124 Error: BuildError,
125 };
126
79127 pub const DarwinVersionMin = union(enum) {
80128 None,
81129 MacOS: []const u8,
......@@ -103,31 +151,17 @@ pub const Module = struct {
103151 LlvmIr,
104152 };
105153
106 pub const CliPkg = struct {
154 pub fn create(
155 loop: *event.Loop,
107156 name: []const u8,
108 path: []const u8,
109 children: ArrayList(*CliPkg),
110 parent: ?*CliPkg,
111
112 pub fn init(allocator: *mem.Allocator, name: []const u8, path: []const u8, parent: ?*CliPkg) !*CliPkg {
113 var pkg = try allocator.create(CliPkg);
114 pkg.name = name;
115 pkg.path = path;
116 pkg.children = ArrayList(*CliPkg).init(allocator);
117 pkg.parent = parent;
118 return pkg;
119 }
120
121 pub fn deinit(self: *CliPkg) void {
122 for (self.children.toSliceConst()) |child| {
123 child.deinit();
124 }
125 self.children.deinit();
126 }
127 };
128
129 pub fn create(allocator: *mem.Allocator, name: []const u8, root_src_path: ?[]const u8, target: *const Target, kind: Kind, build_mode: builtin.Mode, zig_lib_dir: []const u8, cache_dir: []const u8) !*Module {
130 var name_buffer = try Buffer.init(allocator, name);
157 root_src_path: ?[]const u8,
158 target: *const Target,
159 kind: Kind,
160 build_mode: builtin.Mode,
161 zig_lib_dir: []const u8,
162 cache_dir: []const u8,
163 ) !*Module {
164 var name_buffer = try Buffer.init(loop.allocator, name);
131165 errdefer name_buffer.deinit();
132166
133167 const context = c.LLVMContextCreate() orelse return error.OutOfMemory;
......@@ -139,11 +173,12 @@ pub const Module = struct {
139173 const builder = c.LLVMCreateBuilderInContext(context) orelse return error.OutOfMemory;
140174 errdefer c.LLVMDisposeBuilder(builder);
141175
142 const module_ptr = try allocator.create(Module);
143 errdefer allocator.destroy(module_ptr);
176 const events = try event.Channel(Event).create(loop, 0);
177 errdefer events.destroy();
144178
145 module_ptr.* = Module{
146 .allocator = allocator,
179 return loop.allocator.create(Module{
180 .loop = loop,
181 .events = events,
147182 .name = name_buffer,
148183 .root_src_path = root_src_path,
149184 .module = module,
......@@ -188,7 +223,7 @@ pub const Module = struct {
188223 .link_objects = [][]const u8{},
189224 .windows_subsystem_windows = false,
190225 .windows_subsystem_console = false,
191 .link_libs_list = ArrayList(*LinkLib).init(allocator),
226 .link_libs_list = ArrayList(*LinkLib).init(loop.allocator),
192227 .libc_link_lib = null,
193228 .err_color = errmsg.Color.Auto,
194229 .darwin_frameworks = [][]const u8{},
......@@ -196,8 +231,8 @@ pub const Module = struct {
196231 .test_filters = [][]const u8{},
197232 .test_name_prefix = null,
198233 .emit_file_type = Emit.Binary,
199 };
200 return module_ptr;
234 .link_out_file = null,
235 });
201236 }
202237
203238 fn dump(self: *Module) void {
......@@ -205,58 +240,70 @@ pub const Module = struct {
205240 }
206241
207242 pub fn destroy(self: *Module) void {
243 self.events.destroy();
208244 c.LLVMDisposeBuilder(self.builder);
209245 c.LLVMDisposeModule(self.module);
210246 c.LLVMContextDispose(self.context);
211247 self.name.deinit();
212248
213 self.allocator.destroy(self);
249 self.a().destroy(self);
214250 }
215251
216252 pub fn build(self: *Module) !void {
217253 if (self.llvm_argv.len != 0) {
218 var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.allocator, [][]const []const u8{
254 var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.a(), [][]const []const u8{
219255 [][]const u8{"zig (LLVM option parsing)"},
220256 self.llvm_argv,
221257 });
222258 defer c_compatible_args.deinit();
259 // TODO this sets global state
223260 c.ZigLLVMParseCommandLineOptions(self.llvm_argv.len + 1, c_compatible_args.ptr);
224261 }
225262
263 _ = try async<self.a()> self.buildAsync();
264 }
265
266 async fn buildAsync(self: *Module) void {
267 while (true) {
268 // TODO directly awaiting async should guarantee memory allocation elision
269 // TODO also async before suspending should guarantee memory allocation elision
270 (await (async self.addRootSrc() catch unreachable)) catch |err| {
271 await (async self.events.put(Event{ .Error = err }) catch unreachable);
272 return;
273 };
274 await (async self.events.put(Event.Ok) catch unreachable);
275 }
276 }
277
278 async fn addRootSrc(self: *Module) !void {
226279 const root_src_path = self.root_src_path orelse @panic("TODO handle null root src path");
227 const root_src_real_path = os.path.real(self.allocator, root_src_path) catch |err| {
280 const root_src_real_path = os.path.real(self.a(), root_src_path) catch |err| {
228281 try printError("unable to get real path '{}': {}", root_src_path, err);
229282 return err;
230283 };
231 errdefer self.allocator.free(root_src_real_path);
284 errdefer self.a().free(root_src_real_path);
232285
233 const source_code = io.readFileAlloc(self.allocator, root_src_real_path) catch |err| {
286 const source_code = io.readFileAlloc(self.a(), root_src_real_path) catch |err| {
234287 try printError("unable to open '{}': {}", root_src_real_path, err);
235288 return err;
236289 };
237 errdefer self.allocator.free(source_code);
238
239 warn("====input:====\n");
240
241 warn("{}", source_code);
242
243 warn("====parse:====\n");
290 errdefer self.a().free(source_code);
244291
245 var tree = try std.zig.parse(self.allocator, source_code);
292 var tree = try std.zig.parse(self.a(), source_code);
246293 defer tree.deinit();
247294
248 var stderr_file = try std.io.getStdErr();
249 var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file);
250 const out_stream = &stderr_file_out_stream.stream;
251
252 warn("====fmt:====\n");
253 _ = try std.zig.render(self.allocator, out_stream, &tree);
254
255 warn("====ir:====\n");
256 warn("TODO\n\n");
257
258 warn("====llvm ir:====\n");
259 self.dump();
295 //var it = tree.root_node.decls.iterator();
296 //while (it.next()) |decl_ptr| {
297 // const decl = decl_ptr.*;
298 // switch (decl.id) {
299 // ast.Node.Comptime => @panic("TODO"),
300 // ast.Node.VarDecl => @panic("TODO"),
301 // ast.Node.UseDecl => @panic("TODO"),
302 // ast.Node.FnDef => @panic("TODO"),
303 // ast.Node.TestDecl => @panic("TODO"),
304 // else => unreachable,
305 // }
306 //}
260307 }
261308
262309 pub fn link(self: *Module, out_file: ?[]const u8) !void {
......@@ -279,19 +326,22 @@ pub const Module = struct {
279326 }
280327 }
281328
282 const link_lib = try self.allocator.create(LinkLib);
283 link_lib.* = LinkLib{
329 const link_lib = try self.a().create(LinkLib{
284330 .name = name,
285331 .path = null,
286332 .provided_explicitly = provided_explicitly,
287 .symbols = ArrayList([]u8).init(self.allocator),
288 };
333 .symbols = ArrayList([]u8).init(self.a()),
334 });
289335 try self.link_libs_list.append(link_lib);
290336 if (is_libc) {
291337 self.libc_link_lib = link_lib;
292338 }
293339 return link_lib;
294340 }
341
342 fn a(self: Module) *mem.Allocator {
343 return self.loop.allocator;
344 }
295345};
296346
297347fn printError(comptime format: []const u8, args: ...) !void {
src/all_types.hpp+53-1
......@@ -234,6 +234,16 @@ enum RuntimeHintPtr {
234234 RuntimeHintPtrNonStack,
235235};
236236
237enum RuntimeHintSliceId {
238 RuntimeHintSliceIdUnknown,
239 RuntimeHintSliceIdLen,
240};
241
242struct RuntimeHintSlice {
243 enum RuntimeHintSliceId id;
244 uint64_t len;
245};
246
237247struct ConstGlobalRefs {
238248 LLVMValueRef llvm_value;
239249 LLVMValueRef llvm_global;
......@@ -248,6 +258,7 @@ struct ConstExprValue {
248258 // populated if special == ConstValSpecialStatic
249259 BigInt x_bigint;
250260 BigFloat x_bigfloat;
261 float16_t x_f16;
251262 float x_f32;
252263 double x_f64;
253264 float128_t x_f128;
......@@ -270,6 +281,7 @@ struct ConstExprValue {
270281 RuntimeHintErrorUnion rh_error_union;
271282 RuntimeHintOptional rh_maybe;
272283 RuntimeHintPtr rh_ptr;
284 RuntimeHintSlice rh_slice;
273285 } data;
274286};
275287
......@@ -1222,7 +1234,7 @@ struct TypeTableEntry {
12221234
12231235 // use these fields to make sure we don't duplicate type table entries for the same type
12241236 TypeTableEntry *pointer_parent[2]; // [0 - mut, 1 - const]
1225 TypeTableEntry *maybe_parent;
1237 TypeTableEntry *optional_parent;
12261238 TypeTableEntry *promise_parent;
12271239 TypeTableEntry *promise_frame_parent;
12281240 // If we generate a constant name value for this type, we memoize it here.
......@@ -1359,9 +1371,16 @@ enum BuiltinFnId {
13591371 BuiltinFnIdTruncate,
13601372 BuiltinFnIdIntCast,
13611373 BuiltinFnIdFloatCast,
1374 BuiltinFnIdErrSetCast,
1375 BuiltinFnIdToBytes,
1376 BuiltinFnIdFromBytes,
13621377 BuiltinFnIdIntToFloat,
13631378 BuiltinFnIdFloatToInt,
13641379 BuiltinFnIdBoolToInt,
1380 BuiltinFnIdErrToInt,
1381 BuiltinFnIdIntToErr,
1382 BuiltinFnIdEnumToInt,
1383 BuiltinFnIdIntToEnum,
13651384 BuiltinFnIdIntType,
13661385 BuiltinFnIdSetCold,
13671386 BuiltinFnIdSetRuntimeSafety,
......@@ -1416,6 +1435,7 @@ enum PanicMsgId {
14161435 PanicMsgIdIncorrectAlignment,
14171436 PanicMsgIdBadUnionField,
14181437 PanicMsgIdBadEnumValue,
1438 PanicMsgIdFloatToInt,
14191439
14201440 PanicMsgIdCount,
14211441};
......@@ -1579,6 +1599,7 @@ struct CodeGen {
15791599 TypeTableEntry *entry_i128;
15801600 TypeTableEntry *entry_isize;
15811601 TypeTableEntry *entry_usize;
1602 TypeTableEntry *entry_f16;
15821603 TypeTableEntry *entry_f32;
15831604 TypeTableEntry *entry_f64;
15841605 TypeTableEntry *entry_f128;
......@@ -2074,6 +2095,7 @@ enum IrInstructionId {
20742095 IrInstructionIdIntToPtr,
20752096 IrInstructionIdPtrToInt,
20762097 IrInstructionIdIntToEnum,
2098 IrInstructionIdEnumToInt,
20772099 IrInstructionIdIntToErr,
20782100 IrInstructionIdErrToInt,
20792101 IrInstructionIdCheckSwitchProngs,
......@@ -2119,6 +2141,9 @@ enum IrInstructionId {
21192141 IrInstructionIdMergeErrRetTraces,
21202142 IrInstructionIdMarkErrRetTracePtr,
21212143 IrInstructionIdSqrt,
2144 IrInstructionIdErrSetCast,
2145 IrInstructionIdToBytes,
2146 IrInstructionIdFromBytes,
21222147};
21232148
21242149struct IrInstruction {
......@@ -2654,6 +2679,26 @@ struct IrInstructionFloatCast {
26542679 IrInstruction *target;
26552680};
26562681
2682struct IrInstructionErrSetCast {
2683 IrInstruction base;
2684
2685 IrInstruction *dest_type;
2686 IrInstruction *target;
2687};
2688
2689struct IrInstructionToBytes {
2690 IrInstruction base;
2691
2692 IrInstruction *target;
2693};
2694
2695struct IrInstructionFromBytes {
2696 IrInstruction base;
2697
2698 IrInstruction *dest_child_type;
2699 IrInstruction *target;
2700};
2701
26572702struct IrInstructionIntToFloat {
26582703 IrInstruction base;
26592704
......@@ -2864,6 +2909,13 @@ struct IrInstructionIntToPtr {
28642909struct IrInstructionIntToEnum {
28652910 IrInstruction base;
28662911
2912 IrInstruction *dest_type;
2913 IrInstruction *target;
2914};
2915
2916struct IrInstructionEnumToInt {
2917 IrInstruction base;
2918
28672919 IrInstruction *target;
28682920};
28692921
src/analyze.cpp+53-11
......@@ -482,7 +482,7 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)
482482 return return_type->promise_frame_parent;
483483 }
484484
485 TypeTableEntry *awaiter_handle_type = get_maybe_type(g, g->builtin_types.entry_promise);
485 TypeTableEntry *awaiter_handle_type = get_optional_type(g, g->builtin_types.entry_promise);
486486 TypeTableEntry *result_ptr_type = get_pointer_to_type(g, return_type, false);
487487
488488 ZigList<const char *> field_names = {};
......@@ -513,9 +513,9 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)
513513 return entry;
514514}
515515
516TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
517 if (child_type->maybe_parent) {
518 TypeTableEntry *entry = child_type->maybe_parent;
516TypeTableEntry *get_optional_type(CodeGen *g, TypeTableEntry *child_type) {
517 if (child_type->optional_parent) {
518 TypeTableEntry *entry = child_type->optional_parent;
519519 return entry;
520520 } else {
521521 ensure_complete_type(g, child_type);
......@@ -592,7 +592,7 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
592592
593593 entry->data.maybe.child_type = child_type;
594594
595 child_type->maybe_parent = entry;
595 child_type->optional_parent = entry;
596596 return entry;
597597 }
598598}
......@@ -1470,6 +1470,17 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
14701470 calling_convention_name(fn_type_id.cc)));
14711471 return g->builtin_types.entry_invalid;
14721472 }
1473 if (param_node->data.param_decl.type != nullptr) {
1474 TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type);
1475 if (type_is_invalid(type_entry)) {
1476 return g->builtin_types.entry_invalid;
1477 }
1478 FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];
1479 param_info->type = type_entry;
1480 param_info->is_noalias = param_node->data.param_decl.is_noalias;
1481 fn_type_id.next_param_index += 1;
1482 }
1483
14731484 return get_generic_fn_type(g, &fn_type_id);
14741485 } else if (param_is_var_args) {
14751486 if (fn_type_id.cc == CallingConventionC) {
......@@ -2307,8 +2318,9 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
23072318 return;
23082319
23092320 if (enum_type->data.enumeration.zero_bits_loop_flag) {
2310 enum_type->data.enumeration.zero_bits_known = true;
2311 enum_type->data.enumeration.zero_bits_loop_flag = false;
2321 add_node_error(g, enum_type->data.enumeration.decl_node,
2322 buf_sprintf("'%s' depends on itself", buf_ptr(&enum_type->name)));
2323 enum_type->data.enumeration.is_invalid = true;
23122324 return;
23132325 }
23142326
......@@ -2984,7 +2996,7 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {
29842996 return wrong_panic_prototype(g, proto_node, fn_type);
29852997 }
29862998
2987 TypeTableEntry *optional_ptr_to_stack_trace_type = get_maybe_type(g, get_ptr_to_stack_trace_type(g));
2999 TypeTableEntry *optional_ptr_to_stack_trace_type = get_optional_type(g, get_ptr_to_stack_trace_type(g));
29883000 if (fn_type_id->param_info[1].type != optional_ptr_to_stack_trace_type) {
29893001 return wrong_panic_prototype(g, proto_node, fn_type);
29903002 }
......@@ -3716,6 +3728,7 @@ TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt
37163728}
37173729
37183730TypeEnumField *find_enum_field_by_tag(TypeTableEntry *enum_type, const BigInt *tag) {
3731 assert(enum_type->data.enumeration.zero_bits_known);
37193732 for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) {
37203733 TypeEnumField *field = &enum_type->data.enumeration.fields[i];
37213734 if (bigint_cmp(&field->value, tag) == CmpEQ) {
......@@ -4656,6 +4669,13 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
46564669 }
46574670 case TypeTableEntryIdFloat:
46584671 switch (const_val->type->data.floating.bit_count) {
4672 case 16:
4673 {
4674 uint16_t result;
4675 static_assert(sizeof(result) == sizeof(const_val->data.x_f16), "");
4676 memcpy(&result, &const_val->data.x_f16, sizeof(result));
4677 return result * 65537u;
4678 }
46594679 case 32:
46604680 {
46614681 uint32_t result;
......@@ -5116,6 +5136,9 @@ void init_const_float(ConstExprValue *const_val, TypeTableEntry *type, double va
51165136 bigfloat_init_64(&const_val->data.x_bigfloat, value);
51175137 } else if (type->id == TypeTableEntryIdFloat) {
51185138 switch (type->data.floating.bit_count) {
5139 case 16:
5140 const_val->data.x_f16 = zig_double_to_f16(value);
5141 break;
51195142 case 32:
51205143 const_val->data.x_f32 = value;
51215144 break;
......@@ -5429,6 +5452,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
54295452 case TypeTableEntryIdFloat:
54305453 assert(a->type->data.floating.bit_count == b->type->data.floating.bit_count);
54315454 switch (a->type->data.floating.bit_count) {
5455 case 16:
5456 return f16_eq(a->data.x_f16, b->data.x_f16);
54325457 case 32:
54335458 return a->data.x_f32 == b->data.x_f32;
54345459 case 64:
......@@ -5446,8 +5471,22 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
54465471 case TypeTableEntryIdPointer:
54475472 case TypeTableEntryIdFn:
54485473 return const_values_equal_ptr(a, b);
5449 case TypeTableEntryIdArray:
5450 zig_panic("TODO");
5474 case TypeTableEntryIdArray: {
5475 assert(a->type->data.array.len == b->type->data.array.len);
5476 assert(a->data.x_array.special != ConstArraySpecialUndef);
5477 assert(b->data.x_array.special != ConstArraySpecialUndef);
5478
5479 size_t len = a->type->data.array.len;
5480 ConstExprValue *a_elems = a->data.x_array.s_none.elements;
5481 ConstExprValue *b_elems = b->data.x_array.s_none.elements;
5482
5483 for (size_t i = 0; i < len; ++i) {
5484 if (!const_values_equal(&a_elems[i], &b_elems[i]))
5485 return false;
5486 }
5487
5488 return true;
5489 }
54515490 case TypeTableEntryIdStruct:
54525491 for (size_t i = 0; i < a->type->data.structure.src_field_count; i += 1) {
54535492 ConstExprValue *field_a = &a->data.x_struct.fields[i];
......@@ -5558,7 +5597,7 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, TypeT
55585597 return;
55595598 }
55605599 case ConstPtrSpecialHardCodedAddr:
5561 buf_appendf(buf, "(*%s)(%" ZIG_PRI_x64 ")", buf_ptr(&type_entry->data.pointer.child_type->name),
5600 buf_appendf(buf, "(%s)(%" ZIG_PRI_x64 ")", buf_ptr(&type_entry->name),
55625601 const_val->data.x_ptr.data.hard_coded_addr.addr);
55635602 return;
55645603 case ConstPtrSpecialDiscard:
......@@ -5602,6 +5641,9 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
56025641 return;
56035642 case TypeTableEntryIdFloat:
56045643 switch (type_entry->data.floating.bit_count) {
5644 case 16:
5645 buf_appendf(buf, "%f", zig_f16_to_double(const_val->data.x_f16));
5646 return;
56055647 case 32:
56065648 buf_appendf(buf, "%f", const_val->data.x_f32);
56075649 return;
src/analyze.hpp+1-1
......@@ -24,7 +24,7 @@ TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits);
2424TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);
2525TypeTableEntry *get_c_int_type(CodeGen *g, CIntType c_int_type);
2626TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id);
27TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type);
27TypeTableEntry *get_optional_type(CodeGen *g, TypeTableEntry *child_type);
2828TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size);
2929TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *ptr_type);
3030TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind,
src/bigfloat.cpp+8
......@@ -18,6 +18,10 @@ void bigfloat_init_128(BigFloat *dest, float128_t x) {
1818 dest->value = x;
1919}
2020
21void bigfloat_init_16(BigFloat *dest, float16_t x) {
22 f16_to_f128M(x, &dest->value);
23}
24
2125void bigfloat_init_32(BigFloat *dest, float x) {
2226 float32_t f32_val;
2327 memcpy(&f32_val, &x, sizeof(float));
......@@ -146,6 +150,10 @@ Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2) {
146150 }
147151}
148152
153float16_t bigfloat_to_f16(const BigFloat *bigfloat) {
154 return f128M_to_f16(&bigfloat->value);
155}
156
149157float bigfloat_to_f32(const BigFloat *bigfloat) {
150158 float32_t f32_value = f128M_to_f32(&bigfloat->value);
151159 float result;
src/bigfloat.hpp+2
......@@ -22,6 +22,7 @@ struct BigFloat {
2222
2323struct Buf;
2424
25void bigfloat_init_16(BigFloat *dest, float16_t x);
2526void bigfloat_init_32(BigFloat *dest, float x);
2627void bigfloat_init_64(BigFloat *dest, double x);
2728void bigfloat_init_128(BigFloat *dest, float128_t x);
......@@ -29,6 +30,7 @@ void bigfloat_init_bigfloat(BigFloat *dest, const BigFloat *x);
2930void bigfloat_init_bigint(BigFloat *dest, const BigInt *op);
3031int bigfloat_init_buf_base10(BigFloat *dest, const uint8_t *buf_ptr, size_t buf_len);
3132
33float16_t bigfloat_to_f16(const BigFloat *bigfloat);
3234float bigfloat_to_f32(const BigFloat *bigfloat);
3335double bigfloat_to_f64(const BigFloat *bigfloat);
3436float128_t bigfloat_to_f128(const BigFloat *bigfloat);
src/bigint.cpp+9-4
......@@ -1683,10 +1683,15 @@ void bigint_incr(BigInt *x) {
16831683 bigint_init_unsigned(x, 1);
16841684 return;
16851685 }
1686
1687 if (x->digit_count == 1 && x->data.digit != UINT64_MAX) {
1688 x->data.digit += 1;
1689 return;
1686
1687 if (x->digit_count == 1) {
1688 if (x->is_negative && x->data.digit != 0) {
1689 x->data.digit -= 1;
1690 return;
1691 } else if (!x->is_negative && x->data.digit != UINT64_MAX) {
1692 x->data.digit += 1;
1693 return;
1694 }
16901695 }
16911696
16921697 BigInt copy;
src/codegen.cpp+89-58
......@@ -17,6 +17,7 @@
1717#include "os.hpp"
1818#include "translate_c.hpp"
1919#include "target.hpp"
20#include "util.hpp"
2021#include "zig_llvm.h"
2122
2223#include <stdio.h>
......@@ -865,6 +866,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
865866 return buf_create_from_str("access of inactive union field");
866867 case PanicMsgIdBadEnumValue:
867868 return buf_create_from_str("invalid enum value");
869 case PanicMsgIdFloatToInt:
870 return buf_create_from_str("integer part of floating point value out of bounds");
868871 }
869872 zig_unreachable();
870873}
......@@ -1644,7 +1647,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, T
16441647 return trunc_val;
16451648 }
16461649 LLVMValueRef orig_val;
1647 if (actual_type->data.integral.is_signed) {
1650 if (wanted_type->data.integral.is_signed) {
16481651 orig_val = LLVMBuildSExt(g->builder, trunc_val, actual_type->type_ref, "");
16491652 } else {
16501653 orig_val = LLVMBuildZExt(g->builder, trunc_val, actual_type->type_ref, "");
......@@ -2207,12 +2210,12 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
22072210 } else if (type_entry->id == TypeTableEntryIdInt) {
22082211 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, type_entry->data.integral.is_signed);
22092212 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
2210 } else if (type_entry->id == TypeTableEntryIdEnum) {
2211 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
2212 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
2213 } else if (type_entry->id == TypeTableEntryIdErrorSet ||
2213 } else if (type_entry->id == TypeTableEntryIdEnum ||
2214 type_entry->id == TypeTableEntryIdErrorSet ||
22142215 type_entry->id == TypeTableEntryIdPointer ||
2215 type_entry->id == TypeTableEntryIdBool)
2216 type_entry->id == TypeTableEntryIdBool ||
2217 type_entry->id == TypeTableEntryIdPromise ||
2218 type_entry->id == TypeTableEntryIdFn)
22162219 {
22172220 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
22182221 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
......@@ -2509,15 +2512,41 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
25092512 } else {
25102513 return LLVMBuildUIToFP(g->builder, expr_val, wanted_type->type_ref, "");
25112514 }
2512 case CastOpFloatToInt:
2515 case CastOpFloatToInt: {
25132516 assert(wanted_type->id == TypeTableEntryIdInt);
25142517 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &cast_instruction->base));
2518
2519 bool want_safety = ir_want_runtime_safety(g, &cast_instruction->base);
2520
2521 LLVMValueRef result;
25152522 if (wanted_type->data.integral.is_signed) {
2516 return LLVMBuildFPToSI(g->builder, expr_val, wanted_type->type_ref, "");
2523 result = LLVMBuildFPToSI(g->builder, expr_val, wanted_type->type_ref, "");
25172524 } else {
2518 return LLVMBuildFPToUI(g->builder, expr_val, wanted_type->type_ref, "");
2525 result = LLVMBuildFPToUI(g->builder, expr_val, wanted_type->type_ref, "");
25192526 }
25202527
2528 if (want_safety) {
2529 LLVMValueRef back_to_float;
2530 if (wanted_type->data.integral.is_signed) {
2531 back_to_float = LLVMBuildSIToFP(g->builder, result, LLVMTypeOf(expr_val), "");
2532 } else {
2533 back_to_float = LLVMBuildUIToFP(g->builder, result, LLVMTypeOf(expr_val), "");
2534 }
2535 LLVMValueRef difference = LLVMBuildFSub(g->builder, expr_val, back_to_float, "");
2536 LLVMValueRef one_pos = LLVMConstReal(LLVMTypeOf(expr_val), 1.0f);
2537 LLVMValueRef one_neg = LLVMConstReal(LLVMTypeOf(expr_val), -1.0f);
2538 LLVMValueRef ok_bit_pos = LLVMBuildFCmp(g->builder, LLVMRealOLT, difference, one_pos, "");
2539 LLVMValueRef ok_bit_neg = LLVMBuildFCmp(g->builder, LLVMRealOGT, difference, one_neg, "");
2540 LLVMValueRef ok_bit = LLVMBuildAnd(g->builder, ok_bit_pos, ok_bit_neg, "");
2541 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "FloatCheckOk");
2542 LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "FloatCheckFail");
2543 LLVMBuildCondBr(g->builder, ok_bit, ok_block, bad_block);
2544 LLVMPositionBuilderAtEnd(g->builder, bad_block);
2545 gen_safety_crash(g, PanicMsgIdFloatToInt);
2546 LLVMPositionBuilderAtEnd(g->builder, ok_block);
2547 }
2548 return result;
2549 }
25212550 case CastOpBoolToInt:
25222551 assert(wanted_type->id == TypeTableEntryIdInt);
25232552 assert(actual_type->id == TypeTableEntryIdBool);
......@@ -2607,8 +2636,25 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable,
26072636 TypeTableEntry *tag_int_type = wanted_type->data.enumeration.tag_int_type;
26082637
26092638 LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
2610 return gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
2639 LLVMValueRef tag_int_value = gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
26112640 instruction->target->value.type, tag_int_type, target_val);
2641
2642 if (ir_want_runtime_safety(g, &instruction->base)) {
2643 LLVMBasicBlockRef bad_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadValue");
2644 LLVMBasicBlockRef ok_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "OkValue");
2645 size_t field_count = wanted_type->data.enumeration.src_field_count;
2646 LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count);
2647 for (size_t field_i = 0; field_i < field_count; field_i += 1) {
2648 LLVMValueRef this_tag_int_value = bigint_to_llvm_const(tag_int_type->type_ref,
2649 &wanted_type->data.enumeration.fields[field_i].value);
2650 LLVMAddCase(switch_instr, this_tag_int_value, ok_value_block);
2651 }
2652 LLVMPositionBuilderAtEnd(g->builder, bad_value_block);
2653 gen_safety_crash(g, PanicMsgIdBadEnumValue);
2654
2655 LLVMPositionBuilderAtEnd(g->builder, ok_value_block);
2656 }
2657 return tag_int_value;
26122658}
26132659
26142660static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, IrInstructionIntToErr *instruction) {
......@@ -4638,6 +4684,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
46384684 case IrInstructionIdIntToFloat:
46394685 case IrInstructionIdFloatToInt:
46404686 case IrInstructionIdBoolToInt:
4687 case IrInstructionIdErrSetCast:
4688 case IrInstructionIdFromBytes:
4689 case IrInstructionIdToBytes:
4690 case IrInstructionIdEnumToInt:
46414691 zig_unreachable();
46424692
46434693 case IrInstructionIdReturn:
......@@ -5090,6 +5140,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
50905140 const_val->data.x_err_set->value, false);
50915141 case TypeTableEntryIdFloat:
50925142 switch (type_entry->data.floating.bit_count) {
5143 case 16:
5144 return LLVMConstReal(type_entry->type_ref, zig_f16_to_double(const_val->data.x_f16));
50935145 case 32:
50945146 return LLVMConstReal(type_entry->type_ref, const_val->data.x_f32);
50955147 case 64:
......@@ -6056,58 +6108,30 @@ static void define_builtin_types(CodeGen *g) {
60566108 g->builtin_types.entry_usize = entry;
60576109 }
60586110 }
6059 {
6060 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
6061 entry->type_ref = LLVMFloatType();
6062 buf_init_from_str(&entry->name, "f32");
6063 entry->data.floating.bit_count = 32;
6064
6065 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
6066 entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
6067 debug_size_in_bits,
6068 ZigLLVMEncoding_DW_ATE_float());
6069 g->builtin_types.entry_f32 = entry;
6070 g->primitive_type_table.put(&entry->name, entry);
6071 }
6072 {
6073 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
6074 entry->type_ref = LLVMDoubleType();
6075 buf_init_from_str(&entry->name, "f64");
6076 entry->data.floating.bit_count = 64;
60776111
6078 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
6079 entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
6080 debug_size_in_bits,
6081 ZigLLVMEncoding_DW_ATE_float());
6082 g->builtin_types.entry_f64 = entry;
6083 g->primitive_type_table.put(&entry->name, entry);
6084 }
6085 {
6112 auto add_fp_entry = [] (CodeGen *g,
6113 const char *name,
6114 uint32_t bit_count,
6115 LLVMTypeRef type_ref,
6116 TypeTableEntry **field) {
60866117 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
6087 entry->type_ref = LLVMFP128Type();
6088 buf_init_from_str(&entry->name, "f128");
6089 entry->data.floating.bit_count = 128;
6118 entry->type_ref = type_ref;
6119 buf_init_from_str(&entry->name, name);
6120 entry->data.floating.bit_count = bit_count;
60906121
60916122 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
60926123 entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
60936124 debug_size_in_bits,
60946125 ZigLLVMEncoding_DW_ATE_float());
6095 g->builtin_types.entry_f128 = entry;
6126 *field = entry;
60966127 g->primitive_type_table.put(&entry->name, entry);
6097 }
6098 {
6099 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
6100 entry->type_ref = LLVMX86FP80Type();
6101 buf_init_from_str(&entry->name, "c_longdouble");
6102 entry->data.floating.bit_count = 80;
6128 };
6129 add_fp_entry(g, "f16", 16, LLVMHalfType(), &g->builtin_types.entry_f16);
6130 add_fp_entry(g, "f32", 32, LLVMFloatType(), &g->builtin_types.entry_f32);
6131 add_fp_entry(g, "f64", 64, LLVMDoubleType(), &g->builtin_types.entry_f64);
6132 add_fp_entry(g, "f128", 128, LLVMFP128Type(), &g->builtin_types.entry_f128);
6133 add_fp_entry(g, "c_longdouble", 80, LLVMX86FP80Type(), &g->builtin_types.entry_c_longdouble);
61036134
6104 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
6105 entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
6106 debug_size_in_bits,
6107 ZigLLVMEncoding_DW_ATE_float());
6108 g->builtin_types.entry_c_longdouble = entry;
6109 g->primitive_type_table.put(&entry->name, entry);
6110 }
61116135 {
61126136 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVoid);
61136137 entry->type_ref = LLVMVoidType();
......@@ -6231,6 +6255,10 @@ static void define_builtin_fns(CodeGen *g) {
62316255 create_builtin_fn(g, BuiltinFnIdIntToFloat, "intToFloat", 2);
62326256 create_builtin_fn(g, BuiltinFnIdFloatToInt, "floatToInt", 2);
62336257 create_builtin_fn(g, BuiltinFnIdBoolToInt, "boolToInt", 1);
6258 create_builtin_fn(g, BuiltinFnIdErrToInt, "errorToInt", 1);
6259 create_builtin_fn(g, BuiltinFnIdIntToErr, "intToError", 1);
6260 create_builtin_fn(g, BuiltinFnIdEnumToInt, "enumToInt", 1);
6261 create_builtin_fn(g, BuiltinFnIdIntToEnum, "intToEnum", 2);
62346262 create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1);
62356263 create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
62366264 create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int
......@@ -6267,6 +6295,9 @@ static void define_builtin_fns(CodeGen *g) {
62676295 create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0);
62686296 create_builtin_fn(g, BuiltinFnIdAtomicRmw, "atomicRmw", 5);
62696297 create_builtin_fn(g, BuiltinFnIdAtomicLoad, "atomicLoad", 3);
6298 create_builtin_fn(g, BuiltinFnIdErrSetCast, "errSetCast", 2);
6299 create_builtin_fn(g, BuiltinFnIdToBytes, "sliceToBytes", 1);
6300 create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2);
62706301}
62716302
62726303static const char *bool_to_str(bool b) {
......@@ -6538,7 +6569,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
65386569 "\n"
65396570 " pub const Union = struct {\n"
65406571 " layout: ContainerLayout,\n"
6541 " tag_type: type,\n"
6572 " tag_type: ?type,\n"
65426573 " fields: []UnionField,\n"
65436574 " defs: []Definition,\n"
65446575 " };\n"
......@@ -6555,20 +6586,20 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
65556586 " pub const FnArg = struct {\n"
65566587 " is_generic: bool,\n"
65576588 " is_noalias: bool,\n"
6558 " arg_type: type,\n"
6589 " arg_type: ?type,\n"
65596590 " };\n"
65606591 "\n"
65616592 " pub const Fn = struct {\n"
65626593 " calling_convention: CallingConvention,\n"
65636594 " is_generic: bool,\n"
65646595 " is_var_args: bool,\n"
6565 " return_type: type,\n"
6566 " async_allocator_type: type,\n"
6596 " return_type: ?type,\n"
6597 " async_allocator_type: ?type,\n"
65676598 " args: []FnArg,\n"
65686599 " };\n"
65696600 "\n"
65706601 " pub const Promise = struct {\n"
6571 " child: type,\n"
6602 " child: ?type,\n"
65726603 " };\n"
65736604 "\n"
65746605 " pub const Definition = struct {\n"
src/ir.cpp+943-571
......@@ -11,9 +11,10 @@
1111#include "ir.hpp"
1212#include "ir_print.hpp"
1313#include "os.hpp"
14#include "translate_c.hpp"
1514#include "range_set.hpp"
1615#include "softfloat.hpp"
16#include "translate_c.hpp"
17#include "util.hpp"
1718
1819struct IrExecContext {
1920 ConstExprValue *mem_slot_list;
......@@ -65,12 +66,7 @@ enum ConstCastResultId {
6566 ConstCastResultIdNullWrapPtr,
6667};
6768
68struct ConstCastErrSetMismatch {
69 ZigList<ErrorTableEntry *> missing_errors;
70};
71
7269struct ConstCastOnly;
73
7470struct ConstCastArg {
7571 size_t arg_index;
7672 ConstCastOnly *child;
......@@ -80,15 +76,22 @@ struct ConstCastArgNoAlias {
8076 size_t arg_index;
8177};
8278
79struct ConstCastOptionalMismatch;
80struct ConstCastPointerMismatch;
81struct ConstCastSliceMismatch;
82struct ConstCastErrUnionErrSetMismatch;
83struct ConstCastErrUnionPayloadMismatch;
84struct ConstCastErrSetMismatch;
85
8386struct ConstCastOnly {
8487 ConstCastResultId id;
8588 union {
86 ConstCastErrSetMismatch error_set;
87 ConstCastOnly *pointer_child;
88 ConstCastOnly *slice_child;
89 ConstCastOnly *optional_child;
90 ConstCastOnly *error_union_payload;
91 ConstCastOnly *error_union_error_set;
89 ConstCastErrSetMismatch *error_set_mismatch;
90 ConstCastPointerMismatch *pointer_mismatch;
91 ConstCastSliceMismatch *slice_mismatch;
92 ConstCastOptionalMismatch *optional;
93 ConstCastErrUnionPayloadMismatch *error_union_payload;
94 ConstCastErrUnionErrSetMismatch *error_union_error_set;
9295 ConstCastOnly *return_type;
9396 ConstCastOnly *async_allocator_type;
9497 ConstCastOnly *null_wrap_ptr_child;
......@@ -97,6 +100,39 @@ struct ConstCastOnly {
97100 } data;
98101};
99102
103struct ConstCastOptionalMismatch {
104 ConstCastOnly child;
105 TypeTableEntry *wanted_child;
106 TypeTableEntry *actual_child;
107};
108
109struct ConstCastPointerMismatch {
110 ConstCastOnly child;
111 TypeTableEntry *wanted_child;
112 TypeTableEntry *actual_child;
113};
114
115struct ConstCastSliceMismatch {
116 ConstCastOnly child;
117 TypeTableEntry *wanted_child;
118 TypeTableEntry *actual_child;
119};
120
121struct ConstCastErrUnionErrSetMismatch {
122 ConstCastOnly child;
123 TypeTableEntry *wanted_err_set;
124 TypeTableEntry *actual_err_set;
125};
126
127struct ConstCastErrUnionPayloadMismatch {
128 ConstCastOnly child;
129 TypeTableEntry *wanted_payload;
130 TypeTableEntry *actual_payload;
131};
132
133struct ConstCastErrSetMismatch {
134 ZigList<ErrorTableEntry *> missing_errors;
135};
100136
101137static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);
102138static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval);
......@@ -468,6 +504,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFloatCast *) {
468504 return IrInstructionIdFloatCast;
469505}
470506
507static constexpr IrInstructionId ir_instruction_id(IrInstructionErrSetCast *) {
508 return IrInstructionIdErrSetCast;
509}
510
511static constexpr IrInstructionId ir_instruction_id(IrInstructionToBytes *) {
512 return IrInstructionIdToBytes;
513}
514
515static constexpr IrInstructionId ir_instruction_id(IrInstructionFromBytes *) {
516 return IrInstructionIdFromBytes;
517}
518
471519static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToFloat *) {
472520 return IrInstructionIdIntToFloat;
473521}
......@@ -588,6 +636,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToEnum *) {
588636 return IrInstructionIdIntToEnum;
589637}
590638
639static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumToInt *) {
640 return IrInstructionIdEnumToInt;
641}
642
591643static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToErr *) {
592644 return IrInstructionIdIntToErr;
593645}
......@@ -1941,6 +1993,37 @@ static IrInstruction *ir_build_float_cast(IrBuilder *irb, Scope *scope, AstNode
19411993 return &instruction->base;
19421994}
19431995
1996static IrInstruction *ir_build_err_set_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_type, IrInstruction *target) {
1997 IrInstructionErrSetCast *instruction = ir_build_instruction<IrInstructionErrSetCast>(irb, scope, source_node);
1998 instruction->dest_type = dest_type;
1999 instruction->target = target;
2000
2001 ir_ref_instruction(dest_type, irb->current_basic_block);
2002 ir_ref_instruction(target, irb->current_basic_block);
2003
2004 return &instruction->base;
2005}
2006
2007static IrInstruction *ir_build_to_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target) {
2008 IrInstructionToBytes *instruction = ir_build_instruction<IrInstructionToBytes>(irb, scope, source_node);
2009 instruction->target = target;
2010
2011 ir_ref_instruction(target, irb->current_basic_block);
2012
2013 return &instruction->base;
2014}
2015
2016static IrInstruction *ir_build_from_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_child_type, IrInstruction *target) {
2017 IrInstructionFromBytes *instruction = ir_build_instruction<IrInstructionFromBytes>(irb, scope, source_node);
2018 instruction->dest_child_type = dest_child_type;
2019 instruction->target = target;
2020
2021 ir_ref_instruction(dest_child_type, irb->current_basic_block);
2022 ir_ref_instruction(target, irb->current_basic_block);
2023
2024 return &instruction->base;
2025}
2026
19442027static IrInstruction *ir_build_int_to_float(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_type, IrInstruction *target) {
19452028 IrInstructionIntToFloat *instruction = ir_build_instruction<IrInstructionIntToFloat>(irb, scope, source_node);
19462029 instruction->dest_type = dest_type;
......@@ -2335,10 +2418,26 @@ static IrInstruction *ir_build_ptr_to_int(IrBuilder *irb, Scope *scope, AstNode
23352418}
23362419
23372420static IrInstruction *ir_build_int_to_enum(IrBuilder *irb, Scope *scope, AstNode *source_node,
2338 IrInstruction *target)
2421 IrInstruction *dest_type, IrInstruction *target)
23392422{
23402423 IrInstructionIntToEnum *instruction = ir_build_instruction<IrInstructionIntToEnum>(
23412424 irb, scope, source_node);
2425 instruction->dest_type = dest_type;
2426 instruction->target = target;
2427
2428 if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block);
2429 ir_ref_instruction(target, irb->current_basic_block);
2430
2431 return &instruction->base;
2432}
2433
2434
2435
2436static IrInstruction *ir_build_enum_to_int(IrBuilder *irb, Scope *scope, AstNode *source_node,
2437 IrInstruction *target)
2438{
2439 IrInstructionEnumToInt *instruction = ir_build_instruction<IrInstructionEnumToInt>(
2440 irb, scope, source_node);
23422441 instruction->target = target;
23432442
23442443 ir_ref_instruction(target, irb->current_basic_block);
......@@ -2946,7 +3045,7 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
29463045
29473046 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_field_ptr, return_value);
29483047 IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node,
2949 get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
3048 get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
29503049 // TODO replace replacement_value with @intToPtr(?promise, 0x1) when it doesn't crash zig
29513050 IrInstruction *replacement_value = irb->exec->coro_handle;
29523051 IrInstruction *maybe_await_handle = ir_build_atomic_rmw(irb, scope, node,
......@@ -4054,6 +4153,46 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40544153 IrInstruction *result = ir_build_float_cast(irb, scope, node, arg0_value, arg1_value);
40554154 return ir_lval_wrap(irb, scope, result, lval);
40564155 }
4156 case BuiltinFnIdErrSetCast:
4157 {
4158 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4159 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4160 if (arg0_value == irb->codegen->invalid_instruction)
4161 return arg0_value;
4162
4163 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4164 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4165 if (arg1_value == irb->codegen->invalid_instruction)
4166 return arg1_value;
4167
4168 IrInstruction *result = ir_build_err_set_cast(irb, scope, node, arg0_value, arg1_value);
4169 return ir_lval_wrap(irb, scope, result, lval);
4170 }
4171 case BuiltinFnIdFromBytes:
4172 {
4173 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4174 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4175 if (arg0_value == irb->codegen->invalid_instruction)
4176 return arg0_value;
4177
4178 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4179 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4180 if (arg1_value == irb->codegen->invalid_instruction)
4181 return arg1_value;
4182
4183 IrInstruction *result = ir_build_from_bytes(irb, scope, node, arg0_value, arg1_value);
4184 return ir_lval_wrap(irb, scope, result, lval);
4185 }
4186 case BuiltinFnIdToBytes:
4187 {
4188 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4189 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4190 if (arg0_value == irb->codegen->invalid_instruction)
4191 return arg0_value;
4192
4193 IrInstruction *result = ir_build_to_bytes(irb, scope, node, arg0_value);
4194 return ir_lval_wrap(irb, scope, result, lval);
4195 }
40574196 case BuiltinFnIdIntToFloat:
40584197 {
40594198 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
......@@ -4084,6 +4223,26 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40844223 IrInstruction *result = ir_build_float_to_int(irb, scope, node, arg0_value, arg1_value);
40854224 return ir_lval_wrap(irb, scope, result, lval);
40864225 }
4226 case BuiltinFnIdErrToInt:
4227 {
4228 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4229 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4230 if (arg0_value == irb->codegen->invalid_instruction)
4231 return arg0_value;
4232
4233 IrInstruction *result = ir_build_err_to_int(irb, scope, node, arg0_value);
4234 return ir_lval_wrap(irb, scope, result, lval);
4235 }
4236 case BuiltinFnIdIntToErr:
4237 {
4238 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4239 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4240 if (arg0_value == irb->codegen->invalid_instruction)
4241 return arg0_value;
4242
4243 IrInstruction *result = ir_build_int_to_err(irb, scope, node, arg0_value);
4244 return ir_lval_wrap(irb, scope, result, lval);
4245 }
40874246 case BuiltinFnIdBoolToInt:
40884247 {
40894248 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
......@@ -4605,6 +4764,31 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
46054764 // this value does not mean anything since we passed non-null values for other arg
46064765 AtomicOrderMonotonic);
46074766 }
4767 case BuiltinFnIdIntToEnum:
4768 {
4769 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4770 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4771 if (arg0_value == irb->codegen->invalid_instruction)
4772 return arg0_value;
4773
4774 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4775 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4776 if (arg1_value == irb->codegen->invalid_instruction)
4777 return arg1_value;
4778
4779 IrInstruction *result = ir_build_int_to_enum(irb, scope, node, arg0_value, arg1_value);
4780 return ir_lval_wrap(irb, scope, result, lval);
4781 }
4782 case BuiltinFnIdEnumToInt:
4783 {
4784 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4785 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4786 if (arg0_value == irb->codegen->invalid_instruction)
4787 return arg0_value;
4788
4789 IrInstruction *result = ir_build_enum_to_int(irb, scope, node, arg0_value);
4790 return ir_lval_wrap(irb, scope, result, lval);
4791 }
46084792 }
46094793 zig_unreachable();
46104794}
......@@ -6471,7 +6655,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
64716655 ir_build_store_ptr(irb, parent_scope, node, result_ptr_field_ptr, my_result_var_ptr);
64726656 IrInstruction *save_token = ir_build_coro_save(irb, parent_scope, node, irb->exec->coro_handle);
64736657 IrInstruction *promise_type_val = ir_build_const_type(irb, parent_scope, node,
6474 get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
6658 get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
64756659 IrInstruction *maybe_await_handle = ir_build_atomic_rmw(irb, parent_scope, node,
64766660 promise_type_val, awaiter_field_ptr, nullptr, irb->exec->coro_handle, nullptr,
64776661 AtomicRmwOp_xchg, AtomicOrderSeqCst);
......@@ -6805,7 +6989,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
68056989 VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
68066990 IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);
68076991 IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node,
6808 get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
6992 get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
68096993 ir_build_var_decl(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value);
68106994 irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var);
68116995
......@@ -6928,6 +7112,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
69287112 IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr);
69297113 ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr);
69307114 }
7115 // Before we destroy the coroutine frame, we need to load the target promise into
7116 // a register or local variable which does not get spilled into the frame,
7117 // otherwise llvm tries to access memory inside the destroyed frame.
7118 IrInstruction *unwrapped_await_handle_ptr = ir_build_unwrap_maybe(irb, scope, node,
7119 irb->exec->await_handle_var_ptr, false);
7120 IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr);
69317121 ir_build_br(irb, scope, node, check_free_block, const_bool_false);
69327122
69337123 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);
......@@ -6942,6 +7132,14 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
69427132 incoming_values[1] = const_bool_true;
69437133 IrInstruction *resume_awaiter = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
69447134
7135 IrBasicBlock **merge_incoming_blocks = allocate<IrBasicBlock *>(2);
7136 IrInstruction **merge_incoming_values = allocate<IrInstruction *>(2);
7137 merge_incoming_blocks[0] = irb->exec->coro_final_cleanup_block;
7138 merge_incoming_values[0] = ir_build_const_undefined(irb, scope, node);
7139 merge_incoming_blocks[1] = irb->exec->coro_normal_final;
7140 merge_incoming_values[1] = await_handle_in_block;
7141 IrInstruction *awaiter_handle = ir_build_phi(irb, scope, node, 2, merge_incoming_blocks, merge_incoming_values);
7142
69457143 Buf *free_field_name = buf_create_from_str(ASYNC_FREE_FIELD_NAME);
69467144 IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node,
69477145 ImplicitAllocatorIdLocalVar);
......@@ -6968,9 +7166,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
69687166 ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false);
69697167
69707168 ir_set_cursor_at_end_and_append_block(irb, resume_block);
6971 IrInstruction *unwrapped_await_handle_ptr = ir_build_unwrap_maybe(irb, scope, node,
6972 irb->exec->await_handle_var_ptr, false);
6973 IrInstruction *awaiter_handle = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr);
69747169 ir_build_coro_resume(irb, scope, node, awaiter_handle);
69757170 ir_build_br(irb, scope, node, irb->exec->coro_suspend_block, const_bool_false);
69767171 }
......@@ -7055,6 +7250,11 @@ static bool float_has_fraction(ConstExprValue *const_val) {
70557250 return bigfloat_has_fraction(&const_val->data.x_bigfloat);
70567251 } else if (const_val->type->id == TypeTableEntryIdFloat) {
70577252 switch (const_val->type->data.floating.bit_count) {
7253 case 16:
7254 {
7255 float16_t floored = f16_roundToInt(const_val->data.x_f16, softfloat_round_minMag, false);
7256 return !f16_eq(floored, const_val->data.x_f16);
7257 }
70587258 case 32:
70597259 return floorf(const_val->data.x_f32) != const_val->data.x_f32;
70607260 case 64:
......@@ -7078,6 +7278,9 @@ static void float_append_buf(Buf *buf, ConstExprValue *const_val) {
70787278 bigfloat_append_buf(buf, &const_val->data.x_bigfloat);
70797279 } else if (const_val->type->id == TypeTableEntryIdFloat) {
70807280 switch (const_val->type->data.floating.bit_count) {
7281 case 16:
7282 buf_appendf(buf, "%f", zig_f16_to_double(const_val->data.x_f16));
7283 break;
70817284 case 32:
70827285 buf_appendf(buf, "%f", const_val->data.x_f32);
70837286 break;
......@@ -7113,6 +7316,17 @@ static void float_init_bigint(BigInt *bigint, ConstExprValue *const_val) {
71137316 bigint_init_bigfloat(bigint, &const_val->data.x_bigfloat);
71147317 } else if (const_val->type->id == TypeTableEntryIdFloat) {
71157318 switch (const_val->type->data.floating.bit_count) {
7319 case 16:
7320 {
7321 double x = zig_f16_to_double(const_val->data.x_f16);
7322 if (x >= 0) {
7323 bigint_init_unsigned(bigint, (uint64_t)x);
7324 } else {
7325 bigint_init_unsigned(bigint, (uint64_t)-x);
7326 bigint->is_negative = true;
7327 }
7328 break;
7329 }
71167330 case 32:
71177331 if (const_val->data.x_f32 >= 0) {
71187332 bigint_init_unsigned(bigint, (uint64_t)(const_val->data.x_f32));
......@@ -7149,6 +7363,9 @@ static void float_init_bigfloat(ConstExprValue *dest_val, BigFloat *bigfloat) {
71497363 bigfloat_init_bigfloat(&dest_val->data.x_bigfloat, bigfloat);
71507364 } else if (dest_val->type->id == TypeTableEntryIdFloat) {
71517365 switch (dest_val->type->data.floating.bit_count) {
7366 case 16:
7367 dest_val->data.x_f16 = bigfloat_to_f16(bigfloat);
7368 break;
71527369 case 32:
71537370 dest_val->data.x_f32 = bigfloat_to_f32(bigfloat);
71547371 break;
......@@ -7166,11 +7383,39 @@ static void float_init_bigfloat(ConstExprValue *dest_val, BigFloat *bigfloat) {
71667383 }
71677384}
71687385
7386static void float_init_f16(ConstExprValue *dest_val, float16_t x) {
7387 if (dest_val->type->id == TypeTableEntryIdComptimeFloat) {
7388 bigfloat_init_16(&dest_val->data.x_bigfloat, x);
7389 } else if (dest_val->type->id == TypeTableEntryIdFloat) {
7390 switch (dest_val->type->data.floating.bit_count) {
7391 case 16:
7392 dest_val->data.x_f16 = x;
7393 break;
7394 case 32:
7395 dest_val->data.x_f32 = zig_f16_to_double(x);
7396 break;
7397 case 64:
7398 dest_val->data.x_f64 = zig_f16_to_double(x);
7399 break;
7400 case 128:
7401 f16_to_f128M(x, &dest_val->data.x_f128);
7402 break;
7403 default:
7404 zig_unreachable();
7405 }
7406 } else {
7407 zig_unreachable();
7408 }
7409}
7410
71697411static void float_init_f32(ConstExprValue *dest_val, float x) {
71707412 if (dest_val->type->id == TypeTableEntryIdComptimeFloat) {
71717413 bigfloat_init_32(&dest_val->data.x_bigfloat, x);
71727414 } else if (dest_val->type->id == TypeTableEntryIdFloat) {
71737415 switch (dest_val->type->data.floating.bit_count) {
7416 case 16:
7417 dest_val->data.x_f16 = zig_double_to_f16(x);
7418 break;
71747419 case 32:
71757420 dest_val->data.x_f32 = x;
71767421 break;
......@@ -7197,6 +7442,9 @@ static void float_init_f64(ConstExprValue *dest_val, double x) {
71977442 bigfloat_init_64(&dest_val->data.x_bigfloat, x);
71987443 } else if (dest_val->type->id == TypeTableEntryIdFloat) {
71997444 switch (dest_val->type->data.floating.bit_count) {
7445 case 16:
7446 dest_val->data.x_f16 = zig_double_to_f16(x);
7447 break;
72007448 case 32:
72017449 dest_val->data.x_f32 = x;
72027450 break;
......@@ -7223,6 +7471,9 @@ static void float_init_f128(ConstExprValue *dest_val, float128_t x) {
72237471 bigfloat_init_128(&dest_val->data.x_bigfloat, x);
72247472 } else if (dest_val->type->id == TypeTableEntryIdFloat) {
72257473 switch (dest_val->type->data.floating.bit_count) {
7474 case 16:
7475 dest_val->data.x_f16 = f128M_to_f16(&x);
7476 break;
72267477 case 32:
72277478 {
72287479 float32_t f32_val = f128M_to_f32(&x);
......@@ -7253,6 +7504,9 @@ static void float_init_float(ConstExprValue *dest_val, ConstExprValue *src_val)
72537504 float_init_bigfloat(dest_val, &src_val->data.x_bigfloat);
72547505 } else if (src_val->type->id == TypeTableEntryIdFloat) {
72557506 switch (src_val->type->data.floating.bit_count) {
7507 case 16:
7508 float_init_f16(dest_val, src_val->data.x_f16);
7509 break;
72567510 case 32:
72577511 float_init_f32(dest_val, src_val->data.x_f32);
72587512 break;
......@@ -7276,6 +7530,14 @@ static Cmp float_cmp(ConstExprValue *op1, ConstExprValue *op2) {
72767530 return bigfloat_cmp(&op1->data.x_bigfloat, &op2->data.x_bigfloat);
72777531 } else if (op1->type->id == TypeTableEntryIdFloat) {
72787532 switch (op1->type->data.floating.bit_count) {
7533 case 16:
7534 if (f16_lt(op1->data.x_f16, op2->data.x_f16)) {
7535 return CmpLT;
7536 } else if (f16_lt(op2->data.x_f16, op1->data.x_f16)) {
7537 return CmpGT;
7538 } else {
7539 return CmpEQ;
7540 }
72797541 case 32:
72807542 if (op1->data.x_f32 > op2->data.x_f32) {
72817543 return CmpGT;
......@@ -7313,6 +7575,17 @@ static Cmp float_cmp_zero(ConstExprValue *op) {
73137575 return bigfloat_cmp_zero(&op->data.x_bigfloat);
73147576 } else if (op->type->id == TypeTableEntryIdFloat) {
73157577 switch (op->type->data.floating.bit_count) {
7578 case 16:
7579 {
7580 const float16_t zero = zig_double_to_f16(0);
7581 if (f16_lt(op->data.x_f16, zero)) {
7582 return CmpLT;
7583 } else if (f16_lt(zero, op->data.x_f16)) {
7584 return CmpGT;
7585 } else {
7586 return CmpEQ;
7587 }
7588 }
73167589 case 32:
73177590 if (op->data.x_f32 < 0.0) {
73187591 return CmpLT;
......@@ -7354,6 +7627,9 @@ static void float_add(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
73547627 bigfloat_add(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
73557628 } else if (op1->type->id == TypeTableEntryIdFloat) {
73567629 switch (op1->type->data.floating.bit_count) {
7630 case 16:
7631 out_val->data.x_f16 = f16_add(op1->data.x_f16, op2->data.x_f16);
7632 return;
73577633 case 32:
73587634 out_val->data.x_f32 = op1->data.x_f32 + op2->data.x_f32;
73597635 return;
......@@ -7378,6 +7654,9 @@ static void float_sub(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
73787654 bigfloat_sub(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
73797655 } else if (op1->type->id == TypeTableEntryIdFloat) {
73807656 switch (op1->type->data.floating.bit_count) {
7657 case 16:
7658 out_val->data.x_f16 = f16_sub(op1->data.x_f16, op2->data.x_f16);
7659 return;
73817660 case 32:
73827661 out_val->data.x_f32 = op1->data.x_f32 - op2->data.x_f32;
73837662 return;
......@@ -7402,6 +7681,9 @@ static void float_mul(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
74027681 bigfloat_mul(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
74037682 } else if (op1->type->id == TypeTableEntryIdFloat) {
74047683 switch (op1->type->data.floating.bit_count) {
7684 case 16:
7685 out_val->data.x_f16 = f16_mul(op1->data.x_f16, op2->data.x_f16);
7686 return;
74057687 case 32:
74067688 out_val->data.x_f32 = op1->data.x_f32 * op2->data.x_f32;
74077689 return;
......@@ -7426,6 +7708,9 @@ static void float_div(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
74267708 bigfloat_div(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
74277709 } else if (op1->type->id == TypeTableEntryIdFloat) {
74287710 switch (op1->type->data.floating.bit_count) {
7711 case 16:
7712 out_val->data.x_f16 = f16_div(op1->data.x_f16, op2->data.x_f16);
7713 return;
74297714 case 32:
74307715 out_val->data.x_f32 = op1->data.x_f32 / op2->data.x_f32;
74317716 return;
......@@ -7450,21 +7735,15 @@ static void float_div_trunc(ConstExprValue *out_val, ConstExprValue *op1, ConstE
74507735 bigfloat_div_trunc(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
74517736 } else if (op1->type->id == TypeTableEntryIdFloat) {
74527737 switch (op1->type->data.floating.bit_count) {
7738 case 16:
7739 out_val->data.x_f16 = f16_div(op1->data.x_f16, op2->data.x_f16);
7740 out_val->data.x_f16 = f16_roundToInt(out_val->data.x_f16, softfloat_round_minMag, false);
7741 return;
74537742 case 32:
7454 out_val->data.x_f32 = op1->data.x_f32 / op2->data.x_f32;
7455 if (out_val->data.x_f32 >= 0.0) {
7456 out_val->data.x_f32 = floorf(out_val->data.x_f32);
7457 } else {
7458 out_val->data.x_f32 = ceilf(out_val->data.x_f32);
7459 }
7743 out_val->data.x_f32 = truncf(op1->data.x_f32 / op2->data.x_f32);
74607744 return;
74617745 case 64:
7462 out_val->data.x_f64 = op1->data.x_f64 / op2->data.x_f64;
7463 if (out_val->data.x_f64 >= 0.0) {
7464 out_val->data.x_f64 = floor(out_val->data.x_f64);
7465 } else {
7466 out_val->data.x_f64 = ceil(out_val->data.x_f64);
7467 }
7746 out_val->data.x_f64 = trunc(op1->data.x_f64 / op2->data.x_f64);
74687747 return;
74697748 case 128:
74707749 f128M_div(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128);
......@@ -7485,6 +7764,10 @@ static void float_div_floor(ConstExprValue *out_val, ConstExprValue *op1, ConstE
74857764 bigfloat_div_floor(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
74867765 } else if (op1->type->id == TypeTableEntryIdFloat) {
74877766 switch (op1->type->data.floating.bit_count) {
7767 case 16:
7768 out_val->data.x_f16 = f16_div(op1->data.x_f16, op2->data.x_f16);
7769 out_val->data.x_f16 = f16_roundToInt(out_val->data.x_f16, softfloat_round_min, false);
7770 return;
74887771 case 32:
74897772 out_val->data.x_f32 = floorf(op1->data.x_f32 / op2->data.x_f32);
74907773 return;
......@@ -7510,6 +7793,9 @@ static void float_rem(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
75107793 bigfloat_rem(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
75117794 } else if (op1->type->id == TypeTableEntryIdFloat) {
75127795 switch (op1->type->data.floating.bit_count) {
7796 case 16:
7797 out_val->data.x_f16 = f16_rem(op1->data.x_f16, op2->data.x_f16);
7798 return;
75137799 case 32:
75147800 out_val->data.x_f32 = fmodf(op1->data.x_f32, op2->data.x_f32);
75157801 return;
......@@ -7527,6 +7813,24 @@ static void float_rem(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
75277813 }
75287814}
75297815
7816// c = a - b * trunc(a / b)
7817static float16_t zig_f16_mod(float16_t a, float16_t b) {
7818 float16_t c;
7819 c = f16_div(a, b);
7820 c = f16_roundToInt(c, softfloat_round_min, true);
7821 c = f16_mul(b, c);
7822 c = f16_sub(a, c);
7823 return c;
7824}
7825
7826// c = a - b * trunc(a / b)
7827static void zig_f128M_mod(const float128_t* a, const float128_t* b, float128_t* c) {
7828 f128M_div(a, b, c);
7829 f128M_roundToInt(c, softfloat_round_min, true, c);
7830 f128M_mul(b, c, c);
7831 f128M_sub(a, c, c);
7832}
7833
75307834static void float_mod(ConstExprValue *out_val, ConstExprValue *op1, ConstExprValue *op2) {
75317835 assert(op1->type == op2->type);
75327836 out_val->type = op1->type;
......@@ -7534,6 +7838,9 @@ static void float_mod(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
75347838 bigfloat_mod(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
75357839 } else if (op1->type->id == TypeTableEntryIdFloat) {
75367840 switch (op1->type->data.floating.bit_count) {
7841 case 16:
7842 out_val->data.x_f16 = zig_f16_mod(op1->data.x_f16, op2->data.x_f16);
7843 return;
75377844 case 32:
75387845 out_val->data.x_f32 = fmodf(fmodf(op1->data.x_f32, op2->data.x_f32) + op2->data.x_f32, op2->data.x_f32);
75397846 return;
......@@ -7541,9 +7848,7 @@ static void float_mod(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
75417848 out_val->data.x_f64 = fmod(fmod(op1->data.x_f64, op2->data.x_f64) + op2->data.x_f64, op2->data.x_f64);
75427849 return;
75437850 case 128:
7544 f128M_rem(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128);
7545 f128M_add(&out_val->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128);
7546 f128M_rem(&out_val->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128);
7851 zig_f128M_mod(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128);
75477852 return;
75487853 default:
75497854 zig_unreachable();
......@@ -7559,6 +7864,12 @@ static void float_negate(ConstExprValue *out_val, ConstExprValue *op) {
75597864 bigfloat_negate(&out_val->data.x_bigfloat, &op->data.x_bigfloat);
75607865 } else if (op->type->id == TypeTableEntryIdFloat) {
75617866 switch (op->type->data.floating.bit_count) {
7867 case 16:
7868 {
7869 const float16_t zero = zig_double_to_f16(0);
7870 out_val->data.x_f16 = f16_sub(zero, op->data.x_f16);
7871 return;
7872 }
75627873 case 32:
75637874 out_val->data.x_f32 = -op->data.x_f32;
75647875 return;
......@@ -7581,6 +7892,9 @@ static void float_negate(ConstExprValue *out_val, ConstExprValue *op) {
75817892void float_write_ieee597(ConstExprValue *op, uint8_t *buf, bool is_big_endian) {
75827893 if (op->type->id == TypeTableEntryIdFloat) {
75837894 switch (op->type->data.floating.bit_count) {
7895 case 16:
7896 memcpy(buf, &op->data.x_f16, 2); // TODO wrong when compiler is big endian
7897 return;
75847898 case 32:
75857899 memcpy(buf, &op->data.x_f32, 4); // TODO wrong when compiler is big endian
75867900 return;
......@@ -7601,6 +7915,9 @@ void float_write_ieee597(ConstExprValue *op, uint8_t *buf, bool is_big_endian) {
76017915void float_read_ieee597(ConstExprValue *val, uint8_t *buf, bool is_big_endian) {
76027916 if (val->type->id == TypeTableEntryIdFloat) {
76037917 switch (val->type->data.floating.bit_count) {
7918 case 16:
7919 memcpy(&val->data.x_f16, buf, 2); // TODO wrong when compiler is big endian
7920 return;
76047921 case 32:
76057922 memcpy(&val->data.x_f32, buf, 4); // TODO wrong when compiler is big endian
76067923 return;
......@@ -7796,9 +8113,10 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
77968113
77978114 // * and [*] can do a const-cast-only to ?* and ?[*], respectively
77988115 // but not if there is a mutable parent pointer
8116 // and not if the pointer is zero bits
77998117 if (!wanted_is_mutable && wanted_type->id == TypeTableEntryIdOptional &&
78008118 wanted_type->data.maybe.child_type->id == TypeTableEntryIdPointer &&
7801 actual_type->id == TypeTableEntryIdPointer)
8119 actual_type->id == TypeTableEntryIdPointer && type_has_bits(actual_type))
78028120 {
78038121 ConstCastOnly child = types_match_const_cast_only(ira,
78048122 wanted_type->data.maybe.child_type, actual_type, source_node, wanted_is_mutable);
......@@ -7824,8 +8142,10 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
78248142 actual_type->data.pointer.child_type, source_node, !wanted_type->data.pointer.is_const);
78258143 if (child.id != ConstCastResultIdOk) {
78268144 result.id = ConstCastResultIdPointerChild;
7827 result.data.pointer_child = allocate_nonzero<ConstCastOnly>(1);
7828 *result.data.pointer_child = child;
8145 result.data.pointer_mismatch = allocate_nonzero<ConstCastPointerMismatch>(1);
8146 result.data.pointer_mismatch->child = child;
8147 result.data.pointer_mismatch->wanted_child = wanted_type->data.pointer.child_type;
8148 result.data.pointer_mismatch->actual_child = actual_type->data.pointer.child_type;
78298149 }
78308150 return result;
78318151 }
......@@ -7844,8 +8164,10 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
78448164 actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const);
78458165 if (child.id != ConstCastResultIdOk) {
78468166 result.id = ConstCastResultIdSliceChild;
7847 result.data.slice_child = allocate_nonzero<ConstCastOnly>(1);
7848 *result.data.slice_child = child;
8167 result.data.slice_mismatch = allocate_nonzero<ConstCastSliceMismatch>(1);
8168 result.data.slice_mismatch->child = child;
8169 result.data.slice_mismatch->actual_child = actual_ptr_type->data.pointer.child_type;
8170 result.data.slice_mismatch->wanted_child = wanted_ptr_type->data.pointer.child_type;
78498171 }
78508172 return result;
78518173 }
......@@ -7857,8 +8179,10 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
78578179 actual_type->data.maybe.child_type, source_node, wanted_is_mutable);
78588180 if (child.id != ConstCastResultIdOk) {
78598181 result.id = ConstCastResultIdOptionalChild;
7860 result.data.optional_child = allocate_nonzero<ConstCastOnly>(1);
7861 *result.data.optional_child = child;
8182 result.data.optional = allocate_nonzero<ConstCastOptionalMismatch>(1);
8183 result.data.optional->child = child;
8184 result.data.optional->wanted_child = wanted_type->data.maybe.child_type;
8185 result.data.optional->actual_child = actual_type->data.maybe.child_type;
78628186 }
78638187 return result;
78648188 }
......@@ -7869,16 +8193,20 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
78698193 actual_type->data.error_union.payload_type, source_node, wanted_is_mutable);
78708194 if (payload_child.id != ConstCastResultIdOk) {
78718195 result.id = ConstCastResultIdErrorUnionPayload;
7872 result.data.error_union_payload = allocate_nonzero<ConstCastOnly>(1);
7873 *result.data.error_union_payload = payload_child;
8196 result.data.error_union_payload = allocate_nonzero<ConstCastErrUnionPayloadMismatch>(1);
8197 result.data.error_union_payload->child = payload_child;
8198 result.data.error_union_payload->wanted_payload = wanted_type->data.error_union.payload_type;
8199 result.data.error_union_payload->actual_payload = actual_type->data.error_union.payload_type;
78748200 return result;
78758201 }
78768202 ConstCastOnly error_set_child = types_match_const_cast_only(ira, wanted_type->data.error_union.err_set_type,
78778203 actual_type->data.error_union.err_set_type, source_node, wanted_is_mutable);
78788204 if (error_set_child.id != ConstCastResultIdOk) {
78798205 result.id = ConstCastResultIdErrorUnionErrorSet;
7880 result.data.error_union_error_set = allocate_nonzero<ConstCastOnly>(1);
7881 *result.data.error_union_error_set = error_set_child;
8206 result.data.error_union_error_set = allocate_nonzero<ConstCastErrUnionErrSetMismatch>(1);
8207 result.data.error_union_error_set->child = error_set_child;
8208 result.data.error_union_error_set->wanted_err_set = wanted_type->data.error_union.err_set_type;
8209 result.data.error_union_error_set->actual_err_set = actual_type->data.error_union.err_set_type;
78828210 return result;
78838211 }
78848212 return result;
......@@ -7920,8 +8248,9 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
79208248 if (error_entry == nullptr) {
79218249 if (result.id == ConstCastResultIdOk) {
79228250 result.id = ConstCastResultIdErrSet;
8251 result.data.error_set_mismatch = allocate<ConstCastErrSetMismatch>(1);
79238252 }
7924 result.data.error_set.missing_errors.append(contained_error_entry);
8253 result.data.error_set_mismatch->missing_errors.append(contained_error_entry);
79258254 }
79268255 }
79278256 free(errors);
......@@ -8016,325 +8345,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
80168345 return result;
80178346}
80188347
8019enum ImplicitCastMatchResult {
8020 ImplicitCastMatchResultNo,
8021 ImplicitCastMatchResultYes,
8022 ImplicitCastMatchResultReportedError,
8023};
8024
8025static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, TypeTableEntry *wanted_type,
8026 TypeTableEntry *actual_type, IrInstruction *value)
8027{
8028 AstNode *source_node = value->source_node;
8029 ConstCastOnly const_cast_result = types_match_const_cast_only(ira, wanted_type, actual_type,
8030 source_node, false);
8031 if (const_cast_result.id == ConstCastResultIdOk) {
8032 return ImplicitCastMatchResultYes;
8033 }
8034
8035 // if we got here with error sets, make an error showing the incompatibilities
8036 ZigList<ErrorTableEntry *> *missing_errors = nullptr;
8037 if (const_cast_result.id == ConstCastResultIdErrSet) {
8038 missing_errors = &const_cast_result.data.error_set.missing_errors;
8039 }
8040 if (const_cast_result.id == ConstCastResultIdErrorUnionErrorSet) {
8041 if (const_cast_result.data.error_union_error_set->id == ConstCastResultIdErrSet) {
8042 missing_errors = &const_cast_result.data.error_union_error_set->data.error_set.missing_errors;
8043 } else if (const_cast_result.data.error_union_error_set->id == ConstCastResultIdErrSetGlobal) {
8044 ErrorMsg *msg = ir_add_error(ira, value,
8045 buf_sprintf("expected '%s', found '%s'", buf_ptr(&wanted_type->name), buf_ptr(&actual_type->name)));
8046 add_error_note(ira->codegen, msg, value->source_node,
8047 buf_sprintf("unable to cast global error set into smaller set"));
8048 return ImplicitCastMatchResultReportedError;
8049 }
8050 } else if (const_cast_result.id == ConstCastResultIdErrSetGlobal) {
8051 ErrorMsg *msg = ir_add_error(ira, value,
8052 buf_sprintf("expected '%s', found '%s'", buf_ptr(&wanted_type->name), buf_ptr(&actual_type->name)));
8053 add_error_note(ira->codegen, msg, value->source_node,
8054 buf_sprintf("unable to cast global error set into smaller set"));
8055 return ImplicitCastMatchResultReportedError;
8056 }
8057 if (missing_errors != nullptr) {
8058 ErrorMsg *msg = ir_add_error(ira, value,
8059 buf_sprintf("expected '%s', found '%s'", buf_ptr(&wanted_type->name), buf_ptr(&actual_type->name)));
8060 for (size_t i = 0; i < missing_errors->length; i += 1) {
8061 ErrorTableEntry *error_entry = missing_errors->at(i);
8062 add_error_note(ira->codegen, msg, error_entry->decl_node,
8063 buf_sprintf("'error.%s' not a member of destination error set", buf_ptr(&error_entry->name)));
8064 }
8065
8066 return ImplicitCastMatchResultReportedError;
8067 }
8068
8069 // implicit conversion from ?T to ?U
8070 if (wanted_type->id == TypeTableEntryIdOptional && actual_type->id == TypeTableEntryIdOptional) {
8071 ImplicitCastMatchResult res = ir_types_match_with_implicit_cast(ira, wanted_type->data.maybe.child_type,
8072 actual_type->data.maybe.child_type, value);
8073 if (res != ImplicitCastMatchResultNo)
8074 return res;
8075 }
8076
8077 // implicit conversion from non maybe type to maybe type
8078 if (wanted_type->id == TypeTableEntryIdOptional) {
8079 ImplicitCastMatchResult res = ir_types_match_with_implicit_cast(ira, wanted_type->data.maybe.child_type,
8080 actual_type, value);
8081 if (res != ImplicitCastMatchResultNo)
8082 return res;
8083 }
8084
8085 // implicit conversion from null literal to maybe type
8086 if (wanted_type->id == TypeTableEntryIdOptional &&
8087 actual_type->id == TypeTableEntryIdNull)
8088 {
8089 return ImplicitCastMatchResultYes;
8090 }
8091
8092 // implicit T to U!T
8093 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
8094 ir_types_match_with_implicit_cast(ira, wanted_type->data.error_union.payload_type, actual_type, value))
8095 {
8096 return ImplicitCastMatchResultYes;
8097 }
8098
8099 // implicit conversion from error set to error union type
8100 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
8101 actual_type->id == TypeTableEntryIdErrorSet)
8102 {
8103 return ImplicitCastMatchResultYes;
8104 }
8105
8106 // implicit conversion from T to U!?T
8107 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
8108 wanted_type->data.error_union.payload_type->id == TypeTableEntryIdOptional &&
8109 ir_types_match_with_implicit_cast(ira,
8110 wanted_type->data.error_union.payload_type->data.maybe.child_type,
8111 actual_type, value))
8112 {
8113 return ImplicitCastMatchResultYes;
8114 }
8115
8116 // implicit widening conversion
8117 if (wanted_type->id == TypeTableEntryIdInt &&
8118 actual_type->id == TypeTableEntryIdInt &&
8119 wanted_type->data.integral.is_signed == actual_type->data.integral.is_signed &&
8120 wanted_type->data.integral.bit_count >= actual_type->data.integral.bit_count)
8121 {
8122 return ImplicitCastMatchResultYes;
8123 }
8124
8125 // small enough unsigned ints can get casted to large enough signed ints
8126 if (wanted_type->id == TypeTableEntryIdInt && wanted_type->data.integral.is_signed &&
8127 actual_type->id == TypeTableEntryIdInt && !actual_type->data.integral.is_signed &&
8128 wanted_type->data.integral.bit_count > actual_type->data.integral.bit_count)
8129 {
8130 return ImplicitCastMatchResultYes;
8131 }
8132
8133 // implicit float widening conversion
8134 if (wanted_type->id == TypeTableEntryIdFloat &&
8135 actual_type->id == TypeTableEntryIdFloat &&
8136 wanted_type->data.floating.bit_count >= actual_type->data.floating.bit_count)
8137 {
8138 return ImplicitCastMatchResultYes;
8139 }
8140
8141 // implicit [N]T to []const T
8142 if (is_slice(wanted_type) && actual_type->id == TypeTableEntryIdArray) {
8143 TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
8144 assert(ptr_type->id == TypeTableEntryIdPointer);
8145
8146 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
8147 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
8148 source_node, false).id == ConstCastResultIdOk)
8149 {
8150 return ImplicitCastMatchResultYes;
8151 }
8152 }
8153
8154 // implicit &const [N]T to []const T
8155 if (is_slice(wanted_type) &&
8156 actual_type->id == TypeTableEntryIdPointer &&
8157 actual_type->data.pointer.ptr_len == PtrLenSingle &&
8158 actual_type->data.pointer.is_const &&
8159 actual_type->data.pointer.child_type->id == TypeTableEntryIdArray)
8160 {
8161 TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
8162 assert(ptr_type->id == TypeTableEntryIdPointer);
8163
8164 TypeTableEntry *array_type = actual_type->data.pointer.child_type;
8165
8166 if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&
8167 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, array_type->data.array.child_type,
8168 source_node, false).id == ConstCastResultIdOk)
8169 {
8170 return ImplicitCastMatchResultYes;
8171 }
8172 }
8173
8174 // implicit [N]T to &const []const T
8175 if (wanted_type->id == TypeTableEntryIdPointer &&
8176 wanted_type->data.pointer.is_const &&
8177 wanted_type->data.pointer.ptr_len == PtrLenSingle &&
8178 is_slice(wanted_type->data.pointer.child_type) &&
8179 actual_type->id == TypeTableEntryIdArray)
8180 {
8181 TypeTableEntry *ptr_type =
8182 wanted_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry;
8183 assert(ptr_type->id == TypeTableEntryIdPointer);
8184 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
8185 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type,
8186 actual_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk)
8187 {
8188 return ImplicitCastMatchResultYes;
8189 }
8190 }
8191
8192 // implicit *[N]T to [*]T
8193 if (wanted_type->id == TypeTableEntryIdPointer &&
8194 wanted_type->data.pointer.ptr_len == PtrLenUnknown &&
8195 actual_type->id == TypeTableEntryIdPointer &&
8196 actual_type->data.pointer.ptr_len == PtrLenSingle &&
8197 actual_type->data.pointer.child_type->id == TypeTableEntryIdArray &&
8198 types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
8199 actual_type->data.pointer.child_type->data.array.child_type, source_node,
8200 !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
8201 {
8202 return ImplicitCastMatchResultYes;
8203 }
8204
8205 // implicit *[N]T to []T
8206 if (is_slice(wanted_type) &&
8207 actual_type->id == TypeTableEntryIdPointer &&
8208 actual_type->data.pointer.ptr_len == PtrLenSingle &&
8209 actual_type->data.pointer.child_type->id == TypeTableEntryIdArray)
8210 {
8211 TypeTableEntry *slice_ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
8212 assert(slice_ptr_type->id == TypeTableEntryIdPointer);
8213 if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,
8214 actual_type->data.pointer.child_type->data.array.child_type, source_node,
8215 !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk)
8216 {
8217 return ImplicitCastMatchResultYes;
8218 }
8219 }
8220
8221 // implicit [N]T to ?[]const T
8222 if (wanted_type->id == TypeTableEntryIdOptional &&
8223 is_slice(wanted_type->data.maybe.child_type) &&
8224 actual_type->id == TypeTableEntryIdArray)
8225 {
8226 TypeTableEntry *ptr_type =
8227 wanted_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry;
8228 assert(ptr_type->id == TypeTableEntryIdPointer);
8229 if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
8230 types_match_const_cast_only(ira, ptr_type->data.pointer.child_type,
8231 actual_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk)
8232 {
8233 return ImplicitCastMatchResultYes;
8234 }
8235 }
8236
8237
8238 // implicit number literal to typed number
8239 // implicit number literal to &const integer
8240 if (actual_type->id == TypeTableEntryIdComptimeFloat ||
8241 actual_type->id == TypeTableEntryIdComptimeInt)
8242 {
8243 if (wanted_type->id == TypeTableEntryIdPointer &&
8244 wanted_type->data.pointer.ptr_len == PtrLenSingle &&
8245 wanted_type->data.pointer.is_const)
8246 {
8247 if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.pointer.child_type, false)) {
8248 return ImplicitCastMatchResultYes;
8249 } else {
8250 return ImplicitCastMatchResultReportedError;
8251 }
8252 } else if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, false)) {
8253 return ImplicitCastMatchResultYes;
8254 } else {
8255 return ImplicitCastMatchResultReportedError;
8256 }
8257 }
8258
8259 // implicit typed number to integer or float literal.
8260 // works when the number is known
8261 if (value->value.special == ConstValSpecialStatic) {
8262 if (actual_type->id == TypeTableEntryIdInt && wanted_type->id == TypeTableEntryIdComptimeInt) {
8263 return ImplicitCastMatchResultYes;
8264 } else if (actual_type->id == TypeTableEntryIdFloat && wanted_type->id == TypeTableEntryIdComptimeFloat) {
8265 return ImplicitCastMatchResultYes;
8266 }
8267 }
8268
8269 // implicit union to its enum tag type
8270 if (wanted_type->id == TypeTableEntryIdEnum && actual_type->id == TypeTableEntryIdUnion &&
8271 (actual_type->data.unionation.decl_node->data.container_decl.auto_enum ||
8272 actual_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr))
8273 {
8274 type_ensure_zero_bits_known(ira->codegen, actual_type);
8275 if (actual_type->data.unionation.tag_type == wanted_type) {
8276 return ImplicitCastMatchResultYes;
8277 }
8278 }
8279
8280 // implicit enum to union which has the enum as the tag type
8281 if (wanted_type->id == TypeTableEntryIdUnion && actual_type->id == TypeTableEntryIdEnum &&
8282 (wanted_type->data.unionation.decl_node->data.container_decl.auto_enum ||
8283 wanted_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr))
8284 {
8285 type_ensure_zero_bits_known(ira->codegen, wanted_type);
8286 if (wanted_type->data.unionation.tag_type == actual_type) {
8287 return ImplicitCastMatchResultYes;
8288 }
8289 }
8290
8291 // implicit enum to &const union which has the enum as the tag type
8292 if (actual_type->id == TypeTableEntryIdEnum &&
8293 wanted_type->id == TypeTableEntryIdPointer &&
8294 wanted_type->data.pointer.ptr_len == PtrLenSingle)
8295 {
8296 TypeTableEntry *union_type = wanted_type->data.pointer.child_type;
8297 if (union_type->data.unionation.decl_node->data.container_decl.auto_enum ||
8298 union_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)
8299 {
8300 type_ensure_zero_bits_known(ira->codegen, union_type);
8301 if (union_type->data.unionation.tag_type == actual_type) {
8302 return ImplicitCastMatchResultYes;
8303 }
8304 }
8305 }
8306
8307 // implicit T to *T where T is zero bits
8308 if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
8309 types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
8310 actual_type, source_node, false).id == ConstCastResultIdOk)
8311 {
8312 type_ensure_zero_bits_known(ira->codegen, actual_type);
8313 if (!type_has_bits(actual_type)) {
8314 return ImplicitCastMatchResultYes;
8315 }
8316 }
8317
8318 // implicit undefined literal to anything
8319 if (actual_type->id == TypeTableEntryIdUndefined) {
8320 return ImplicitCastMatchResultYes;
8321 }
8322
8323 // implicitly take a const pointer to something
8324 if (!type_requires_comptime(actual_type)) {
8325 TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);
8326 if (wanted_type->id == TypeTableEntryIdPointer &&
8327 wanted_type->data.pointer.ptr_len == PtrLenSingle &&
8328 types_match_const_cast_only(ira, wanted_type, const_ptr_actual,
8329 source_node, false).id == ConstCastResultIdOk)
8330 {
8331 return ImplicitCastMatchResultYes;
8332 }
8333 }
8334
8335 return ImplicitCastMatchResultNo;
8336}
8337
83388348static void update_errors_helper(CodeGen *g, ErrorTableEntry ***errors, size_t *errors_count) {
83398349 size_t old_errors_count = *errors_count;
83408350 *errors_count = g->errors_by_index.length;
......@@ -8881,7 +8891,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
88818891 } else if (prev_inst->value.type->id == TypeTableEntryIdOptional) {
88828892 return prev_inst->value.type;
88838893 } else {
8884 return get_maybe_type(ira->codegen, prev_inst->value.type);
8894 return get_optional_type(ira->codegen, prev_inst->value.type);
88858895 }
88868896 } else {
88878897 return prev_inst->value.type;
......@@ -8909,7 +8919,8 @@ static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_
89098919 }
89108920}
89118921
8912static void eval_const_expr_implicit_cast(CastOp cast_op,
8922static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_instr,
8923 CastOp cast_op,
89138924 ConstExprValue *other_val, TypeTableEntry *other_type,
89148925 ConstExprValue *const_val, TypeTableEntry *new_type)
89158926{
......@@ -8934,6 +8945,9 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
89348945 if (other_val->type->id == TypeTableEntryIdComptimeFloat) {
89358946 assert(new_type->id == TypeTableEntryIdFloat);
89368947 switch (new_type->data.floating.bit_count) {
8948 case 16:
8949 const_val->data.x_f16 = bigfloat_to_f16(&other_val->data.x_bigfloat);
8950 break;
89378951 case 32:
89388952 const_val->data.x_f32 = bigfloat_to_f32(&other_val->data.x_bigfloat);
89398953 break;
......@@ -8964,6 +8978,9 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
89648978 BigFloat bigfloat;
89658979 bigfloat_init_bigint(&bigfloat, &other_val->data.x_bigint);
89668980 switch (new_type->data.floating.bit_count) {
8981 case 16:
8982 const_val->data.x_f16 = bigfloat_to_f16(&bigfloat);
8983 break;
89678984 case 32:
89688985 const_val->data.x_f32 = bigfloat_to_f32(&bigfloat);
89698986 break;
......@@ -8981,6 +8998,20 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
89818998 }
89828999 case CastOpFloatToInt:
89839000 float_init_bigint(&const_val->data.x_bigint, other_val);
9001 if (new_type->id == TypeTableEntryIdInt) {
9002 if (!bigint_fits_in_bits(&const_val->data.x_bigint, new_type->data.integral.bit_count,
9003 new_type->data.integral.is_signed))
9004 {
9005 Buf *int_buf = buf_alloc();
9006 bigint_append_buf(int_buf, &const_val->data.x_bigint, 10);
9007
9008 ir_add_error(ira, source_instr,
9009 buf_sprintf("integer value '%s' cannot be stored in type '%s'",
9010 buf_ptr(int_buf), buf_ptr(&new_type->name)));
9011 return false;
9012 }
9013 }
9014
89849015 const_val->special = ConstValSpecialStatic;
89859016 break;
89869017 case CastOpBoolToInt:
......@@ -8988,6 +9019,7 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
89889019 const_val->special = ConstValSpecialStatic;
89899020 break;
89909021 }
9022 return true;
89919023}
89929024static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
89939025 TypeTableEntry *wanted_type, CastOp cast_op, bool need_alloca)
......@@ -8997,8 +9029,11 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst
89979029 {
89989030 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
89999031 source_instr->source_node, wanted_type);
9000 eval_const_expr_implicit_cast(cast_op, &value->value, value->value.type,
9001 &result->value, wanted_type);
9032 if (!eval_const_expr_implicit_cast(ira, source_instr, cast_op, &value->value, value->value.type,
9033 &result->value, wanted_type))
9034 {
9035 return ira->codegen->invalid_instruction;
9036 }
90029037 return result;
90039038 } else {
90049039 IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type, value, cast_op);
......@@ -9073,11 +9108,6 @@ static bool is_container(TypeTableEntry *type) {
90739108 type->id == TypeTableEntryIdUnion;
90749109}
90759110
9076static bool is_u8(TypeTableEntry *type) {
9077 return type->id == TypeTableEntryIdInt &&
9078 !type->data.integral.is_signed && type->data.integral.bit_count == 8;
9079}
9080
90819111static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb, IrInstruction *ref_old_instruction) {
90829112 assert(old_bb);
90839113
......@@ -9631,6 +9661,8 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
96319661 IrInstruction *result = ir_build_slice(&ira->new_irb, source_instr->scope,
96329662 source_instr->source_node, array_ptr, start, end, false);
96339663 result->value.type = wanted_type;
9664 result->value.data.rh_slice.id = RuntimeHintSliceIdLen;
9665 result->value.data.rh_slice.len = array_type->data.array.len;
96349666 ir_add_alloca(ira, result, result->value.type);
96359667
96369668 return result;
......@@ -9851,7 +9883,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
98519883 }
98529884
98539885 IrInstruction *result = ir_build_int_to_enum(&ira->new_irb, source_instr->scope,
9854 source_instr->source_node, target);
9886 source_instr->source_node, nullptr, target);
98559887 result->value.type = wanted_type;
98569888 return result;
98579889}
......@@ -10063,6 +10095,83 @@ static IrInstruction *ir_analyze_ptr_to_array(IrAnalyze *ira, IrInstruction *sou
1006310095 return result;
1006410096}
1006510097
10098static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCastOnly *cast_result,
10099 ErrorMsg *parent_msg)
10100{
10101 switch (cast_result->id) {
10102 case ConstCastResultIdOk:
10103 zig_unreachable();
10104 case ConstCastResultIdOptionalChild: {
10105 ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node,
10106 buf_sprintf("optional type child '%s' cannot cast into optional type child '%s'",
10107 buf_ptr(&cast_result->data.optional->actual_child->name),
10108 buf_ptr(&cast_result->data.optional->wanted_child->name)));
10109 report_recursive_error(ira, source_node, &cast_result->data.optional->child, msg);
10110 break;
10111 }
10112 case ConstCastResultIdErrorUnionErrorSet: {
10113 ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node,
10114 buf_sprintf("error set '%s' cannot cast into error set '%s'",
10115 buf_ptr(&cast_result->data.error_union_error_set->actual_err_set->name),
10116 buf_ptr(&cast_result->data.error_union_error_set->wanted_err_set->name)));
10117 report_recursive_error(ira, source_node, &cast_result->data.error_union_error_set->child, msg);
10118 break;
10119 }
10120 case ConstCastResultIdErrSet: {
10121 ZigList<ErrorTableEntry *> *missing_errors = &cast_result->data.error_set_mismatch->missing_errors;
10122 for (size_t i = 0; i < missing_errors->length; i += 1) {
10123 ErrorTableEntry *error_entry = missing_errors->at(i);
10124 add_error_note(ira->codegen, parent_msg, error_entry->decl_node,
10125 buf_sprintf("'error.%s' not a member of destination error set", buf_ptr(&error_entry->name)));
10126 }
10127 break;
10128 }
10129 case ConstCastResultIdErrSetGlobal: {
10130 add_error_note(ira->codegen, parent_msg, source_node,
10131 buf_sprintf("cannot cast global error set into smaller set"));
10132 break;
10133 }
10134 case ConstCastResultIdPointerChild: {
10135 ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node,
10136 buf_sprintf("pointer type child '%s' cannot cast into pointer type child '%s'",
10137 buf_ptr(&cast_result->data.pointer_mismatch->actual_child->name),
10138 buf_ptr(&cast_result->data.pointer_mismatch->wanted_child->name)));
10139 report_recursive_error(ira, source_node, &cast_result->data.pointer_mismatch->child, msg);
10140 break;
10141 }
10142 case ConstCastResultIdSliceChild: {
10143 ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node,
10144 buf_sprintf("slice type child '%s' cannot cast into slice type child '%s'",
10145 buf_ptr(&cast_result->data.slice_mismatch->actual_child->name),
10146 buf_ptr(&cast_result->data.slice_mismatch->wanted_child->name)));
10147 report_recursive_error(ira, source_node, &cast_result->data.slice_mismatch->child, msg);
10148 break;
10149 }
10150 case ConstCastResultIdErrorUnionPayload: {
10151 ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node,
10152 buf_sprintf("error union payload '%s' cannot cast into error union payload '%s'",
10153 buf_ptr(&cast_result->data.error_union_payload->actual_payload->name),
10154 buf_ptr(&cast_result->data.error_union_payload->wanted_payload->name)));
10155 report_recursive_error(ira, source_node, &cast_result->data.error_union_payload->child, msg);
10156 break;
10157 }
10158 case ConstCastResultIdFnAlign: // TODO
10159 case ConstCastResultIdFnCC: // TODO
10160 case ConstCastResultIdFnVarArgs: // TODO
10161 case ConstCastResultIdFnIsGeneric: // TODO
10162 case ConstCastResultIdFnReturnType: // TODO
10163 case ConstCastResultIdFnArgCount: // TODO
10164 case ConstCastResultIdFnGenericArgCount: // TODO
10165 case ConstCastResultIdFnArg: // TODO
10166 case ConstCastResultIdFnArgNoAlias: // TODO
10167 case ConstCastResultIdType: // TODO
10168 case ConstCastResultIdUnresolvedInferredErrSet: // TODO
10169 case ConstCastResultIdAsyncAllocatorType: // TODO
10170 case ConstCastResultIdNullWrapPtr: // TODO
10171 break;
10172 }
10173}
10174
1006610175static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
1006710176 TypeTableEntry *wanted_type, IrInstruction *value)
1006810177{
......@@ -10073,12 +10182,14 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1007310182 return ira->codegen->invalid_instruction;
1007410183 }
1007510184
10076 // explicit match or non-const to const
10077 if (types_match_const_cast_only(ira, wanted_type, actual_type, source_node, false).id == ConstCastResultIdOk) {
10185 // perfect match or non-const to const
10186 ConstCastOnly const_cast_result = types_match_const_cast_only(ira, wanted_type, actual_type,
10187 source_node, false);
10188 if (const_cast_result.id == ConstCastResultIdOk) {
1007810189 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);
1007910190 }
1008010191
10081 // explicit widening conversion
10192 // widening conversion
1008210193 if (wanted_type->id == TypeTableEntryIdInt &&
1008310194 actual_type->id == TypeTableEntryIdInt &&
1008410195 wanted_type->data.integral.is_signed == actual_type->data.integral.is_signed &&
......@@ -10095,7 +10206,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1009510206 return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
1009610207 }
1009710208
10098 // explicit float widening conversion
10209 // float widening conversion
1009910210 if (wanted_type->id == TypeTableEntryIdFloat &&
1010010211 actual_type->id == TypeTableEntryIdFloat &&
1010110212 wanted_type->data.floating.bit_count >= actual_type->data.floating.bit_count)
......@@ -10104,14 +10215,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1010410215 }
1010510216
1010610217
10107 // explicit error set cast
10108 if (wanted_type->id == TypeTableEntryIdErrorSet &&
10109 actual_type->id == TypeTableEntryIdErrorSet)
10110 {
10111 return ir_analyze_err_set_cast(ira, source_instr, value, wanted_type);
10112 }
10113
10114 // explicit cast from [N]T to []const T
10218 // cast from [N]T to []const T
1011510219 if (is_slice(wanted_type) && actual_type->id == TypeTableEntryIdArray) {
1011610220 TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
1011710221 assert(ptr_type->id == TypeTableEntryIdPointer);
......@@ -10123,7 +10227,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1012310227 }
1012410228 }
1012510229
10126 // explicit cast from &const [N]T to []const T
10230 // cast from *const [N]T to []const T
1012710231 if (is_slice(wanted_type) &&
1012810232 actual_type->id == TypeTableEntryIdPointer &&
1012910233 actual_type->data.pointer.is_const &&
......@@ -10142,7 +10246,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1014210246 }
1014310247 }
1014410248
10145 // explicit cast from [N]T to &const []const N
10249 // cast from [N]T to *const []const T
1014610250 if (wanted_type->id == TypeTableEntryIdPointer &&
1014710251 wanted_type->data.pointer.is_const &&
1014810252 is_slice(wanted_type->data.pointer.child_type) &&
......@@ -10167,7 +10271,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1016710271 }
1016810272 }
1016910273
10170 // explicit cast from [N]T to ?[]const N
10274 // cast from [N]T to ?[]const T
1017110275 if (wanted_type->id == TypeTableEntryIdOptional &&
1017210276 is_slice(wanted_type->data.maybe.child_type) &&
1017310277 actual_type->id == TypeTableEntryIdArray)
......@@ -10191,53 +10295,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1019110295 }
1019210296 }
1019310297
10194 // explicit cast from []T to []u8 or []u8 to []T
10195 if (is_slice(wanted_type) && is_slice(actual_type)) {
10196 TypeTableEntry *wanted_ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
10197 TypeTableEntry *actual_ptr_type = actual_type->data.structure.fields[slice_ptr_index].type_entry;
10198 if ((is_u8(wanted_ptr_type->data.pointer.child_type) || is_u8(actual_ptr_type->data.pointer.child_type)) &&
10199 (wanted_ptr_type->data.pointer.is_const || !actual_ptr_type->data.pointer.is_const))
10200 {
10201 uint32_t src_align_bytes = get_ptr_align(actual_ptr_type);
10202 uint32_t dest_align_bytes = get_ptr_align(wanted_ptr_type);
10203
10204 if (dest_align_bytes > src_align_bytes) {
10205 ErrorMsg *msg = ir_add_error(ira, source_instr,
10206 buf_sprintf("cast increases pointer alignment"));
10207 add_error_note(ira->codegen, msg, source_instr->source_node,
10208 buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&actual_type->name), src_align_bytes));
10209 add_error_note(ira->codegen, msg, source_instr->source_node,
10210 buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&wanted_type->name), dest_align_bytes));
10211 return ira->codegen->invalid_instruction;
10212 }
10213
10214 if (!ir_emit_global_runtime_side_effect(ira, source_instr))
10215 return ira->codegen->invalid_instruction;
10216 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpResizeSlice, true);
10217 }
10218 }
10219
10220 // explicit cast from [N]u8 to []const T
10221 if (is_slice(wanted_type) &&
10222 wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const &&
10223 actual_type->id == TypeTableEntryIdArray &&
10224 is_u8(actual_type->data.array.child_type))
10225 {
10226 if (!ir_emit_global_runtime_side_effect(ira, source_instr))
10227 return ira->codegen->invalid_instruction;
10228 uint64_t child_type_size = type_size(ira->codegen,
10229 wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type);
10230 if (actual_type->data.array.len % child_type_size == 0) {
10231 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpBytesToSlice, true);
10232 } else {
10233 ir_add_error_node(ira, source_instr->source_node,
10234 buf_sprintf("unable to convert %s to %s: size mismatch",
10235 buf_ptr(&actual_type->name), buf_ptr(&wanted_type->name)));
10236 return ira->codegen->invalid_instruction;
10237 }
10238 }
10239
10240 // explicit *[N]T to [*]T
10298 // *[N]T to [*]T
1024110299 if (wanted_type->id == TypeTableEntryIdPointer &&
1024210300 wanted_type->data.pointer.ptr_len == PtrLenUnknown &&
1024310301 actual_type->id == TypeTableEntryIdPointer &&
......@@ -10251,7 +10309,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1025110309 return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_type);
1025210310 }
1025310311
10254 // explicit *[N]T to []T
10312 // *[N]T to []T
1025510313 if (is_slice(wanted_type) &&
1025610314 actual_type->id == TypeTableEntryIdPointer &&
1025710315 actual_type->data.pointer.ptr_len == PtrLenSingle &&
......@@ -10268,7 +10326,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1026810326 }
1026910327
1027010328
10271 // explicit cast from T to ?T
10329 // cast from T to ?T
1027210330 // note that the *T to ?*T case is handled via the "ConstCastOnly" mechanism
1027310331 if (wanted_type->id == TypeTableEntryIdOptional) {
1027410332 TypeTableEntry *wanted_child_type = wanted_type->data.maybe.child_type;
......@@ -10300,14 +10358,14 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1030010358 }
1030110359 }
1030210360
10303 // explicit cast from null literal to maybe type
10361 // cast from null literal to maybe type
1030410362 if (wanted_type->id == TypeTableEntryIdOptional &&
1030510363 actual_type->id == TypeTableEntryIdNull)
1030610364 {
1030710365 return ir_analyze_null_to_maybe(ira, source_instr, value, wanted_type);
1030810366 }
1030910367
10310 // explicit cast from child type of error type to error type
10368 // cast from child type of error type to error type
1031110369 if (wanted_type->id == TypeTableEntryIdErrorUnion) {
1031210370 if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type,
1031310371 source_node, false).id == ConstCastResultIdOk)
......@@ -10324,7 +10382,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1032410382 }
1032510383 }
1032610384
10327 // explicit cast from [N]T to E![]const T
10385 // cast from [N]T to E![]const T
1032810386 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
1032910387 is_slice(wanted_type->data.error_union.payload_type) &&
1033010388 actual_type->id == TypeTableEntryIdArray)
......@@ -10348,14 +10406,14 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1034810406 }
1034910407 }
1035010408
10351 // explicit cast from error set to error union type
10409 // cast from error set to error union type
1035210410 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
1035310411 actual_type->id == TypeTableEntryIdErrorSet)
1035410412 {
1035510413 return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type);
1035610414 }
1035710415
10358 // explicit cast from T to E!?T
10416 // cast from T to E!?T
1035910417 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
1036010418 wanted_type->data.error_union.payload_type->id == TypeTableEntryIdOptional &&
1036110419 actual_type->id != TypeTableEntryIdOptional)
......@@ -10378,8 +10436,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1037810436 }
1037910437 }
1038010438
10381 // explicit cast from number literal to another type
10382 // explicit cast from number literal to *const integer
10439 // cast from number literal to another type
10440 // cast from number literal to *const integer
1038310441 if (actual_type->id == TypeTableEntryIdComptimeFloat ||
1038410442 actual_type->id == TypeTableEntryIdComptimeInt)
1038510443 {
......@@ -10429,7 +10487,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1042910487 }
1043010488 }
1043110489
10432 // explicit cast from typed number to integer or float literal.
10490 // cast from typed number to integer or float literal.
1043310491 // works when the number is known at compile time
1043410492 if (instr_is_comptime(value) &&
1043510493 ((actual_type->id == TypeTableEntryIdInt && wanted_type->id == TypeTableEntryIdComptimeInt) ||
......@@ -10438,32 +10496,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1043810496 return ir_analyze_number_to_literal(ira, source_instr, value, wanted_type);
1043910497 }
1044010498
10441 // explicit cast from T!void to integer type which can fit it
10442 bool actual_type_is_void_err = actual_type->id == TypeTableEntryIdErrorUnion &&
10443 !type_has_bits(actual_type->data.error_union.payload_type);
10444 bool actual_type_is_err_set = actual_type->id == TypeTableEntryIdErrorSet;
10445 if ((actual_type_is_void_err || actual_type_is_err_set) && wanted_type->id == TypeTableEntryIdInt) {
10446 return ir_analyze_err_to_int(ira, source_instr, value, wanted_type);
10447 }
10448
10449 // explicit cast from integer to error set
10450 if (wanted_type->id == TypeTableEntryIdErrorSet && actual_type->id == TypeTableEntryIdInt &&
10451 !actual_type->data.integral.is_signed)
10452 {
10453 return ir_analyze_int_to_err(ira, source_instr, value, wanted_type);
10454 }
10455
10456 // explicit cast from integer to enum type with no payload
10457 if (actual_type->id == TypeTableEntryIdInt && wanted_type->id == TypeTableEntryIdEnum) {
10458 return ir_analyze_int_to_enum(ira, source_instr, value, wanted_type);
10459 }
10460
10461 // explicit cast from enum type with no payload to integer
10462 if (wanted_type->id == TypeTableEntryIdInt && actual_type->id == TypeTableEntryIdEnum) {
10463 return ir_analyze_enum_to_int(ira, source_instr, value, wanted_type);
10464 }
10465
10466 // explicit cast from union to the enum type of the union
10499 // cast from union to the enum type of the union
1046710500 if (actual_type->id == TypeTableEntryIdUnion && wanted_type->id == TypeTableEntryIdEnum) {
1046810501 type_ensure_zero_bits_known(ira->codegen, actual_type);
1046910502 if (type_is_invalid(actual_type))
......@@ -10474,7 +10507,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1047410507 }
1047510508 }
1047610509
10477 // explicit enum to union which has the enum as the tag type
10510 // enum to union which has the enum as the tag type
1047810511 if (wanted_type->id == TypeTableEntryIdUnion && actual_type->id == TypeTableEntryIdEnum &&
1047910512 (wanted_type->data.unionation.decl_node->data.container_decl.auto_enum ||
1048010513 wanted_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr))
......@@ -10485,7 +10518,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1048510518 }
1048610519 }
1048710520
10488 // explicit enum to &const union which has the enum as the tag type
10521 // enum to &const union which has the enum as the tag type
1048910522 if (actual_type->id == TypeTableEntryIdEnum && wanted_type->id == TypeTableEntryIdPointer) {
1049010523 TypeTableEntry *union_type = wanted_type->data.pointer.child_type;
1049110524 if (union_type->data.unionation.decl_node->data.container_decl.auto_enum ||
......@@ -10506,7 +10539,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1050610539 }
1050710540 }
1050810541
10509 // explicit cast from *T to *[1]T
10542 // cast from *T to *[1]T
1051010543 if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
1051110544 actual_type->id == TypeTableEntryIdPointer && actual_type->data.pointer.ptr_len == PtrLenSingle)
1051210545 {
......@@ -10530,7 +10563,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1053010563 }
1053110564 }
1053210565
10533 // explicit cast from T to *T where T is zero bits
10566 // cast from T to *T where T is zero bits
1053410567 if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
1053510568 types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
1053610569 actual_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
......@@ -10545,12 +10578,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1054510578 }
1054610579
1054710580
10548 // explicit cast from undefined to anything
10581 // cast from undefined to anything
1054910582 if (actual_type->id == TypeTableEntryIdUndefined) {
1055010583 return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type);
1055110584 }
1055210585
10553 // explicit cast from something to const pointer of it
10586 // cast from something to const pointer of it
1055410587 if (!type_requires_comptime(actual_type)) {
1055510588 TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);
1055610589 if (types_match_const_cast_only(ira, wanted_type, const_ptr_actual, source_node, false).id == ConstCastResultIdOk) {
......@@ -10558,10 +10591,11 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1055810591 }
1055910592 }
1056010593
10561 ir_add_error_node(ira, source_instr->source_node,
10562 buf_sprintf("invalid cast from type '%s' to '%s'",
10563 buf_ptr(&actual_type->name),
10564 buf_ptr(&wanted_type->name)));
10594 ErrorMsg *parent_msg = ir_add_error_node(ira, source_instr->source_node,
10595 buf_sprintf("expected type '%s', found '%s'",
10596 buf_ptr(&wanted_type->name),
10597 buf_ptr(&actual_type->name)));
10598 report_recursive_error(ira, source_instr->source_node, &const_cast_result, parent_msg);
1056510599 return ira->codegen->invalid_instruction;
1056610600}
1056710601
......@@ -10578,22 +10612,7 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Typ
1057810612 if (value->value.type->id == TypeTableEntryIdUnreachable)
1057910613 return value;
1058010614
10581 ImplicitCastMatchResult result = ir_types_match_with_implicit_cast(ira, expected_type, value->value.type, value);
10582 switch (result) {
10583 case ImplicitCastMatchResultNo:
10584 ir_add_error(ira, value,
10585 buf_sprintf("expected type '%s', found '%s'",
10586 buf_ptr(&expected_type->name),
10587 buf_ptr(&value->value.type->name)));
10588 return ira->codegen->invalid_instruction;
10589
10590 case ImplicitCastMatchResultYes:
10591 return ir_analyze_cast(ira, value, expected_type, value);
10592 case ImplicitCastMatchResultReportedError:
10593 return ira->codegen->invalid_instruction;
10594 }
10595
10596 zig_unreachable();
10615 return ir_analyze_cast(ira, value, expected_type, value);
1059710616}
1059810617
1059910618static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) {
......@@ -10889,10 +10908,15 @@ static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp
1088910908 if (casted_op2 == ira->codegen->invalid_instruction)
1089010909 return ira->codegen->builtin_types.entry_invalid;
1089110910
10892 ConstExprValue *op1_val = &casted_op1->value;
10893 ConstExprValue *op2_val = &casted_op2->value;
10894 if (op1_val->special != ConstValSpecialRuntime && op2_val->special != ConstValSpecialRuntime) {
10911 if (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2)) {
1089510912 ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base);
10913 ConstExprValue *op1_val = ir_resolve_const(ira, casted_op1, UndefBad);
10914 if (op1_val == nullptr)
10915 return ira->codegen->builtin_types.entry_invalid;
10916
10917 ConstExprValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad);
10918 if (op2_val == nullptr)
10919 return ira->codegen->builtin_types.entry_invalid;
1089610920
1089710921 assert(casted_op1->value.type->id == TypeTableEntryIdBool);
1089810922 assert(casted_op2->value.type->id == TypeTableEntryIdBool);
......@@ -11042,9 +11066,14 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
1104211066 }
1104311067 }
1104411068
11045 ConstExprValue *op1_val = &op1->value;
11046 ConstExprValue *op2_val = &op2->value;
11047 if (value_is_comptime(op1_val) && value_is_comptime(op2_val)) {
11069 if (instr_is_comptime(op1) && instr_is_comptime(op2)) {
11070 ConstExprValue *op1_val = ir_resolve_const(ira, op1, UndefBad);
11071 if (op1_val == nullptr)
11072 return ira->codegen->builtin_types.entry_invalid;
11073 ConstExprValue *op2_val = ir_resolve_const(ira, op2, UndefBad);
11074 if (op2_val == nullptr)
11075 return ira->codegen->builtin_types.entry_invalid;
11076
1104811077 bool answer;
1104911078 bool are_equal = op1_val->data.x_err_set->value == op2_val->data.x_err_set->value;
1105011079 if (op_id == IrBinOpCmpEq) {
......@@ -11133,10 +11162,15 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
1113311162 if (casted_op2 == ira->codegen->invalid_instruction)
1113411163 return ira->codegen->builtin_types.entry_invalid;
1113511164
11136 ConstExprValue *op1_val = &casted_op1->value;
11137 ConstExprValue *op2_val = &casted_op2->value;
1113811165 bool one_possible_value = !type_requires_comptime(resolved_type) && !type_has_bits(resolved_type);
11139 if (one_possible_value || (value_is_comptime(op1_val) && value_is_comptime(op2_val))) {
11166 if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) {
11167 ConstExprValue *op1_val = one_possible_value ? &casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad);
11168 if (op1_val == nullptr)
11169 return ira->codegen->builtin_types.entry_invalid;
11170 ConstExprValue *op2_val = one_possible_value ? &casted_op2->value : ir_resolve_const(ira, casted_op2, UndefBad);
11171 if (op2_val == nullptr)
11172 return ira->codegen->builtin_types.entry_invalid;
11173
1114011174 bool answer;
1114111175 if (resolved_type->id == TypeTableEntryIdComptimeFloat || resolved_type->id == TypeTableEntryIdFloat) {
1114211176 Cmp cmp_result = float_cmp(op1_val, op2_val);
......@@ -11164,11 +11198,17 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
1116411198 if (resolved_type->id == TypeTableEntryIdInt && !resolved_type->data.integral.is_signed) {
1116511199 ConstExprValue *known_left_val;
1116611200 IrBinOp flipped_op_id;
11167 if (value_is_comptime(op1_val)) {
11168 known_left_val = op1_val;
11201 if (instr_is_comptime(casted_op1)) {
11202 known_left_val = ir_resolve_const(ira, casted_op1, UndefBad);
11203 if (known_left_val == nullptr)
11204 return ira->codegen->builtin_types.entry_invalid;
11205
1116911206 flipped_op_id = op_id;
11170 } else if (value_is_comptime(op2_val)) {
11171 known_left_val = op2_val;
11207 } else if (instr_is_comptime(casted_op2)) {
11208 known_left_val = ir_resolve_const(ira, casted_op2, UndefBad);
11209 if (known_left_val == nullptr)
11210 return ira->codegen->builtin_types.entry_invalid;
11211
1117211212 if (op_id == IrBinOpCmpLessThan) {
1117311213 flipped_op_id = IrBinOpCmpGreaterThan;
1117411214 } else if (op_id == IrBinOpCmpGreaterThan) {
......@@ -11413,6 +11453,26 @@ static TypeTableEntry *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *
1141311453 } else {
1141411454 TypeTableEntry *shift_amt_type = get_smallest_unsigned_int_type(ira->codegen,
1141511455 op1->value.type->data.integral.bit_count - 1);
11456 if (bin_op_instruction->op_id == IrBinOpBitShiftLeftLossy &&
11457 op2->value.type->id == TypeTableEntryIdComptimeInt) {
11458 if (!bigint_fits_in_bits(&op2->value.data.x_bigint,
11459 shift_amt_type->data.integral.bit_count,
11460 op2->value.data.x_bigint.is_negative)) {
11461 Buf *val_buf = buf_alloc();
11462 bigint_append_buf(val_buf, &op2->value.data.x_bigint, 10);
11463 ErrorMsg* msg = ir_add_error(ira,
11464 &bin_op_instruction->base,
11465 buf_sprintf("RHS of shift is too large for LHS type"));
11466 add_error_note(
11467 ira->codegen,
11468 msg,
11469 op2->source_node,
11470 buf_sprintf("value %s cannot fit into type %s",
11471 buf_ptr(val_buf),
11472 buf_ptr(&shift_amt_type->name)));
11473 return ira->codegen->builtin_types.entry_invalid;
11474 }
11475 }
1141611476
1141711477 casted_op2 = ir_implicit_cast(ira, op2, shift_amt_type);
1141811478 if (casted_op2 == ira->codegen->invalid_instruction)
......@@ -11420,8 +11480,14 @@ static TypeTableEntry *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *
1142011480 }
1142111481
1142211482 if (instr_is_comptime(op1) && instr_is_comptime(casted_op2)) {
11423 ConstExprValue *op1_val = &op1->value;
11424 ConstExprValue *op2_val = &casted_op2->value;
11483 ConstExprValue *op1_val = ir_resolve_const(ira, op1, UndefBad);
11484 if (op1_val == nullptr)
11485 return ira->codegen->builtin_types.entry_invalid;
11486
11487 ConstExprValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad);
11488 if (op2_val == nullptr)
11489 return ira->codegen->builtin_types.entry_invalid;
11490
1142511491 IrInstruction *result_instruction = ir_get_const(ira, &bin_op_instruction->base);
1142611492 ir_link_new_instruction(result_instruction, &bin_op_instruction->base);
1142711493 ConstExprValue *out_val = &result_instruction->value;
......@@ -11500,7 +11566,15 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
1150011566 if (is_signed_div) {
1150111567 bool ok = false;
1150211568 if (instr_is_comptime(op1) && instr_is_comptime(op2)) {
11503 if (bigint_cmp_zero(&op2->value.data.x_bigint) == CmpEQ) {
11569 ConstExprValue *op1_val = ir_resolve_const(ira, op1, UndefBad);
11570 if (op1_val == nullptr)
11571 return ira->codegen->builtin_types.entry_invalid;
11572
11573 ConstExprValue *op2_val = ir_resolve_const(ira, op2, UndefBad);
11574 if (op2_val == nullptr)
11575 return ira->codegen->builtin_types.entry_invalid;
11576
11577 if (bigint_cmp_zero(&op2_val->data.x_bigint) == CmpEQ) {
1150411578 // the division by zero error will be caught later, but we don't have a
1150511579 // division function ambiguity problem.
1150611580 op_id = IrBinOpDivTrunc;
......@@ -11508,8 +11582,8 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
1150811582 } else {
1150911583 BigInt trunc_result;
1151011584 BigInt floor_result;
11511 bigint_div_trunc(&trunc_result, &op1->value.data.x_bigint, &op2->value.data.x_bigint);
11512 bigint_div_floor(&floor_result, &op1->value.data.x_bigint, &op2->value.data.x_bigint);
11585 bigint_div_trunc(&trunc_result, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
11586 bigint_div_floor(&floor_result, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
1151311587 if (bigint_cmp(&trunc_result, &floor_result) == CmpEQ) {
1151411588 ok = true;
1151511589 op_id = IrBinOpDivTrunc;
......@@ -11530,7 +11604,15 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
1153011604 if (is_signed_div && (is_int || is_float)) {
1153111605 bool ok = false;
1153211606 if (instr_is_comptime(op1) && instr_is_comptime(op2)) {
11607 ConstExprValue *op1_val = ir_resolve_const(ira, op1, UndefBad);
11608 if (op1_val == nullptr)
11609 return ira->codegen->builtin_types.entry_invalid;
11610
1153311611 if (is_int) {
11612 ConstExprValue *op2_val = ir_resolve_const(ira, op2, UndefBad);
11613 if (op2_val == nullptr)
11614 return ira->codegen->builtin_types.entry_invalid;
11615
1153411616 if (bigint_cmp_zero(&op2->value.data.x_bigint) == CmpEQ) {
1153511617 // the division by zero error will be caught later, but we don't
1153611618 // have a remainder function ambiguity problem
......@@ -11538,14 +11620,19 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
1153811620 } else {
1153911621 BigInt rem_result;
1154011622 BigInt mod_result;
11541 bigint_rem(&rem_result, &op1->value.data.x_bigint, &op2->value.data.x_bigint);
11542 bigint_mod(&mod_result, &op1->value.data.x_bigint, &op2->value.data.x_bigint);
11623 bigint_rem(&rem_result, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
11624 bigint_mod(&mod_result, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
1154311625 ok = bigint_cmp(&rem_result, &mod_result) == CmpEQ;
1154411626 }
1154511627 } else {
1154611628 IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, resolved_type);
1154711629 if (casted_op2 == ira->codegen->invalid_instruction)
1154811630 return ira->codegen->builtin_types.entry_invalid;
11631
11632 ConstExprValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad);
11633 if (op2_val == nullptr)
11634 return ira->codegen->builtin_types.entry_invalid;
11635
1154911636 if (float_cmp_zero(&casted_op2->value) == CmpEQ) {
1155011637 // the division by zero error will be caught later, but we don't
1155111638 // have a remainder function ambiguity problem
......@@ -11553,8 +11640,8 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
1155311640 } else {
1155411641 ConstExprValue rem_result;
1155511642 ConstExprValue mod_result;
11556 float_rem(&rem_result, &op1->value, &casted_op2->value);
11557 float_mod(&mod_result, &op1->value, &casted_op2->value);
11643 float_rem(&rem_result, op1_val, op2_val);
11644 float_mod(&mod_result, op1_val, op2_val);
1155811645 ok = float_cmp(&rem_result, &mod_result) == CmpEQ;
1155911646 }
1156011647 }
......@@ -11612,8 +11699,13 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
1161211699 return ira->codegen->builtin_types.entry_invalid;
1161311700
1161411701 if (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2)) {
11615 ConstExprValue *op1_val = &casted_op1->value;
11616 ConstExprValue *op2_val = &casted_op2->value;
11702 ConstExprValue *op1_val = ir_resolve_const(ira, casted_op1, UndefBad);
11703 if (op1_val == nullptr)
11704 return ira->codegen->builtin_types.entry_invalid;
11705 ConstExprValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad);
11706 if (op2_val == nullptr)
11707 return ira->codegen->builtin_types.entry_invalid;
11708
1161711709 IrInstruction *result_instruction = ir_get_const(ira, &bin_op_instruction->base);
1161811710 ir_link_new_instruction(result_instruction, &bin_op_instruction->base);
1161911711 ConstExprValue *out_val = &result_instruction->value;
......@@ -11788,9 +11880,16 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *
1178811880 out_val->data.x_ptr.data.base_array.array_val = out_array_val;
1178911881 out_val->data.x_ptr.data.base_array.elem_index = 0;
1179011882 }
11791 out_array_val->data.x_array.s_none.elements = create_const_vals(new_len);
1179211883
11884 if (op1_array_val->data.x_array.special == ConstArraySpecialUndef &&
11885 op2_array_val->data.x_array.special == ConstArraySpecialUndef) {
11886 out_array_val->data.x_array.special = ConstArraySpecialUndef;
11887 return result_type;
11888 }
11889
11890 out_array_val->data.x_array.s_none.elements = create_const_vals(new_len);
1179311891 expand_undef_array(ira->codegen, op1_array_val);
11892 expand_undef_array(ira->codegen, op2_array_val);
1179411893
1179511894 size_t next_index = 0;
1179611895 for (size_t i = op1_array_index; i < op1_array_end; i += 1, next_index += 1) {
......@@ -11842,10 +11941,14 @@ static TypeTableEntry *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp
1184211941 }
1184311942
1184411943 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
11944 if (array_val->data.x_array.special == ConstArraySpecialUndef) {
11945 out_val->data.x_array.special = ConstArraySpecialUndef;
1184511946
11846 out_val->data.x_array.s_none.elements = create_const_vals(new_array_len);
11947 TypeTableEntry *child_type = array_type->data.array.child_type;
11948 return get_array_type(ira->codegen, child_type, new_array_len);
11949 }
1184711950
11848 expand_undef_array(ira->codegen, array_val);
11951 out_val->data.x_array.s_none.elements = create_const_vals(new_array_len);
1184911952
1185011953 uint64_t i = 0;
1185111954 for (uint64_t x = 0; x < mult_amt; x += 1) {
......@@ -12243,7 +12346,7 @@ static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
1224312346{
1224412347 if (instruction->optional == IrInstructionErrorReturnTrace::Null) {
1224512348 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
12246 TypeTableEntry *optional_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);
12349 TypeTableEntry *optional_type = get_optional_type(ira->codegen, ptr_to_stack_trace_type);
1224712350 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {
1224812351 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
1224912352 assert(get_codegen_ptr_type(optional_type) != nullptr);
......@@ -13172,7 +13275,11 @@ static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp
1317213275 // one of the ptr instructions
1317313276
1317413277 if (instr_is_comptime(value)) {
13175 ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &value->value);
13278 ConstExprValue *comptime_value = ir_resolve_const(ira, value, UndefBad);
13279 if (comptime_value == nullptr)
13280 return ira->codegen->builtin_types.entry_invalid;
13281
13282 ConstExprValue *pointee = const_ptr_pointee(ira->codegen, comptime_value);
1317613283 if (pointee->type == child_type) {
1317713284 ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base);
1317813285 copy_const_val(out_val, pointee, value->value.data.x_ptr.mut == ConstPtrMutComptimeConst);
......@@ -13221,7 +13328,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
1322113328 case TypeTableEntryIdPromise:
1322213329 {
1322313330 ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base);
13224 out_val->data.x_type = get_maybe_type(ira->codegen, type_entry);
13331 out_val->data.x_type = get_optional_type(ira->codegen, type_entry);
1322513332 return ira->codegen->builtin_types.entry_type;
1322613333 }
1322713334 case TypeTableEntryIdUnreachable:
......@@ -13289,7 +13396,7 @@ static TypeTableEntry *ir_analyze_bin_not(IrAnalyze *ira, IrInstructionUnOp *ins
1328913396 if (expr_type->id == TypeTableEntryIdInt) {
1329013397 if (instr_is_comptime(value)) {
1329113398 ConstExprValue *target_const_val = ir_resolve_const(ira, value, UndefBad);
13292 if (!target_const_val)
13399 if (target_const_val == nullptr)
1329313400 return ira->codegen->builtin_types.entry_invalid;
1329413401
1329513402 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
......@@ -16045,6 +16152,9 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIn
1604516152 assert(target->value.type->id == TypeTableEntryIdEnum);
1604616153
1604716154 if (instr_is_comptime(target)) {
16155 type_ensure_zero_bits_known(ira->codegen, target->value.type);
16156 if (type_is_invalid(target->value.type))
16157 return ira->codegen->builtin_types.entry_invalid;
1604816158 TypeEnumField *field = find_enum_field_by_tag(target->value.type, &target->value.data.x_bigint);
1604916159 ConstExprValue *array_val = create_const_str_lit(ira->codegen, field->name);
1605016160 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
......@@ -16442,7 +16552,7 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop
1644216552 true, false, PtrLenUnknown,
1644316553 get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8),
1644416554 0, 0);
16445 fn_def_fields[6].type = get_maybe_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr));
16555 fn_def_fields[6].type = get_optional_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr));
1644616556 if (fn_node->is_extern && buf_len(fn_node->lib_name) > 0) {
1644716557 fn_def_fields[6].data.x_optional = create_const_vals(1);
1644816558 ConstExprValue *lib_name = create_const_str_lit(ira->codegen, fn_node->lib_name);
......@@ -16722,16 +16832,20 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
1672216832 ConstExprValue *fields = create_const_vals(1);
1672316833 result->data.x_struct.fields = fields;
1672416834
16725 // @TODO ?type instead of using @typeOf(undefined) when we have no type.
16726 // child: type
16835 // child: ?type
1672716836 ensure_field_index(result->type, "child", 0);
1672816837 fields[0].special = ConstValSpecialStatic;
16729 fields[0].type = ira->codegen->builtin_types.entry_type;
16838 fields[0].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
1673016839
1673116840 if (type_entry->data.promise.result_type == nullptr)
16732 fields[0].data.x_type = ira->codegen->builtin_types.entry_undef;
16733 else
16734 fields[0].data.x_type = type_entry->data.promise.result_type;
16841 fields[0].data.x_optional = nullptr;
16842 else {
16843 ConstExprValue *child_type = create_const_vals(1);
16844 child_type->special = ConstValSpecialStatic;
16845 child_type->type = ira->codegen->builtin_types.entry_type;
16846 child_type->data.x_type = type_entry->data.promise.result_type;
16847 fields[0].data.x_optional = child_type;
16848 }
1673516849
1673616850 break;
1673716851 }
......@@ -16872,19 +16986,23 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
1687216986 fields[0].special = ConstValSpecialStatic;
1687316987 fields[0].type = ir_type_info_get_type(ira, "ContainerLayout");
1687416988 bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.unionation.layout);
16875 // tag_type: type
16989 // tag_type: ?type
1687616990 ensure_field_index(result->type, "tag_type", 1);
1687716991 fields[1].special = ConstValSpecialStatic;
16878 fields[1].type = ira->codegen->builtin_types.entry_type;
16879 // @TODO ?type instead of using @typeOf(undefined) when we have no type.
16992 fields[1].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
16993
1688016994 AstNode *union_decl_node = type_entry->data.unionation.decl_node;
1688116995 if (union_decl_node->data.container_decl.auto_enum ||
1688216996 union_decl_node->data.container_decl.init_arg_expr != nullptr)
1688316997 {
16884 fields[1].data.x_type = type_entry->data.unionation.tag_type;
16998 ConstExprValue *tag_type = create_const_vals(1);
16999 tag_type->special = ConstValSpecialStatic;
17000 tag_type->type = ira->codegen->builtin_types.entry_type;
17001 tag_type->data.x_type = type_entry->data.unionation.tag_type;
17002 fields[1].data.x_optional = tag_type;
1688517003 }
1688617004 else
16887 fields[1].data.x_type = ira->codegen->builtin_types.entry_undef;
17005 fields[1].data.x_optional = nullptr;
1688817006 // fields: []TypeInfo.UnionField
1688917007 ensure_field_index(result->type, "fields", 2);
1689017008
......@@ -16911,9 +17029,9 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
1691117029
1691217030 ConstExprValue *inner_fields = create_const_vals(3);
1691317031 inner_fields[1].special = ConstValSpecialStatic;
16914 inner_fields[1].type = get_maybe_type(ira->codegen, type_info_enum_field_type);
17032 inner_fields[1].type = get_optional_type(ira->codegen, type_info_enum_field_type);
1691517033
16916 if (fields[1].data.x_type == ira->codegen->builtin_types.entry_undef) {
17034 if (fields[1].data.x_optional == nullptr) {
1691717035 inner_fields[1].data.x_optional = nullptr;
1691817036 } else {
1691917037 inner_fields[1].data.x_optional = create_const_vals(1);
......@@ -16982,7 +17100,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
1698217100
1698317101 ConstExprValue *inner_fields = create_const_vals(3);
1698417102 inner_fields[1].special = ConstValSpecialStatic;
16985 inner_fields[1].type = get_maybe_type(ira->codegen, ira->codegen->builtin_types.entry_usize);
17103 inner_fields[1].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_usize);
1698617104
1698717105 if (!type_has_bits(struct_field->type_entry)) {
1698817106 inner_fields[1].data.x_optional = nullptr;
......@@ -17022,8 +17140,6 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
1702217140 ConstExprValue *fields = create_const_vals(6);
1702317141 result->data.x_struct.fields = fields;
1702417142
17025 // @TODO Fix type = undefined with ?type
17026
1702717143 // calling_convention: TypeInfo.CallingConvention
1702817144 ensure_field_index(result->type, "calling_convention", 0);
1702917145 fields[0].special = ConstValSpecialStatic;
......@@ -17041,22 +17157,32 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
1704117157 fields[2].special = ConstValSpecialStatic;
1704217158 fields[2].type = ira->codegen->builtin_types.entry_bool;
1704317159 fields[2].data.x_bool = type_entry->data.fn.fn_type_id.is_var_args;
17044 // return_type: type
17160 // return_type: ?type
1704517161 ensure_field_index(result->type, "return_type", 3);
1704617162 fields[3].special = ConstValSpecialStatic;
17047 fields[3].type = ira->codegen->builtin_types.entry_type;
17163 fields[3].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
1704817164 if (type_entry->data.fn.fn_type_id.return_type == nullptr)
17049 fields[3].data.x_type = ira->codegen->builtin_types.entry_undef;
17050 else
17051 fields[3].data.x_type = type_entry->data.fn.fn_type_id.return_type;
17165 fields[3].data.x_optional = nullptr;
17166 else {
17167 ConstExprValue *return_type = create_const_vals(1);
17168 return_type->special = ConstValSpecialStatic;
17169 return_type->type = ira->codegen->builtin_types.entry_type;
17170 return_type->data.x_type = type_entry->data.fn.fn_type_id.return_type;
17171 fields[3].data.x_optional = return_type;
17172 }
1705217173 // async_allocator_type: type
1705317174 ensure_field_index(result->type, "async_allocator_type", 4);
1705417175 fields[4].special = ConstValSpecialStatic;
17055 fields[4].type = ira->codegen->builtin_types.entry_type;
17176 fields[4].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
1705617177 if (type_entry->data.fn.fn_type_id.async_allocator_type == nullptr)
17057 fields[4].data.x_type = ira->codegen->builtin_types.entry_undef;
17058 else
17059 fields[4].data.x_type = type_entry->data.fn.fn_type_id.async_allocator_type;
17178 fields[4].data.x_optional = nullptr;
17179 else {
17180 ConstExprValue *async_alloc_type = create_const_vals(1);
17181 async_alloc_type->special = ConstValSpecialStatic;
17182 async_alloc_type->type = ira->codegen->builtin_types.entry_type;
17183 async_alloc_type->data.x_type = type_entry->data.fn.fn_type_id.async_allocator_type;
17184 fields[4].data.x_optional = async_alloc_type;
17185 }
1706017186 // args: []TypeInfo.FnArg
1706117187 TypeTableEntry *type_info_fn_arg_type = ir_type_info_get_type(ira, "FnArg");
1706217188 size_t fn_arg_count = type_entry->data.fn.fn_type_id.param_count -
......@@ -17090,12 +17216,17 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
1709017216 inner_fields[1].type = ira->codegen->builtin_types.entry_bool;
1709117217 inner_fields[1].data.x_bool = fn_param_info->is_noalias;
1709217218 inner_fields[2].special = ConstValSpecialStatic;
17093 inner_fields[2].type = ira->codegen->builtin_types.entry_type;
17219 inner_fields[2].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
1709417220
1709517221 if (arg_is_generic)
17096 inner_fields[2].data.x_type = ira->codegen->builtin_types.entry_undef;
17097 else
17098 inner_fields[2].data.x_type = fn_param_info->type;
17222 inner_fields[2].data.x_optional = nullptr;
17223 else {
17224 ConstExprValue *arg_type = create_const_vals(1);
17225 arg_type->special = ConstValSpecialStatic;
17226 arg_type->type = ira->codegen->builtin_types.entry_type;
17227 arg_type->data.x_type = fn_param_info->type;
17228 inner_fields[2].data.x_optional = arg_type;
17229 }
1709917230
1710017231 fn_arg_val->data.x_struct.fields = inner_fields;
1710117232 fn_arg_val->data.x_struct.parent.id = ConstParentIdArray;
......@@ -17437,7 +17568,7 @@ static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstruct
1743717568 IrInstruction *result = ir_build_cmpxchg(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
1743817569 nullptr, casted_ptr, casted_cmp_value, casted_new_value, nullptr, nullptr, instruction->is_weak,
1743917570 operand_type, success_order, failure_order);
17440 result->value.type = get_maybe_type(ira->codegen, operand_type);
17571 result->value.type = get_optional_type(ira->codegen, operand_type);
1744117572 ir_link_new_instruction(result, &instruction->base);
1744217573 ir_add_alloca(ira, result, result->value.type);
1744317574 return result->value.type;
......@@ -17593,6 +17724,137 @@ static TypeTableEntry *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstr
1759317724 return dest_type;
1759417725}
1759517726
17727static TypeTableEntry *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstructionErrSetCast *instruction) {
17728 TypeTableEntry *dest_type = ir_resolve_type(ira, instruction->dest_type->other);
17729 if (type_is_invalid(dest_type))
17730 return ira->codegen->builtin_types.entry_invalid;
17731
17732 if (dest_type->id != TypeTableEntryIdErrorSet) {
17733 ir_add_error(ira, instruction->dest_type,
17734 buf_sprintf("expected error set type, found '%s'", buf_ptr(&dest_type->name)));
17735 return ira->codegen->builtin_types.entry_invalid;
17736 }
17737
17738 IrInstruction *target = instruction->target->other;
17739 if (type_is_invalid(target->value.type))
17740 return ira->codegen->builtin_types.entry_invalid;
17741
17742 if (target->value.type->id != TypeTableEntryIdErrorSet) {
17743 ir_add_error(ira, instruction->target,
17744 buf_sprintf("expected error set type, found '%s'", buf_ptr(&target->value.type->name)));
17745 return ira->codegen->builtin_types.entry_invalid;
17746 }
17747
17748 IrInstruction *result = ir_analyze_err_set_cast(ira, &instruction->base, target, dest_type);
17749 if (type_is_invalid(result->value.type))
17750 return ira->codegen->builtin_types.entry_invalid;
17751 ir_link_new_instruction(result, &instruction->base);
17752 return dest_type;
17753}
17754
17755static TypeTableEntry *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionFromBytes *instruction) {
17756 TypeTableEntry *dest_child_type = ir_resolve_type(ira, instruction->dest_child_type->other);
17757 if (type_is_invalid(dest_child_type))
17758 return ira->codegen->builtin_types.entry_invalid;
17759
17760 IrInstruction *target = instruction->target->other;
17761 if (type_is_invalid(target->value.type))
17762 return ira->codegen->builtin_types.entry_invalid;
17763
17764 bool src_ptr_const;
17765 bool src_ptr_volatile;
17766 uint32_t src_ptr_align;
17767 if (target->value.type->id == TypeTableEntryIdPointer) {
17768 src_ptr_const = target->value.type->data.pointer.is_const;
17769 src_ptr_volatile = target->value.type->data.pointer.is_volatile;
17770 src_ptr_align = target->value.type->data.pointer.alignment;
17771 } else if (is_slice(target->value.type)) {
17772 TypeTableEntry *src_ptr_type = target->value.type->data.structure.fields[slice_ptr_index].type_entry;
17773 src_ptr_const = src_ptr_type->data.pointer.is_const;
17774 src_ptr_volatile = src_ptr_type->data.pointer.is_volatile;
17775 src_ptr_align = src_ptr_type->data.pointer.alignment;
17776 } else {
17777 src_ptr_const = true;
17778 src_ptr_volatile = false;
17779 src_ptr_align = get_abi_alignment(ira->codegen, target->value.type);
17780 }
17781
17782 TypeTableEntry *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_child_type,
17783 src_ptr_const, src_ptr_volatile, PtrLenUnknown,
17784 src_ptr_align, 0, 0);
17785 TypeTableEntry *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type);
17786
17787 TypeTableEntry *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
17788 src_ptr_const, src_ptr_volatile, PtrLenUnknown,
17789 src_ptr_align, 0, 0);
17790 TypeTableEntry *u8_slice = get_slice_type(ira->codegen, u8_ptr);
17791
17792 IrInstruction *casted_value = ir_implicit_cast(ira, target, u8_slice);
17793 if (type_is_invalid(casted_value->value.type))
17794 return ira->codegen->builtin_types.entry_invalid;
17795
17796 bool have_known_len = false;
17797 uint64_t known_len;
17798
17799 if (instr_is_comptime(casted_value)) {
17800 ConstExprValue *val = ir_resolve_const(ira, casted_value, UndefBad);
17801 if (!val)
17802 return ira->codegen->builtin_types.entry_invalid;
17803
17804 ConstExprValue *len_val = &val->data.x_struct.fields[slice_len_index];
17805 if (value_is_comptime(len_val)) {
17806 known_len = bigint_as_unsigned(&len_val->data.x_bigint);
17807 have_known_len = true;
17808 }
17809 }
17810
17811 if (casted_value->value.data.rh_slice.id == RuntimeHintSliceIdLen) {
17812 known_len = casted_value->value.data.rh_slice.len;
17813 have_known_len = true;
17814 }
17815
17816 if (have_known_len) {
17817 uint64_t child_type_size = type_size(ira->codegen, dest_child_type);
17818 uint64_t remainder = known_len % child_type_size;
17819 if (remainder != 0) {
17820 ErrorMsg *msg = ir_add_error(ira, &instruction->base,
17821 buf_sprintf("unable to convert [%" ZIG_PRI_u64 "]u8 to %s: size mismatch",
17822 known_len, buf_ptr(&dest_slice_type->name)));
17823 add_error_note(ira->codegen, msg, instruction->dest_child_type->source_node,
17824 buf_sprintf("%s has size %" ZIG_PRI_u64 "; remaining bytes: %" ZIG_PRI_u64,
17825 buf_ptr(&dest_child_type->name), child_type_size, remainder));
17826 return ira->codegen->builtin_types.entry_invalid;
17827 }
17828 }
17829
17830 IrInstruction *result = ir_resolve_cast(ira, &instruction->base, casted_value, dest_slice_type, CastOpResizeSlice, true);
17831 ir_link_new_instruction(result, &instruction->base);
17832 return dest_slice_type;
17833}
17834
17835static TypeTableEntry *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstructionToBytes *instruction) {
17836 IrInstruction *target = instruction->target->other;
17837 if (type_is_invalid(target->value.type))
17838 return ira->codegen->builtin_types.entry_invalid;
17839
17840 if (!is_slice(target->value.type)) {
17841 ir_add_error(ira, instruction->target,
17842 buf_sprintf("expected slice, found '%s'", buf_ptr(&target->value.type->name)));
17843 return ira->codegen->builtin_types.entry_invalid;
17844 }
17845
17846 TypeTableEntry *src_ptr_type = target->value.type->data.structure.fields[slice_ptr_index].type_entry;
17847
17848 TypeTableEntry *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
17849 src_ptr_type->data.pointer.is_const, src_ptr_type->data.pointer.is_volatile, PtrLenUnknown,
17850 src_ptr_type->data.pointer.alignment, 0, 0);
17851 TypeTableEntry *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type);
17852
17853 IrInstruction *result = ir_resolve_cast(ira, &instruction->base, target, dest_slice_type, CastOpResizeSlice, true);
17854 ir_link_new_instruction(result, &instruction->base);
17855 return dest_slice_type;
17856}
17857
1759617858static TypeTableEntry *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) {
1759717859 TypeTableEntry *dest_type = ir_resolve_type(ira, instruction->dest_type->other);
1759817860 if (type_is_invalid(dest_type))
......@@ -17627,6 +17889,39 @@ static TypeTableEntry *ir_analyze_instruction_float_to_int(IrAnalyze *ira, IrIns
1762717889 return dest_type;
1762817890}
1762917891
17892static TypeTableEntry *ir_analyze_instruction_err_to_int(IrAnalyze *ira, IrInstructionErrToInt *instruction) {
17893 IrInstruction *target = instruction->target->other;
17894 if (type_is_invalid(target->value.type))
17895 return ira->codegen->builtin_types.entry_invalid;
17896
17897 IrInstruction *casted_target;
17898 if (target->value.type->id == TypeTableEntryIdErrorSet) {
17899 casted_target = target;
17900 } else {
17901 casted_target = ir_implicit_cast(ira, target, ira->codegen->builtin_types.entry_global_error_set);
17902 if (type_is_invalid(casted_target->value.type))
17903 return ira->codegen->builtin_types.entry_invalid;
17904 }
17905
17906 IrInstruction *result = ir_analyze_err_to_int(ira, &instruction->base, casted_target, ira->codegen->err_tag_type);
17907 ir_link_new_instruction(result, &instruction->base);
17908 return result->value.type;
17909}
17910
17911static TypeTableEntry *ir_analyze_instruction_int_to_err(IrAnalyze *ira, IrInstructionIntToErr *instruction) {
17912 IrInstruction *target = instruction->target->other;
17913 if (type_is_invalid(target->value.type))
17914 return ira->codegen->builtin_types.entry_invalid;
17915
17916 IrInstruction *casted_target = ir_implicit_cast(ira, target, ira->codegen->err_tag_type);
17917 if (type_is_invalid(casted_target->value.type))
17918 return ira->codegen->builtin_types.entry_invalid;
17919
17920 IrInstruction *result = ir_analyze_int_to_err(ira, &instruction->base, casted_target, ira->codegen->builtin_types.entry_global_error_set);
17921 ir_link_new_instruction(result, &instruction->base);
17922 return result->value.type;
17923}
17924
1763017925static TypeTableEntry *ir_analyze_instruction_bool_to_int(IrAnalyze *ira, IrInstructionBoolToInt *instruction) {
1763117926 IrInstruction *target = instruction->target->other;
1763217927 if (type_is_invalid(target->value.type))
......@@ -17681,9 +17976,13 @@ static TypeTableEntry *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstruc
1768117976 if (type_is_invalid(casted_value->value.type))
1768217977 return ira->codegen->builtin_types.entry_invalid;
1768317978
17684 if (casted_value->value.special != ConstValSpecialRuntime) {
17979 if (instr_is_comptime(casted_value)) {
17980 ConstExprValue *value = ir_resolve_const(ira, casted_value, UndefBad);
17981 if (value == nullptr)
17982 return ira->codegen->builtin_types.entry_invalid;
17983
1768517984 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
17686 out_val->data.x_bool = !casted_value->value.data.x_bool;
17985 out_val->data.x_bool = !value->data.x_bool;
1768717986 return bool_type;
1768817987 }
1768917988
......@@ -18944,7 +19243,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
1894419243 old_align_bytes = ptr_type->data.pointer.alignment;
1894519244 TypeTableEntry *better_ptr_type = adjust_ptr_align(ira->codegen, ptr_type, align_bytes);
1894619245
18947 result_type = get_maybe_type(ira->codegen, better_ptr_type);
19246 result_type = get_optional_type(ira->codegen, better_ptr_type);
1894819247 } else if (target_type->id == TypeTableEntryIdOptional &&
1894919248 target_type->data.maybe.child_type->id == TypeTableEntryIdFn)
1895019249 {
......@@ -18952,7 +19251,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
1895219251 old_align_bytes = fn_type_id.alignment;
1895319252 fn_type_id.alignment = align_bytes;
1895419253 TypeTableEntry *fn_type = get_fn_type(ira->codegen, &fn_type_id);
18955 result_type = get_maybe_type(ira->codegen, fn_type);
19254 result_type = get_optional_type(ira->codegen, fn_type);
1895619255 } else if (is_slice(target_type)) {
1895719256 TypeTableEntry *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;
1895819257 old_align_bytes = slice_ptr_type->data.pointer.alignment;
......@@ -19713,7 +20012,7 @@ static TypeTableEntry *ir_analyze_instruction_coro_free(IrAnalyze *ira, IrInstru
1971320012 instruction->base.source_node, coro_id, coro_handle);
1971420013 ir_link_new_instruction(result, &instruction->base);
1971520014 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, false);
19716 result->value.type = get_maybe_type(ira->codegen, ptr_type);
20015 result->value.type = get_optional_type(ira->codegen, ptr_type);
1971720016 return result->value.type;
1971820017}
1971920018
......@@ -19781,7 +20080,7 @@ static TypeTableEntry *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira,
1978120080 instruction->base.source_node, alloc_fn, coro_size);
1978220081 ir_link_new_instruction(result, &instruction->base);
1978320082 TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, false);
19784 result->value.type = get_maybe_type(ira->codegen, u8_ptr_type);
20083 result->value.type = get_optional_type(ira->codegen, u8_ptr_type);
1978520084 return result->value.type;
1978620085}
1978720086
......@@ -20034,6 +20333,9 @@ static TypeTableEntry *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstruction
2003420333 bigfloat_sqrt(&out_val->data.x_bigfloat, &val->data.x_bigfloat);
2003520334 } else if (float_type->id == TypeTableEntryIdFloat) {
2003620335 switch (float_type->data.floating.bit_count) {
20336 case 16:
20337 out_val->data.x_f16 = f16_sqrt(val->data.x_f16);
20338 break;
2003720339 case 32:
2003820340 out_val->data.x_f32 = sqrtf(val->data.x_f32);
2003920341 break;
......@@ -20054,7 +20356,9 @@ static TypeTableEntry *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstruction
2005420356 }
2005520357
2005620358 assert(float_type->id == TypeTableEntryIdFloat);
20057 if (float_type->data.floating.bit_count != 32 && float_type->data.floating.bit_count != 64) {
20359 if (float_type->data.floating.bit_count != 16 &&
20360 float_type->data.floating.bit_count != 32 &&
20361 float_type->data.floating.bit_count != 64) {
2005820362 ir_add_error(ira, instruction->type, buf_sprintf("compiler TODO: add implementation of sqrt for '%s'", buf_ptr(&float_type->name)));
2005920363 return ira->codegen->builtin_types.entry_invalid;
2006020364 }
......@@ -20066,13 +20370,63 @@ static TypeTableEntry *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstruction
2006620370 return result->value.type;
2006720371}
2006820372
20373static TypeTableEntry *ir_analyze_instruction_enum_to_int(IrAnalyze *ira, IrInstructionEnumToInt *instruction) {
20374 IrInstruction *target = instruction->target->other;
20375 if (type_is_invalid(target->value.type))
20376 return ira->codegen->builtin_types.entry_invalid;
20377
20378 if (target->value.type->id != TypeTableEntryIdEnum) {
20379 ir_add_error(ira, instruction->target,
20380 buf_sprintf("expected enum, found type '%s'", buf_ptr(&target->value.type->name)));
20381 return ira->codegen->builtin_types.entry_invalid;
20382 }
20383
20384 type_ensure_zero_bits_known(ira->codegen, target->value.type);
20385 if (type_is_invalid(target->value.type))
20386 return ira->codegen->builtin_types.entry_invalid;
20387
20388 TypeTableEntry *tag_type = target->value.type->data.enumeration.tag_int_type;
20389
20390 IrInstruction *result = ir_analyze_enum_to_int(ira, &instruction->base, target, tag_type);
20391 ir_link_new_instruction(result, &instruction->base);
20392 return result->value.type;
20393}
20394
20395static TypeTableEntry *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInstructionIntToEnum *instruction) {
20396 IrInstruction *dest_type_value = instruction->dest_type->other;
20397 TypeTableEntry *dest_type = ir_resolve_type(ira, dest_type_value);
20398 if (type_is_invalid(dest_type))
20399 return ira->codegen->builtin_types.entry_invalid;
20400
20401 if (dest_type->id != TypeTableEntryIdEnum) {
20402 ir_add_error(ira, instruction->dest_type,
20403 buf_sprintf("expected enum, found type '%s'", buf_ptr(&dest_type->name)));
20404 return ira->codegen->builtin_types.entry_invalid;
20405 }
20406
20407 type_ensure_zero_bits_known(ira->codegen, dest_type);
20408 if (type_is_invalid(dest_type))
20409 return ira->codegen->builtin_types.entry_invalid;
20410
20411 TypeTableEntry *tag_type = dest_type->data.enumeration.tag_int_type;
20412
20413 IrInstruction *target = instruction->target->other;
20414 if (type_is_invalid(target->value.type))
20415 return ira->codegen->builtin_types.entry_invalid;
20416
20417 IrInstruction *casted_target = ir_implicit_cast(ira, target, tag_type);
20418 if (type_is_invalid(casted_target->value.type))
20419 return ira->codegen->builtin_types.entry_invalid;
20420
20421 IrInstruction *result = ir_analyze_int_to_enum(ira, &instruction->base, casted_target, dest_type);
20422 ir_link_new_instruction(result, &instruction->base);
20423 return result->value.type;
20424}
20425
2006920426static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
2007020427 switch (instruction->id) {
2007120428 case IrInstructionIdInvalid:
2007220429 case IrInstructionIdWidenOrShorten:
20073 case IrInstructionIdIntToEnum:
20074 case IrInstructionIdIntToErr:
20075 case IrInstructionIdErrToInt:
2007620430 case IrInstructionIdStructInit:
2007720431 case IrInstructionIdUnionInit:
2007820432 case IrInstructionIdStructFieldPtr:
......@@ -20193,6 +20547,12 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
2019320547 return ir_analyze_instruction_int_cast(ira, (IrInstructionIntCast *)instruction);
2019420548 case IrInstructionIdFloatCast:
2019520549 return ir_analyze_instruction_float_cast(ira, (IrInstructionFloatCast *)instruction);
20550 case IrInstructionIdErrSetCast:
20551 return ir_analyze_instruction_err_set_cast(ira, (IrInstructionErrSetCast *)instruction);
20552 case IrInstructionIdFromBytes:
20553 return ir_analyze_instruction_from_bytes(ira, (IrInstructionFromBytes *)instruction);
20554 case IrInstructionIdToBytes:
20555 return ir_analyze_instruction_to_bytes(ira, (IrInstructionToBytes *)instruction);
2019620556 case IrInstructionIdIntToFloat:
2019720557 return ir_analyze_instruction_int_to_float(ira, (IrInstructionIntToFloat *)instruction);
2019820558 case IrInstructionIdFloatToInt:
......@@ -20327,6 +20687,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
2032720687 return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction);
2032820688 case IrInstructionIdSqrt:
2032920689 return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction);
20690 case IrInstructionIdIntToErr:
20691 return ir_analyze_instruction_int_to_err(ira, (IrInstructionIntToErr *)instruction);
20692 case IrInstructionIdErrToInt:
20693 return ir_analyze_instruction_err_to_int(ira, (IrInstructionErrToInt *)instruction);
20694 case IrInstructionIdIntToEnum:
20695 return ir_analyze_instruction_int_to_enum(ira, (IrInstructionIntToEnum *)instruction);
20696 case IrInstructionIdEnumToInt:
20697 return ir_analyze_instruction_enum_to_int(ira, (IrInstructionEnumToInt *)instruction);
2033020698 }
2033120699 zig_unreachable();
2033220700}
......@@ -20544,9 +20912,13 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2054420912 case IrInstructionIdAtomicLoad:
2054520913 case IrInstructionIdIntCast:
2054620914 case IrInstructionIdFloatCast:
20915 case IrInstructionIdErrSetCast:
2054720916 case IrInstructionIdIntToFloat:
2054820917 case IrInstructionIdFloatToInt:
2054920918 case IrInstructionIdBoolToInt:
20919 case IrInstructionIdFromBytes:
20920 case IrInstructionIdToBytes:
20921 case IrInstructionIdEnumToInt:
2055020922 return false;
2055120923
2055220924 case IrInstructionIdAsm:
src/ir_print.cpp+45
......@@ -664,6 +664,28 @@ static void ir_print_float_cast(IrPrint *irp, IrInstructionFloatCast *instructio
664664 fprintf(irp->f, ")");
665665}
666666
667static void ir_print_err_set_cast(IrPrint *irp, IrInstructionErrSetCast *instruction) {
668 fprintf(irp->f, "@errSetCast(");
669 ir_print_other_instruction(irp, instruction->dest_type);
670 fprintf(irp->f, ", ");
671 ir_print_other_instruction(irp, instruction->target);
672 fprintf(irp->f, ")");
673}
674
675static void ir_print_from_bytes(IrPrint *irp, IrInstructionFromBytes *instruction) {
676 fprintf(irp->f, "@bytesToSlice(");
677 ir_print_other_instruction(irp, instruction->dest_child_type);
678 fprintf(irp->f, ", ");
679 ir_print_other_instruction(irp, instruction->target);
680 fprintf(irp->f, ")");
681}
682
683static void ir_print_to_bytes(IrPrint *irp, IrInstructionToBytes *instruction) {
684 fprintf(irp->f, "@sliceToBytes(");
685 ir_print_other_instruction(irp, instruction->target);
686 fprintf(irp->f, ")");
687}
688
667689static void ir_print_int_to_float(IrPrint *irp, IrInstructionIntToFloat *instruction) {
668690 fprintf(irp->f, "@intToFloat(");
669691 ir_print_other_instruction(irp, instruction->dest_type);
......@@ -906,6 +928,17 @@ static void ir_print_int_to_ptr(IrPrint *irp, IrInstructionIntToPtr *instruction
906928
907929static void ir_print_int_to_enum(IrPrint *irp, IrInstructionIntToEnum *instruction) {
908930 fprintf(irp->f, "@intToEnum(");
931 if (instruction->dest_type == nullptr) {
932 fprintf(irp->f, "(null)");
933 } else {
934 ir_print_other_instruction(irp, instruction->dest_type);
935 }
936 ir_print_other_instruction(irp, instruction->target);
937 fprintf(irp->f, ")");
938}
939
940static void ir_print_enum_to_int(IrPrint *irp, IrInstructionEnumToInt *instruction) {
941 fprintf(irp->f, "@enumToInt(");
909942 ir_print_other_instruction(irp, instruction->target);
910943 fprintf(irp->f, ")");
911944}
......@@ -1461,6 +1494,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
14611494 case IrInstructionIdFloatCast:
14621495 ir_print_float_cast(irp, (IrInstructionFloatCast *)instruction);
14631496 break;
1497 case IrInstructionIdErrSetCast:
1498 ir_print_err_set_cast(irp, (IrInstructionErrSetCast *)instruction);
1499 break;
1500 case IrInstructionIdFromBytes:
1501 ir_print_from_bytes(irp, (IrInstructionFromBytes *)instruction);
1502 break;
1503 case IrInstructionIdToBytes:
1504 ir_print_to_bytes(irp, (IrInstructionToBytes *)instruction);
1505 break;
14641506 case IrInstructionIdIntToFloat:
14651507 ir_print_int_to_float(irp, (IrInstructionIntToFloat *)instruction);
14661508 break;
......@@ -1686,6 +1728,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
16861728 case IrInstructionIdAtomicLoad:
16871729 ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction);
16881730 break;
1731 case IrInstructionIdEnumToInt:
1732 ir_print_enum_to_int(irp, (IrInstructionEnumToInt *)instruction);
1733 break;
16891734 }
16901735 fprintf(irp->f, "\n");
16911736}
src/link.cpp+7-4
......@@ -325,10 +325,13 @@ static void construct_linker_job_elf(LinkJob *lj) {
325325 lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
326326 }
327327
328 if (g->libc_link_lib == nullptr && (g->out_type == OutTypeExe || g->out_type == OutTypeLib)) {
329 Buf *builtin_o_path = build_o(g, "builtin");
330 lj->args.append(buf_ptr(builtin_o_path));
328 if (g->out_type == OutTypeExe || g->out_type == OutTypeLib) {
329 if (g->libc_link_lib == nullptr) {
330 Buf *builtin_o_path = build_o(g, "builtin");
331 lj->args.append(buf_ptr(builtin_o_path));
332 }
331333
334 // sometimes libgcc is missing stuff, so we still build compiler_rt and rely on weak linkage
332335 Buf *compiler_rt_o_path = build_compiler_rt(g);
333336 lj->args.append(buf_ptr(compiler_rt_o_path));
334337 }
......@@ -554,7 +557,7 @@ static void construct_linker_job_coff(LinkJob *lj) {
554557 lj->args.append(buf_ptr(builtin_o_path));
555558 }
556559
557 // msvc compiler_rt is missing some stuff, so we still build it and rely on LinkOnce
560 // msvc compiler_rt is missing some stuff, so we still build it and rely on weak linkage
558561 Buf *compiler_rt_o_path = build_compiler_rt(g);
559562 lj->args.append(buf_ptr(compiler_rt_o_path));
560563 }
src/main.cpp+2
......@@ -924,6 +924,8 @@ int main(int argc, char **argv) {
924924 codegen_print_timing_report(g, stdout);
925925 return EXIT_SUCCESS;
926926 } else if (cmd == CmdTest) {
927 codegen_set_emit_file_type(g, emit_file_type);
928
927929 ZigTarget native;
928930 get_native_target(&native);
929931
src/os.cpp+5
......@@ -225,6 +225,11 @@ void os_path_extname(Buf *full_path, Buf *out_basename, Buf *out_extname) {
225225}
226226
227227void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) {
228 if (buf_len(dirname) == 0) {
229 buf_init_from_buf(out_full_path, basename);
230 return;
231 }
232
228233 buf_init_from_buf(out_full_path, dirname);
229234 uint8_t c = *(buf_ptr(out_full_path) + buf_len(out_full_path) - 1);
230235 if (!os_is_sep(c))
src/tokenizer.cpp+9-2
......@@ -357,12 +357,19 @@ static void end_float_token(Tokenize *t) {
357357 // Mask the sign bit to 0 since always non-negative lex
358358 const uint64_t exp_mask = 0xffffull << exp_shift;
359359
360 if (shift >= 64) {
360 // must be special-cased to avoid undefined behavior on shift == 64
361 if (shift == 128) {
362 f_bits.repr[0] = 0;
363 f_bits.repr[1] = sig_bits[0];
364 } else if (shift == 0) {
365 f_bits.repr[0] = sig_bits[0];
366 f_bits.repr[1] = sig_bits[1];
367 } else if (shift >= 64) {
361368 f_bits.repr[0] = 0;
362369 f_bits.repr[1] = sig_bits[0] << (shift - 64);
363370 } else {
364371 f_bits.repr[0] = sig_bits[0] << shift;
365 f_bits.repr[1] = ((sig_bits[1] << shift) | (sig_bits[0] >> (64 - shift)));
372 f_bits.repr[1] = (sig_bits[1] << shift) | (sig_bits[0] >> (64 - shift));
366373 }
367374
368375 f_bits.repr[1] &= ~exp_mask;
src/util.hpp+19
......@@ -31,6 +31,8 @@
3131
3232#endif
3333
34#include "softfloat.hpp"
35
3436#define BREAKPOINT __asm("int $0x03")
3537
3638ATTRIBUTE_COLD
......@@ -165,4 +167,21 @@ static inline uint8_t log2_u64(uint64_t x) {
165167 return (63 - clzll(x));
166168}
167169
170static inline float16_t zig_double_to_f16(double x) {
171 float64_t y;
172 static_assert(sizeof(x) == sizeof(y), "");
173 memcpy(&y, &x, sizeof(x));
174 return f64_to_f16(y);
175}
176
177
178// Return value is safe to coerce to float even when |x| is NaN or Infinity.
179static inline double zig_f16_to_double(float16_t x) {
180 float64_t y = f16_to_f64(x);
181 double z;
182 static_assert(sizeof(y) == sizeof(z), "");
183 memcpy(&z, &y, sizeof(y));
184 return z;
185}
186
168187#endif
std/atomic/index.zig+5-3
......@@ -1,7 +1,9 @@
11pub const Stack = @import("stack.zig").Stack;
2pub const Queue = @import("queue.zig").Queue;
2pub const QueueMpsc = @import("queue_mpsc.zig").QueueMpsc;
3pub const QueueMpmc = @import("queue_mpmc.zig").QueueMpmc;
34
45test "std.atomic" {
5 _ = @import("stack.zig").Stack;
6 _ = @import("queue.zig").Queue;
6 _ = @import("stack.zig");
7 _ = @import("queue_mpsc.zig");
8 _ = @import("queue_mpmc.zig");
79}
std/atomic/queue.zig deleted-137
......@@ -1,137 +0,0 @@
1const builtin = @import("builtin");
2const AtomicOrder = builtin.AtomicOrder;
3const AtomicRmwOp = builtin.AtomicRmwOp;
4
5/// Many reader, many writer, non-allocating, thread-safe, lock-free
6pub fn Queue(comptime T: type) type {
7 return struct {
8 head: *Node,
9 tail: *Node,
10 root: Node,
11
12 pub const Self = this;
13
14 pub const Node = struct {
15 next: ?*Node,
16 data: T,
17 };
18
19 // TODO: well defined copy elision: https://github.com/ziglang/zig/issues/287
20 pub fn init(self: *Self) void {
21 self.root.next = null;
22 self.head = &self.root;
23 self.tail = &self.root;
24 }
25
26 pub fn put(self: *Self, node: *Node) void {
27 node.next = null;
28
29 const tail = @atomicRmw(*Node, &self.tail, AtomicRmwOp.Xchg, node, AtomicOrder.SeqCst);
30 _ = @atomicRmw(?*Node, &tail.next, AtomicRmwOp.Xchg, node, AtomicOrder.SeqCst);
31 }
32
33 pub fn get(self: *Self) ?*Node {
34 var head = @atomicLoad(*Node, &self.head, AtomicOrder.SeqCst);
35 while (true) {
36 const node = head.next orelse return null;
37 head = @cmpxchgWeak(*Node, &self.head, head, node, AtomicOrder.SeqCst, AtomicOrder.SeqCst) orelse return node;
38 }
39 }
40 };
41}
42
43const std = @import("std");
44const Context = struct {
45 allocator: *std.mem.Allocator,
46 queue: *Queue(i32),
47 put_sum: isize,
48 get_sum: isize,
49 get_count: usize,
50 puts_done: u8, // TODO make this a bool
51};
52
53// TODO add lazy evaluated build options and then put puts_per_thread behind
54// some option such as: "AggressiveMultithreadedFuzzTest". In the AppVeyor
55// CI we would use a less aggressive setting since at 1 core, while we still
56// want this test to pass, we need a smaller value since there is so much thrashing
57// we would also use a less aggressive setting when running in valgrind
58const puts_per_thread = 500;
59const put_thread_count = 3;
60
61test "std.atomic.queue" {
62 var direct_allocator = std.heap.DirectAllocator.init();
63 defer direct_allocator.deinit();
64
65 var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 300 * 1024);
66 defer direct_allocator.allocator.free(plenty_of_memory);
67
68 var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory);
69 var a = &fixed_buffer_allocator.allocator;
70
71 var queue: Queue(i32) = undefined;
72 queue.init();
73 var context = Context{
74 .allocator = a,
75 .queue = &queue,
76 .put_sum = 0,
77 .get_sum = 0,
78 .puts_done = 0,
79 .get_count = 0,
80 };
81
82 var putters: [put_thread_count]*std.os.Thread = undefined;
83 for (putters) |*t| {
84 t.* = try std.os.spawnThread(&context, startPuts);
85 }
86 var getters: [put_thread_count]*std.os.Thread = undefined;
87 for (getters) |*t| {
88 t.* = try std.os.spawnThread(&context, startGets);
89 }
90
91 for (putters) |t|
92 t.wait();
93 _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
94 for (getters) |t|
95 t.wait();
96
97 if (context.put_sum != context.get_sum) {
98 std.debug.panic("failure\nput_sum:{} != get_sum:{}", context.put_sum, context.get_sum);
99 }
100
101 if (context.get_count != puts_per_thread * put_thread_count) {
102 std.debug.panic(
103 "failure\nget_count:{} != puts_per_thread:{} * put_thread_count:{}",
104 context.get_count,
105 u32(puts_per_thread),
106 u32(put_thread_count),
107 );
108 }
109}
110
111fn startPuts(ctx: *Context) u8 {
112 var put_count: usize = puts_per_thread;
113 var r = std.rand.DefaultPrng.init(0xdeadbeef);
114 while (put_count != 0) : (put_count -= 1) {
115 std.os.time.sleep(0, 1); // let the os scheduler be our fuzz
116 const x = @bitCast(i32, r.random.scalar(u32));
117 const node = ctx.allocator.create(Queue(i32).Node) catch unreachable;
118 node.data = x;
119 ctx.queue.put(node);
120 _ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst);
121 }
122 return 0;
123}
124
125fn startGets(ctx: *Context) u8 {
126 while (true) {
127 const last = @atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1;
128
129 while (ctx.queue.get()) |node| {
130 std.os.time.sleep(0, 1); // let the os scheduler be our fuzz
131 _ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);
132 _ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);
133 }
134
135 if (last) return 0;
136 }
137}
std/atomic/queue_mpmc.zig created+214
......@@ -0,0 +1,214 @@
1const builtin = @import("builtin");
2const AtomicOrder = builtin.AtomicOrder;
3const AtomicRmwOp = builtin.AtomicRmwOp;
4
5/// Many producer, many consumer, non-allocating, thread-safe, lock-free
6/// This implementation has a crippling limitation - it hangs onto node
7/// memory for 1 extra get() and 1 extra put() operation - when get() returns a node, that
8/// node must not be freed until both the next get() and the next put() completes.
9pub fn QueueMpmc(comptime T: type) type {
10 return struct {
11 head: *Node,
12 tail: *Node,
13 root: Node,
14
15 pub const Self = this;
16
17 pub const Node = struct {
18 next: ?*Node,
19 data: T,
20 };
21
22 /// TODO: well defined copy elision: https://github.com/ziglang/zig/issues/287
23 pub fn init(self: *Self) void {
24 self.root.next = null;
25 self.head = &self.root;
26 self.tail = &self.root;
27 }
28
29 pub fn put(self: *Self, node: *Node) void {
30 node.next = null;
31
32 const tail = @atomicRmw(*Node, &self.tail, AtomicRmwOp.Xchg, node, AtomicOrder.SeqCst);
33 _ = @atomicRmw(?*Node, &tail.next, AtomicRmwOp.Xchg, node, AtomicOrder.SeqCst);
34 }
35
36 /// node must not be freed until both the next get() and the next put() complete
37 pub fn get(self: *Self) ?*Node {
38 var head = @atomicLoad(*Node, &self.head, AtomicOrder.SeqCst);
39 while (true) {
40 const node = head.next orelse return null;
41 head = @cmpxchgWeak(*Node, &self.head, head, node, AtomicOrder.SeqCst, AtomicOrder.SeqCst) orelse return node;
42 }
43 }
44
45 ///// This is a debug function that is not thread-safe.
46 pub fn dump(self: *Self) void {
47 std.debug.warn("head: ");
48 dumpRecursive(self.head, 0);
49 std.debug.warn("tail: ");
50 dumpRecursive(self.tail, 0);
51 }
52
53 fn dumpRecursive(optional_node: ?*Node, indent: usize) void {
54 var stderr_file = std.io.getStdErr() catch return;
55 const stderr = &std.io.FileOutStream.init(&stderr_file).stream;
56 stderr.writeByteNTimes(' ', indent) catch return;
57 if (optional_node) |node| {
58 std.debug.warn("0x{x}={}\n", @ptrToInt(node), node.data);
59 dumpRecursive(node.next, indent + 1);
60 } else {
61 std.debug.warn("(null)\n");
62 }
63 }
64 };
65}
66
67const std = @import("std");
68const assert = std.debug.assert;
69
70const Context = struct {
71 allocator: *std.mem.Allocator,
72 queue: *QueueMpmc(i32),
73 put_sum: isize,
74 get_sum: isize,
75 get_count: usize,
76 puts_done: u8, // TODO make this a bool
77};
78
79// TODO add lazy evaluated build options and then put puts_per_thread behind
80// some option such as: "AggressiveMultithreadedFuzzTest". In the AppVeyor
81// CI we would use a less aggressive setting since at 1 core, while we still
82// want this test to pass, we need a smaller value since there is so much thrashing
83// we would also use a less aggressive setting when running in valgrind
84const puts_per_thread = 500;
85const put_thread_count = 3;
86
87test "std.atomic.queue_mpmc" {
88 var direct_allocator = std.heap.DirectAllocator.init();
89 defer direct_allocator.deinit();
90
91 var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 300 * 1024);
92 defer direct_allocator.allocator.free(plenty_of_memory);
93
94 var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory);
95 var a = &fixed_buffer_allocator.allocator;
96
97 var queue: QueueMpmc(i32) = undefined;
98 queue.init();
99 var context = Context{
100 .allocator = a,
101 .queue = &queue,
102 .put_sum = 0,
103 .get_sum = 0,
104 .puts_done = 0,
105 .get_count = 0,
106 };
107
108 var putters: [put_thread_count]*std.os.Thread = undefined;
109 for (putters) |*t| {
110 t.* = try std.os.spawnThread(&context, startPuts);
111 }
112 var getters: [put_thread_count]*std.os.Thread = undefined;
113 for (getters) |*t| {
114 t.* = try std.os.spawnThread(&context, startGets);
115 }
116
117 for (putters) |t|
118 t.wait();
119 _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
120 for (getters) |t|
121 t.wait();
122
123 if (context.put_sum != context.get_sum) {
124 std.debug.panic("failure\nput_sum:{} != get_sum:{}", context.put_sum, context.get_sum);
125 }
126
127 if (context.get_count != puts_per_thread * put_thread_count) {
128 std.debug.panic(
129 "failure\nget_count:{} != puts_per_thread:{} * put_thread_count:{}",
130 context.get_count,
131 u32(puts_per_thread),
132 u32(put_thread_count),
133 );
134 }
135}
136
137fn startPuts(ctx: *Context) u8 {
138 var put_count: usize = puts_per_thread;
139 var r = std.rand.DefaultPrng.init(0xdeadbeef);
140 while (put_count != 0) : (put_count -= 1) {
141 std.os.time.sleep(0, 1); // let the os scheduler be our fuzz
142 const x = @bitCast(i32, r.random.scalar(u32));
143 const node = ctx.allocator.create(QueueMpmc(i32).Node{
144 .next = undefined,
145 .data = x,
146 }) catch unreachable;
147 ctx.queue.put(node);
148 _ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst);
149 }
150 return 0;
151}
152
153fn startGets(ctx: *Context) u8 {
154 while (true) {
155 const last = @atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1;
156
157 while (ctx.queue.get()) |node| {
158 std.os.time.sleep(0, 1); // let the os scheduler be our fuzz
159 _ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);
160 _ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);
161 }
162
163 if (last) return 0;
164 }
165}
166
167test "std.atomic.queue_mpmc single-threaded" {
168 var queue: QueueMpmc(i32) = undefined;
169 queue.init();
170
171 var node_0 = QueueMpmc(i32).Node{
172 .data = 0,
173 .next = undefined,
174 };
175 queue.put(&node_0);
176
177 var node_1 = QueueMpmc(i32).Node{
178 .data = 1,
179 .next = undefined,
180 };
181 queue.put(&node_1);
182
183 assert(queue.get().?.data == 0);
184
185 var node_2 = QueueMpmc(i32).Node{
186 .data = 2,
187 .next = undefined,
188 };
189 queue.put(&node_2);
190
191 var node_3 = QueueMpmc(i32).Node{
192 .data = 3,
193 .next = undefined,
194 };
195 queue.put(&node_3);
196
197 assert(queue.get().?.data == 1);
198
199 assert(queue.get().?.data == 2);
200
201 var node_4 = QueueMpmc(i32).Node{
202 .data = 4,
203 .next = undefined,
204 };
205 queue.put(&node_4);
206
207 assert(queue.get().?.data == 3);
208 // if we were to set node_3.next to null here, it would cause this test
209 // to fail. this demonstrates the limitation of hanging on to extra memory.
210
211 assert(queue.get().?.data == 4);
212
213 assert(queue.get() == null);
214}
std/atomic/queue_mpsc.zig created+143
......@@ -0,0 +1,143 @@
1const std = @import("../index.zig");
2const assert = std.debug.assert;
3const builtin = @import("builtin");
4const AtomicOrder = builtin.AtomicOrder;
5const AtomicRmwOp = builtin.AtomicRmwOp;
6
7/// Many producer, single consumer, non-allocating, thread-safe, lock-free
8pub fn QueueMpsc(comptime T: type) type {
9 return struct {
10 inboxes: [2]std.atomic.Stack(T),
11 outbox: std.atomic.Stack(T),
12 inbox_index: usize,
13
14 pub const Self = this;
15
16 pub const Node = std.atomic.Stack(T).Node;
17
18 pub fn init() Self {
19 return Self{
20 .inboxes = []std.atomic.Stack(T){
21 std.atomic.Stack(T).init(),
22 std.atomic.Stack(T).init(),
23 },
24 .outbox = std.atomic.Stack(T).init(),
25 .inbox_index = 0,
26 };
27 }
28
29 pub fn put(self: *Self, node: *Node) void {
30 const inbox_index = @atomicLoad(usize, &self.inbox_index, AtomicOrder.SeqCst);
31 const inbox = &self.inboxes[inbox_index];
32 inbox.push(node);
33 }
34
35 pub fn get(self: *Self) ?*Node {
36 if (self.outbox.pop()) |node| {
37 return node;
38 }
39 const prev_inbox_index = @atomicRmw(usize, &self.inbox_index, AtomicRmwOp.Xor, 0x1, AtomicOrder.SeqCst);
40 const prev_inbox = &self.inboxes[prev_inbox_index];
41 while (prev_inbox.pop()) |node| {
42 self.outbox.push(node);
43 }
44 return self.outbox.pop();
45 }
46 };
47}
48
49const Context = struct {
50 allocator: *std.mem.Allocator,
51 queue: *QueueMpsc(i32),
52 put_sum: isize,
53 get_sum: isize,
54 get_count: usize,
55 puts_done: u8, // TODO make this a bool
56};
57
58// TODO add lazy evaluated build options and then put puts_per_thread behind
59// some option such as: "AggressiveMultithreadedFuzzTest". In the AppVeyor
60// CI we would use a less aggressive setting since at 1 core, while we still
61// want this test to pass, we need a smaller value since there is so much thrashing
62// we would also use a less aggressive setting when running in valgrind
63const puts_per_thread = 500;
64const put_thread_count = 3;
65
66test "std.atomic.queue_mpsc" {
67 var direct_allocator = std.heap.DirectAllocator.init();
68 defer direct_allocator.deinit();
69
70 var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 300 * 1024);
71 defer direct_allocator.allocator.free(plenty_of_memory);
72
73 var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory);
74 var a = &fixed_buffer_allocator.allocator;
75
76 var queue = QueueMpsc(i32).init();
77 var context = Context{
78 .allocator = a,
79 .queue = &queue,
80 .put_sum = 0,
81 .get_sum = 0,
82 .puts_done = 0,
83 .get_count = 0,
84 };
85
86 var putters: [put_thread_count]*std.os.Thread = undefined;
87 for (putters) |*t| {
88 t.* = try std.os.spawnThread(&context, startPuts);
89 }
90 var getters: [1]*std.os.Thread = undefined;
91 for (getters) |*t| {
92 t.* = try std.os.spawnThread(&context, startGets);
93 }
94
95 for (putters) |t|
96 t.wait();
97 _ = @atomicRmw(u8, &context.puts_done, builtin.AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
98 for (getters) |t|
99 t.wait();
100
101 if (context.put_sum != context.get_sum) {
102 std.debug.panic("failure\nput_sum:{} != get_sum:{}", context.put_sum, context.get_sum);
103 }
104
105 if (context.get_count != puts_per_thread * put_thread_count) {
106 std.debug.panic(
107 "failure\nget_count:{} != puts_per_thread:{} * put_thread_count:{}",
108 context.get_count,
109 u32(puts_per_thread),
110 u32(put_thread_count),
111 );
112 }
113}
114
115fn startPuts(ctx: *Context) u8 {
116 var put_count: usize = puts_per_thread;
117 var r = std.rand.DefaultPrng.init(0xdeadbeef);
118 while (put_count != 0) : (put_count -= 1) {
119 std.os.time.sleep(0, 1); // let the os scheduler be our fuzz
120 const x = @bitCast(i32, r.random.scalar(u32));
121 const node = ctx.allocator.create(QueueMpsc(i32).Node{
122 .next = undefined,
123 .data = x,
124 }) catch unreachable;
125 ctx.queue.put(node);
126 _ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst);
127 }
128 return 0;
129}
130
131fn startGets(ctx: *Context) u8 {
132 while (true) {
133 const last = @atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1;
134
135 while (ctx.queue.get()) |node| {
136 std.os.time.sleep(0, 1); // let the os scheduler be our fuzz
137 _ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);
138 _ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);
139 }
140
141 if (last) return 0;
142 }
143}
std/atomic/stack.zig+4-2
......@@ -117,8 +117,10 @@ fn startPuts(ctx: *Context) u8 {
117117 while (put_count != 0) : (put_count -= 1) {
118118 std.os.time.sleep(0, 1); // let the os scheduler be our fuzz
119119 const x = @bitCast(i32, r.random.scalar(u32));
120 const node = ctx.allocator.create(Stack(i32).Node) catch unreachable;
121 node.data = x;
120 const node = ctx.allocator.create(Stack(i32).Node{
121 .next = undefined,
122 .data = x,
123 }) catch unreachable;
122124 ctx.stack.push(node);
123125 _ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst);
124126 }
std/build.zig+20-35
......@@ -158,8 +158,7 @@ pub const Builder = struct {
158158 }
159159
160160 pub fn addTest(self: *Builder, root_src: []const u8) *TestStep {
161 const test_step = self.allocator.create(TestStep) catch unreachable;
162 test_step.* = TestStep.init(self, root_src);
161 const test_step = self.allocator.create(TestStep.init(self, root_src)) catch unreachable;
163162 return test_step;
164163 }
165164
......@@ -191,21 +190,18 @@ pub const Builder = struct {
191190 }
192191
193192 pub fn addWriteFile(self: *Builder, file_path: []const u8, data: []const u8) *WriteFileStep {
194 const write_file_step = self.allocator.create(WriteFileStep) catch unreachable;
195 write_file_step.* = WriteFileStep.init(self, file_path, data);
193 const write_file_step = self.allocator.create(WriteFileStep.init(self, file_path, data)) catch unreachable;
196194 return write_file_step;
197195 }
198196
199197 pub fn addLog(self: *Builder, comptime format: []const u8, args: ...) *LogStep {
200198 const data = self.fmt(format, args);
201 const log_step = self.allocator.create(LogStep) catch unreachable;
202 log_step.* = LogStep.init(self, data);
199 const log_step = self.allocator.create(LogStep.init(self, data)) catch unreachable;
203200 return log_step;
204201 }
205202
206203 pub fn addRemoveDirTree(self: *Builder, dir_path: []const u8) *RemoveDirStep {
207 const remove_dir_step = self.allocator.create(RemoveDirStep) catch unreachable;
208 remove_dir_step.* = RemoveDirStep.init(self, dir_path);
204 const remove_dir_step = self.allocator.create(RemoveDirStep.init(self, dir_path)) catch unreachable;
209205 return remove_dir_step;
210206 }
211207
......@@ -404,11 +400,10 @@ pub const Builder = struct {
404400 }
405401
406402 pub fn step(self: *Builder, name: []const u8, description: []const u8) *Step {
407 const step_info = self.allocator.create(TopLevelStep) catch unreachable;
408 step_info.* = TopLevelStep{
403 const step_info = self.allocator.create(TopLevelStep{
409404 .step = Step.initNoOp(name, self.allocator),
410405 .description = description,
411 };
406 }) catch unreachable;
412407 self.top_level_steps.append(step_info) catch unreachable;
413408 return &step_info.step;
414409 }
......@@ -598,8 +593,7 @@ pub const Builder = struct {
598593 const full_dest_path = os.path.resolve(self.allocator, self.prefix, dest_rel_path) catch unreachable;
599594 self.pushInstalledFile(full_dest_path);
600595
601 const install_step = self.allocator.create(InstallFileStep) catch unreachable;
602 install_step.* = InstallFileStep.init(self, src_path, full_dest_path);
596 const install_step = self.allocator.create(InstallFileStep.init(self, src_path, full_dest_path)) catch unreachable;
603597 return install_step;
604598 }
605599
......@@ -837,51 +831,43 @@ pub const LibExeObjStep = struct {
837831 };
838832
839833 pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8, ver: *const Version) *LibExeObjStep {
840 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
841 self.* = initExtraArgs(builder, name, root_src, Kind.Lib, false, ver);
834 const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Lib, false, ver)) catch unreachable;
842835 return self;
843836 }
844837
845838 pub fn createCSharedLibrary(builder: *Builder, name: []const u8, version: *const Version) *LibExeObjStep {
846 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
847 self.* = initC(builder, name, Kind.Lib, version, false);
839 const self = builder.allocator.create(initC(builder, name, Kind.Lib, version, false)) catch unreachable;
848840 return self;
849841 }
850842
851843 pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
852 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
853 self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0));
844 const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0))) catch unreachable;
854845 return self;
855846 }
856847
857848 pub fn createCStaticLibrary(builder: *Builder, name: []const u8) *LibExeObjStep {
858 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
859 self.* = initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true);
849 const self = builder.allocator.create(initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true)) catch unreachable;
860850 return self;
861851 }
862852
863853 pub fn createObject(builder: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep {
864 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
865 self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0));
854 const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0))) catch unreachable;
866855 return self;
867856 }
868857
869858 pub fn createCObject(builder: *Builder, name: []const u8, src: []const u8) *LibExeObjStep {
870 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
871 self.* = initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false);
859 const self = builder.allocator.create(initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false)) catch unreachable;
872860 self.object_src = src;
873861 return self;
874862 }
875863
876864 pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
877 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
878 self.* = initExtraArgs(builder, name, root_src, Kind.Exe, false, builder.version(0, 0, 0));
865 const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Exe, false, builder.version(0, 0, 0))) catch unreachable;
879866 return self;
880867 }
881868
882869 pub fn createCExecutable(builder: *Builder, name: []const u8) *LibExeObjStep {
883 const self = builder.allocator.create(LibExeObjStep) catch unreachable;
884 self.* = initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false);
870 const self = builder.allocator.create(initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false)) catch unreachable;
885871 return self;
886872 }
887873
......@@ -1748,14 +1734,14 @@ pub const CommandStep = struct {
17481734
17491735 /// ::argv is copied.
17501736 pub fn create(builder: *Builder, cwd: ?[]const u8, env_map: *const BufMap, argv: []const []const u8) *CommandStep {
1751 const self = builder.allocator.create(CommandStep) catch unreachable;
1752 self.* = CommandStep{
1737 const self = builder.allocator.create(CommandStep{
17531738 .builder = builder,
17541739 .step = Step.init(argv[0], builder.allocator, make),
17551740 .argv = builder.allocator.alloc([]u8, argv.len) catch unreachable,
17561741 .cwd = cwd,
17571742 .env_map = env_map,
1758 };
1743 }) catch unreachable;
1744
17591745 mem.copy([]const u8, self.argv, argv);
17601746 self.step.name = self.argv[0];
17611747 return self;
......@@ -1778,18 +1764,17 @@ const InstallArtifactStep = struct {
17781764 const Self = this;
17791765
17801766 pub fn create(builder: *Builder, artifact: *LibExeObjStep) *Self {
1781 const self = builder.allocator.create(Self) catch unreachable;
17821767 const dest_dir = switch (artifact.kind) {
17831768 LibExeObjStep.Kind.Obj => unreachable,
17841769 LibExeObjStep.Kind.Exe => builder.exe_dir,
17851770 LibExeObjStep.Kind.Lib => builder.lib_dir,
17861771 };
1787 self.* = Self{
1772 const self = builder.allocator.create(Self{
17881773 .builder = builder,
17891774 .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),
17901775 .artifact = artifact,
17911776 .dest_file = os.path.join(builder.allocator, dest_dir, artifact.out_filename) catch unreachable,
1792 };
1777 }) catch unreachable;
17931778 self.step.dependOn(&artifact.step);
17941779 builder.pushInstalledFile(self.dest_file);
17951780 if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) {
std/cstr.zig+1-1
......@@ -79,7 +79,7 @@ pub const NullTerminated2DArray = struct {
7979 errdefer allocator.free(buf);
8080
8181 var write_index = index_size;
82 const index_buf = ([]?[*]u8)(buf);
82 const index_buf = @bytesToSlice(?[*]u8, buf);
8383
8484 var i: usize = 0;
8585 for (slices) |slice| {
std/debug/index.zig+5-10
......@@ -249,9 +249,7 @@ fn printSourceAtAddress(debug_info: *ElfStackTrace, out_stream: var, address: us
249249pub fn openSelfDebugInfo(allocator: *mem.Allocator) !*ElfStackTrace {
250250 switch (builtin.object_format) {
251251 builtin.ObjectFormat.elf => {
252 const st = try allocator.create(ElfStackTrace);
253 errdefer allocator.destroy(st);
254 st.* = ElfStackTrace{
252 const st = try allocator.create(ElfStackTrace{
255253 .self_exe_file = undefined,
256254 .elf = undefined,
257255 .debug_info = undefined,
......@@ -261,7 +259,8 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !*ElfStackTrace {
261259 .debug_ranges = null,
262260 .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
263261 .compile_unit_list = ArrayList(CompileUnit).init(allocator),
264 };
262 });
263 errdefer allocator.destroy(st);
265264 st.self_exe_file = try os.openSelfExe();
266265 errdefer st.self_exe_file.close();
267266
......@@ -280,11 +279,8 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !*ElfStackTrace {
280279 var exe_file = try os.openSelfExe();
281280 defer exe_file.close();
282281
283 const st = try allocator.create(ElfStackTrace);
282 const st = try allocator.create(ElfStackTrace{ .symbol_table = try macho.loadSymbols(allocator, &io.FileInStream.init(&exe_file)) });
284283 errdefer allocator.destroy(st);
285
286 st.* = ElfStackTrace{ .symbol_table = try macho.loadSymbols(allocator, &io.FileInStream.init(&exe_file)) };
287
288284 return st;
289285 },
290286 builtin.ObjectFormat.coff => {
......@@ -974,8 +970,7 @@ fn scanAllCompileUnits(st: *ElfStackTrace) !void {
974970
975971 try st.self_exe_file.seekTo(compile_unit_pos);
976972
977 const compile_unit_die = try st.allocator().create(Die);
978 compile_unit_die.* = try parseDie(st, abbrev_table, is_64);
973 const compile_unit_die = try st.allocator().create(try parseDie(st, abbrev_table, is_64));
979974
980975 if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
981976
std/event.zig+325-13
......@@ -4,6 +4,8 @@ const assert = std.debug.assert;
44const event = this;
55const mem = std.mem;
66const posix = std.os.posix;
7const AtomicRmwOp = builtin.AtomicRmwOp;
8const AtomicOrder = builtin.AtomicOrder;
79
810pub const TcpServer = struct {
911 handleRequestFn: async<*mem.Allocator> fn (*TcpServer, *const std.net.Address, *const std.os.File) void,
......@@ -93,16 +95,56 @@ pub const TcpServer = struct {
9395
9496pub const Loop = struct {
9597 allocator: *mem.Allocator,
96 epollfd: i32,
9798 keep_running: bool,
99 next_tick_queue: std.atomic.QueueMpsc(promise),
100 os_data: OsData,
101
102 const OsData = switch (builtin.os) {
103 builtin.Os.linux => struct {
104 epollfd: i32,
105 },
106 else => struct {},
107 };
108
109 pub const NextTickNode = std.atomic.QueueMpsc(promise).Node;
98110
99 fn init(allocator: *mem.Allocator) !Loop {
100 const epollfd = try std.os.linuxEpollCreate(std.os.linux.EPOLL_CLOEXEC);
101 return Loop{
111 /// The allocator must be thread-safe because we use it for multiplexing
112 /// coroutines onto kernel threads.
113 pub fn init(allocator: *mem.Allocator) !Loop {
114 var self = Loop{
102115 .keep_running = true,
103116 .allocator = allocator,
104 .epollfd = epollfd,
117 .os_data = undefined,
118 .next_tick_queue = std.atomic.QueueMpsc(promise).init(),
105119 };
120 try self.initOsData();
121 errdefer self.deinitOsData();
122
123 return self;
124 }
125
126 /// must call stop before deinit
127 pub fn deinit(self: *Loop) void {
128 self.deinitOsData();
129 }
130
131 const InitOsDataError = std.os.LinuxEpollCreateError;
132
133 fn initOsData(self: *Loop) InitOsDataError!void {
134 switch (builtin.os) {
135 builtin.Os.linux => {
136 self.os_data.epollfd = try std.os.linuxEpollCreate(std.os.linux.EPOLL_CLOEXEC);
137 errdefer std.os.close(self.os_data.epollfd);
138 },
139 else => {},
140 }
141 }
142
143 fn deinitOsData(self: *Loop) void {
144 switch (builtin.os) {
145 builtin.Os.linux => std.os.close(self.os_data.epollfd),
146 else => {},
147 }
106148 }
107149
108150 pub fn addFd(self: *Loop, fd: i32, prom: promise) !void {
......@@ -110,11 +152,11 @@ pub const Loop = struct {
110152 .events = std.os.linux.EPOLLIN | std.os.linux.EPOLLOUT | std.os.linux.EPOLLET,
111153 .data = std.os.linux.epoll_data{ .ptr = @ptrToInt(prom) },
112154 };
113 try std.os.linuxEpollCtl(self.epollfd, std.os.linux.EPOLL_CTL_ADD, fd, &ev);
155 try std.os.linuxEpollCtl(self.os_data.epollfd, std.os.linux.EPOLL_CTL_ADD, fd, &ev);
114156 }
115157
116158 pub fn removeFd(self: *Loop, fd: i32) void {
117 std.os.linuxEpollCtl(self.epollfd, std.os.linux.EPOLL_CTL_DEL, fd, undefined) catch {};
159 std.os.linuxEpollCtl(self.os_data.epollfd, std.os.linux.EPOLL_CTL_DEL, fd, undefined) catch {};
118160 }
119161 async fn waitFd(self: *Loop, fd: i32) !void {
120162 defer self.removeFd(fd);
......@@ -126,21 +168,250 @@ pub const Loop = struct {
126168 pub fn stop(self: *Loop) void {
127169 // TODO make atomic
128170 self.keep_running = false;
129 // TODO activate an fd in the epoll set
171 // TODO activate an fd in the epoll set which should cancel all the promises
172 }
173
174 /// bring your own linked list node. this means it can't fail.
175 pub fn onNextTick(self: *Loop, node: *NextTickNode) void {
176 self.next_tick_queue.put(node);
130177 }
131178
132179 pub fn run(self: *Loop) void {
133180 while (self.keep_running) {
134 var events: [16]std.os.linux.epoll_event = undefined;
135 const count = std.os.linuxEpollWait(self.epollfd, events[0..], -1);
136 for (events[0..count]) |ev| {
137 const p = @intToPtr(promise, ev.data.ptr);
138 resume p;
181 // TODO multiplex the next tick queue and the epoll event results onto a thread pool
182 while (self.next_tick_queue.get()) |node| {
183 resume node.data;
139184 }
185 if (!self.keep_running) break;
186
187 self.dispatchOsEvents();
188 }
189 }
190
191 fn dispatchOsEvents(self: *Loop) void {
192 switch (builtin.os) {
193 builtin.Os.linux => {
194 var events: [16]std.os.linux.epoll_event = undefined;
195 const count = std.os.linuxEpollWait(self.os_data.epollfd, events[0..], -1);
196 for (events[0..count]) |ev| {
197 const p = @intToPtr(promise, ev.data.ptr);
198 resume p;
199 }
200 },
201 else => {},
140202 }
141203 }
142204};
143205
206/// many producer, many consumer, thread-safe, lock-free, runtime configurable buffer size
207/// when buffer is empty, consumers suspend and are resumed by producers
208/// when buffer is full, producers suspend and are resumed by consumers
209pub fn Channel(comptime T: type) type {
210 return struct {
211 loop: *Loop,
212
213 getters: std.atomic.QueueMpsc(GetNode),
214 putters: std.atomic.QueueMpsc(PutNode),
215 get_count: usize,
216 put_count: usize,
217 dispatch_lock: u8, // TODO make this a bool
218 need_dispatch: u8, // TODO make this a bool
219
220 // simple fixed size ring buffer
221 buffer_nodes: []T,
222 buffer_index: usize,
223 buffer_len: usize,
224
225 const SelfChannel = this;
226 const GetNode = struct {
227 ptr: *T,
228 tick_node: *Loop.NextTickNode,
229 };
230 const PutNode = struct {
231 data: T,
232 tick_node: *Loop.NextTickNode,
233 };
234
235 /// call destroy when done
236 pub fn create(loop: *Loop, capacity: usize) !*SelfChannel {
237 const buffer_nodes = try loop.allocator.alloc(T, capacity);
238 errdefer loop.allocator.free(buffer_nodes);
239
240 const self = try loop.allocator.create(SelfChannel{
241 .loop = loop,
242 .buffer_len = 0,
243 .buffer_nodes = buffer_nodes,
244 .buffer_index = 0,
245 .dispatch_lock = 0,
246 .need_dispatch = 0,
247 .getters = std.atomic.QueueMpsc(GetNode).init(),
248 .putters = std.atomic.QueueMpsc(PutNode).init(),
249 .get_count = 0,
250 .put_count = 0,
251 });
252 errdefer loop.allocator.destroy(self);
253
254 return self;
255 }
256
257 /// must be called when all calls to put and get have suspended and no more calls occur
258 pub fn destroy(self: *SelfChannel) void {
259 while (self.getters.get()) |get_node| {
260 cancel get_node.data.tick_node.data;
261 }
262 while (self.putters.get()) |put_node| {
263 cancel put_node.data.tick_node.data;
264 }
265 self.loop.allocator.free(self.buffer_nodes);
266 self.loop.allocator.destroy(self);
267 }
268
269 /// puts a data item in the channel. The promise completes when the value has been added to the
270 /// buffer, or in the case of a zero size buffer, when the item has been retrieved by a getter.
271 pub async fn put(self: *SelfChannel, data: T) void {
272 // TODO should be able to group memory allocation failure before first suspend point
273 // so that the async invocation catches it
274 var dispatch_tick_node_ptr: *Loop.NextTickNode = undefined;
275 _ = async self.dispatch(&dispatch_tick_node_ptr) catch unreachable;
276
277 suspend |handle| {
278 var my_tick_node = Loop.NextTickNode{
279 .next = undefined,
280 .data = handle,
281 };
282 var queue_node = std.atomic.QueueMpsc(PutNode).Node{
283 .data = PutNode{
284 .tick_node = &my_tick_node,
285 .data = data,
286 },
287 .next = undefined,
288 };
289 self.putters.put(&queue_node);
290 _ = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
291
292 self.loop.onNextTick(dispatch_tick_node_ptr);
293 }
294 }
295
296 /// await this function to get an item from the channel. If the buffer is empty, the promise will
297 /// complete when the next item is put in the channel.
298 pub async fn get(self: *SelfChannel) T {
299 // TODO should be able to group memory allocation failure before first suspend point
300 // so that the async invocation catches it
301 var dispatch_tick_node_ptr: *Loop.NextTickNode = undefined;
302 _ = async self.dispatch(&dispatch_tick_node_ptr) catch unreachable;
303
304 // TODO integrate this function with named return values
305 // so we can get rid of this extra result copy
306 var result: T = undefined;
307 var debug_handle: usize = undefined;
308 suspend |handle| {
309 debug_handle = @ptrToInt(handle);
310 var my_tick_node = Loop.NextTickNode{
311 .next = undefined,
312 .data = handle,
313 };
314 var queue_node = std.atomic.QueueMpsc(GetNode).Node{
315 .data = GetNode{
316 .ptr = &result,
317 .tick_node = &my_tick_node,
318 },
319 .next = undefined,
320 };
321 self.getters.put(&queue_node);
322 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
323
324 self.loop.onNextTick(dispatch_tick_node_ptr);
325 }
326 return result;
327 }
328
329 async fn dispatch(self: *SelfChannel, tick_node_ptr: **Loop.NextTickNode) void {
330 // resumed by onNextTick
331 suspend |handle| {
332 var tick_node = Loop.NextTickNode{
333 .data = handle,
334 .next = undefined,
335 };
336 tick_node_ptr.* = &tick_node;
337 }
338
339 // set the "need dispatch" flag
340 _ = @atomicRmw(u8, &self.need_dispatch, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
341
342 lock: while (true) {
343 // set the lock flag
344 const prev_lock = @atomicRmw(u8, &self.dispatch_lock, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
345 if (prev_lock != 0) return;
346
347 // clear the need_dispatch flag since we're about to do it
348 _ = @atomicRmw(u8, &self.need_dispatch, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
349
350 while (true) {
351 one_dispatch: {
352 // later we correct these extra subtractions
353 var get_count = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
354 var put_count = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
355
356 // transfer self.buffer to self.getters
357 while (self.buffer_len != 0) {
358 if (get_count == 0) break :one_dispatch;
359
360 const get_node = &self.getters.get().?.data;
361 get_node.ptr.* = self.buffer_nodes[self.buffer_index -% self.buffer_len];
362 self.loop.onNextTick(get_node.tick_node);
363 self.buffer_len -= 1;
364
365 get_count = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
366 }
367
368 // direct transfer self.putters to self.getters
369 while (get_count != 0 and put_count != 0) {
370 const get_node = &self.getters.get().?.data;
371 const put_node = &self.putters.get().?.data;
372
373 get_node.ptr.* = put_node.data;
374 self.loop.onNextTick(get_node.tick_node);
375 self.loop.onNextTick(put_node.tick_node);
376
377 get_count = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
378 put_count = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
379 }
380
381 // transfer self.putters to self.buffer
382 while (self.buffer_len != self.buffer_nodes.len and put_count != 0) {
383 const put_node = &self.putters.get().?.data;
384
385 self.buffer_nodes[self.buffer_index] = put_node.data;
386 self.loop.onNextTick(put_node.tick_node);
387 self.buffer_index +%= 1;
388 self.buffer_len += 1;
389
390 put_count = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
391 }
392 }
393
394 // undo the extra subtractions
395 _ = @atomicRmw(usize, &self.get_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
396 _ = @atomicRmw(usize, &self.put_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
397
398 // clear need-dispatch flag
399 const need_dispatch = @atomicRmw(u8, &self.need_dispatch, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
400 if (need_dispatch != 0) continue;
401
402 const my_lock = @atomicRmw(u8, &self.dispatch_lock, AtomicRmwOp.Xchg, 0, AtomicOrder.SeqCst);
403 assert(my_lock != 0);
404
405 // we have to check again now that we unlocked
406 if (@atomicLoad(u8, &self.need_dispatch, AtomicOrder.SeqCst) != 0) continue :lock;
407
408 return;
409 }
410 }
411 }
412 };
413}
414
144415pub async fn connect(loop: *Loop, _address: *const std.net.Address) !std.os.File {
145416 var address = _address.*; // TODO https://github.com/ziglang/zig/issues/733
146417
......@@ -199,6 +470,7 @@ test "listen on a port, send bytes, receive bytes" {
199470 defer cancel p;
200471 loop.run();
201472}
473
202474async fn doAsyncTest(loop: *Loop, address: *const std.net.Address) void {
203475 errdefer @panic("test failure");
204476
......@@ -211,3 +483,43 @@ async fn doAsyncTest(loop: *Loop, address: *const std.net.Address) void {
211483 assert(mem.eql(u8, msg, "hello from server\n"));
212484 loop.stop();
213485}
486
487test "std.event.Channel" {
488 var da = std.heap.DirectAllocator.init();
489 defer da.deinit();
490
491 const allocator = &da.allocator;
492
493 var loop = try Loop.init(allocator);
494 defer loop.deinit();
495
496 const channel = try Channel(i32).create(&loop, 0);
497 defer channel.destroy();
498
499 const handle = try async<allocator> testChannelGetter(&loop, channel);
500 defer cancel handle;
501
502 const putter = try async<allocator> testChannelPutter(channel);
503 defer cancel putter;
504
505 loop.run();
506}
507
508async fn testChannelGetter(loop: *Loop, channel: *Channel(i32)) void {
509 errdefer @panic("test failed");
510
511 const value1_promise = try async channel.get();
512 const value1 = await value1_promise;
513 assert(value1 == 1234);
514
515 const value2_promise = try async channel.get();
516 const value2 = await value2_promise;
517 assert(value2 == 4567);
518
519 loop.stop();
520}
521
522async fn testChannelPutter(channel: *Channel(i32)) void {
523 await (async channel.put(1234) catch @panic("out of memory"));
524 await (async channel.put(4567) catch @panic("out of memory"));
525}
std/fmt/index.zig+4-1
......@@ -130,6 +130,9 @@ pub fn formatType(
130130 try output(context, "error.");
131131 return output(context, @errorName(value));
132132 },
133 builtin.TypeId.Promise => {
134 return format(context, Errors, output, "promise@{x}", @ptrToInt(value));
135 },
133136 builtin.TypeId.Pointer => |ptr_info| switch (ptr_info.size) {
134137 builtin.TypeInfo.Pointer.Size.One => switch (@typeInfo(ptr_info.child)) {
135138 builtin.TypeId.Array => |info| {
......@@ -327,7 +330,7 @@ pub fn formatFloatScientific(
327330 comptime Errors: type,
328331 output: fn (@typeOf(context), []const u8) Errors!void,
329332) Errors!void {
330 var x = f64(value);
333 var x = @floatCast(f64, value);
331334
332335 // Errol doesn't handle these special cases.
333336 if (math.signbit(x)) {
std/heap.zig+3-3
......@@ -38,6 +38,7 @@ fn cFree(self: *Allocator, old_mem: []u8) void {
3838}
3939
4040/// This allocator makes a syscall directly for every allocation and free.
41/// TODO make this thread-safe. The windows implementation will need some atomics.
4142pub const DirectAllocator = struct {
4243 allocator: Allocator,
4344 heap_handle: ?HeapHandle,
......@@ -221,7 +222,7 @@ pub const ArenaAllocator = struct {
221222 if (len >= actual_min_size) break;
222223 }
223224 const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);
224 const buf_node_slice = ([]BufNode)(buf[0..@sizeOf(BufNode)]);
225 const buf_node_slice = @bytesToSlice(BufNode, buf[0..@sizeOf(BufNode)]);
225226 const buf_node = &buf_node_slice[0];
226227 buf_node.* = BufNode{
227228 .data = buf,
......@@ -407,8 +408,7 @@ fn testAllocator(allocator: *mem.Allocator) !void {
407408 var slice = try allocator.alloc(*i32, 100);
408409
409410 for (slice) |*item, i| {
410 item.* = try allocator.create(i32);
411 item.*.* = @intCast(i32, i);
411 item.* = try allocator.create(@intCast(i32, i));
412412 }
413413
414414 for (slice) |item, i| {
std/io.zig+3-5
......@@ -414,14 +414,12 @@ pub const BufferedAtomicFile = struct {
414414
415415 pub fn create(allocator: *mem.Allocator, dest_path: []const u8) !*BufferedAtomicFile {
416416 // TODO with well defined copy elision we don't need this allocation
417 var self = try allocator.create(BufferedAtomicFile);
418 errdefer allocator.destroy(self);
419
420 self.* = BufferedAtomicFile{
417 var self = try allocator.create(BufferedAtomicFile{
421418 .atomic_file = undefined,
422419 .file_stream = undefined,
423420 .buffered_stream = undefined,
424 };
421 });
422 errdefer allocator.destroy(self);
425423
426424 self.atomic_file = try os.AtomicFile.init(allocator, dest_path, os.default_file_mode);
427425 errdefer self.atomic_file.deinit();
std/json.zig+1-1
......@@ -180,7 +180,7 @@ pub const StreamingParser = struct {
180180 pub fn fromInt(x: var) State {
181181 debug.assert(x == 0 or x == 1);
182182 const T = @TagType(State);
183 return State(@intCast(T, x));
183 return @intToEnum(State, @intCast(T, x));
184184 }
185185 };
186186
std/linked_list.zig+1-1
......@@ -193,7 +193,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
193193 /// A pointer to the new node.
194194 pub fn allocateNode(list: *Self, allocator: *Allocator) !*Node {
195195 comptime assert(!isIntrusive());
196 return allocator.create(Node);
196 return allocator.create(Node(undefined));
197197 }
198198
199199 /// Deallocate a node.
std/macho.zig+1-1
......@@ -161,7 +161,7 @@ pub fn loadSymbols(allocator: *mem.Allocator, in: *io.FileInStream) !SymbolTable
161161}
162162
163163fn readNoEof(in: *io.FileInStream, comptime T: type, result: []T) !void {
164 return in.stream.readNoEof(([]u8)(result));
164 return in.stream.readNoEof(@sliceToBytes(result));
165165}
166166fn readOneNoEof(in: *io.FileInStream, comptime T: type, result: *T) !void {
167167 return readNoEof(in, T, (*[1]T)(result)[0..]);
std/math/copysign.zig+18
......@@ -4,12 +4,22 @@ const assert = std.debug.assert;
44
55pub fn copysign(comptime T: type, x: T, y: T) T {
66 return switch (T) {
7 f16 => copysign16(x, y),
78 f32 => copysign32(x, y),
89 f64 => copysign64(x, y),
910 else => @compileError("copysign not implemented for " ++ @typeName(T)),
1011 };
1112}
1213
14fn copysign16(x: f16, y: f16) f16 {
15 const ux = @bitCast(u16, x);
16 const uy = @bitCast(u16, y);
17
18 const h1 = ux & (@maxValue(u16) / 2);
19 const h2 = uy & (u16(1) << 15);
20 return @bitCast(f16, h1 | h2);
21}
22
1323fn copysign32(x: f32, y: f32) f32 {
1424 const ux = @bitCast(u32, x);
1525 const uy = @bitCast(u32, y);
......@@ -29,10 +39,18 @@ fn copysign64(x: f64, y: f64) f64 {
2939}
3040
3141test "math.copysign" {
42 assert(copysign(f16, 1.0, 1.0) == copysign16(1.0, 1.0));
3243 assert(copysign(f32, 1.0, 1.0) == copysign32(1.0, 1.0));
3344 assert(copysign(f64, 1.0, 1.0) == copysign64(1.0, 1.0));
3445}
3546
47test "math.copysign16" {
48 assert(copysign16(5.0, 1.0) == 5.0);
49 assert(copysign16(5.0, -1.0) == -5.0);
50 assert(copysign16(-5.0, -1.0) == -5.0);
51 assert(copysign16(-5.0, 1.0) == 5.0);
52}
53
3654test "math.copysign32" {
3755 assert(copysign32(5.0, 1.0) == 5.0);
3856 assert(copysign32(5.0, -1.0) == -5.0);
std/math/expm1.zig+8
......@@ -20,6 +20,10 @@ pub fn expm1(x: var) @typeOf(x) {
2020
2121fn expm1_32(x_: f32) f32 {
2222 @setFloatMode(this, builtin.FloatMode.Strict);
23
24 if (math.isNan(x_))
25 return math.nan(f32);
26
2327 const o_threshold: f32 = 8.8721679688e+01;
2428 const ln2_hi: f32 = 6.9313812256e-01;
2529 const ln2_lo: f32 = 9.0580006145e-06;
......@@ -146,6 +150,10 @@ fn expm1_32(x_: f32) f32 {
146150
147151fn expm1_64(x_: f64) f64 {
148152 @setFloatMode(this, builtin.FloatMode.Strict);
153
154 if (math.isNan(x_))
155 return math.nan(f64);
156
149157 const o_threshold: f64 = 7.09782712893383973096e+02;
150158 const ln2_hi: f64 = 6.93147180369123816490e-01;
151159 const ln2_lo: f64 = 1.90821492927058770002e-10;
std/math/fabs.zig+19
......@@ -10,12 +10,19 @@ const assert = std.debug.assert;
1010pub fn fabs(x: var) @typeOf(x) {
1111 const T = @typeOf(x);
1212 return switch (T) {
13 f16 => fabs16(x),
1314 f32 => fabs32(x),
1415 f64 => fabs64(x),
1516 else => @compileError("fabs not implemented for " ++ @typeName(T)),
1617 };
1718}
1819
20fn fabs16(x: f16) f16 {
21 var u = @bitCast(u16, x);
22 u &= 0x7FFF;
23 return @bitCast(f16, u);
24}
25
1926fn fabs32(x: f32) f32 {
2027 var u = @bitCast(u32, x);
2128 u &= 0x7FFFFFFF;
......@@ -29,10 +36,16 @@ fn fabs64(x: f64) f64 {
2936}
3037
3138test "math.fabs" {
39 assert(fabs(f16(1.0)) == fabs16(1.0));
3240 assert(fabs(f32(1.0)) == fabs32(1.0));
3341 assert(fabs(f64(1.0)) == fabs64(1.0));
3442}
3543
44test "math.fabs16" {
45 assert(fabs16(1.0) == 1.0);
46 assert(fabs16(-1.0) == 1.0);
47}
48
3649test "math.fabs32" {
3750 assert(fabs32(1.0) == 1.0);
3851 assert(fabs32(-1.0) == 1.0);
......@@ -43,6 +56,12 @@ test "math.fabs64" {
4356 assert(fabs64(-1.0) == 1.0);
4457}
4558
59test "math.fabs16.special" {
60 assert(math.isPositiveInf(fabs(math.inf(f16))));
61 assert(math.isPositiveInf(fabs(-math.inf(f16))));
62 assert(math.isNan(fabs(math.nan(f16))));
63}
64
4665test "math.fabs32.special" {
4766 assert(math.isPositiveInf(fabs(math.inf(f32))));
4867 assert(math.isPositiveInf(fabs(-math.inf(f32))));
std/math/floor.zig+50
......@@ -12,12 +12,47 @@ const math = std.math;
1212pub fn floor(x: var) @typeOf(x) {
1313 const T = @typeOf(x);
1414 return switch (T) {
15 f16 => floor16(x),
1516 f32 => floor32(x),
1617 f64 => floor64(x),
1718 else => @compileError("floor not implemented for " ++ @typeName(T)),
1819 };
1920}
2021
22fn floor16(x: f16) f16 {
23 var u = @bitCast(u16, x);
24 const e = @intCast(i16, (u >> 10) & 31) - 15;
25 var m: u16 = undefined;
26
27 // TODO: Shouldn't need this explicit check.
28 if (x == 0.0) {
29 return x;
30 }
31
32 if (e >= 10) {
33 return x;
34 }
35
36 if (e >= 0) {
37 m = u16(1023) >> @intCast(u4, e);
38 if (u & m == 0) {
39 return x;
40 }
41 math.forceEval(x + 0x1.0p120);
42 if (u >> 15 != 0) {
43 u += m;
44 }
45 return @bitCast(f16, u & ~m);
46 } else {
47 math.forceEval(x + 0x1.0p120);
48 if (u >> 15 == 0) {
49 return 0.0;
50 } else {
51 return -1.0;
52 }
53 }
54}
55
2156fn floor32(x: f32) f32 {
2257 var u = @bitCast(u32, x);
2358 const e = @intCast(i32, (u >> 23) & 0xFF) - 0x7F;
......@@ -84,10 +119,17 @@ fn floor64(x: f64) f64 {
84119}
85120
86121test "math.floor" {
122 assert(floor(f16(1.3)) == floor16(1.3));
87123 assert(floor(f32(1.3)) == floor32(1.3));
88124 assert(floor(f64(1.3)) == floor64(1.3));
89125}
90126
127test "math.floor16" {
128 assert(floor16(1.3) == 1.0);
129 assert(floor16(-1.3) == -2.0);
130 assert(floor16(0.2) == 0.0);
131}
132
91133test "math.floor32" {
92134 assert(floor32(1.3) == 1.0);
93135 assert(floor32(-1.3) == -2.0);
......@@ -100,6 +142,14 @@ test "math.floor64" {
100142 assert(floor64(0.2) == 0.0);
101143}
102144
145test "math.floor16.special" {
146 assert(floor16(0.0) == 0.0);
147 assert(floor16(-0.0) == -0.0);
148 assert(math.isPositiveInf(floor16(math.inf(f16))));
149 assert(math.isNegativeInf(floor16(-math.inf(f16))));
150 assert(math.isNan(floor16(math.nan(f16))));
151}
152
103153test "math.floor32.special" {
104154 assert(floor32(0.0) == 0.0);
105155 assert(floor32(-0.0) == -0.0);
std/math/index.zig+43-1
......@@ -19,6 +19,18 @@ pub const f32_max = 3.40282346638528859812e+38;
1919pub const f32_epsilon = 1.1920928955078125e-07;
2020pub const f32_toint = 1.0 / f32_epsilon;
2121
22pub const f16_true_min = 0.000000059604644775390625; // 2**-24
23pub const f16_min = 0.00006103515625; // 2**-14
24pub const f16_max = 65504;
25pub const f16_epsilon = 0.0009765625; // 2**-10
26pub const f16_toint = 1.0 / f16_epsilon;
27
28pub const nan_u16 = u16(0x7C01);
29pub const nan_f16 = @bitCast(f16, nan_u16);
30
31pub const inf_u16 = u16(0x7C00);
32pub const inf_f16 = @bitCast(f16, inf_u16);
33
2234pub const nan_u32 = u32(0x7F800001);
2335pub const nan_f32 = @bitCast(f32, nan_u32);
2436
......@@ -44,6 +56,11 @@ pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) bool {
4456pub fn forceEval(value: var) void {
4557 const T = @typeOf(value);
4658 switch (T) {
59 f16 => {
60 var x: f16 = undefined;
61 const p = @ptrCast(*volatile f16, &x);
62 p.* = x;
63 },
4764 f32 => {
4865 var x: f32 = undefined;
4966 const p = @ptrCast(*volatile f32, &x);
......@@ -183,6 +200,32 @@ test "math" {
183200 _ = @import("big/index.zig");
184201}
185202
203pub fn floatMantissaBits(comptime T: type) comptime_int {
204 assert(@typeId(T) == builtin.TypeId.Float);
205
206 return switch (T.bit_count) {
207 16 => 10,
208 32 => 23,
209 64 => 52,
210 80 => 64,
211 128 => 112,
212 else => @compileError("unknown floating point type " ++ @typeName(T)),
213 };
214}
215
216pub fn floatExponentBits(comptime T: type) comptime_int {
217 assert(@typeId(T) == builtin.TypeId.Float);
218
219 return switch (T.bit_count) {
220 16 => 5,
221 32 => 8,
222 64 => 11,
223 80 => 15,
224 128 => 15,
225 else => @compileError("unknown floating point type " ++ @typeName(T)),
226 };
227}
228
186229pub fn min(x: var, y: var) @typeOf(x + y) {
187230 return if (x < y) x else y;
188231}
......@@ -607,4 +650,3 @@ pub fn lossyCast(comptime T: type, value: var) T {
607650 else => @compileError("bad type"),
608651 }
609652}
610
std/math/inf.zig+1-1
......@@ -1,9 +1,9 @@
11const std = @import("../index.zig");
22const math = std.math;
3const assert = std.debug.assert;
43
54pub fn inf(comptime T: type) T {
65 return switch (T) {
6 f16 => @bitCast(f16, math.inf_u16),
77 f32 => @bitCast(f32, math.inf_u32),
88 f64 => @bitCast(f64, math.inf_u64),
99 else => @compileError("inf not implemented for " ++ @typeName(T)),
std/math/isfinite.zig+8
......@@ -5,6 +5,10 @@ const assert = std.debug.assert;
55pub fn isFinite(x: var) bool {
66 const T = @typeOf(x);
77 switch (T) {
8 f16 => {
9 const bits = @bitCast(u16, x);
10 return bits & 0x7FFF < 0x7C00;
11 },
812 f32 => {
913 const bits = @bitCast(u32, x);
1014 return bits & 0x7FFFFFFF < 0x7F800000;
......@@ -20,10 +24,14 @@ pub fn isFinite(x: var) bool {
2024}
2125
2226test "math.isFinite" {
27 assert(isFinite(f16(0.0)));
28 assert(isFinite(f16(-0.0)));
2329 assert(isFinite(f32(0.0)));
2430 assert(isFinite(f32(-0.0)));
2531 assert(isFinite(f64(0.0)));
2632 assert(isFinite(f64(-0.0)));
33 assert(!isFinite(math.inf(f16)));
34 assert(!isFinite(-math.inf(f16)));
2735 assert(!isFinite(math.inf(f32)));
2836 assert(!isFinite(-math.inf(f32)));
2937 assert(!isFinite(math.inf(f64)));
std/math/isinf.zig+22
......@@ -5,6 +5,10 @@ const assert = std.debug.assert;
55pub fn isInf(x: var) bool {
66 const T = @typeOf(x);
77 switch (T) {
8 f16 => {
9 const bits = @bitCast(u16, x);
10 return bits & 0x7FFF == 0x7C00;
11 },
812 f32 => {
913 const bits = @bitCast(u32, x);
1014 return bits & 0x7FFFFFFF == 0x7F800000;
......@@ -22,6 +26,9 @@ pub fn isInf(x: var) bool {
2226pub fn isPositiveInf(x: var) bool {
2327 const T = @typeOf(x);
2428 switch (T) {
29 f16 => {
30 return @bitCast(u16, x) == 0x7C00;
31 },
2532 f32 => {
2633 return @bitCast(u32, x) == 0x7F800000;
2734 },
......@@ -37,6 +44,9 @@ pub fn isPositiveInf(x: var) bool {
3744pub fn isNegativeInf(x: var) bool {
3845 const T = @typeOf(x);
3946 switch (T) {
47 f16 => {
48 return @bitCast(u16, x) == 0xFC00;
49 },
4050 f32 => {
4151 return @bitCast(u32, x) == 0xFF800000;
4252 },
......@@ -50,10 +60,14 @@ pub fn isNegativeInf(x: var) bool {
5060}
5161
5262test "math.isInf" {
63 assert(!isInf(f16(0.0)));
64 assert(!isInf(f16(-0.0)));
5365 assert(!isInf(f32(0.0)));
5466 assert(!isInf(f32(-0.0)));
5567 assert(!isInf(f64(0.0)));
5668 assert(!isInf(f64(-0.0)));
69 assert(isInf(math.inf(f16)));
70 assert(isInf(-math.inf(f16)));
5771 assert(isInf(math.inf(f32)));
5872 assert(isInf(-math.inf(f32)));
5973 assert(isInf(math.inf(f64)));
......@@ -61,10 +75,14 @@ test "math.isInf" {
6175}
6276
6377test "math.isPositiveInf" {
78 assert(!isPositiveInf(f16(0.0)));
79 assert(!isPositiveInf(f16(-0.0)));
6480 assert(!isPositiveInf(f32(0.0)));
6581 assert(!isPositiveInf(f32(-0.0)));
6682 assert(!isPositiveInf(f64(0.0)));
6783 assert(!isPositiveInf(f64(-0.0)));
84 assert(isPositiveInf(math.inf(f16)));
85 assert(!isPositiveInf(-math.inf(f16)));
6886 assert(isPositiveInf(math.inf(f32)));
6987 assert(!isPositiveInf(-math.inf(f32)));
7088 assert(isPositiveInf(math.inf(f64)));
......@@ -72,10 +90,14 @@ test "math.isPositiveInf" {
7290}
7391
7492test "math.isNegativeInf" {
93 assert(!isNegativeInf(f16(0.0)));
94 assert(!isNegativeInf(f16(-0.0)));
7595 assert(!isNegativeInf(f32(0.0)));
7696 assert(!isNegativeInf(f32(-0.0)));
7797 assert(!isNegativeInf(f64(0.0)));
7898 assert(!isNegativeInf(f64(-0.0)));
99 assert(!isNegativeInf(math.inf(f16)));
100 assert(isNegativeInf(-math.inf(f16)));
79101 assert(!isNegativeInf(math.inf(f32)));
80102 assert(isNegativeInf(-math.inf(f32)));
81103 assert(!isNegativeInf(math.inf(f64)));
std/math/isnan.zig+6
......@@ -5,6 +5,10 @@ const assert = std.debug.assert;
55pub fn isNan(x: var) bool {
66 const T = @typeOf(x);
77 switch (T) {
8 f16 => {
9 const bits = @bitCast(u16, x);
10 return (bits & 0x7fff) > 0x7c00;
11 },
812 f32 => {
913 const bits = @bitCast(u32, x);
1014 return bits & 0x7FFFFFFF > 0x7F800000;
......@@ -26,8 +30,10 @@ pub fn isSignalNan(x: var) bool {
2630}
2731
2832test "math.isNan" {
33 assert(isNan(math.nan(f16)));
2934 assert(isNan(math.nan(f32)));
3035 assert(isNan(math.nan(f64)));
36 assert(!isNan(f16(1.0)));
3137 assert(!isNan(f32(1.0)));
3238 assert(!isNan(f64(1.0)));
3339}
std/math/isnormal.zig+9
......@@ -5,6 +5,10 @@ const assert = std.debug.assert;
55pub fn isNormal(x: var) bool {
66 const T = @typeOf(x);
77 switch (T) {
8 f16 => {
9 const bits = @bitCast(u16, x);
10 return (bits + 1024) & 0x7FFF >= 2048;
11 },
812 f32 => {
913 const bits = @bitCast(u32, x);
1014 return (bits + 0x00800000) & 0x7FFFFFFF >= 0x01000000;
......@@ -20,8 +24,13 @@ pub fn isNormal(x: var) bool {
2024}
2125
2226test "math.isNormal" {
27 assert(!isNormal(math.nan(f16)));
2328 assert(!isNormal(math.nan(f32)));
2429 assert(!isNormal(math.nan(f64)));
30 assert(!isNormal(f16(0)));
31 assert(!isNormal(f32(0)));
32 assert(!isNormal(f64(0)));
33 assert(isNormal(f16(1.0)));
2534 assert(isNormal(f32(1.0)));
2635 assert(isNormal(f64(1.0)));
2736}
std/math/nan.zig+2
......@@ -2,6 +2,7 @@ const math = @import("index.zig");
22
33pub fn nan(comptime T: type) T {
44 return switch (T) {
5 f16 => @bitCast(f16, math.nan_u16),
56 f32 => @bitCast(f32, math.nan_u32),
67 f64 => @bitCast(f64, math.nan_u64),
78 else => @compileError("nan not implemented for " ++ @typeName(T)),
......@@ -12,6 +13,7 @@ pub fn nan(comptime T: type) T {
1213// representation in the future when required.
1314pub fn snan(comptime T: type) T {
1415 return switch (T) {
16 f16 => @bitCast(f16, math.nan_u16),
1517 f32 => @bitCast(f32, math.nan_u32),
1618 f64 => @bitCast(f64, math.nan_u64),
1719 else => @compileError("snan not implemented for " ++ @typeName(T)),
std/math/signbit.zig+12
......@@ -5,12 +5,18 @@ const assert = std.debug.assert;
55pub fn signbit(x: var) bool {
66 const T = @typeOf(x);
77 return switch (T) {
8 f16 => signbit16(x),
89 f32 => signbit32(x),
910 f64 => signbit64(x),
1011 else => @compileError("signbit not implemented for " ++ @typeName(T)),
1112 };
1213}
1314
15fn signbit16(x: f16) bool {
16 const bits = @bitCast(u16, x);
17 return bits >> 15 != 0;
18}
19
1420fn signbit32(x: f32) bool {
1521 const bits = @bitCast(u32, x);
1622 return bits >> 31 != 0;
......@@ -22,10 +28,16 @@ fn signbit64(x: f64) bool {
2228}
2329
2430test "math.signbit" {
31 assert(signbit(f16(4.0)) == signbit16(4.0));
2532 assert(signbit(f32(4.0)) == signbit32(4.0));
2633 assert(signbit(f64(4.0)) == signbit64(4.0));
2734}
2835
36test "math.signbit16" {
37 assert(!signbit16(4.0));
38 assert(signbit16(-3.0));
39}
40
2941test "math.signbit32" {
3042 assert(!signbit32(4.0));
3143 assert(signbit32(-3.0));
std/math/sqrt.zig+23
......@@ -31,10 +31,25 @@ pub fn sqrt(x: var) (if (@typeId(@typeOf(x)) == TypeId.Int) @IntType(false, @typ
3131}
3232
3333test "math.sqrt" {
34 assert(sqrt(f16(0.0)) == @sqrt(f16, 0.0));
3435 assert(sqrt(f32(0.0)) == @sqrt(f32, 0.0));
3536 assert(sqrt(f64(0.0)) == @sqrt(f64, 0.0));
3637}
3738
39test "math.sqrt16" {
40 const epsilon = 0.000001;
41
42 assert(@sqrt(f16, 0.0) == 0.0);
43 assert(math.approxEq(f16, @sqrt(f16, 2.0), 1.414214, epsilon));
44 assert(math.approxEq(f16, @sqrt(f16, 3.6), 1.897367, epsilon));
45 assert(@sqrt(f16, 4.0) == 2.0);
46 assert(math.approxEq(f16, @sqrt(f16, 7.539840), 2.745877, epsilon));
47 assert(math.approxEq(f16, @sqrt(f16, 19.230934), 4.385309, epsilon));
48 assert(@sqrt(f16, 64.0) == 8.0);
49 assert(math.approxEq(f16, @sqrt(f16, 64.1), 8.006248, epsilon));
50 assert(math.approxEq(f16, @sqrt(f16, 8942.230469), 94.563370, epsilon));
51}
52
3853test "math.sqrt32" {
3954 const epsilon = 0.000001;
4055
......@@ -63,6 +78,14 @@ test "math.sqrt64" {
6378 assert(math.approxEq(f64, @sqrt(f64, 8942.230469), 94.563367, epsilon));
6479}
6580
81test "math.sqrt16.special" {
82 assert(math.isPositiveInf(@sqrt(f16, math.inf(f16))));
83 assert(@sqrt(f16, 0.0) == 0.0);
84 assert(@sqrt(f16, -0.0) == -0.0);
85 assert(math.isNan(@sqrt(f16, -1.0)));
86 assert(math.isNan(@sqrt(f16, math.nan(f16))));
87}
88
6689test "math.sqrt32.special" {
6790 assert(math.isPositiveInf(@sqrt(f32, math.inf(f32))));
6891 assert(@sqrt(f32, 0.0) == 0.0);
std/mem.zig+9-17
......@@ -31,16 +31,8 @@ pub const Allocator = struct {
3131 /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`
3232 freeFn: fn (self: *Allocator, old_mem: []u8) void,
3333
34 /// Call destroy with the result
35 pub fn create(self: *Allocator, comptime T: type) !*T {
36 if (@sizeOf(T) == 0) return *{};
37 const slice = try self.alloc(T, 1);
38 return &slice[0];
39 }
40
41 /// Call destroy with the result
42 /// TODO once #733 is solved, this will replace create
43 pub fn construct(self: *Allocator, init: var) Error!*@typeOf(init) {
34 /// Call `destroy` with the result
35 pub fn create(self: *Allocator, init: var) Error!*@typeOf(init) {
4436 const T = @typeOf(init);
4537 if (@sizeOf(T) == 0) return &{};
4638 const slice = try self.alloc(T, 1);
......@@ -49,7 +41,7 @@ pub const Allocator = struct {
4941 return ptr;
5042 }
5143
52 /// `ptr` should be the return value of `construct` or `create`
44 /// `ptr` should be the return value of `create`
5345 pub fn destroy(self: *Allocator, ptr: var) void {
5446 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr));
5547 self.freeFn(self, non_const_ptr[0..@sizeOf(@typeOf(ptr).Child)]);
......@@ -70,7 +62,7 @@ pub const Allocator = struct {
7062 for (byte_slice) |*byte| {
7163 byte.* = undefined;
7264 }
73 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
65 return @bytesToSlice(T, @alignCast(alignment, byte_slice));
7466 }
7567
7668 pub fn realloc(self: *Allocator, comptime T: type, old_mem: []T, n: usize) ![]T {
......@@ -86,7 +78,7 @@ pub const Allocator = struct {
8678 return ([*]align(alignment) T)(undefined)[0..0];
8779 }
8880
89 const old_byte_slice = ([]u8)(old_mem);
81 const old_byte_slice = @sliceToBytes(old_mem);
9082 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
9183 const byte_slice = try self.reallocFn(self, old_byte_slice, byte_count, alignment);
9284 assert(byte_slice.len == byte_count);
......@@ -96,7 +88,7 @@ pub const Allocator = struct {
9688 byte.* = undefined;
9789 }
9890 }
99 return ([]T)(@alignCast(alignment, byte_slice));
91 return @bytesToSlice(T, @alignCast(alignment, byte_slice));
10092 }
10193
10294 /// Reallocate, but `n` must be less than or equal to `old_mem.len`.
......@@ -118,13 +110,13 @@ pub const Allocator = struct {
118110 // n <= old_mem.len and the multiplication didn't overflow for that operation.
119111 const byte_count = @sizeOf(T) * n;
120112
121 const byte_slice = self.reallocFn(self, ([]u8)(old_mem), byte_count, alignment) catch unreachable;
113 const byte_slice = self.reallocFn(self, @sliceToBytes(old_mem), byte_count, alignment) catch unreachable;
122114 assert(byte_slice.len == byte_count);
123 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
115 return @bytesToSlice(T, @alignCast(alignment, byte_slice));
124116 }
125117
126118 pub fn free(self: *Allocator, memory: var) void {
127 const bytes = ([]const u8)(memory);
119 const bytes = @sliceToBytes(memory);
128120 if (bytes.len == 0) return;
129121 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(bytes.ptr));
130122 self.freeFn(self, non_const_ptr[0..bytes.len]);
std/net.zig+1-1
......@@ -68,7 +68,7 @@ pub const Address = struct {
6868
6969pub fn parseIp4(buf: []const u8) !u32 {
7070 var result: u32 = undefined;
71 const out_ptr = ([]u8)((*[1]u32)(&result)[0..]);
71 const out_ptr = @sliceToBytes((*[1]u32)(&result)[0..]);
7272
7373 var x: u8 = 0;
7474 var index: u8 = 0;
std/os/child_process.zig+5-8
......@@ -85,10 +85,7 @@ pub const ChildProcess = struct {
8585 /// First argument in argv is the executable.
8686 /// On success must call deinit.
8787 pub fn init(argv: []const []const u8, allocator: *mem.Allocator) !*ChildProcess {
88 const child = try allocator.create(ChildProcess);
89 errdefer allocator.destroy(child);
90
91 child.* = ChildProcess{
88 const child = try allocator.create(ChildProcess{
9289 .allocator = allocator,
9390 .argv = argv,
9491 .pid = undefined,
......@@ -109,8 +106,8 @@ pub const ChildProcess = struct {
109106 .stdin_behavior = StdIo.Inherit,
110107 .stdout_behavior = StdIo.Inherit,
111108 .stderr_behavior = StdIo.Inherit,
112 };
113
109 });
110 errdefer allocator.destroy(child);
114111 return child;
115112 }
116113
......@@ -318,7 +315,7 @@ pub const ChildProcess = struct {
318315 // Here we potentially return the fork child's error
319316 // from the parent pid.
320317 if (err_int != @maxValue(ErrInt)) {
321 return SpawnError(err_int);
318 return @errSetCast(SpawnError, @intToError(err_int));
322319 }
323320
324321 return statusToTerm(status);
......@@ -756,7 +753,7 @@ fn destroyPipe(pipe: *const [2]i32) void {
756753// Child of fork calls this to report an error to the fork parent.
757754// Then the child exits.
758755fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {
759 _ = writeIntFd(fd, ErrInt(err));
756 _ = writeIntFd(fd, ErrInt(@errorToInt(err)));
760757 posix.exit(1);
761758}
762759
std/os/index.zig+12-6
......@@ -1805,7 +1805,7 @@ pub fn argsAlloc(allocator: *mem.Allocator) ![]const []u8 {
18051805 const buf = try allocator.alignedAlloc(u8, @alignOf([]u8), total_bytes);
18061806 errdefer allocator.free(buf);
18071807
1808 const result_slice_list = ([][]u8)(buf[0..slice_list_bytes]);
1808 const result_slice_list = @bytesToSlice([]u8, buf[0..slice_list_bytes]);
18091809 const result_contents = buf[slice_list_bytes..];
18101810 mem.copy(u8, result_contents, contents_slice);
18111811
......@@ -2468,7 +2468,7 @@ pub const Thread = struct {
24682468 data: Data,
24692469
24702470 pub const use_pthreads = is_posix and builtin.link_libc;
2471 const Data = if (use_pthreads)
2471 pub const Data = if (use_pthreads)
24722472 struct {
24732473 handle: c.pthread_t,
24742474 stack_addr: usize,
......@@ -2582,10 +2582,16 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread
25822582 const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) orelse return SpawnThreadError.OutOfMemory;
25832583 errdefer assert(windows.HeapFree(heap_handle, 0, bytes_ptr) != 0);
25842584 const bytes = @ptrCast([*]u8, bytes_ptr)[0..byte_count];
2585 const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext) catch unreachable;
2586 outer_context.inner = context;
2587 outer_context.thread.data.heap_handle = heap_handle;
2588 outer_context.thread.data.alloc_start = bytes_ptr;
2585 const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext{
2586 .thread = Thread{
2587 .data = Thread.Data{
2588 .heap_handle = heap_handle,
2589 .alloc_start = bytes_ptr,
2590 .handle = undefined,
2591 },
2592 },
2593 .inner = context,
2594 }) catch unreachable;
25892595
25902596 const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner);
25912597 outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse {
std/os/windows/util.zig+1-1
......@@ -79,7 +79,7 @@ pub fn windowsIsCygwinPty(handle: windows.HANDLE) bool {
7979
8080 const name_info = @ptrCast(*const windows.FILE_NAME_INFO, &name_info_bytes[0]);
8181 const name_bytes = name_info_bytes[size .. size + usize(name_info.FileNameLength)];
82 const name_wide = ([]u16)(name_bytes);
82 const name_wide = @bytesToSlice(u16, name_bytes);
8383 return mem.indexOf(u16, name_wide, []u16{ 'm', 's', 'y', 's', '-' }) != null or
8484 mem.indexOf(u16, name_wide, []u16{ '-', 'p', 't', 'y' }) != null;
8585}
std/rand/index.zig+2-2
......@@ -116,7 +116,7 @@ pub const Random = struct {
116116 pub fn floatNorm(r: *Random, comptime T: type) T {
117117 const value = ziggurat.next_f64(r, ziggurat.NormDist);
118118 switch (T) {
119 f32 => return f32(value),
119 f32 => return @floatCast(f32, value),
120120 f64 => return value,
121121 else => @compileError("unknown floating point type"),
122122 }
......@@ -128,7 +128,7 @@ pub const Random = struct {
128128 pub fn floatExp(r: *Random, comptime T: type) T {
129129 const value = ziggurat.next_f64(r, ziggurat.ExpDist);
130130 switch (T) {
131 f32 => return f32(value),
131 f32 => return @floatCast(f32, value),
132132 f64 => return value,
133133 else => @compileError("unknown floating point type"),
134134 }
std/rand/ziggurat.zig+6-2
......@@ -84,12 +84,12 @@ fn ZigTableGen(
8484
8585 for (tables.x[2..256]) |*entry, i| {
8686 const last = tables.x[2 + i - 1];
87 *entry = f_inv(v / last + f(last));
87 entry.* = f_inv(v / last + f(last));
8888 }
8989 tables.x[256] = 0;
9090
9191 for (tables.f[0..]) |*entry, i| {
92 *entry = f(tables.x[i]);
92 entry.* = f(tables.x[i]);
9393 }
9494
9595 return tables;
......@@ -160,3 +160,7 @@ test "ziggurant exp dist sanity" {
160160 _ = prng.random.floatExp(f64);
161161 }
162162}
163
164test "ziggurat table gen" {
165 const table = NormDist;
166}
std/special/builtin.zig+3-1
......@@ -210,7 +210,9 @@ fn generic_fmod(comptime T: type, x: T, y: T) T {
210210}
211211
212212fn isNan(comptime T: type, bits: T) bool {
213 if (T == u32) {
213 if (T == u16) {
214 return (bits & 0x7fff) > 0x7c00;
215 } else if (T == u32) {
214216 return (bits & 0x7fffffff) > 0x7f800000;
215217 } else if (T == u64) {
216218 return (bits & (@maxValue(u64) >> 1)) > (u64(0x7ff) << 52);
std/special/compiler_rt/extendXfYf2.zig created+89
......@@ -0,0 +1,89 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const is_test = builtin.is_test;
4
5pub extern fn __extenddftf2(a: f64) f128 {
6 return extendXfYf2(f128, f64, a);
7}
8
9pub extern fn __extendsftf2(a: f32) f128 {
10 return extendXfYf2(f128, f32, a);
11}
12
13pub extern fn __extendhfsf2(a: u16) f32 {
14 return extendXfYf2(f32, f16, @bitCast(f16, a));
15}
16
17const CHAR_BIT = 8;
18
19inline fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t {
20 const src_rep_t = @IntType(false, @typeInfo(src_t).Float.bits);
21 const dst_rep_t = @IntType(false, @typeInfo(dst_t).Float.bits);
22 const srcSigBits = std.math.floatMantissaBits(src_t);
23 const dstSigBits = std.math.floatMantissaBits(dst_t);
24 const SrcShift = std.math.Log2Int(src_rep_t);
25 const DstShift = std.math.Log2Int(dst_rep_t);
26
27 // Various constants whose values follow from the type parameters.
28 // Any reasonable optimizer will fold and propagate all of these.
29 const srcBits = @sizeOf(src_t) * CHAR_BIT;
30 const srcExpBits = srcBits - srcSigBits - 1;
31 const srcInfExp = (1 << srcExpBits) - 1;
32 const srcExpBias = srcInfExp >> 1;
33
34 const srcMinNormal = 1 << srcSigBits;
35 const srcInfinity = srcInfExp << srcSigBits;
36 const srcSignMask = 1 << (srcSigBits + srcExpBits);
37 const srcAbsMask = srcSignMask - 1;
38 const srcQNaN = 1 << (srcSigBits - 1);
39 const srcNaNCode = srcQNaN - 1;
40
41 const dstBits = @sizeOf(dst_t) * CHAR_BIT;
42 const dstExpBits = dstBits - dstSigBits - 1;
43 const dstInfExp = (1 << dstExpBits) - 1;
44 const dstExpBias = dstInfExp >> 1;
45
46 const dstMinNormal: dst_rep_t = dst_rep_t(1) << dstSigBits;
47
48 // Break a into a sign and representation of the absolute value
49 const aRep: src_rep_t = @bitCast(src_rep_t, a);
50 const aAbs: src_rep_t = aRep & srcAbsMask;
51 const sign: src_rep_t = aRep & srcSignMask;
52 var absResult: dst_rep_t = undefined;
53
54 if (aAbs -% srcMinNormal < srcInfinity - srcMinNormal) {
55 // a is a normal number.
56 // Extend to the destination type by shifting the significand and
57 // exponent into the proper position and rebiasing the exponent.
58 absResult = dst_rep_t(aAbs) << (dstSigBits - srcSigBits);
59 absResult += (dstExpBias - srcExpBias) << dstSigBits;
60 } else if (aAbs >= srcInfinity) {
61 // a is NaN or infinity.
62 // Conjure the result by beginning with infinity, then setting the qNaN
63 // bit (if needed) and right-aligning the rest of the trailing NaN
64 // payload field.
65 absResult = dstInfExp << dstSigBits;
66 absResult |= dst_rep_t(aAbs & srcQNaN) << (dstSigBits - srcSigBits);
67 absResult |= dst_rep_t(aAbs & srcNaNCode) << (dstSigBits - srcSigBits);
68 } else if (aAbs != 0) {
69 // a is denormal.
70 // renormalize the significand and clear the leading bit, then insert
71 // the correct adjusted exponent in the destination type.
72 const scale: u32 = @clz(aAbs) - @clz(src_rep_t(srcMinNormal));
73 absResult = dst_rep_t(aAbs) << @intCast(DstShift, dstSigBits - srcSigBits + scale);
74 absResult ^= dstMinNormal;
75 const resultExponent: u32 = dstExpBias - srcExpBias - scale + 1;
76 absResult |= @intCast(dst_rep_t, resultExponent) << dstSigBits;
77 } else {
78 // a is zero.
79 absResult = 0;
80 }
81
82 // Apply the signbit to (dst_t)abs(a).
83 const result: dst_rep_t align(@alignOf(dst_t)) = absResult | dst_rep_t(sign) << (dstBits - srcBits);
84 return @bitCast(dst_t, result);
85}
86
87test "import extendXfYf2" {
88 _ = @import("extendXfYf2_test.zig");
89}
std/special/compiler_rt/extendXfYf2_test.zig created+155
......@@ -0,0 +1,155 @@
1const __extenddftf2 = @import("extendXfYf2.zig").__extenddftf2;
2const __extendhfsf2 = @import("extendXfYf2.zig").__extendhfsf2;
3const __extendsftf2 = @import("extendXfYf2.zig").__extendsftf2;
4const assert = @import("std").debug.assert;
5
6fn test__extenddftf2(a: f64, expectedHi: u64, expectedLo: u64) void {
7 const x = __extenddftf2(a);
8
9 const rep = @bitCast(u128, x);
10 const hi = @intCast(u64, rep >> 64);
11 const lo = @truncate(u64, rep);
12
13 if (hi == expectedHi and lo == expectedLo)
14 return;
15
16 // test other possible NaN representation(signal NaN)
17 if (expectedHi == 0x7fff800000000000 and expectedLo == 0x0) {
18 if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and
19 ((hi & 0xffffffffffff) > 0 or lo > 0))
20 {
21 return;
22 }
23 }
24
25 @panic("__extenddftf2 test failure");
26}
27
28fn test__extendhfsf2(a: u16, expected: u32) void {
29 const x = __extendhfsf2(a);
30 const rep = @bitCast(u32, x);
31
32 if (rep == expected) {
33 if (rep & 0x7fffffff > 0x7f800000) {
34 return; // NaN is always unequal.
35 }
36 if (x == @bitCast(f32, expected)) {
37 return;
38 }
39 }
40
41 @panic("__extendhfsf2 test failure");
42}
43
44fn test__extendsftf2(a: f32, expectedHi: u64, expectedLo: u64) void {
45 const x = __extendsftf2(a);
46
47 const rep = @bitCast(u128, x);
48 const hi = @intCast(u64, rep >> 64);
49 const lo = @truncate(u64, rep);
50
51 if (hi == expectedHi and lo == expectedLo)
52 return;
53
54 // test other possible NaN representation(signal NaN)
55 if (expectedHi == 0x7fff800000000000 and expectedLo == 0x0) {
56 if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and
57 ((hi & 0xffffffffffff) > 0 or lo > 0))
58 {
59 return;
60 }
61 }
62
63 @panic("__extendsftf2 test failure");
64}
65
66test "extenddftf2" {
67 // qNaN
68 test__extenddftf2(makeQNaN64(), 0x7fff800000000000, 0x0);
69
70 // NaN
71 test__extenddftf2(makeNaN64(0x7100000000000), 0x7fff710000000000, 0x0);
72
73 // inf
74 test__extenddftf2(makeInf64(), 0x7fff000000000000, 0x0);
75
76 // zero
77 test__extenddftf2(0.0, 0x0, 0x0);
78
79 test__extenddftf2(0x1.23456789abcdefp+5, 0x400423456789abcd, 0xf000000000000000);
80
81 test__extenddftf2(0x1.edcba987654321fp-9, 0x3ff6edcba9876543, 0x2000000000000000);
82
83 test__extenddftf2(0x1.23456789abcdefp+45, 0x402c23456789abcd, 0xf000000000000000);
84
85 test__extenddftf2(0x1.edcba987654321fp-45, 0x3fd2edcba9876543, 0x2000000000000000);
86}
87
88test "extendhfsf2" {
89 test__extendhfsf2(0x7e00, 0x7fc00000); // qNaN
90 test__extendhfsf2(0x7f00, 0x7fe00000); // sNaN
91 test__extendhfsf2(0x7c01, 0x7f802000); // sNaN
92
93 test__extendhfsf2(0, 0); // 0
94 test__extendhfsf2(0x8000, 0x80000000); // -0
95
96 test__extendhfsf2(0x7c00, 0x7f800000); // inf
97 test__extendhfsf2(0xfc00, 0xff800000); // -inf
98
99 test__extendhfsf2(0x0001, 0x33800000); // denormal (min), 2**-24
100 test__extendhfsf2(0x8001, 0xb3800000); // denormal (min), -2**-24
101
102 test__extendhfsf2(0x03ff, 0x387fc000); // denormal (max), 2**-14 - 2**-24
103 test__extendhfsf2(0x83ff, 0xb87fc000); // denormal (max), -2**-14 + 2**-24
104
105 test__extendhfsf2(0x0400, 0x38800000); // normal (min), 2**-14
106 test__extendhfsf2(0x8400, 0xb8800000); // normal (min), -2**-14
107
108 test__extendhfsf2(0x7bff, 0x477fe000); // normal (max), 65504
109 test__extendhfsf2(0xfbff, 0xc77fe000); // normal (max), -65504
110
111 test__extendhfsf2(0x3c01, 0x3f802000); // normal, 1 + 2**-10
112 test__extendhfsf2(0xbc01, 0xbf802000); // normal, -1 - 2**-10
113
114 test__extendhfsf2(0x3555, 0x3eaaa000); // normal, approx. 1/3
115 test__extendhfsf2(0xb555, 0xbeaaa000); // normal, approx. -1/3
116}
117
118test "extendsftf2" {
119 // qNaN
120 test__extendsftf2(makeQNaN32(), 0x7fff800000000000, 0x0);
121 // NaN
122 test__extendsftf2(makeNaN32(0x410000), 0x7fff820000000000, 0x0);
123 // inf
124 test__extendsftf2(makeInf32(), 0x7fff000000000000, 0x0);
125 // zero
126 test__extendsftf2(0.0, 0x0, 0x0);
127 test__extendsftf2(0x1.23456p+5, 0x4004234560000000, 0x0);
128 test__extendsftf2(0x1.edcbap-9, 0x3ff6edcba0000000, 0x0);
129 test__extendsftf2(0x1.23456p+45, 0x402c234560000000, 0x0);
130 test__extendsftf2(0x1.edcbap-45, 0x3fd2edcba0000000, 0x0);
131}
132
133fn makeQNaN64() f64 {
134 return @bitCast(f64, u64(0x7ff8000000000000));
135}
136
137fn makeInf64() f64 {
138 return @bitCast(f64, u64(0x7ff0000000000000));
139}
140
141fn makeNaN64(rand: u64) f64 {
142 return @bitCast(f64, 0x7ff0000000000000 | (rand & 0xfffffffffffff));
143}
144
145fn makeQNaN32() f32 {
146 return @bitCast(f32, u32(0x7fc00000));
147}
148
149fn makeNaN32(rand: u32) f32 {
150 return @bitCast(f32, 0x7f800000 | (rand & 0x7fffff));
151}
152
153fn makeInf32() f32 {
154 return @bitCast(f32, u32(0x7f800000));
155}
std/special/compiler_rt/floattidf.zig created+69
......@@ -0,0 +1,69 @@
1const builtin = @import("builtin");
2const is_test = builtin.is_test;
3
4const DBL_MANT_DIG = 53;
5
6pub extern fn __floattidf(arg: i128) f64 {
7 @setRuntimeSafety(is_test);
8
9 if (arg == 0)
10 return 0.0;
11
12 var ai = arg;
13 const N: u32 = 128;
14 const si = ai >> @intCast(u7, (N - 1));
15 ai = ((ai ^ si) -% si);
16 var a = @bitCast(u128, ai);
17
18 const sd = @bitCast(i32, N - @clz(a)); // number of significant digits
19 var e: i32 = sd - 1; // exponent
20 if (sd > DBL_MANT_DIG) {
21 // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
22 // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
23 // 12345678901234567890123456
24 // 1 = msb 1 bit
25 // P = bit DBL_MANT_DIG-1 bits to the right of 1
26 // Q = bit DBL_MANT_DIG bits to the right of 1
27 // R = "or" of all bits to the right of Q
28 switch (sd) {
29 DBL_MANT_DIG + 1 => {
30 a <<= 1;
31 },
32 DBL_MANT_DIG + 2 => {},
33 else => {
34 const shift1_amt = @intCast(i32, sd - (DBL_MANT_DIG + 2));
35 const shift1_amt_u7 = @intCast(u7, shift1_amt);
36
37 const shift2_amt = @intCast(i32, N + (DBL_MANT_DIG + 2)) - sd;
38 const shift2_amt_u7 = @intCast(u7, shift2_amt);
39
40 a = (a >> shift1_amt_u7) | @boolToInt((a & (@intCast(u128, @maxValue(u128)) >> shift2_amt_u7)) != 0);
41 },
42 }
43 // finish
44 a |= @boolToInt((a & 4) != 0); // Or P into R
45 a += 1; // round - this step may add a significant bit
46 a >>= 2; // dump Q and R
47 // a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits
48 if ((a & (u128(1) << DBL_MANT_DIG)) != 0) {
49 a >>= 1;
50 e += 1;
51 }
52 // a is now rounded to DBL_MANT_DIG bits
53 } else {
54 a <<= @intCast(u7, DBL_MANT_DIG - sd);
55 // a is now rounded to DBL_MANT_DIG bits
56 }
57
58 const s = @bitCast(u128, arg) >> (128 - 32);
59 const high: u64 = (@intCast(u64, s) & 0x80000000) | // sign
60 (@intCast(u32, (e + 1023)) << 20) | // exponent
61 (@truncate(u32, a >> 32) & 0x000fffff); // mantissa-high
62 const low: u64 = @truncate(u32, a); // mantissa-low
63
64 return @bitCast(f64, low | (high << 32));
65}
66
67test "import floattidf" {
68 _ = @import("floattidf_test.zig");
69}
std/special/compiler_rt/floattidf_test.zig created+84
......@@ -0,0 +1,84 @@
1const __floattidf = @import("floattidf.zig").__floattidf;
2const assert = @import("std").debug.assert;
3
4fn test__floattidf(a: i128, expected: f64) void {
5 const x = __floattidf(a);
6 assert(x == expected);
7}
8
9test "floattidf" {
10 test__floattidf(0, 0.0);
11
12 test__floattidf(1, 1.0);
13 test__floattidf(2, 2.0);
14 test__floattidf(20, 20.0);
15 test__floattidf(-1, -1.0);
16 test__floattidf(-2, -2.0);
17 test__floattidf(-20, -20.0);
18
19 test__floattidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
20 test__floattidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62);
21 test__floattidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
22 test__floattidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62);
23
24 test__floattidf(make_ti(0x8000008000000000, 0), -0x1.FFFFFEp+126);
25 test__floattidf(make_ti(0x8000000000000800, 0), -0x1.FFFFFFFFFFFFEp+126);
26 test__floattidf(make_ti(0x8000010000000000, 0), -0x1.FFFFFCp+126);
27 test__floattidf(make_ti(0x8000000000001000, 0), -0x1.FFFFFFFFFFFFCp+126);
28
29 test__floattidf(make_ti(0x8000000000000000, 0), -0x1.000000p+127);
30 test__floattidf(make_ti(0x8000000000000001, 0), -0x1.000000p+127);
31
32 test__floattidf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
33
34 test__floattidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
35 test__floattidf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
36 test__floattidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50);
37 test__floattidf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
38 test__floattidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50);
39
40 test__floattidf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
41 test__floattidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
42 test__floattidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50);
43 test__floattidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50);
44 test__floattidf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
45
46 test__floattidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57);
47 test__floattidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57);
48 test__floattidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57);
49 test__floattidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57);
50 test__floattidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57);
51 test__floattidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57);
52 test__floattidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57);
53 test__floattidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57);
54 test__floattidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57);
55 test__floattidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57);
56 test__floattidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57);
57 test__floattidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57);
58 test__floattidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57);
59 test__floattidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57);
60 test__floattidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57);
61
62 test__floattidf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121);
63 test__floattidf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496Dp+121);
64 test__floattidf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496Ep+121);
65 test__floattidf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496Ep+121);
66 test__floattidf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496Ep+121);
67 test__floattidf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496Ep+121);
68 test__floattidf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496Ep+121);
69 test__floattidf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496Ep+121);
70 test__floattidf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496Ep+121);
71 test__floattidf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496Ep+121);
72 test__floattidf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496Ep+121);
73 test__floattidf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496Fp+121);
74 test__floattidf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496Fp+121);
75 test__floattidf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496Fp+121);
76 test__floattidf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121);
77}
78
79fn make_ti(high: u64, low: u64) i128 {
80 var result: u128 = high;
81 result <<= 64;
82 result |= low;
83 return @bitCast(i128, result);
84}
std/special/compiler_rt/floattisf.zig created+69
......@@ -0,0 +1,69 @@
1const builtin = @import("builtin");
2const is_test = builtin.is_test;
3
4const FLT_MANT_DIG = 24;
5
6pub extern fn __floattisf(arg: i128) f32 {
7 @setRuntimeSafety(is_test);
8
9 if (arg == 0)
10 return 0.0;
11
12 var ai = arg;
13 const N: u32 = 128;
14 const si = ai >> @intCast(u7, (N - 1));
15 ai = ((ai ^ si) -% si);
16 var a = @bitCast(u128, ai);
17
18 const sd = @bitCast(i32, N - @clz(a)); // number of significant digits
19 var e: i32 = sd - 1; // exponent
20
21 if (sd > FLT_MANT_DIG) {
22 // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
23 // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
24 // 12345678901234567890123456
25 // 1 = msb 1 bit
26 // P = bit FLT_MANT_DIG-1 bits to the right of 1
27 // Q = bit FLT_MANT_DIG bits to the right of 1
28 // R = "or" of all bits to the right of Q
29 switch (sd) {
30 FLT_MANT_DIG + 1 => {
31 a <<= 1;
32 },
33 FLT_MANT_DIG + 2 => {},
34 else => {
35 const shift1_amt = @intCast(i32, sd - (FLT_MANT_DIG + 2));
36 const shift1_amt_u7 = @intCast(u7, shift1_amt);
37
38 const shift2_amt = @intCast(i32, N + (FLT_MANT_DIG + 2)) - sd;
39 const shift2_amt_u7 = @intCast(u7, shift2_amt);
40
41 a = (a >> shift1_amt_u7) | @boolToInt((a & (@intCast(u128, @maxValue(u128)) >> shift2_amt_u7)) != 0);
42 },
43 }
44 // finish
45 a |= @boolToInt((a & 4) != 0); // Or P into R
46 a += 1; // round - this step may add a significant bit
47 a >>= 2; // dump Q and R
48 // a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits
49 if ((a & (u128(1) << FLT_MANT_DIG)) != 0) {
50 a >>= 1;
51 e += 1;
52 }
53 // a is now rounded to FLT_MANT_DIG bits
54 } else {
55 a <<= @intCast(u7, FLT_MANT_DIG - sd);
56 // a is now rounded to FLT_MANT_DIG bits
57 }
58
59 const s = @bitCast(u128, arg) >> (128 - 32);
60 const r = (@intCast(u32, s) & 0x80000000) | // sign
61 (@intCast(u32, (e + 127)) << 23) | // exponent
62 (@truncate(u32, a) & 0x007fffff); // mantissa-high
63
64 return @bitCast(f32, r);
65}
66
67test "import floattisf" {
68 _ = @import("floattisf_test.zig");
69}
std/special/compiler_rt/floattisf_test.zig created+60
......@@ -0,0 +1,60 @@
1const __floattisf = @import("floattisf.zig").__floattisf;
2const assert = @import("std").debug.assert;
3
4fn test__floattisf(a: i128, expected: f32) void {
5 const x = __floattisf(a);
6 assert(x == expected);
7}
8
9test "floattisf" {
10 test__floattisf(0, 0.0);
11
12 test__floattisf(1, 1.0);
13 test__floattisf(2, 2.0);
14 test__floattisf(-1, -1.0);
15 test__floattisf(-2, -2.0);
16
17 test__floattisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
18 test__floattisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
19
20 test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000008000000000), -0x1.FFFFFEp+62);
21 test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000010000000000), -0x1.FFFFFCp+62);
22
23 test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000000000000000), -0x1.000000p+63);
24 test__floattisf(make_ti(0xFFFFFFFFFFFFFFFF, 0x8000000000000001), -0x1.000000p+63);
25
26 test__floattisf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
27
28 test__floattisf(0x0007FB72EA000000, 0x1.FEDCBAp+50);
29 test__floattisf(0x0007FB72EB000000, 0x1.FEDCBAp+50);
30 test__floattisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50);
31 test__floattisf(0x0007FB72EC000000, 0x1.FEDCBCp+50);
32 test__floattisf(0x0007FB72E8000001, 0x1.FEDCBAp+50);
33
34 test__floattisf(0x0007FB72E6000000, 0x1.FEDCBAp+50);
35 test__floattisf(0x0007FB72E7000000, 0x1.FEDCBAp+50);
36 test__floattisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50);
37 test__floattisf(0x0007FB72E4000001, 0x1.FEDCBAp+50);
38 test__floattisf(0x0007FB72E4000000, 0x1.FEDCB8p+50);
39
40 test__floattisf(make_ti(0x0007FB72E8000000, 0), 0x1.FEDCBAp+114);
41
42 test__floattisf(make_ti(0x0007FB72EA000000, 0), 0x1.FEDCBAp+114);
43 test__floattisf(make_ti(0x0007FB72EB000000, 0), 0x1.FEDCBAp+114);
44 test__floattisf(make_ti(0x0007FB72EBFFFFFF, 0), 0x1.FEDCBAp+114);
45 test__floattisf(make_ti(0x0007FB72EC000000, 0), 0x1.FEDCBCp+114);
46 test__floattisf(make_ti(0x0007FB72E8000001, 0), 0x1.FEDCBAp+114);
47
48 test__floattisf(make_ti(0x0007FB72E6000000, 0), 0x1.FEDCBAp+114);
49 test__floattisf(make_ti(0x0007FB72E7000000, 0), 0x1.FEDCBAp+114);
50 test__floattisf(make_ti(0x0007FB72E7FFFFFF, 0), 0x1.FEDCBAp+114);
51 test__floattisf(make_ti(0x0007FB72E4000001, 0), 0x1.FEDCBAp+114);
52 test__floattisf(make_ti(0x0007FB72E4000000, 0), 0x1.FEDCB8p+114);
53}
54
55fn make_ti(high: u64, low: u64) i128 {
56 var result: u128 = high;
57 result <<= 64;
58 result |= low;
59 return @bitCast(i128, result);
60}
std/special/compiler_rt/floattitf.zig created+69
......@@ -0,0 +1,69 @@
1const builtin = @import("builtin");
2const is_test = builtin.is_test;
3
4const LDBL_MANT_DIG = 113;
5
6pub extern fn __floattitf(arg: i128) f128 {
7 @setRuntimeSafety(is_test);
8
9 if (arg == 0)
10 return 0.0;
11
12 var ai = arg;
13 const N: u32 = 128;
14 const si = ai >> @intCast(u7, (N - 1));
15 ai = ((ai ^ si) -% si);
16 var a = @bitCast(u128, ai);
17
18 const sd = @bitCast(i32, N - @clz(a)); // number of significant digits
19 var e: i32 = sd - 1; // exponent
20 if (sd > LDBL_MANT_DIG) {
21 // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
22 // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
23 // 12345678901234567890123456
24 // 1 = msb 1 bit
25 // P = bit LDBL_MANT_DIG-1 bits to the right of 1
26 // Q = bit LDBL_MANT_DIG bits to the right of 1
27 // R = "or" of all bits to the right of Q
28 switch (sd) {
29 LDBL_MANT_DIG + 1 => {
30 a <<= 1;
31 },
32 LDBL_MANT_DIG + 2 => {},
33 else => {
34 const shift1_amt = @intCast(i32, sd - (LDBL_MANT_DIG + 2));
35 const shift1_amt_u7 = @intCast(u7, shift1_amt);
36
37 const shift2_amt = @intCast(i32, N + (LDBL_MANT_DIG + 2)) - sd;
38 const shift2_amt_u7 = @intCast(u7, shift2_amt);
39
40 a = (a >> shift1_amt_u7) | @boolToInt((a & (@intCast(u128, @maxValue(u128)) >> shift2_amt_u7)) != 0);
41 },
42 }
43 // finish
44 a |= @boolToInt((a & 4) != 0); // Or P into R
45 a += 1; // round - this step may add a significant bit
46 a >>= 2; // dump Q and R
47 // a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits
48 if ((a & (u128(1) << LDBL_MANT_DIG)) != 0) {
49 a >>= 1;
50 e += 1;
51 }
52 // a is now rounded to LDBL_MANT_DIG bits
53 } else {
54 a <<= @intCast(u7, LDBL_MANT_DIG - sd);
55 // a is now rounded to LDBL_MANT_DIG bits
56 }
57
58 const s = @bitCast(u128, arg) >> (128 - 64);
59 const high: u128 = (@intCast(u64, s) & 0x8000000000000000) | // sign
60 (@intCast(u64, (e + 16383)) << 48) | // exponent
61 (@truncate(u64, a >> 64) & 0x0000ffffffffffff); // mantissa-high
62 const low = @truncate(u64, a); // mantissa-low
63
64 return @bitCast(f128, low | (high << 64));
65}
66
67test "import floattitf" {
68 _ = @import("floattitf_test.zig");
69}
std/special/compiler_rt/floattitf_test.zig created+96
......@@ -0,0 +1,96 @@
1const __floattitf = @import("floattitf.zig").__floattitf;
2const assert = @import("std").debug.assert;
3
4fn test__floattitf(a: i128, expected: f128) void {
5 const x = __floattitf(a);
6 assert(x == expected);
7}
8
9test "floattitf" {
10 test__floattitf(0, 0.0);
11
12 test__floattitf(1, 1.0);
13 test__floattitf(2, 2.0);
14 test__floattitf(20, 20.0);
15 test__floattitf(-1, -1.0);
16 test__floattitf(-2, -2.0);
17 test__floattitf(-20, -20.0);
18
19 test__floattitf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
20 test__floattitf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62);
21 test__floattitf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
22 test__floattitf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62);
23
24 test__floattitf(make_ti(0x8000008000000000, 0), -0x1.FFFFFEp+126);
25 test__floattitf(make_ti(0x8000000000000800, 0), -0x1.FFFFFFFFFFFFEp+126);
26 test__floattitf(make_ti(0x8000010000000000, 0), -0x1.FFFFFCp+126);
27 test__floattitf(make_ti(0x8000000000001000, 0), -0x1.FFFFFFFFFFFFCp+126);
28
29 test__floattitf(make_ti(0x8000000000000000, 0), -0x1.000000p+127);
30 test__floattitf(make_ti(0x8000000000000001, 0), -0x1.FFFFFFFFFFFFFFFCp+126);
31
32 test__floattitf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
33
34 test__floattitf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
35 test__floattitf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
36 test__floattitf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50);
37 test__floattitf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
38 test__floattitf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50);
39
40 test__floattitf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
41 test__floattitf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
42 test__floattitf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50);
43 test__floattitf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50);
44 test__floattitf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
45
46 test__floattitf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57);
47 test__floattitf(0x023479FD0E092DA1, 0x1.1A3CFE870496D08p+57);
48 test__floattitf(0x023479FD0E092DB0, 0x1.1A3CFE870496D8p+57);
49 test__floattitf(0x023479FD0E092DB8, 0x1.1A3CFE870496DCp+57);
50 test__floattitf(0x023479FD0E092DB6, 0x1.1A3CFE870496DBp+57);
51 test__floattitf(0x023479FD0E092DBF, 0x1.1A3CFE870496DF8p+57);
52 test__floattitf(0x023479FD0E092DC1, 0x1.1A3CFE870496E08p+57);
53 test__floattitf(0x023479FD0E092DC7, 0x1.1A3CFE870496E38p+57);
54 test__floattitf(0x023479FD0E092DC8, 0x1.1A3CFE870496E4p+57);
55 test__floattitf(0x023479FD0E092DCF, 0x1.1A3CFE870496E78p+57);
56 test__floattitf(0x023479FD0E092DD0, 0x1.1A3CFE870496E8p+57);
57 test__floattitf(0x023479FD0E092DD1, 0x1.1A3CFE870496E88p+57);
58 test__floattitf(0x023479FD0E092DD8, 0x1.1A3CFE870496ECp+57);
59 test__floattitf(0x023479FD0E092DDF, 0x1.1A3CFE870496EF8p+57);
60 test__floattitf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57);
61
62 test__floattitf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121);
63 test__floattitf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496D08p+121);
64 test__floattitf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496D8p+121);
65 test__floattitf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496DCp+121);
66 test__floattitf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496DBp+121);
67 test__floattitf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496DF8p+121);
68 test__floattitf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496E08p+121);
69 test__floattitf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496E38p+121);
70 test__floattitf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496E4p+121);
71 test__floattitf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496E78p+121);
72 test__floattitf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496E8p+121);
73 test__floattitf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496E88p+121);
74 test__floattitf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496ECp+121);
75 test__floattitf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496EF8p+121);
76 test__floattitf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121);
77
78 test__floattitf(make_ti(0, 0xFFFFFFFFFFFFFFFF), 0x1.FFFFFFFFFFFFFFFEp+63);
79
80 test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC2801), 0x1.23456789ABCDEF0123456789ABC3p+124);
81 test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3000), 0x1.23456789ABCDEF0123456789ABC3p+124);
82 test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC37FF), 0x1.23456789ABCDEF0123456789ABC3p+124);
83 test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3800), 0x1.23456789ABCDEF0123456789ABC4p+124);
84 test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4000), 0x1.23456789ABCDEF0123456789ABC4p+124);
85 test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC47FF), 0x1.23456789ABCDEF0123456789ABC4p+124);
86 test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4800), 0x1.23456789ABCDEF0123456789ABC4p+124);
87 test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4801), 0x1.23456789ABCDEF0123456789ABC5p+124);
88 test__floattitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC57FF), 0x1.23456789ABCDEF0123456789ABC5p+124);
89}
90
91fn make_ti(high: u64, low: u64) i128 {
92 var result: u128 = high;
93 result <<= 64;
94 result |= low;
95 return @bitCast(i128, result);
96}
std/special/compiler_rt/floatunditf.zig created+28
......@@ -0,0 +1,28 @@
1const builtin = @import("builtin");
2const is_test = builtin.is_test;
3const std = @import("std");
4
5pub extern fn __floatunditf(a: u128) f128 {
6 @setRuntimeSafety(is_test);
7
8 if (a == 0) {
9 return 0;
10 }
11
12 const mantissa_bits = std.math.floatMantissaBits(f128);
13 const exponent_bits = std.math.floatExponentBits(f128);
14 const exponent_bias = (1 << (exponent_bits - 1)) - 1;
15 const implicit_bit = 1 << mantissa_bits;
16
17 const exp = (u128.bit_count - 1) - @clz(a);
18 const shift = mantissa_bits - @intCast(u7, exp);
19
20 var result: u128 align(16) = (a << shift) ^ implicit_bit;
21 result += (@intCast(u128, exp) + exponent_bias) << mantissa_bits;
22
23 return @bitCast(f128, result);
24}
25
26test "import floatunditf" {
27 _ = @import("floatunditf_test.zig");
28}
std/special/compiler_rt/floatunditf_test.zig created+33
......@@ -0,0 +1,33 @@
1const __floatunditf = @import("floatunditf.zig").__floatunditf;
2const assert = @import("std").debug.assert;
3
4fn test__floatunditf(a: u128, expected_hi: u64, expected_lo: u64) void {
5 const x = __floatunditf(a);
6
7 const x_repr = @bitCast(u128, x);
8 const x_hi = @intCast(u64, x_repr >> 64);
9 const x_lo = @truncate(u64, x_repr);
10
11 if (x_hi == expected_hi and x_lo == expected_lo) {
12 return;
13 }
14 // nan repr
15 else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) {
16 if ((x_hi & 0x7fff000000000000) == 0x7fff000000000000 and ((x_hi & 0xffffffffffff) > 0 or x_lo > 0)) {
17 return;
18 }
19 }
20
21 @panic("__floatunditf test failure");
22}
23
24test "floatunditf" {
25 test__floatunditf(0xffffffffffffffff, 0x403effffffffffff, 0xfffe000000000000);
26 test__floatunditf(0xfffffffffffffffe, 0x403effffffffffff, 0xfffc000000000000);
27 test__floatunditf(0x8000000000000000, 0x403e000000000000, 0x0);
28 test__floatunditf(0x7fffffffffffffff, 0x403dffffffffffff, 0xfffc000000000000);
29 test__floatunditf(0x123456789abcdef1, 0x403b23456789abcd, 0xef10000000000000);
30 test__floatunditf(0x2, 0x4000000000000000, 0x0);
31 test__floatunditf(0x1, 0x3fff000000000000, 0x0);
32 test__floatunditf(0x0, 0x0, 0x0);
33}
std/special/compiler_rt/floatunsitf.zig created+29
......@@ -0,0 +1,29 @@
1const builtin = @import("builtin");
2const is_test = builtin.is_test;
3const std = @import("std");
4
5pub extern fn __floatunsitf(a: u64) f128 {
6 @setRuntimeSafety(is_test);
7
8 if (a == 0) {
9 return 0;
10 }
11
12 const mantissa_bits = std.math.floatMantissaBits(f128);
13 const exponent_bits = std.math.floatExponentBits(f128);
14 const exponent_bias = (1 << (exponent_bits - 1)) - 1;
15 const implicit_bit = 1 << mantissa_bits;
16
17 const exp = (u64.bit_count - 1) - @clz(a);
18 const shift = mantissa_bits - @intCast(u7, exp);
19
20 // TODO: @bitCast alignment error
21 var result align(16) = (@intCast(u128, a) << shift) ^ implicit_bit;
22 result += (@intCast(u128, exp) + exponent_bias) << mantissa_bits;
23
24 return @bitCast(f128, result);
25}
26
27test "import floatunsitf" {
28 _ = @import("floatunsitf_test.zig");
29}
std/special/compiler_rt/floatunsitf_test.zig created+29
......@@ -0,0 +1,29 @@
1const __floatunsitf = @import("floatunsitf.zig").__floatunsitf;
2const assert = @import("std").debug.assert;
3
4fn test__floatunsitf(a: u64, expected_hi: u64, expected_lo: u64) void {
5 const x = __floatunsitf(a);
6
7 const x_repr = @bitCast(u128, x);
8 const x_hi = @intCast(u64, x_repr >> 64);
9 const x_lo = @truncate(u64, x_repr);
10
11 if (x_hi == expected_hi and x_lo == expected_lo) {
12 return;
13 }
14 // nan repr
15 else if (expected_hi == 0x7fff800000000000 and expected_lo == 0x0) {
16 if ((x_hi & 0x7fff000000000000) == 0x7fff000000000000 and ((x_hi & 0xffffffffffff) > 0 or x_lo > 0)) {
17 return;
18 }
19 }
20
21 @panic("__floatunsitf test failure");
22}
23
24test "floatunsitf" {
25 test__floatunsitf(0x7fffffff, 0x401dfffffffc0000, 0x0);
26 test__floatunsitf(0, 0x0, 0x0);
27 test__floatunsitf(0xffffffff, 0x401efffffffe0000, 0x0);
28 test__floatunsitf(0x12345678, 0x401b234567800000, 0x0);
29}
std/special/compiler_rt/floatuntidf.zig created+60
......@@ -0,0 +1,60 @@
1const builtin = @import("builtin");
2const is_test = builtin.is_test;
3
4const DBL_MANT_DIG = 53;
5
6pub extern fn __floatuntidf(arg: u128) f64 {
7 @setRuntimeSafety(is_test);
8
9 if (arg == 0)
10 return 0.0;
11
12 var a = arg;
13 const N: u32 = @sizeOf(u128) * 8;
14 const sd = @bitCast(i32, N - @clz(a)); // number of significant digits
15 var e: i32 = sd - 1; // exponent
16 if (sd > DBL_MANT_DIG) {
17 // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
18 // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
19 // 12345678901234567890123456
20 // 1 = msb 1 bit
21 // P = bit DBL_MANT_DIG-1 bits to the right of 1
22 // Q = bit DBL_MANT_DIG bits to the right of 1
23 // R = "or" of all bits to the right of Q
24 switch (sd) {
25 DBL_MANT_DIG + 1 => {
26 a <<= 1;
27 },
28 DBL_MANT_DIG + 2 => {},
29 else => {
30 const shift_amt = @bitCast(i32, N + (DBL_MANT_DIG + 2)) - sd;
31 const shift_amt_u7 = @intCast(u7, shift_amt);
32 a = (a >> @intCast(u7, sd - (DBL_MANT_DIG + 2))) |
33 @boolToInt((a & (u128(@maxValue(u128)) >> shift_amt_u7)) != 0);
34 },
35 }
36 // finish
37 a |= @boolToInt((a & 4) != 0); // Or P into R
38 a += 1; // round - this step may add a significant bit
39 a >>= 2; // dump Q and R
40 // a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits
41 if ((a & (u128(1) << DBL_MANT_DIG)) != 0) {
42 a >>= 1;
43 e += 1;
44 }
45 // a is now rounded to DBL_MANT_DIG bits
46 } else {
47 a <<= @intCast(u7, DBL_MANT_DIG - sd);
48 // a is now rounded to DBL_MANT_DIG bits
49 }
50
51 const high: u64 = @bitCast(u32, (e + 1023) << 20) | // exponent
52 (@truncate(u32, a >> 32) & 0x000FFFFF); // mantissa-high
53 const low = @truncate(u32, a); // mantissa-low
54
55 return @bitCast(f64, low | (high << 32));
56}
57
58test "import floatuntidf" {
59 _ = @import("floatuntidf_test.zig");
60}
std/special/compiler_rt/floatuntidf_test.zig created+81
......@@ -0,0 +1,81 @@
1const __floatuntidf = @import("floatuntidf.zig").__floatuntidf;
2const assert = @import("std").debug.assert;
3
4fn test__floatuntidf(a: u128, expected: f64) void {
5 const x = __floatuntidf(a);
6 assert(x == expected);
7}
8
9test "floatuntidf" {
10 test__floatuntidf(0, 0.0);
11
12 test__floatuntidf(1, 1.0);
13 test__floatuntidf(2, 2.0);
14 test__floatuntidf(20, 20.0);
15
16 test__floatuntidf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
17 test__floatuntidf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62);
18 test__floatuntidf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
19 test__floatuntidf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62);
20
21 test__floatuntidf(make_ti(0x8000008000000000, 0), 0x1.000001p+127);
22 test__floatuntidf(make_ti(0x8000000000000800, 0), 0x1.0000000000001p+127);
23 test__floatuntidf(make_ti(0x8000010000000000, 0), 0x1.000002p+127);
24 test__floatuntidf(make_ti(0x8000000000001000, 0), 0x1.0000000000002p+127);
25
26 test__floatuntidf(make_ti(0x8000000000000000, 0), 0x1.000000p+127);
27 test__floatuntidf(make_ti(0x8000000000000001, 0), 0x1.0000000000000002p+127);
28
29 test__floatuntidf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
30
31 test__floatuntidf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
32 test__floatuntidf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
33 test__floatuntidf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50);
34 test__floatuntidf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
35 test__floatuntidf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50);
36
37 test__floatuntidf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
38 test__floatuntidf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
39 test__floatuntidf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50);
40 test__floatuntidf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50);
41 test__floatuntidf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
42
43 test__floatuntidf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57);
44 test__floatuntidf(0x023479FD0E092DA1, 0x1.1A3CFE870496Dp+57);
45 test__floatuntidf(0x023479FD0E092DB0, 0x1.1A3CFE870496Ep+57);
46 test__floatuntidf(0x023479FD0E092DB8, 0x1.1A3CFE870496Ep+57);
47 test__floatuntidf(0x023479FD0E092DB6, 0x1.1A3CFE870496Ep+57);
48 test__floatuntidf(0x023479FD0E092DBF, 0x1.1A3CFE870496Ep+57);
49 test__floatuntidf(0x023479FD0E092DC1, 0x1.1A3CFE870496Ep+57);
50 test__floatuntidf(0x023479FD0E092DC7, 0x1.1A3CFE870496Ep+57);
51 test__floatuntidf(0x023479FD0E092DC8, 0x1.1A3CFE870496Ep+57);
52 test__floatuntidf(0x023479FD0E092DCF, 0x1.1A3CFE870496Ep+57);
53 test__floatuntidf(0x023479FD0E092DD0, 0x1.1A3CFE870496Ep+57);
54 test__floatuntidf(0x023479FD0E092DD1, 0x1.1A3CFE870496Fp+57);
55 test__floatuntidf(0x023479FD0E092DD8, 0x1.1A3CFE870496Fp+57);
56 test__floatuntidf(0x023479FD0E092DDF, 0x1.1A3CFE870496Fp+57);
57 test__floatuntidf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57);
58
59 test__floatuntidf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121);
60 test__floatuntidf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496Dp+121);
61 test__floatuntidf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496Ep+121);
62 test__floatuntidf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496Ep+121);
63 test__floatuntidf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496Ep+121);
64 test__floatuntidf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496Ep+121);
65 test__floatuntidf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496Ep+121);
66 test__floatuntidf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496Ep+121);
67 test__floatuntidf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496Ep+121);
68 test__floatuntidf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496Ep+121);
69 test__floatuntidf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496Ep+121);
70 test__floatuntidf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496Fp+121);
71 test__floatuntidf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496Fp+121);
72 test__floatuntidf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496Fp+121);
73 test__floatuntidf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121);
74}
75
76fn make_ti(high: u64, low: u64) u128 {
77 var result: u128 = high;
78 result <<= 64;
79 result |= low;
80 return result;
81}
std/special/compiler_rt/floatuntisf.zig created+59
......@@ -0,0 +1,59 @@
1const builtin = @import("builtin");
2const is_test = builtin.is_test;
3
4const FLT_MANT_DIG = 24;
5
6pub extern fn __floatuntisf(arg: u128) f32 {
7 @setRuntimeSafety(is_test);
8
9 if (arg == 0)
10 return 0.0;
11
12 var a = arg;
13 const N: u32 = @sizeOf(u128) * 8;
14 const sd = @bitCast(i32, N - @clz(a)); // number of significant digits
15 var e: i32 = sd - 1; // exponent
16 if (sd > FLT_MANT_DIG) {
17 // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
18 // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
19 // 12345678901234567890123456
20 // 1 = msb 1 bit
21 // P = bit FLT_MANT_DIG-1 bits to the right of 1
22 // Q = bit FLT_MANT_DIG bits to the right of 1
23 // R = "or" of all bits to the right of Q
24 switch (sd) {
25 FLT_MANT_DIG + 1 => {
26 a <<= 1;
27 },
28 FLT_MANT_DIG + 2 => {},
29 else => {
30 const shift_amt = @bitCast(i32, N + (FLT_MANT_DIG + 2)) - sd;
31 const shift_amt_u7 = @intCast(u7, shift_amt);
32 a = (a >> @intCast(u7, sd - (FLT_MANT_DIG + 2))) |
33 @boolToInt((a & (u128(@maxValue(u128)) >> shift_amt_u7)) != 0);
34 },
35 }
36 // finish
37 a |= @boolToInt((a & 4) != 0); // Or P into R
38 a += 1; // round - this step may add a significant bit
39 a >>= 2; // dump Q and R
40 // a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits
41 if ((a & (u128(1) << FLT_MANT_DIG)) != 0) {
42 a >>= 1;
43 e += 1;
44 }
45 // a is now rounded to FLT_MANT_DIG bits
46 } else {
47 a <<= @intCast(u7, FLT_MANT_DIG - sd);
48 // a is now rounded to FLT_MANT_DIG bits
49 }
50
51 const high = @bitCast(u32, (e + 127) << 23); // exponent
52 const low = @truncate(u32, a) & 0x007fffff; // mantissa
53
54 return @bitCast(f32, high | low);
55}
56
57test "import floatuntisf" {
58 _ = @import("floatuntisf_test.zig");
59}
std/special/compiler_rt/floatuntisf_test.zig created+72
......@@ -0,0 +1,72 @@
1const __floatuntisf = @import("floatuntisf.zig").__floatuntisf;
2const assert = @import("std").debug.assert;
3
4fn test__floatuntisf(a: u128, expected: f32) void {
5 const x = __floatuntisf(a);
6 assert(x == expected);
7}
8
9test "floatuntisf" {
10 test__floatuntisf(0, 0.0);
11
12 test__floatuntisf(1, 1.0);
13 test__floatuntisf(2, 2.0);
14 test__floatuntisf(20, 20.0);
15
16 test__floatuntisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
17 test__floatuntisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
18
19 test__floatuntisf(make_ti(0x8000008000000000, 0), 0x1.000001p+127);
20 test__floatuntisf(make_ti(0x8000000000000800, 0), 0x1.0p+127);
21 test__floatuntisf(make_ti(0x8000010000000000, 0), 0x1.000002p+127);
22
23 test__floatuntisf(make_ti(0x8000000000000000, 0), 0x1.000000p+127);
24
25 test__floatuntisf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
26
27 test__floatuntisf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
28 test__floatuntisf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
29
30 test__floatuntisf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
31
32 test__floatuntisf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
33 test__floatuntisf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
34 test__floatuntisf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
35
36 test__floatuntisf(0xFFFFFFFFFFFFFFFE, 0x1p+64);
37 test__floatuntisf(0xFFFFFFFFFFFFFFFF, 0x1p+64);
38
39 test__floatuntisf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
40
41 test__floatuntisf(0x0007FB72EA000000, 0x1.FEDCBAp+50);
42 test__floatuntisf(0x0007FB72EB000000, 0x1.FEDCBAp+50);
43 test__floatuntisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50);
44 test__floatuntisf(0x0007FB72EC000000, 0x1.FEDCBCp+50);
45 test__floatuntisf(0x0007FB72E8000001, 0x1.FEDCBAp+50);
46
47 test__floatuntisf(0x0007FB72E6000000, 0x1.FEDCBAp+50);
48 test__floatuntisf(0x0007FB72E7000000, 0x1.FEDCBAp+50);
49 test__floatuntisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50);
50 test__floatuntisf(0x0007FB72E4000001, 0x1.FEDCBAp+50);
51 test__floatuntisf(0x0007FB72E4000000, 0x1.FEDCB8p+50);
52
53 test__floatuntisf(make_ti(0x0000000000001FED, 0xCB90000000000001), 0x1.FEDCBAp+76);
54 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBA0000000000000), 0x1.FEDCBAp+76);
55 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBAFFFFFFFFFFFFF), 0x1.FEDCBAp+76);
56 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBB0000000000000), 0x1.FEDCBCp+76);
57 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBB0000000000001), 0x1.FEDCBCp+76);
58 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBBFFFFFFFFFFFFF), 0x1.FEDCBCp+76);
59 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBC0000000000000), 0x1.FEDCBCp+76);
60 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBC0000000000001), 0x1.FEDCBCp+76);
61 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBD0000000000000), 0x1.FEDCBCp+76);
62 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBD0000000000001), 0x1.FEDCBEp+76);
63 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBDFFFFFFFFFFFFF), 0x1.FEDCBEp+76);
64 test__floatuntisf(make_ti(0x0000000000001FED, 0xCBE0000000000000), 0x1.FEDCBEp+76);
65}
66
67fn make_ti(high: u64, low: u64) u128 {
68 var result: u128 = high;
69 result <<= 64;
70 result |= low;
71 return result;
72}
std/special/compiler_rt/floatuntitf.zig created+60
......@@ -0,0 +1,60 @@
1const builtin = @import("builtin");
2const is_test = builtin.is_test;
3
4const LDBL_MANT_DIG = 113;
5
6pub extern fn __floatuntitf(arg: u128) f128 {
7 @setRuntimeSafety(is_test);
8
9 if (arg == 0)
10 return 0.0;
11
12 var a = arg;
13 const N: u32 = @sizeOf(u128) * 8;
14 const sd = @bitCast(i32, N - @clz(a)); // number of significant digits
15 var e: i32 = sd - 1; // exponent
16 if (sd > LDBL_MANT_DIG) {
17 // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
18 // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
19 // 12345678901234567890123456
20 // 1 = msb 1 bit
21 // P = bit LDBL_MANT_DIG-1 bits to the right of 1
22 // Q = bit LDBL_MANT_DIG bits to the right of 1
23 // R = "or" of all bits to the right of Q
24 switch (sd) {
25 LDBL_MANT_DIG + 1 => {
26 a <<= 1;
27 },
28 LDBL_MANT_DIG + 2 => {},
29 else => {
30 const shift_amt = @bitCast(i32, N + (LDBL_MANT_DIG + 2)) - sd;
31 const shift_amt_u7 = @intCast(u7, shift_amt);
32 a = (a >> @intCast(u7, sd - (LDBL_MANT_DIG + 2))) |
33 @boolToInt((a & (u128(@maxValue(u128)) >> shift_amt_u7)) != 0);
34 },
35 }
36 // finish
37 a |= @boolToInt((a & 4) != 0); // Or P into R
38 a += 1; // round - this step may add a significant bit
39 a >>= 2; // dump Q and R
40 // a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits
41 if ((a & (u128(1) << LDBL_MANT_DIG)) != 0) {
42 a >>= 1;
43 e += 1;
44 }
45 // a is now rounded to LDBL_MANT_DIG bits
46 } else {
47 a <<= @intCast(u7, LDBL_MANT_DIG - sd);
48 // a is now rounded to LDBL_MANT_DIG bits
49 }
50
51 const high: u128 = (@intCast(u64, (e + 16383)) << 48) | // exponent
52 (@truncate(u64, a >> 64) & 0x0000ffffffffffff); // mantissa-high
53 const low = @truncate(u64, a); // mantissa-low
54
55 return @bitCast(f128, low | (high << 64));
56}
57
58test "import floatuntitf" {
59 _ = @import("floatuntitf_test.zig");
60}
std/special/compiler_rt/floatuntitf_test.zig created+99
......@@ -0,0 +1,99 @@
1const __floatuntitf = @import("floatuntitf.zig").__floatuntitf;
2const assert = @import("std").debug.assert;
3
4fn test__floatuntitf(a: u128, expected: f128) void {
5 const x = __floatuntitf(a);
6 assert(x == expected);
7}
8
9test "floatuntitf" {
10 test__floatuntitf(0, 0.0);
11
12 test__floatuntitf(1, 1.0);
13 test__floatuntitf(2, 2.0);
14 test__floatuntitf(20, 20.0);
15
16 test__floatuntitf(0x7FFFFF8000000000, 0x1.FFFFFEp+62);
17 test__floatuntitf(0x7FFFFFFFFFFFF800, 0x1.FFFFFFFFFFFFEp+62);
18 test__floatuntitf(0x7FFFFF0000000000, 0x1.FFFFFCp+62);
19 test__floatuntitf(0x7FFFFFFFFFFFF000, 0x1.FFFFFFFFFFFFCp+62);
20 test__floatuntitf(0x7FFFFFFFFFFFFFFF, 0xF.FFFFFFFFFFFFFFEp+59);
21 test__floatuntitf(0xFFFFFFFFFFFFFFFE, 0xF.FFFFFFFFFFFFFFEp+60);
22 test__floatuntitf(0xFFFFFFFFFFFFFFFF, 0xF.FFFFFFFFFFFFFFFp+60);
23
24 test__floatuntitf(0x8000008000000000, 0x8.000008p+60);
25 test__floatuntitf(0x8000000000000800, 0x8.0000000000008p+60);
26 test__floatuntitf(0x8000010000000000, 0x8.00001p+60);
27 test__floatuntitf(0x8000000000001000, 0x8.000000000001p+60);
28
29 test__floatuntitf(0x8000000000000000, 0x8p+60);
30 test__floatuntitf(0x8000000000000001, 0x8.000000000000001p+60);
31
32 test__floatuntitf(0x0007FB72E8000000, 0x1.FEDCBAp+50);
33
34 test__floatuntitf(0x0007FB72EA000000, 0x1.FEDCBA8p+50);
35 test__floatuntitf(0x0007FB72EB000000, 0x1.FEDCBACp+50);
36 test__floatuntitf(0x0007FB72EBFFFFFF, 0x1.FEDCBAFFFFFFCp+50);
37 test__floatuntitf(0x0007FB72EC000000, 0x1.FEDCBBp+50);
38 test__floatuntitf(0x0007FB72E8000001, 0x1.FEDCBA0000004p+50);
39
40 test__floatuntitf(0x0007FB72E6000000, 0x1.FEDCB98p+50);
41 test__floatuntitf(0x0007FB72E7000000, 0x1.FEDCB9Cp+50);
42 test__floatuntitf(0x0007FB72E7FFFFFF, 0x1.FEDCB9FFFFFFCp+50);
43 test__floatuntitf(0x0007FB72E4000001, 0x1.FEDCB90000004p+50);
44 test__floatuntitf(0x0007FB72E4000000, 0x1.FEDCB9p+50);
45
46 test__floatuntitf(0x023479FD0E092DC0, 0x1.1A3CFE870496Ep+57);
47 test__floatuntitf(0x023479FD0E092DA1, 0x1.1A3CFE870496D08p+57);
48 test__floatuntitf(0x023479FD0E092DB0, 0x1.1A3CFE870496D8p+57);
49 test__floatuntitf(0x023479FD0E092DB8, 0x1.1A3CFE870496DCp+57);
50 test__floatuntitf(0x023479FD0E092DB6, 0x1.1A3CFE870496DBp+57);
51 test__floatuntitf(0x023479FD0E092DBF, 0x1.1A3CFE870496DF8p+57);
52 test__floatuntitf(0x023479FD0E092DC1, 0x1.1A3CFE870496E08p+57);
53 test__floatuntitf(0x023479FD0E092DC7, 0x1.1A3CFE870496E38p+57);
54 test__floatuntitf(0x023479FD0E092DC8, 0x1.1A3CFE870496E4p+57);
55 test__floatuntitf(0x023479FD0E092DCF, 0x1.1A3CFE870496E78p+57);
56 test__floatuntitf(0x023479FD0E092DD0, 0x1.1A3CFE870496E8p+57);
57 test__floatuntitf(0x023479FD0E092DD1, 0x1.1A3CFE870496E88p+57);
58 test__floatuntitf(0x023479FD0E092DD8, 0x1.1A3CFE870496ECp+57);
59 test__floatuntitf(0x023479FD0E092DDF, 0x1.1A3CFE870496EF8p+57);
60 test__floatuntitf(0x023479FD0E092DE0, 0x1.1A3CFE870496Fp+57);
61
62 test__floatuntitf(make_ti(0x023479FD0E092DC0, 0), 0x1.1A3CFE870496Ep+121);
63 test__floatuntitf(make_ti(0x023479FD0E092DA1, 1), 0x1.1A3CFE870496D08p+121);
64 test__floatuntitf(make_ti(0x023479FD0E092DB0, 2), 0x1.1A3CFE870496D8p+121);
65 test__floatuntitf(make_ti(0x023479FD0E092DB8, 3), 0x1.1A3CFE870496DCp+121);
66 test__floatuntitf(make_ti(0x023479FD0E092DB6, 4), 0x1.1A3CFE870496DBp+121);
67 test__floatuntitf(make_ti(0x023479FD0E092DBF, 5), 0x1.1A3CFE870496DF8p+121);
68 test__floatuntitf(make_ti(0x023479FD0E092DC1, 6), 0x1.1A3CFE870496E08p+121);
69 test__floatuntitf(make_ti(0x023479FD0E092DC7, 7), 0x1.1A3CFE870496E38p+121);
70 test__floatuntitf(make_ti(0x023479FD0E092DC8, 8), 0x1.1A3CFE870496E4p+121);
71 test__floatuntitf(make_ti(0x023479FD0E092DCF, 9), 0x1.1A3CFE870496E78p+121);
72 test__floatuntitf(make_ti(0x023479FD0E092DD0, 0), 0x1.1A3CFE870496E8p+121);
73 test__floatuntitf(make_ti(0x023479FD0E092DD1, 11), 0x1.1A3CFE870496E88p+121);
74 test__floatuntitf(make_ti(0x023479FD0E092DD8, 12), 0x1.1A3CFE870496ECp+121);
75 test__floatuntitf(make_ti(0x023479FD0E092DDF, 13), 0x1.1A3CFE870496EF8p+121);
76 test__floatuntitf(make_ti(0x023479FD0E092DE0, 14), 0x1.1A3CFE870496Fp+121);
77
78 test__floatuntitf(make_ti(0, 0xFFFFFFFFFFFFFFFF), 0x1.FFFFFFFFFFFFFFFEp+63);
79
80 test__floatuntitf(make_ti(0xFFFFFFFFFFFFFFFF, 0x0000000000000000), 0x1.FFFFFFFFFFFFFFFEp+127);
81 test__floatuntitf(make_ti(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF), 0x1.0000000000000000p+128);
82
83 test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC2801), 0x1.23456789ABCDEF0123456789ABC3p+124);
84 test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3000), 0x1.23456789ABCDEF0123456789ABC3p+124);
85 test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC37FF), 0x1.23456789ABCDEF0123456789ABC3p+124);
86 test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC3800), 0x1.23456789ABCDEF0123456789ABC4p+124);
87 test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4000), 0x1.23456789ABCDEF0123456789ABC4p+124);
88 test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC47FF), 0x1.23456789ABCDEF0123456789ABC4p+124);
89 test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4800), 0x1.23456789ABCDEF0123456789ABC4p+124);
90 test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC4801), 0x1.23456789ABCDEF0123456789ABC5p+124);
91 test__floatuntitf(make_ti(0x123456789ABCDEF0, 0x123456789ABC57FF), 0x1.23456789ABCDEF0123456789ABC5p+124);
92}
93
94fn make_ti(high: u64, low: u64) u128 {
95 var result: u128 = high;
96 result <<= 64;
97 result |= low;
98 return result;
99}
std/special/compiler_rt/index.zig+21
......@@ -15,10 +15,31 @@ comptime {
1515 @export("__lttf2", @import("comparetf2.zig").__letf2, linkage);
1616 @export("__netf2", @import("comparetf2.zig").__letf2, linkage);
1717 @export("__gttf2", @import("comparetf2.zig").__getf2, linkage);
18 @export("__gnu_h2f_ieee", @import("extendXfYf2.zig").__extendhfsf2, linkage);
19 @export("__gnu_f2h_ieee", @import("truncXfYf2.zig").__truncsfhf2, linkage);
1820 }
1921
2022 @export("__unordtf2", @import("comparetf2.zig").__unordtf2, linkage);
2123
24 @export("__floattitf", @import("floattitf.zig").__floattitf, linkage);
25 @export("__floattidf", @import("floattidf.zig").__floattidf, linkage);
26 @export("__floattisf", @import("floattisf.zig").__floattisf, linkage);
27
28 @export("__floatunditf", @import("floatunditf.zig").__floatunditf, linkage);
29 @export("__floatunsitf", @import("floatunsitf.zig").__floatunsitf, linkage);
30
31 @export("__floatuntitf", @import("floatuntitf.zig").__floatuntitf, linkage);
32 @export("__floatuntidf", @import("floatuntidf.zig").__floatuntidf, linkage);
33 @export("__floatuntisf", @import("floatuntisf.zig").__floatuntisf, linkage);
34
35 @export("__extenddftf2", @import("extendXfYf2.zig").__extenddftf2, linkage);
36 @export("__extendsftf2", @import("extendXfYf2.zig").__extendsftf2, linkage);
37 @export("__extendhfsf2", @import("extendXfYf2.zig").__extendhfsf2, linkage);
38
39 @export("__truncsfhf2", @import("truncXfYf2.zig").__truncsfhf2, linkage);
40 @export("__trunctfdf2", @import("truncXfYf2.zig").__trunctfdf2, linkage);
41 @export("__trunctfsf2", @import("truncXfYf2.zig").__trunctfsf2, linkage);
42
2243 @export("__fixunssfsi", @import("fixunssfsi.zig").__fixunssfsi, linkage);
2344 @export("__fixunssfdi", @import("fixunssfdi.zig").__fixunssfdi, linkage);
2445 @export("__fixunssfti", @import("fixunssfti.zig").__fixunssfti, linkage);
std/special/compiler_rt/truncXfYf2.zig created+117
......@@ -0,0 +1,117 @@
1const std = @import("std");
2
3pub extern fn __truncsfhf2(a: f32) u16 {
4 return @bitCast(u16, truncXfYf2(f16, f32, a));
5}
6
7pub extern fn __trunctfsf2(a: f128) f32 {
8 return truncXfYf2(f32, f128, a);
9}
10
11pub extern fn __trunctfdf2(a: f128) f64 {
12 return truncXfYf2(f64, f128, a);
13}
14
15inline fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t {
16 const src_rep_t = @IntType(false, @typeInfo(src_t).Float.bits);
17 const dst_rep_t = @IntType(false, @typeInfo(dst_t).Float.bits);
18 const srcSigBits = std.math.floatMantissaBits(src_t);
19 const dstSigBits = std.math.floatMantissaBits(dst_t);
20 const SrcShift = std.math.Log2Int(src_rep_t);
21 const DstShift = std.math.Log2Int(dst_rep_t);
22
23 // Various constants whose values follow from the type parameters.
24 // Any reasonable optimizer will fold and propagate all of these.
25 const srcBits = src_t.bit_count;
26 const srcExpBits = srcBits - srcSigBits - 1;
27 const srcInfExp = (1 << srcExpBits) - 1;
28 const srcExpBias = srcInfExp >> 1;
29
30 const srcMinNormal = 1 << srcSigBits;
31 const srcSignificandMask = srcMinNormal - 1;
32 const srcInfinity = srcInfExp << srcSigBits;
33 const srcSignMask = 1 << (srcSigBits + srcExpBits);
34 const srcAbsMask = srcSignMask - 1;
35 const roundMask = (1 << (srcSigBits - dstSigBits)) - 1;
36 const halfway = 1 << (srcSigBits - dstSigBits - 1);
37 const srcQNaN = 1 << (srcSigBits - 1);
38 const srcNaNCode = srcQNaN - 1;
39
40 const dstBits = dst_t.bit_count;
41 const dstExpBits = dstBits - dstSigBits - 1;
42 const dstInfExp = (1 << dstExpBits) - 1;
43 const dstExpBias = dstInfExp >> 1;
44
45 const underflowExponent = srcExpBias + 1 - dstExpBias;
46 const overflowExponent = srcExpBias + dstInfExp - dstExpBias;
47 const underflow = underflowExponent << srcSigBits;
48 const overflow = overflowExponent << srcSigBits;
49
50 const dstQNaN = 1 << (dstSigBits - 1);
51 const dstNaNCode = dstQNaN - 1;
52
53 // Break a into a sign and representation of the absolute value
54 const aRep: src_rep_t = @bitCast(src_rep_t, a);
55 const aAbs: src_rep_t = aRep & srcAbsMask;
56 const sign: src_rep_t = aRep & srcSignMask;
57 var absResult: dst_rep_t = undefined;
58
59 if (aAbs -% underflow < aAbs -% overflow) {
60 // The exponent of a is within the range of normal numbers in the
61 // destination format. We can convert by simply right-shifting with
62 // rounding and adjusting the exponent.
63 absResult = @truncate(dst_rep_t, aAbs >> (srcSigBits - dstSigBits));
64 absResult -%= dst_rep_t(srcExpBias - dstExpBias) << dstSigBits;
65
66 const roundBits: src_rep_t = aAbs & roundMask;
67 if (roundBits > halfway) {
68 // Round to nearest
69 absResult += 1;
70 } else if (roundBits == halfway) {
71 // Ties to even
72 absResult += absResult & 1;
73 }
74 } else if (aAbs > srcInfinity) {
75 // a is NaN.
76 // Conjure the result by beginning with infinity, setting the qNaN
77 // bit and inserting the (truncated) trailing NaN field.
78 absResult = @intCast(dst_rep_t, dstInfExp) << dstSigBits;
79 absResult |= dstQNaN;
80 absResult |= @intCast(dst_rep_t, ((aAbs & srcNaNCode) >> (srcSigBits - dstSigBits)) & dstNaNCode);
81 } else if (aAbs >= overflow) {
82 // a overflows to infinity.
83 absResult = @intCast(dst_rep_t, dstInfExp) << dstSigBits;
84 } else {
85 // a underflows on conversion to the destination type or is an exact
86 // zero. The result may be a denormal or zero. Extract the exponent
87 // to get the shift amount for the denormalization.
88 const aExp = @intCast(u32, aAbs >> srcSigBits);
89 const shift = @intCast(u32, srcExpBias - dstExpBias - aExp + 1);
90
91 const significand: src_rep_t = (aRep & srcSignificandMask) | srcMinNormal;
92
93 // Right shift by the denormalization amount with sticky.
94 if (shift > srcSigBits) {
95 absResult = 0;
96 } else {
97 const sticky: src_rep_t = significand << @intCast(SrcShift, srcBits - shift);
98 const denormalizedSignificand: src_rep_t = significand >> @intCast(SrcShift, shift) | sticky;
99 absResult = @intCast(dst_rep_t, denormalizedSignificand >> (srcSigBits - dstSigBits));
100 const roundBits: src_rep_t = denormalizedSignificand & roundMask;
101 if (roundBits > halfway) {
102 // Round to nearest
103 absResult += 1;
104 } else if (roundBits == halfway) {
105 // Ties to even
106 absResult += absResult & 1;
107 }
108 }
109 }
110
111 const result: dst_rep_t align(@alignOf(dst_t)) = absResult | @truncate(dst_rep_t, sign >> @intCast(SrcShift, srcBits - dstBits));
112 return @bitCast(dst_t, result);
113}
114
115test "import truncXfYf2" {
116 _ = @import("truncXfYf2_test.zig");
117}
std/special/compiler_rt/truncXfYf2_test.zig created+134
......@@ -0,0 +1,134 @@
1const __truncsfhf2 = @import("truncXfYf2.zig").__truncsfhf2;
2
3fn test__truncsfhf2(a: u32, expected: u16) void {
4 const actual = __truncsfhf2(@bitCast(f32, a));
5
6 if (actual == expected) {
7 return;
8 }
9
10 @panic("__truncsfhf2 test failure");
11}
12
13test "truncsfhf2" {
14 test__truncsfhf2(0x7fc00000, 0x7e00); // qNaN
15 test__truncsfhf2(0x7fe00000, 0x7f00); // sNaN
16
17 test__truncsfhf2(0, 0); // 0
18 test__truncsfhf2(0x80000000, 0x8000); // -0
19
20 test__truncsfhf2(0x7f800000, 0x7c00); // inf
21 test__truncsfhf2(0xff800000, 0xfc00); // -inf
22
23 test__truncsfhf2(0x477ff000, 0x7c00); // 65520 -> inf
24 test__truncsfhf2(0xc77ff000, 0xfc00); // -65520 -> -inf
25
26 test__truncsfhf2(0x71cc3892, 0x7c00); // 0x1.987124876876324p+100 -> inf
27 test__truncsfhf2(0xf1cc3892, 0xfc00); // -0x1.987124876876324p+100 -> -inf
28
29 test__truncsfhf2(0x38800000, 0x0400); // normal (min), 2**-14
30 test__truncsfhf2(0xb8800000, 0x8400); // normal (min), -2**-14
31
32 test__truncsfhf2(0x477fe000, 0x7bff); // normal (max), 65504
33 test__truncsfhf2(0xc77fe000, 0xfbff); // normal (max), -65504
34
35 test__truncsfhf2(0x477fe100, 0x7bff); // normal, 65505 -> 65504
36 test__truncsfhf2(0xc77fe100, 0xfbff); // normal, -65505 -> -65504
37
38 test__truncsfhf2(0x477fef00, 0x7bff); // normal, 65519 -> 65504
39 test__truncsfhf2(0xc77fef00, 0xfbff); // normal, -65519 -> -65504
40
41 test__truncsfhf2(0x3f802000, 0x3c01); // normal, 1 + 2**-10
42 test__truncsfhf2(0xbf802000, 0xbc01); // normal, -1 - 2**-10
43
44 test__truncsfhf2(0x3eaaa000, 0x3555); // normal, approx. 1/3
45 test__truncsfhf2(0xbeaaa000, 0xb555); // normal, approx. -1/3
46
47 test__truncsfhf2(0x40490fdb, 0x4248); // normal, 3.1415926535
48 test__truncsfhf2(0xc0490fdb, 0xc248); // normal, -3.1415926535
49
50 test__truncsfhf2(0x45cc3892, 0x6e62); // normal, 0x1.987124876876324p+12
51
52 test__truncsfhf2(0x3f800000, 0x3c00); // normal, 1
53 test__truncsfhf2(0x38800000, 0x0400); // normal, 0x1.0p-14
54
55 test__truncsfhf2(0x33800000, 0x0001); // denormal (min), 2**-24
56 test__truncsfhf2(0xb3800000, 0x8001); // denormal (min), -2**-24
57
58 test__truncsfhf2(0x387fc000, 0x03ff); // denormal (max), 2**-14 - 2**-24
59 test__truncsfhf2(0xb87fc000, 0x83ff); // denormal (max), -2**-14 + 2**-24
60
61 test__truncsfhf2(0x35800000, 0x0010); // denormal, 0x1.0p-20
62 test__truncsfhf2(0x33280000, 0x0001); // denormal, 0x1.5p-25 -> 0x1.0p-24
63 test__truncsfhf2(0x33000000, 0x0000); // 0x1.0p-25 -> zero
64}
65
66const __trunctfsf2 = @import("truncXfYf2.zig").__trunctfsf2;
67
68fn test__trunctfsf2(a: f128, expected: u32) void {
69 const x = __trunctfsf2(a);
70
71 const rep = @bitCast(u32, x);
72 if (rep == expected) {
73 return;
74 }
75 // test other possible NaN representation(signal NaN)
76 else if (expected == 0x7fc00000) {
77 if ((rep & 0x7f800000) == 0x7f800000 and (rep & 0x7fffff) > 0) {
78 return;
79 }
80 }
81
82 @panic("__trunctfsf2 test failure");
83}
84
85test "trunctfsf2" {
86 // qnan
87 test__trunctfsf2(@bitCast(f128, u128(0x7fff800000000000 << 64)), 0x7fc00000);
88 // nan
89 test__trunctfsf2(@bitCast(f128, u128((0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7fc08000);
90 // inf
91 test__trunctfsf2(@bitCast(f128, u128(0x7fff000000000000 << 64)), 0x7f800000);
92 // zero
93 test__trunctfsf2(0.0, 0x0);
94
95 test__trunctfsf2(0x1.23a2abb4a2ddee355f36789abcdep+5, 0x4211d156);
96 test__trunctfsf2(0x1.e3d3c45bd3abfd98b76a54cc321fp-9, 0x3b71e9e2);
97 test__trunctfsf2(0x1.234eebb5faa678f4488693abcdefp+4534, 0x7f800000);
98 test__trunctfsf2(0x1.edcba9bb8c76a5a43dd21f334634p-435, 0x0);
99}
100
101const __trunctfdf2 = @import("truncXfYf2.zig").__trunctfdf2;
102
103fn test__trunctfdf2(a: f128, expected: u64) void {
104 const x = __trunctfdf2(a);
105
106 const rep = @bitCast(u64, x);
107 if (rep == expected) {
108 return;
109 }
110 // test other possible NaN representation(signal NaN)
111 else if (expected == 0x7ff8000000000000) {
112 if ((rep & 0x7ff0000000000000) == 0x7ff0000000000000 and (rep & 0xfffffffffffff) > 0) {
113 return;
114 }
115 }
116
117 @panic("__trunctfsf2 test failure");
118}
119
120test "trunctfdf2" {
121 // qnan
122 test__trunctfdf2(@bitCast(f128, u128(0x7fff800000000000 << 64)), 0x7ff8000000000000);
123 // nan
124 test__trunctfdf2(@bitCast(f128, u128((0x7fff000000000000 | (0x810000000000 & 0xffffffffffff)) << 64)), 0x7ff8100000000000);
125 // inf
126 test__trunctfdf2(@bitCast(f128, u128(0x7fff000000000000 << 64)), 0x7ff0000000000000);
127 // zero
128 test__trunctfdf2(0.0, 0x0);
129
130 test__trunctfdf2(0x1.af23456789bbaaab347645365cdep+5, 0x404af23456789bbb);
131 test__trunctfdf2(0x1.dedafcff354b6ae9758763545432p-9, 0x3f6dedafcff354b7);
132 test__trunctfdf2(0x1.2f34dd5f437e849b4baab754cdefp+4534, 0x7ff0000000000000);
133 test__trunctfdf2(0x1.edcbff8ad76ab5bf46463233214fp-435, 0x24cedcbff8ad76ab);
134}
std/zig/ast.zig+1
......@@ -858,6 +858,7 @@ pub const Node = struct {
858858
859859 pub fn firstToken(self: *FnProto) TokenIndex {
860860 if (self.visib_token) |visib_token| return visib_token;
861 if (self.async_attr) |async_attr| return async_attr.firstToken();
861862 if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
862863 assert(self.lib_name == null);
863864 if (self.cc_token) |cc_token| return cc_token;
std/zig/parse.zig+75-75
......@@ -17,7 +17,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1717 defer stack.deinit();
1818
1919 const arena = &tree_arena.allocator;
20 const root_node = try arena.construct(ast.Node.Root{
20 const root_node = try arena.create(ast.Node.Root{
2121 .base = ast.Node{ .id = ast.Node.Id.Root },
2222 .decls = ast.Node.Root.DeclList.init(arena),
2323 .doc_comments = null,
......@@ -65,14 +65,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
6565 Token.Id.Keyword_test => {
6666 stack.append(State.TopLevel) catch unreachable;
6767
68 const block = try arena.construct(ast.Node.Block{
68 const block = try arena.create(ast.Node.Block{
6969 .base = ast.Node{ .id = ast.Node.Id.Block },
7070 .label = null,
7171 .lbrace = undefined,
7272 .statements = ast.Node.Block.StatementList.init(arena),
7373 .rbrace = undefined,
7474 });
75 const test_node = try arena.construct(ast.Node.TestDecl{
75 const test_node = try arena.create(ast.Node.TestDecl{
7676 .base = ast.Node{ .id = ast.Node.Id.TestDecl },
7777 .doc_comments = comments,
7878 .test_token = token_index,
......@@ -109,14 +109,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
109109 continue;
110110 },
111111 Token.Id.Keyword_comptime => {
112 const block = try arena.construct(ast.Node.Block{
112 const block = try arena.create(ast.Node.Block{
113113 .base = ast.Node{ .id = ast.Node.Id.Block },
114114 .label = null,
115115 .lbrace = undefined,
116116 .statements = ast.Node.Block.StatementList.init(arena),
117117 .rbrace = undefined,
118118 });
119 const node = try arena.construct(ast.Node.Comptime{
119 const node = try arena.create(ast.Node.Comptime{
120120 .base = ast.Node{ .id = ast.Node.Id.Comptime },
121121 .comptime_token = token_index,
122122 .expr = &block.base,
......@@ -225,7 +225,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
225225 return tree;
226226 }
227227
228 const node = try arena.construct(ast.Node.Use{
228 const node = try arena.create(ast.Node.Use{
229229 .base = ast.Node{ .id = ast.Node.Id.Use },
230230 .use_token = token_index,
231231 .visib_token = ctx.visib_token,
......@@ -266,7 +266,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
266266 continue;
267267 },
268268 Token.Id.Keyword_fn, Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc, Token.Id.Keyword_async => {
269 const fn_proto = try arena.construct(ast.Node.FnProto{
269 const fn_proto = try arena.create(ast.Node.FnProto{
270270 .base = ast.Node{ .id = ast.Node.Id.FnProto },
271271 .doc_comments = ctx.comments,
272272 .visib_token = ctx.visib_token,
......@@ -298,7 +298,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
298298 continue;
299299 },
300300 Token.Id.Keyword_async => {
301 const async_node = try arena.construct(ast.Node.AsyncAttribute{
301 const async_node = try arena.create(ast.Node.AsyncAttribute{
302302 .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute },
303303 .async_token = token_index,
304304 .allocator_type = null,
......@@ -330,7 +330,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
330330 },
331331 State.TopLevelExternOrField => |ctx| {
332332 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |identifier| {
333 const node = try arena.construct(ast.Node.StructField{
333 const node = try arena.create(ast.Node.StructField{
334334 .base = ast.Node{ .id = ast.Node.Id.StructField },
335335 .doc_comments = ctx.comments,
336336 .visib_token = ctx.visib_token,
......@@ -375,7 +375,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
375375 const token = nextToken(&tok_it, &tree);
376376 const token_index = token.index;
377377 const token_ptr = token.ptr;
378 const node = try arena.construct(ast.Node.ContainerDecl{
378 const node = try arena.create(ast.Node.ContainerDecl{
379379 .base = ast.Node{ .id = ast.Node.Id.ContainerDecl },
380380 .layout_token = ctx.layout_token,
381381 .kind_token = switch (token_ptr.id) {
......@@ -448,7 +448,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
448448 Token.Id.Identifier => {
449449 switch (tree.tokens.at(container_decl.kind_token).id) {
450450 Token.Id.Keyword_struct => {
451 const node = try arena.construct(ast.Node.StructField{
451 const node = try arena.create(ast.Node.StructField{
452452 .base = ast.Node{ .id = ast.Node.Id.StructField },
453453 .doc_comments = comments,
454454 .visib_token = null,
......@@ -464,7 +464,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
464464 continue;
465465 },
466466 Token.Id.Keyword_union => {
467 const node = try arena.construct(ast.Node.UnionTag{
467 const node = try arena.create(ast.Node.UnionTag{
468468 .base = ast.Node{ .id = ast.Node.Id.UnionTag },
469469 .name_token = token_index,
470470 .type_expr = null,
......@@ -480,7 +480,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
480480 continue;
481481 },
482482 Token.Id.Keyword_enum => {
483 const node = try arena.construct(ast.Node.EnumTag{
483 const node = try arena.create(ast.Node.EnumTag{
484484 .base = ast.Node{ .id = ast.Node.Id.EnumTag },
485485 .name_token = token_index,
486486 .value = null,
......@@ -562,7 +562,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
562562 },
563563
564564 State.VarDecl => |ctx| {
565 const var_decl = try arena.construct(ast.Node.VarDecl{
565 const var_decl = try arena.create(ast.Node.VarDecl{
566566 .base = ast.Node{ .id = ast.Node.Id.VarDecl },
567567 .doc_comments = ctx.comments,
568568 .visib_token = ctx.visib_token,
......@@ -660,7 +660,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
660660 const token_ptr = token.ptr;
661661 switch (token_ptr.id) {
662662 Token.Id.LBrace => {
663 const block = try arena.construct(ast.Node.Block{
663 const block = try arena.create(ast.Node.Block{
664664 .base = ast.Node{ .id = ast.Node.Id.Block },
665665 .label = null,
666666 .lbrace = token_index,
......@@ -712,7 +712,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
712712 // TODO: this is a special case. Remove this when #760 is fixed
713713 if (token_ptr.id == Token.Id.Keyword_error) {
714714 if (tok_it.peek().?.id == Token.Id.LBrace) {
715 const error_type_node = try arena.construct(ast.Node.ErrorType{
715 const error_type_node = try arena.create(ast.Node.ErrorType{
716716 .base = ast.Node{ .id = ast.Node.Id.ErrorType },
717717 .token = token_index,
718718 });
......@@ -733,7 +733,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
733733 if (eatToken(&tok_it, &tree, Token.Id.RParen)) |_| {
734734 continue;
735735 }
736 const param_decl = try arena.construct(ast.Node.ParamDecl{
736 const param_decl = try arena.create(ast.Node.ParamDecl{
737737 .base = ast.Node{ .id = ast.Node.Id.ParamDecl },
738738 .comptime_token = null,
739739 .noalias_token = null,
......@@ -819,7 +819,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
819819 const token_ptr = token.ptr;
820820 switch (token_ptr.id) {
821821 Token.Id.LBrace => {
822 const block = try arena.construct(ast.Node.Block{
822 const block = try arena.create(ast.Node.Block{
823823 .base = ast.Node{ .id = ast.Node.Id.Block },
824824 .label = ctx.label,
825825 .lbrace = token_index,
......@@ -853,7 +853,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
853853 continue;
854854 },
855855 Token.Id.Keyword_suspend => {
856 const node = try arena.construct(ast.Node.Suspend{
856 const node = try arena.create(ast.Node.Suspend{
857857 .base = ast.Node{ .id = ast.Node.Id.Suspend },
858858 .label = ctx.label,
859859 .suspend_token = token_index,
......@@ -925,7 +925,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
925925 }
926926 },
927927 State.While => |ctx| {
928 const node = try arena.construct(ast.Node.While{
928 const node = try arena.create(ast.Node.While{
929929 .base = ast.Node{ .id = ast.Node.Id.While },
930930 .label = ctx.label,
931931 .inline_token = ctx.inline_token,
......@@ -954,7 +954,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
954954 continue;
955955 },
956956 State.For => |ctx| {
957 const node = try arena.construct(ast.Node.For{
957 const node = try arena.create(ast.Node.For{
958958 .base = ast.Node{ .id = ast.Node.Id.For },
959959 .label = ctx.label,
960960 .inline_token = ctx.inline_token,
......@@ -975,7 +975,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
975975 },
976976 State.Else => |dest| {
977977 if (eatToken(&tok_it, &tree, Token.Id.Keyword_else)) |else_token| {
978 const node = try arena.construct(ast.Node.Else{
978 const node = try arena.create(ast.Node.Else{
979979 .base = ast.Node{ .id = ast.Node.Id.Else },
980980 .else_token = else_token,
981981 .payload = null,
......@@ -1038,7 +1038,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
10381038 continue;
10391039 },
10401040 Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {
1041 const node = try arena.construct(ast.Node.Defer{
1041 const node = try arena.create(ast.Node.Defer{
10421042 .base = ast.Node{ .id = ast.Node.Id.Defer },
10431043 .defer_token = token_index,
10441044 .kind = switch (token_ptr.id) {
......@@ -1056,7 +1056,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
10561056 continue;
10571057 },
10581058 Token.Id.LBrace => {
1059 const inner_block = try arena.construct(ast.Node.Block{
1059 const inner_block = try arena.create(ast.Node.Block{
10601060 .base = ast.Node{ .id = ast.Node.Id.Block },
10611061 .label = null,
10621062 .lbrace = token_index,
......@@ -1124,7 +1124,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
11241124 continue;
11251125 }
11261126
1127 const node = try arena.construct(ast.Node.AsmOutput{
1127 const node = try arena.create(ast.Node.AsmOutput{
11281128 .base = ast.Node{ .id = ast.Node.Id.AsmOutput },
11291129 .lbracket = lbracket_index,
11301130 .symbolic_name = undefined,
......@@ -1178,7 +1178,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
11781178 continue;
11791179 }
11801180
1181 const node = try arena.construct(ast.Node.AsmInput{
1181 const node = try arena.create(ast.Node.AsmInput{
11821182 .base = ast.Node{ .id = ast.Node.Id.AsmInput },
11831183 .lbracket = lbracket_index,
11841184 .symbolic_name = undefined,
......@@ -1243,7 +1243,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
12431243 continue;
12441244 }
12451245
1246 const node = try arena.construct(ast.Node.FieldInitializer{
1246 const node = try arena.create(ast.Node.FieldInitializer{
12471247 .base = ast.Node{ .id = ast.Node.Id.FieldInitializer },
12481248 .period_token = undefined,
12491249 .name_token = undefined,
......@@ -1332,7 +1332,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
13321332 }
13331333
13341334 const comments = try eatDocComments(arena, &tok_it, &tree);
1335 const node = try arena.construct(ast.Node.SwitchCase{
1335 const node = try arena.create(ast.Node.SwitchCase{
13361336 .base = ast.Node{ .id = ast.Node.Id.SwitchCase },
13371337 .items = ast.Node.SwitchCase.ItemList.init(arena),
13381338 .payload = null,
......@@ -1369,7 +1369,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
13691369 const token_index = token.index;
13701370 const token_ptr = token.ptr;
13711371 if (token_ptr.id == Token.Id.Keyword_else) {
1372 const else_node = try arena.construct(ast.Node.SwitchElse{
1372 const else_node = try arena.create(ast.Node.SwitchElse{
13731373 .base = ast.Node{ .id = ast.Node.Id.SwitchElse },
13741374 .token = token_index,
13751375 });
......@@ -1468,7 +1468,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
14681468
14691469 State.ExternType => |ctx| {
14701470 if (eatToken(&tok_it, &tree, Token.Id.Keyword_fn)) |fn_token| {
1471 const fn_proto = try arena.construct(ast.Node.FnProto{
1471 const fn_proto = try arena.create(ast.Node.FnProto{
14721472 .base = ast.Node{ .id = ast.Node.Id.FnProto },
14731473 .doc_comments = ctx.comments,
14741474 .visib_token = null,
......@@ -1641,7 +1641,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
16411641 continue;
16421642 }
16431643
1644 const node = try arena.construct(ast.Node.Payload{
1644 const node = try arena.create(ast.Node.Payload{
16451645 .base = ast.Node{ .id = ast.Node.Id.Payload },
16461646 .lpipe = token_index,
16471647 .error_symbol = undefined,
......@@ -1677,7 +1677,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
16771677 continue;
16781678 }
16791679
1680 const node = try arena.construct(ast.Node.PointerPayload{
1680 const node = try arena.create(ast.Node.PointerPayload{
16811681 .base = ast.Node{ .id = ast.Node.Id.PointerPayload },
16821682 .lpipe = token_index,
16831683 .ptr_token = null,
......@@ -1720,7 +1720,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
17201720 continue;
17211721 }
17221722
1723 const node = try arena.construct(ast.Node.PointerIndexPayload{
1723 const node = try arena.create(ast.Node.PointerIndexPayload{
17241724 .base = ast.Node{ .id = ast.Node.Id.PointerIndexPayload },
17251725 .lpipe = token_index,
17261726 .ptr_token = null,
......@@ -1754,7 +1754,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
17541754 const token_ptr = token.ptr;
17551755 switch (token_ptr.id) {
17561756 Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => {
1757 const node = try arena.construct(ast.Node.ControlFlowExpression{
1757 const node = try arena.create(ast.Node.ControlFlowExpression{
17581758 .base = ast.Node{ .id = ast.Node.Id.ControlFlowExpression },
17591759 .ltoken = token_index,
17601760 .kind = undefined,
......@@ -1783,7 +1783,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
17831783 continue;
17841784 },
17851785 Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {
1786 const node = try arena.construct(ast.Node.PrefixOp{
1786 const node = try arena.create(ast.Node.PrefixOp{
17871787 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },
17881788 .op_token = token_index,
17891789 .op = switch (token_ptr.id) {
......@@ -1817,7 +1817,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
18171817 const lhs = opt_ctx.get() orelse continue;
18181818
18191819 if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| {
1820 const node = try arena.construct(ast.Node.InfixOp{
1820 const node = try arena.create(ast.Node.InfixOp{
18211821 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
18221822 .lhs = lhs,
18231823 .op_token = ellipsis3,
......@@ -1842,7 +1842,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
18421842 const token_index = token.index;
18431843 const token_ptr = token.ptr;
18441844 if (tokenIdToAssignment(token_ptr.id)) |ass_id| {
1845 const node = try arena.construct(ast.Node.InfixOp{
1845 const node = try arena.create(ast.Node.InfixOp{
18461846 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
18471847 .lhs = lhs,
18481848 .op_token = token_index,
......@@ -1872,7 +1872,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
18721872 const token_index = token.index;
18731873 const token_ptr = token.ptr;
18741874 if (tokenIdToUnwrapExpr(token_ptr.id)) |unwrap_id| {
1875 const node = try arena.construct(ast.Node.InfixOp{
1875 const node = try arena.create(ast.Node.InfixOp{
18761876 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
18771877 .lhs = lhs,
18781878 .op_token = token_index,
......@@ -1904,7 +1904,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
19041904 const lhs = opt_ctx.get() orelse continue;
19051905
19061906 if (eatToken(&tok_it, &tree, Token.Id.Keyword_or)) |or_token| {
1907 const node = try arena.construct(ast.Node.InfixOp{
1907 const node = try arena.create(ast.Node.InfixOp{
19081908 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
19091909 .lhs = lhs,
19101910 .op_token = or_token,
......@@ -1928,7 +1928,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
19281928 const lhs = opt_ctx.get() orelse continue;
19291929
19301930 if (eatToken(&tok_it, &tree, Token.Id.Keyword_and)) |and_token| {
1931 const node = try arena.construct(ast.Node.InfixOp{
1931 const node = try arena.create(ast.Node.InfixOp{
19321932 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
19331933 .lhs = lhs,
19341934 .op_token = and_token,
......@@ -1955,7 +1955,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
19551955 const token_index = token.index;
19561956 const token_ptr = token.ptr;
19571957 if (tokenIdToComparison(token_ptr.id)) |comp_id| {
1958 const node = try arena.construct(ast.Node.InfixOp{
1958 const node = try arena.create(ast.Node.InfixOp{
19591959 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
19601960 .lhs = lhs,
19611961 .op_token = token_index,
......@@ -1982,7 +1982,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
19821982 const lhs = opt_ctx.get() orelse continue;
19831983
19841984 if (eatToken(&tok_it, &tree, Token.Id.Pipe)) |pipe| {
1985 const node = try arena.construct(ast.Node.InfixOp{
1985 const node = try arena.create(ast.Node.InfixOp{
19861986 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
19871987 .lhs = lhs,
19881988 .op_token = pipe,
......@@ -2006,7 +2006,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
20062006 const lhs = opt_ctx.get() orelse continue;
20072007
20082008 if (eatToken(&tok_it, &tree, Token.Id.Caret)) |caret| {
2009 const node = try arena.construct(ast.Node.InfixOp{
2009 const node = try arena.create(ast.Node.InfixOp{
20102010 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
20112011 .lhs = lhs,
20122012 .op_token = caret,
......@@ -2030,7 +2030,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
20302030 const lhs = opt_ctx.get() orelse continue;
20312031
20322032 if (eatToken(&tok_it, &tree, Token.Id.Ampersand)) |ampersand| {
2033 const node = try arena.construct(ast.Node.InfixOp{
2033 const node = try arena.create(ast.Node.InfixOp{
20342034 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
20352035 .lhs = lhs,
20362036 .op_token = ampersand,
......@@ -2057,7 +2057,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
20572057 const token_index = token.index;
20582058 const token_ptr = token.ptr;
20592059 if (tokenIdToBitShift(token_ptr.id)) |bitshift_id| {
2060 const node = try arena.construct(ast.Node.InfixOp{
2060 const node = try arena.create(ast.Node.InfixOp{
20612061 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
20622062 .lhs = lhs,
20632063 .op_token = token_index,
......@@ -2087,7 +2087,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
20872087 const token_index = token.index;
20882088 const token_ptr = token.ptr;
20892089 if (tokenIdToAddition(token_ptr.id)) |add_id| {
2090 const node = try arena.construct(ast.Node.InfixOp{
2090 const node = try arena.create(ast.Node.InfixOp{
20912091 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
20922092 .lhs = lhs,
20932093 .op_token = token_index,
......@@ -2117,7 +2117,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
21172117 const token_index = token.index;
21182118 const token_ptr = token.ptr;
21192119 if (tokenIdToMultiply(token_ptr.id)) |mult_id| {
2120 const node = try arena.construct(ast.Node.InfixOp{
2120 const node = try arena.create(ast.Node.InfixOp{
21212121 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
21222122 .lhs = lhs,
21232123 .op_token = token_index,
......@@ -2145,7 +2145,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
21452145 const lhs = opt_ctx.get() orelse continue;
21462146
21472147 if (tok_it.peek().?.id == Token.Id.Period) {
2148 const node = try arena.construct(ast.Node.SuffixOp{
2148 const node = try arena.create(ast.Node.SuffixOp{
21492149 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
21502150 .lhs = lhs,
21512151 .op = ast.Node.SuffixOp.Op{ .StructInitializer = ast.Node.SuffixOp.Op.InitList.init(arena) },
......@@ -2164,7 +2164,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
21642164 continue;
21652165 }
21662166
2167 const node = try arena.construct(ast.Node.SuffixOp{
2167 const node = try arena.create(ast.Node.SuffixOp{
21682168 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
21692169 .lhs = lhs,
21702170 .op = ast.Node.SuffixOp.Op{ .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(arena) },
......@@ -2193,7 +2193,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
21932193 const lhs = opt_ctx.get() orelse continue;
21942194
21952195 if (eatToken(&tok_it, &tree, Token.Id.Bang)) |bang| {
2196 const node = try arena.construct(ast.Node.InfixOp{
2196 const node = try arena.create(ast.Node.InfixOp{
21972197 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
21982198 .lhs = lhs,
21992199 .op_token = bang,
......@@ -2212,7 +2212,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
22122212 const token_index = token.index;
22132213 const token_ptr = token.ptr;
22142214 if (tokenIdToPrefixOp(token_ptr.id)) |prefix_id| {
2215 var node = try arena.construct(ast.Node.PrefixOp{
2215 var node = try arena.create(ast.Node.PrefixOp{
22162216 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },
22172217 .op_token = token_index,
22182218 .op = prefix_id,
......@@ -2222,7 +2222,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
22222222
22232223 // Treat '**' token as two pointer types
22242224 if (token_ptr.id == Token.Id.AsteriskAsterisk) {
2225 const child = try arena.construct(ast.Node.PrefixOp{
2225 const child = try arena.create(ast.Node.PrefixOp{
22262226 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },
22272227 .op_token = token_index,
22282228 .op = prefix_id,
......@@ -2246,7 +2246,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
22462246
22472247 State.SuffixOpExpressionBegin => |opt_ctx| {
22482248 if (eatToken(&tok_it, &tree, Token.Id.Keyword_async)) |async_token| {
2249 const async_node = try arena.construct(ast.Node.AsyncAttribute{
2249 const async_node = try arena.create(ast.Node.AsyncAttribute{
22502250 .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute },
22512251 .async_token = async_token,
22522252 .allocator_type = null,
......@@ -2277,7 +2277,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
22772277 const token_ptr = token.ptr;
22782278 switch (token_ptr.id) {
22792279 Token.Id.LParen => {
2280 const node = try arena.construct(ast.Node.SuffixOp{
2280 const node = try arena.create(ast.Node.SuffixOp{
22812281 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
22822282 .lhs = lhs,
22832283 .op = ast.Node.SuffixOp.Op{
......@@ -2301,7 +2301,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
23012301 continue;
23022302 },
23032303 Token.Id.LBracket => {
2304 const node = try arena.construct(ast.Node.SuffixOp{
2304 const node = try arena.create(ast.Node.SuffixOp{
23052305 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
23062306 .lhs = lhs,
23072307 .op = ast.Node.SuffixOp.Op{ .ArrayAccess = undefined },
......@@ -2316,7 +2316,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
23162316 },
23172317 Token.Id.Period => {
23182318 if (eatToken(&tok_it, &tree, Token.Id.Asterisk)) |asterisk_token| {
2319 const node = try arena.construct(ast.Node.SuffixOp{
2319 const node = try arena.create(ast.Node.SuffixOp{
23202320 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
23212321 .lhs = lhs,
23222322 .op = ast.Node.SuffixOp.Op.Deref,
......@@ -2327,7 +2327,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
23272327 continue;
23282328 }
23292329 if (eatToken(&tok_it, &tree, Token.Id.QuestionMark)) |question_token| {
2330 const node = try arena.construct(ast.Node.SuffixOp{
2330 const node = try arena.create(ast.Node.SuffixOp{
23312331 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
23322332 .lhs = lhs,
23332333 .op = ast.Node.SuffixOp.Op.UnwrapOptional,
......@@ -2337,7 +2337,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
23372337 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
23382338 continue;
23392339 }
2340 const node = try arena.construct(ast.Node.InfixOp{
2340 const node = try arena.create(ast.Node.InfixOp{
23412341 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
23422342 .lhs = lhs,
23432343 .op_token = token_index,
......@@ -2397,7 +2397,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
23972397 continue;
23982398 },
23992399 Token.Id.Keyword_promise => {
2400 const node = try arena.construct(ast.Node.PromiseType{
2400 const node = try arena.create(ast.Node.PromiseType{
24012401 .base = ast.Node{ .id = ast.Node.Id.PromiseType },
24022402 .promise_token = token.index,
24032403 .result = null,
......@@ -2423,7 +2423,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
24232423 continue;
24242424 },
24252425 Token.Id.LParen => {
2426 const node = try arena.construct(ast.Node.GroupedExpression{
2426 const node = try arena.create(ast.Node.GroupedExpression{
24272427 .base = ast.Node{ .id = ast.Node.Id.GroupedExpression },
24282428 .lparen = token.index,
24292429 .expr = undefined,
......@@ -2441,7 +2441,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
24412441 continue;
24422442 },
24432443 Token.Id.Builtin => {
2444 const node = try arena.construct(ast.Node.BuiltinCall{
2444 const node = try arena.create(ast.Node.BuiltinCall{
24452445 .base = ast.Node{ .id = ast.Node.Id.BuiltinCall },
24462446 .builtin_token = token.index,
24472447 .params = ast.Node.BuiltinCall.ParamList.init(arena),
......@@ -2460,7 +2460,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
24602460 continue;
24612461 },
24622462 Token.Id.LBracket => {
2463 const node = try arena.construct(ast.Node.PrefixOp{
2463 const node = try arena.create(ast.Node.PrefixOp{
24642464 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },
24652465 .op_token = token.index,
24662466 .op = undefined,
......@@ -2519,7 +2519,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
25192519 continue;
25202520 },
25212521 Token.Id.Keyword_fn => {
2522 const fn_proto = try arena.construct(ast.Node.FnProto{
2522 const fn_proto = try arena.create(ast.Node.FnProto{
25232523 .base = ast.Node{ .id = ast.Node.Id.FnProto },
25242524 .doc_comments = null,
25252525 .visib_token = null,
......@@ -2540,7 +2540,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
25402540 continue;
25412541 },
25422542 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {
2543 const fn_proto = try arena.construct(ast.Node.FnProto{
2543 const fn_proto = try arena.create(ast.Node.FnProto{
25442544 .base = ast.Node{ .id = ast.Node.Id.FnProto },
25452545 .doc_comments = null,
25462546 .visib_token = null,
......@@ -2567,7 +2567,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
25672567 continue;
25682568 },
25692569 Token.Id.Keyword_asm => {
2570 const node = try arena.construct(ast.Node.Asm{
2570 const node = try arena.create(ast.Node.Asm{
25712571 .base = ast.Node{ .id = ast.Node.Id.Asm },
25722572 .asm_token = token.index,
25732573 .volatile_token = null,
......@@ -2629,7 +2629,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
26292629 continue;
26302630 }
26312631
2632 const node = try arena.construct(ast.Node.ErrorSetDecl{
2632 const node = try arena.create(ast.Node.ErrorSetDecl{
26332633 .base = ast.Node{ .id = ast.Node.Id.ErrorSetDecl },
26342634 .error_token = ctx.error_token,
26352635 .decls = ast.Node.ErrorSetDecl.DeclList.init(arena),
......@@ -2695,7 +2695,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
26952695 return tree;
26962696 }
26972697
2698 const node = try arena.construct(ast.Node.ErrorTag{
2698 const node = try arena.create(ast.Node.ErrorTag{
26992699 .base = ast.Node{ .id = ast.Node.Id.ErrorTag },
27002700 .doc_comments = comments,
27012701 .name_token = ident_token_index,
......@@ -3032,7 +3032,7 @@ fn pushDocComment(arena: *mem.Allocator, line_comment: TokenIndex, result: *?*as
30323032 if (result.*) |comment_node| {
30333033 break :blk comment_node;
30343034 } else {
3035 const comment_node = try arena.construct(ast.Node.DocComment{
3035 const comment_node = try arena.create(ast.Node.DocComment{
30363036 .base = ast.Node{ .id = ast.Node.Id.DocComment },
30373037 .lines = ast.Node.DocComment.LineList.init(arena),
30383038 });
......@@ -3061,7 +3061,7 @@ fn parseStringLiteral(arena: *mem.Allocator, tok_it: *ast.Tree.TokenList.Iterato
30613061 return &(try createLiteral(arena, ast.Node.StringLiteral, token_index)).base;
30623062 },
30633063 Token.Id.MultilineStringLiteralLine => {
3064 const node = try arena.construct(ast.Node.MultilineStringLiteral{
3064 const node = try arena.create(ast.Node.MultilineStringLiteral{
30653065 .base = ast.Node{ .id = ast.Node.Id.MultilineStringLiteral },
30663066 .lines = ast.Node.MultilineStringLiteral.LineList.init(arena),
30673067 });
......@@ -3089,7 +3089,7 @@ fn parseStringLiteral(arena: *mem.Allocator, tok_it: *ast.Tree.TokenList.Iterato
30893089fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: *const OptionalCtx, token_ptr: *const Token, token_index: TokenIndex) !bool {
30903090 switch (token_ptr.id) {
30913091 Token.Id.Keyword_suspend => {
3092 const node = try arena.construct(ast.Node.Suspend{
3092 const node = try arena.create(ast.Node.Suspend{
30933093 .base = ast.Node{ .id = ast.Node.Id.Suspend },
30943094 .label = null,
30953095 .suspend_token = token_index,
......@@ -3103,7 +3103,7 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: *con
31033103 return true;
31043104 },
31053105 Token.Id.Keyword_if => {
3106 const node = try arena.construct(ast.Node.If{
3106 const node = try arena.create(ast.Node.If{
31073107 .base = ast.Node{ .id = ast.Node.Id.If },
31083108 .if_token = token_index,
31093109 .condition = undefined,
......@@ -3144,7 +3144,7 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: *con
31443144 return true;
31453145 },
31463146 Token.Id.Keyword_switch => {
3147 const node = try arena.construct(ast.Node.Switch{
3147 const node = try arena.create(ast.Node.Switch{
31483148 .base = ast.Node{ .id = ast.Node.Id.Switch },
31493149 .switch_token = token_index,
31503150 .expr = undefined,
......@@ -3166,7 +3166,7 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: *con
31663166 return true;
31673167 },
31683168 Token.Id.Keyword_comptime => {
3169 const node = try arena.construct(ast.Node.Comptime{
3169 const node = try arena.create(ast.Node.Comptime{
31703170 .base = ast.Node{ .id = ast.Node.Id.Comptime },
31713171 .comptime_token = token_index,
31723172 .expr = undefined,
......@@ -3178,7 +3178,7 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: *con
31783178 return true;
31793179 },
31803180 Token.Id.LBrace => {
3181 const block = try arena.construct(ast.Node.Block{
3181 const block = try arena.create(ast.Node.Block{
31823182 .base = ast.Node{ .id = ast.Node.Id.Block },
31833183 .label = null,
31843184 .lbrace = token_index,
......@@ -3318,7 +3318,7 @@ fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.Node.PrefixOp.Op {
33183318}
33193319
33203320fn createLiteral(arena: *mem.Allocator, comptime T: type, token_index: TokenIndex) !*T {
3321 return arena.construct(T{
3321 return arena.create(T{
33223322 .base = ast.Node{ .id = ast.Node.typeToId(T) },
33233323 .token = token_index,
33243324 });
std/zig/parser_test.zig+9
......@@ -1,3 +1,12 @@
1test "zig fmt: preserve space between async fn definitions" {
2 try testCanonical(
3 \\async fn a() void {}
4 \\
5 \\async fn b() void {}
6 \\
7 );
8}
9
110test "zig fmt: comment to disable/enable zig fmt first" {
211 try testCanonical(
312 \\// Test trailing comma syntax
test/behavior.zig+3
......@@ -13,6 +13,7 @@ comptime {
1313 _ = @import("cases/bugs/656.zig");
1414 _ = @import("cases/bugs/828.zig");
1515 _ = @import("cases/bugs/920.zig");
16 _ = @import("cases/bugs/1111.zig");
1617 _ = @import("cases/byval_arg_var.zig");
1718 _ = @import("cases/cast.zig");
1819 _ = @import("cases/const_slice_child.zig");
......@@ -34,6 +35,7 @@ comptime {
3435 _ = @import("cases/math.zig");
3536 _ = @import("cases/merge_error_sets.zig");
3637 _ = @import("cases/misc.zig");
38 _ = @import("cases/optional.zig");
3739 _ = @import("cases/namespace_depends_on_compile_var/index.zig");
3840 _ = @import("cases/new_stack_call.zig");
3941 _ = @import("cases/null.zig");
......@@ -58,4 +60,5 @@ comptime {
5860 _ = @import("cases/var_args.zig");
5961 _ = @import("cases/void.zig");
6062 _ = @import("cases/while.zig");
63 _ = @import("cases/widening.zig");
6164}
test/cases/align.zig+1-1
......@@ -90,7 +90,7 @@ fn testBytesAlignSlice(b: u8) void {
9090 b,
9191 b,
9292 };
93 const slice = ([]u32)(bytes[0..]);
93 const slice: []u32 = @bytesToSlice(u32, bytes[0..]);
9494 assert(slice[0] == 0x33333333);
9595}
9696
test/cases/array.zig+8
......@@ -152,3 +152,11 @@ fn testImplicitCastSingleItemPtr() void {
152152 slice[0] += 1;
153153 assert(byte == 101);
154154}
155
156fn testArrayByValAtComptime(b: [2]u8) u8 { return b[0]; }
157
158test "comptime evalutating function that takes array by value" {
159 const arr = []u8{0,1};
160 _ = comptime testArrayByValAtComptime(arr);
161 _ = comptime testArrayByValAtComptime(arr);
162}
test/cases/bugs/1111.zig created+12
......@@ -0,0 +1,12 @@
1const Foo = extern enum {
2 Bar = -1,
3};
4
5test "issue 1111 fixed" {
6 const v = Foo.Bar;
7
8 switch (v) {
9 Foo.Bar => return,
10 else => return,
11 }
12}
test/cases/cast.zig+62-14
......@@ -140,8 +140,8 @@ test "explicit cast from integer to error type" {
140140 comptime testCastIntToErr(error.ItBroke);
141141}
142142fn testCastIntToErr(err: error) void {
143 const x = usize(err);
144 const y = error(x);
143 const x = @errorToInt(err);
144 const y = @intToError(x);
145145 assert(error.ItBroke == y);
146146}
147147
......@@ -340,11 +340,26 @@ fn testPeerErrorAndArray2(x: u8) error![]const u8 {
340340 };
341341}
342342
343test "explicit cast float number literal to integer if no fraction component" {
343test "@floatToInt" {
344 testFloatToInts();
345 comptime testFloatToInts();
346}
347
348fn testFloatToInts() void {
344349 const x = i32(1e4);
345350 assert(x == 10000);
346351 const y = @floatToInt(i32, f32(1e4));
347352 assert(y == 10000);
353 expectFloatToInt(f16, 255.1, u8, 255);
354 expectFloatToInt(f16, 127.2, i8, 127);
355 expectFloatToInt(f16, -128.2, i8, -128);
356 expectFloatToInt(f32, 255.1, u8, 255);
357 expectFloatToInt(f32, 127.2, i8, 127);
358 expectFloatToInt(f32, -128.2, i8, -128);
359}
360
361fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) void {
362 assert(@floatToInt(I, f) == i);
348363}
349364
350365test "cast u128 to f128 and back" {
......@@ -372,7 +387,7 @@ test "const slice widen cast" {
372387 0x12,
373388 };
374389
375 const u32_value = ([]const u32)(bytes[0..])[0];
390 const u32_value = @bytesToSlice(u32, bytes[0..])[0];
376391 assert(u32_value == 0x12121212);
377392
378393 assert(@bitCast(u32, bytes) == 0x12121212);
......@@ -406,17 +421,50 @@ test "@intCast comptime_int" {
406421}
407422
408423test "@floatCast comptime_int and comptime_float" {
409 const result = @floatCast(f32, 1234);
410 assert(@typeOf(result) == f32);
411 assert(result == 1234.0);
412
413 const result2 = @floatCast(f32, 1234.0);
414 assert(@typeOf(result) == f32);
415 assert(result == 1234.0);
424 {
425 const result = @floatCast(f16, 1234);
426 assert(@typeOf(result) == f16);
427 assert(result == 1234.0);
428 }
429 {
430 const result = @floatCast(f16, 1234.0);
431 assert(@typeOf(result) == f16);
432 assert(result == 1234.0);
433 }
434 {
435 const result = @floatCast(f32, 1234);
436 assert(@typeOf(result) == f32);
437 assert(result == 1234.0);
438 }
439 {
440 const result = @floatCast(f32, 1234.0);
441 assert(@typeOf(result) == f32);
442 assert(result == 1234.0);
443 }
416444}
417445
418446test "comptime_int @intToFloat" {
419 const result = @intToFloat(f32, 1234);
420 assert(@typeOf(result) == f32);
421 assert(result == 1234.0);
447 {
448 const result = @intToFloat(f16, 1234);
449 assert(@typeOf(result) == f16);
450 assert(result == 1234.0);
451 }
452 {
453 const result = @intToFloat(f32, 1234);
454 assert(@typeOf(result) == f32);
455 assert(result == 1234.0);
456 }
457}
458
459test "@bytesToSlice keeps pointer alignment" {
460 var bytes = []u8{ 0x01, 0x02, 0x03, 0x04 };
461 const numbers = @bytesToSlice(u32, bytes[0..]);
462 comptime assert(@typeOf(numbers) == []align(@alignOf(@typeOf(bytes))) u32);
463}
464
465test "@intCast i32 to u7" {
466 var x: u128 = @maxValue(u128);
467 var y: i32 = 120;
468 var z = x >> @intCast(u7, y);
469 assert(z == 0xff);
422470}
test/cases/coroutines.zig+32-9
......@@ -5,7 +5,10 @@ const assert = std.debug.assert;
55var x: i32 = 1;
66
77test "create a coroutine and cancel it" {
8 const p = try async<std.debug.global_allocator> simpleAsyncFn();
8 var da = std.heap.DirectAllocator.init();
9 defer da.deinit();
10
11 const p = try async<&da.allocator> simpleAsyncFn();
912 comptime assert(@typeOf(p) == promise->void);
1013 cancel p;
1114 assert(x == 2);
......@@ -17,8 +20,11 @@ async fn simpleAsyncFn() void {
1720}
1821
1922test "coroutine suspend, resume, cancel" {
23 var da = std.heap.DirectAllocator.init();
24 defer da.deinit();
25
2026 seq('a');
21 const p = try async<std.debug.global_allocator> testAsyncSeq();
27 const p = try async<&da.allocator> testAsyncSeq();
2228 seq('c');
2329 resume p;
2430 seq('f');
......@@ -43,7 +49,10 @@ fn seq(c: u8) void {
4349}
4450
4551test "coroutine suspend with block" {
46 const p = try async<std.debug.global_allocator> testSuspendBlock();
52 var da = std.heap.DirectAllocator.init();
53 defer da.deinit();
54
55 const p = try async<&da.allocator> testSuspendBlock();
4756 std.debug.assert(!result);
4857 resume a_promise;
4958 std.debug.assert(result);
......@@ -64,8 +73,11 @@ var await_a_promise: promise = undefined;
6473var await_final_result: i32 = 0;
6574
6675test "coroutine await" {
76 var da = std.heap.DirectAllocator.init();
77 defer da.deinit();
78
6779 await_seq('a');
68 const p = async<std.debug.global_allocator> await_amain() catch unreachable;
80 const p = async<&da.allocator> await_amain() catch unreachable;
6981 await_seq('f');
7082 resume await_a_promise;
7183 await_seq('i');
......@@ -100,8 +112,11 @@ fn await_seq(c: u8) void {
100112var early_final_result: i32 = 0;
101113
102114test "coroutine await early return" {
115 var da = std.heap.DirectAllocator.init();
116 defer da.deinit();
117
103118 early_seq('a');
104 const p = async<std.debug.global_allocator> early_amain() catch unreachable;
119 const p = async<&da.allocator> early_amain() catch unreachable;
105120 early_seq('f');
106121 assert(early_final_result == 1234);
107122 assert(std.mem.eql(u8, early_points, "abcdef"));
......@@ -146,7 +161,9 @@ test "async function with dot syntax" {
146161 suspend;
147162 }
148163 };
149 const p = try async<std.debug.global_allocator> S.foo();
164 var da = std.heap.DirectAllocator.init();
165 defer da.deinit();
166 const p = try async<&da.allocator> S.foo();
150167 cancel p;
151168 assert(S.y == 2);
152169}
......@@ -157,7 +174,9 @@ test "async fn pointer in a struct field" {
157174 bar: async<*std.mem.Allocator> fn (*i32) void,
158175 };
159176 var foo = Foo{ .bar = simpleAsyncFn2 };
160 const p = (async<std.debug.global_allocator> foo.bar(&data)) catch unreachable;
177 var da = std.heap.DirectAllocator.init();
178 defer da.deinit();
179 const p = (async<&da.allocator> foo.bar(&data)) catch unreachable;
161180 assert(data == 2);
162181 cancel p;
163182 assert(data == 4);
......@@ -169,7 +188,9 @@ async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void {
169188}
170189
171190test "async fn with inferred error set" {
172 const p = (async<std.debug.global_allocator> failing()) catch unreachable;
191 var da = std.heap.DirectAllocator.init();
192 defer da.deinit();
193 const p = (async<&da.allocator> failing()) catch unreachable;
173194 resume p;
174195 cancel p;
175196}
......@@ -181,7 +202,9 @@ async fn failing() !void {
181202test "error return trace across suspend points - early return" {
182203 const p = nonFailing();
183204 resume p;
184 const p2 = try async<std.debug.global_allocator> printTrace(p);
205 var da = std.heap.DirectAllocator.init();
206 defer da.deinit();
207 const p2 = try async<&da.allocator> printTrace(p);
185208 cancel p2;
186209}
187210
test/cases/enum.zig+8-8
......@@ -92,14 +92,14 @@ test "enum to int" {
9292}
9393
9494fn shouldEqual(n: Number, expected: u3) void {
95 assert(u3(n) == expected);
95 assert(@enumToInt(n) == expected);
9696}
9797
9898test "int to enum" {
9999 testIntToEnumEval(3);
100100}
101101fn testIntToEnumEval(x: i32) void {
102 assert(IntToEnumNumber(@intCast(u3, x)) == IntToEnumNumber.Three);
102 assert(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three);
103103}
104104const IntToEnumNumber = enum {
105105 Zero,
......@@ -768,7 +768,7 @@ test "casting enum to its tag type" {
768768}
769769
770770fn testCastEnumToTagType(value: Small2) void {
771 assert(u2(value) == 1);
771 assert(@enumToInt(value) == 1);
772772}
773773
774774const MultipleChoice = enum(u32) {
......@@ -784,7 +784,7 @@ test "enum with specified tag values" {
784784}
785785
786786fn testEnumWithSpecifiedTagValues(x: MultipleChoice) void {
787 assert(u32(x) == 60);
787 assert(@enumToInt(x) == 60);
788788 assert(1234 == switch (x) {
789789 MultipleChoice.A => 1,
790790 MultipleChoice.B => 2,
......@@ -811,7 +811,7 @@ test "enum with specified and unspecified tag values" {
811811}
812812
813813fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
814 assert(u32(x) == 1000);
814 assert(@enumToInt(x) == 1000);
815815 assert(1234 == switch (x) {
816816 MultipleChoice2.A => 1,
817817 MultipleChoice2.B => 2,
......@@ -826,8 +826,8 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
826826}
827827
828828test "cast integer literal to enum" {
829 assert(MultipleChoice2(0) == MultipleChoice2.Unspecified1);
830 assert(MultipleChoice2(40) == MultipleChoice2.B);
829 assert(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1);
830 assert(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B);
831831}
832832
833833const EnumWithOneMember = enum {
......@@ -865,7 +865,7 @@ const EnumWithTagValues = enum(u4) {
865865 D = 1 << 3,
866866};
867867test "enum with tag values don't require parens" {
868 assert(u4(EnumWithTagValues.C) == 0b0100);
868 assert(@enumToInt(EnumWithTagValues.C) == 0b0100);
869869}
870870
871871test "enum with 1 field but explicit tag type should still have the tag type" {
test/cases/error.zig+7-7
......@@ -31,8 +31,8 @@ test "@errorName" {
3131}
3232
3333test "error values" {
34 const a = i32(error.err1);
35 const b = i32(error.err2);
34 const a = @errorToInt(error.err1);
35 const b = @errorToInt(error.err2);
3636 assert(a != b);
3737}
3838
......@@ -124,8 +124,8 @@ const Set2 = error{
124124};
125125
126126fn testExplicitErrorSetCast(set1: Set1) void {
127 var x = Set2(set1);
128 var y = Set1(x);
127 var x = @errSetCast(Set2, set1);
128 var y = @errSetCast(Set1, x);
129129 assert(y == error.A);
130130}
131131
......@@ -147,14 +147,14 @@ test "syntax: optional operator in front of error union operator" {
147147}
148148
149149test "comptime err to int of error set with only 1 possible value" {
150 testErrToIntWithOnePossibleValue(error.A, u32(error.A));
151 comptime testErrToIntWithOnePossibleValue(error.A, u32(error.A));
150 testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));
151 comptime testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));
152152}
153153fn testErrToIntWithOnePossibleValue(
154154 x: error{A},
155155 comptime value: u32,
156156) void {
157 if (u32(x) != value) {
157 if (@errorToInt(x) != value) {
158158 @compileError("bad");
159159 }
160160}
test/cases/eval.zig+19
......@@ -623,3 +623,22 @@ test "function which returns struct with type field causes implicit comptime" {
623623 const ty = wrap(i32).T;
624624 assert(ty == i32);
625625}
626
627test "call method with comptime pass-by-non-copying-value self parameter" {
628 const S = struct {
629 a: u8,
630
631 fn b(comptime s: this) u8 {
632 return s.a;
633 }
634 };
635
636 const s = S{ .a = 2 };
637 var b = s.b();
638 assert(b == 2);
639}
640
641test "@tagName of @typeId" {
642 const str = @tagName(@typeId(u8));
643 assert(std.mem.eql(u8, str, "Int"));
644}
test/cases/math.zig+34
......@@ -6,15 +6,20 @@ test "division" {
66}
77fn testDivision() void {
88 assert(div(u32, 13, 3) == 4);
9 assert(div(f16, 1.0, 2.0) == 0.5);
910 assert(div(f32, 1.0, 2.0) == 0.5);
1011
1112 assert(divExact(u32, 55, 11) == 5);
1213 assert(divExact(i32, -55, 11) == -5);
14 assert(divExact(f16, 55.0, 11.0) == 5.0);
15 assert(divExact(f16, -55.0, 11.0) == -5.0);
1316 assert(divExact(f32, 55.0, 11.0) == 5.0);
1417 assert(divExact(f32, -55.0, 11.0) == -5.0);
1518
1619 assert(divFloor(i32, 5, 3) == 1);
1720 assert(divFloor(i32, -5, 3) == -2);
21 assert(divFloor(f16, 5.0, 3.0) == 1.0);
22 assert(divFloor(f16, -5.0, 3.0) == -2.0);
1823 assert(divFloor(f32, 5.0, 3.0) == 1.0);
1924 assert(divFloor(f32, -5.0, 3.0) == -2.0);
2025 assert(divFloor(i32, -0x80000000, -2) == 0x40000000);
......@@ -24,8 +29,12 @@ fn testDivision() void {
2429
2530 assert(divTrunc(i32, 5, 3) == 1);
2631 assert(divTrunc(i32, -5, 3) == -1);
32 assert(divTrunc(f16, 5.0, 3.0) == 1.0);
33 assert(divTrunc(f16, -5.0, 3.0) == -1.0);
2734 assert(divTrunc(f32, 5.0, 3.0) == 1.0);
2835 assert(divTrunc(f32, -5.0, 3.0) == -1.0);
36 assert(divTrunc(f64, 5.0, 3.0) == 1.0);
37 assert(divTrunc(f64, -5.0, 3.0) == -1.0);
2938
3039 comptime {
3140 assert(
......@@ -287,6 +296,14 @@ test "quad hex float literal parsing in range" {
287296 const d = 0x1.edcbff8ad76ab5bf46463233214fp-435;
288297}
289298
299test "quad hex float literal parsing accurate" {
300 const a: f128 = 0x1.1111222233334444555566667777p+0;
301
302 // implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing.
303 const expected: u128 = 0x3fff1111222233334444555566667777;
304 assert(@bitCast(u128, a) == expected);
305}
306
290307test "hex float literal within range" {
291308 const a = 0x1.0p16383;
292309 const b = 0x0.1p16387;
......@@ -434,11 +451,28 @@ test "comptime float rem int" {
434451 }
435452}
436453
454test "remainder division" {
455 comptime remdiv(f16);
456 comptime remdiv(f32);
457 comptime remdiv(f64);
458 comptime remdiv(f128);
459 remdiv(f16);
460 remdiv(f64);
461 remdiv(f128);
462}
463
464fn remdiv(comptime T: type) void {
465 assert(T(1) == T(1) % T(2));
466 assert(T(1) == T(7) % T(3));
467}
468
437469test "@sqrt" {
438470 testSqrt(f64, 12.0);
439471 comptime testSqrt(f64, 12.0);
440472 testSqrt(f32, 13.0);
441473 comptime testSqrt(f32, 13.0);
474 testSqrt(f16, 13.0);
475 comptime testSqrt(f16, 13.0);
442476
443477 const x = 14.0;
444478 const y = x * x;
test/cases/misc.zig+8-2
......@@ -53,6 +53,7 @@ test "@IntType builtin" {
5353}
5454
5555test "floating point primitive bit counts" {
56 assert(f16.bit_count == 16);
5657 assert(f32.bit_count == 32);
5758 assert(f64.bit_count == 64);
5859}
......@@ -422,14 +423,14 @@ test "cast slice to u8 slice" {
422423 4,
423424 };
424425 const big_thing_slice: []i32 = big_thing_array[0..];
425 const bytes = ([]u8)(big_thing_slice);
426 const bytes = @sliceToBytes(big_thing_slice);
426427 assert(bytes.len == 4 * 4);
427428 bytes[4] = 0;
428429 bytes[5] = 0;
429430 bytes[6] = 0;
430431 bytes[7] = 0;
431432 assert(big_thing_slice[1] == 0);
432 const big_thing_again = ([]align(1) i32)(bytes);
433 const big_thing_again = @bytesToSlice(i32, bytes);
433434 assert(big_thing_again[2] == 3);
434435 big_thing_again[2] = -1;
435436 assert(bytes[8] == @maxValue(u8));
......@@ -701,3 +702,8 @@ test "comptime cast fn to ptr" {
701702 const addr2 = @ptrCast(*const u8, emptyFn);
702703 comptime assert(addr1 == addr2);
703704}
705
706test "equality compare fn ptrs" {
707 var a = emptyFn;
708 assert(a == a);
709}
test/cases/null.zig+1-1
......@@ -146,7 +146,7 @@ test "null with default unwrap" {
146146
147147test "optional types" {
148148 comptime {
149 const opt_type_struct = StructWithOptionalType { .t=u8, };
149 const opt_type_struct = StructWithOptionalType{ .t = u8 };
150150 assert(opt_type_struct.t != null and opt_type_struct.t.? == u8);
151151 }
152152}
test/cases/optional.zig created+9
......@@ -0,0 +1,9 @@
1const assert = @import("std").debug.assert;
2
3pub const EmptyStruct = struct {};
4
5test "optional pointer to size zero struct" {
6 var e = EmptyStruct{};
7 var o: ?*EmptyStruct = &e;
8 assert(o != null);
9}
test/cases/struct.zig+2-2
......@@ -302,7 +302,7 @@ test "packed array 24bits" {
302302
303303 var bytes = []u8{0} ** (@sizeOf(FooArray24Bits) + 1);
304304 bytes[bytes.len - 1] = 0xaa;
305 const ptr = &([]FooArray24Bits)(bytes[0 .. bytes.len - 1])[0];
305 const ptr = &@bytesToSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0];
306306 assert(ptr.a == 0);
307307 assert(ptr.b[0].field == 0);
308308 assert(ptr.b[1].field == 0);
......@@ -351,7 +351,7 @@ test "aligned array of packed struct" {
351351 }
352352
353353 var bytes = []u8{0xbb} ** @sizeOf(FooArrayOfAligned);
354 const ptr = &([]FooArrayOfAligned)(bytes[0..bytes.len])[0];
354 const ptr = &@bytesToSlice(FooArrayOfAligned, bytes[0..bytes.len])[0];
355355
356356 assert(ptr.a[0].a == 0xbb);
357357 assert(ptr.a[0].b == 0xbb);
test/cases/type_info.zig+9-9
......@@ -107,11 +107,11 @@ test "type info: promise info" {
107107fn testPromise() void {
108108 const null_promise_info = @typeInfo(promise);
109109 assert(TypeId(null_promise_info) == TypeId.Promise);
110 assert(null_promise_info.Promise.child == @typeOf(undefined));
110 assert(null_promise_info.Promise.child == null);
111111
112112 const promise_info = @typeInfo(promise->usize);
113113 assert(TypeId(promise_info) == TypeId.Promise);
114 assert(promise_info.Promise.child == usize);
114 assert(promise_info.Promise.child.? == usize);
115115}
116116
117117test "type info: error set, error union info" {
......@@ -130,7 +130,7 @@ fn testErrorSet() void {
130130 assert(TypeId(error_set_info) == TypeId.ErrorSet);
131131 assert(error_set_info.ErrorSet.errors.len == 3);
132132 assert(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First"));
133 assert(error_set_info.ErrorSet.errors[2].value == usize(TestErrorSet.Third));
133 assert(error_set_info.ErrorSet.errors[2].value == @errorToInt(TestErrorSet.Third));
134134
135135 const error_union_info = @typeInfo(TestErrorSet!usize);
136136 assert(TypeId(error_union_info) == TypeId.ErrorUnion);
......@@ -165,7 +165,7 @@ fn testUnion() void {
165165 const typeinfo_info = @typeInfo(TypeInfo);
166166 assert(TypeId(typeinfo_info) == TypeId.Union);
167167 assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
168 assert(typeinfo_info.Union.tag_type == TypeId);
168 assert(typeinfo_info.Union.tag_type.? == TypeId);
169169 assert(typeinfo_info.Union.fields.len == 25);
170170 assert(typeinfo_info.Union.fields[4].enum_field != null);
171171 assert(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
......@@ -179,7 +179,7 @@ fn testUnion() void {
179179
180180 const notag_union_info = @typeInfo(TestNoTagUnion);
181181 assert(TypeId(notag_union_info) == TypeId.Union);
182 assert(notag_union_info.Union.tag_type == @typeOf(undefined));
182 assert(notag_union_info.Union.tag_type == null);
183183 assert(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto);
184184 assert(notag_union_info.Union.fields.len == 2);
185185 assert(notag_union_info.Union.fields[0].enum_field == null);
......@@ -191,7 +191,7 @@ fn testUnion() void {
191191
192192 const extern_union_info = @typeInfo(TestExternUnion);
193193 assert(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern);
194 assert(extern_union_info.Union.tag_type == @typeOf(undefined));
194 assert(extern_union_info.Union.tag_type == null);
195195 assert(extern_union_info.Union.fields[0].enum_field == null);
196196 assert(extern_union_info.Union.fields[0].field_type == *c_void);
197197}
......@@ -238,13 +238,13 @@ fn testFunction() void {
238238 assert(fn_info.Fn.is_generic);
239239 assert(fn_info.Fn.args.len == 2);
240240 assert(fn_info.Fn.is_var_args);
241 assert(fn_info.Fn.return_type == @typeOf(undefined));
242 assert(fn_info.Fn.async_allocator_type == @typeOf(undefined));
241 assert(fn_info.Fn.return_type == null);
242 assert(fn_info.Fn.async_allocator_type == null);
243243
244244 const test_instance: TestStruct = undefined;
245245 const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));
246246 assert(TypeId(bound_fn_info) == TypeId.BoundFn);
247 assert(bound_fn_info.BoundFn.args[0].arg_type == *const TestStruct);
247 assert(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct);
248248}
249249
250250fn foo(comptime a: usize, b: bool, args: ...) usize {
test/cases/union.zig+2-2
......@@ -126,7 +126,7 @@ const MultipleChoice = union(enum(u32)) {
126126test "simple union(enum(u32))" {
127127 var x = MultipleChoice.C;
128128 assert(x == MultipleChoice.C);
129 assert(u32(@TagType(MultipleChoice)(x)) == 60);
129 assert(@enumToInt(@TagType(MultipleChoice)(x)) == 60);
130130}
131131
132132const MultipleChoice2 = union(enum(u32)) {
......@@ -148,7 +148,7 @@ test "union(enum(u32)) with specified and unspecified tag values" {
148148}
149149
150150fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: *const MultipleChoice2) void {
151 assert(u32(@TagType(MultipleChoice2)(x.*)) == 60);
151 assert(@enumToInt(@TagType(MultipleChoice2)(x.*)) == 60);
152152 assert(1123 == switch (x.*) {
153153 MultipleChoice2.A => 1,
154154 MultipleChoice2.B => 2,
test/cases/widening.zig created+27
......@@ -0,0 +1,27 @@
1const std = @import("std");
2const assert = std.debug.assert;
3const mem = std.mem;
4
5test "integer widening" {
6 var a: u8 = 250;
7 var b: u16 = a;
8 var c: u32 = b;
9 var d: u64 = c;
10 var e: u64 = d;
11 var f: u128 = e;
12 assert(f == a);
13}
14
15test "implicit unsigned integer to signed integer" {
16 var a: u8 = 250;
17 var b: i16 = a;
18 assert(b == 250);
19}
20
21test "float widening" {
22 var a: f16 = 12.34;
23 var b: f32 = a;
24 var c: f64 = b;
25 var d: f128 = c;
26 assert(d == a);
27}
test/compile_errors.zig+490-64
......@@ -1,6 +1,36 @@
11const tests = @import("tests.zig");
22
33pub fn addCases(cases: *tests.CompileErrorContext) void {
4 cases.add(
5 "enum field value references enum",
6 \\pub const Foo = extern enum {
7 \\ A = Foo.B,
8 \\ C = D,
9 \\};
10 \\export fn entry() void {
11 \\ var s: Foo = Foo.E;
12 \\}
13 ,
14 ".tmp_source.zig:1:17: error: 'Foo' depends on itself",
15 );
16
17 cases.add(
18 "@floatToInt comptime safety",
19 \\comptime {
20 \\ _ = @floatToInt(i8, f32(-129.1));
21 \\}
22 \\comptime {
23 \\ _ = @floatToInt(u8, f32(-1.1));
24 \\}
25 \\comptime {
26 \\ _ = @floatToInt(u8, f32(256.1));
27 \\}
28 ,
29 ".tmp_source.zig:2:9: error: integer value '-129' cannot be stored in type 'i8'",
30 ".tmp_source.zig:5:9: error: integer value '-1' cannot be stored in type 'u8'",
31 ".tmp_source.zig:8:9: error: integer value '256' cannot be stored in type 'u8'",
32 );
33
434 cases.add(
535 "use c_void as return type of fn ptr",
636 \\export fn entry() void {
......@@ -83,7 +113,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
83113 \\ var rule_set = try Foo.init();
84114 \\}
85115 ,
86 ".tmp_source.zig:2:13: error: invalid cast from type 'type' to 'i32'",
116 ".tmp_source.zig:2:13: error: expected type 'i32', found 'type'",
87117 );
88118
89119 cases.add(
......@@ -105,7 +135,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
105135 );
106136
107137 cases.add(
108 "invalid deref on switch target",
138 "nested error set mismatch",
109139 \\const NextError = error{NextError};
110140 \\const OtherError = error{OutOfMemory};
111141 \\
......@@ -117,7 +147,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
117147 \\ return null;
118148 \\}
119149 ,
120 ".tmp_source.zig:5:34: error: expected 'NextError!i32', found 'OtherError!i32'",
150 ".tmp_source.zig:5:34: error: expected type '?NextError!i32', found '?OtherError!i32'",
151 ".tmp_source.zig:5:34: note: optional type child 'OtherError!i32' cannot cast into optional type child 'NextError!i32'",
152 ".tmp_source.zig:5:34: note: error set 'OtherError' cannot cast into error set 'NextError'",
121153 ".tmp_source.zig:2:26: note: 'error.OutOfMemory' not a member of destination error set",
122154 );
123155
......@@ -404,10 +436,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
404436 \\const Set2 = error {A, C};
405437 \\comptime {
406438 \\ var x = Set1.B;
407 \\ var y = Set2(x);
439 \\ var y = @errSetCast(Set2, x);
408440 \\}
409441 ,
410 ".tmp_source.zig:5:17: error: error.B not a member of error set 'Set2'",
442 ".tmp_source.zig:5:13: error: error.B not a member of error set 'Set2'",
411443 );
412444
413445 cases.add(
......@@ -420,8 +452,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
420452 \\ return error.B;
421453 \\}
422454 ,
423 ".tmp_source.zig:3:35: error: expected 'SmallErrorSet!i32', found 'error!i32'",
424 ".tmp_source.zig:3:35: note: unable to cast global error set into smaller set",
455 ".tmp_source.zig:3:35: error: expected type 'SmallErrorSet!i32', found 'error!i32'",
456 ".tmp_source.zig:3:35: note: error set 'error' cannot cast into error set 'SmallErrorSet'",
457 ".tmp_source.zig:3:35: note: cannot cast global error set into smaller set",
425458 );
426459
427460 cases.add(
......@@ -434,8 +467,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
434467 \\ return error.B;
435468 \\}
436469 ,
437 ".tmp_source.zig:3:31: error: expected 'SmallErrorSet', found 'error'",
438 ".tmp_source.zig:3:31: note: unable to cast global error set into smaller set",
470 ".tmp_source.zig:3:31: error: expected type 'SmallErrorSet', found 'error'",
471 ".tmp_source.zig:3:31: note: cannot cast global error set into smaller set",
439472 );
440473
441474 cases.add(
......@@ -461,31 +494,40 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
461494 \\ var x: Set2 = set1;
462495 \\}
463496 ,
464 ".tmp_source.zig:7:19: error: expected 'Set2', found 'Set1'",
497 ".tmp_source.zig:7:19: error: expected type 'Set2', found 'Set1'",
465498 ".tmp_source.zig:1:23: note: 'error.B' not a member of destination error set",
466499 );
467500
468501 cases.add(
469502 "int to err global invalid number",
470 \\const Set1 = error{A, B};
503 \\const Set1 = error{
504 \\ A,
505 \\ B,
506 \\};
471507 \\comptime {
472 \\ var x: usize = 3;
473 \\ var y = error(x);
508 \\ var x: u16 = 3;
509 \\ var y = @intToError(x);
474510 \\}
475511 ,
476 ".tmp_source.zig:4:18: error: integer value 3 represents no error",
512 ".tmp_source.zig:7:13: error: integer value 3 represents no error",
477513 );
478514
479515 cases.add(
480516 "int to err non global invalid number",
481 \\const Set1 = error{A, B};
482 \\const Set2 = error{A, C};
517 \\const Set1 = error{
518 \\ A,
519 \\ B,
520 \\};
521 \\const Set2 = error{
522 \\ A,
523 \\ C,
524 \\};
483525 \\comptime {
484 \\ var x = usize(Set1.B);
485 \\ var y = Set2(x);
526 \\ var x = @errorToInt(Set1.B);
527 \\ var y = @errSetCast(Set2, @intToError(x));
486528 \\}
487529 ,
488 ".tmp_source.zig:5:17: error: integer value 2 represents no error in 'Set2'",
530 ".tmp_source.zig:11:13: error: error.B not a member of error set 'Set2'",
489531 );
490532
491533 cases.add(
......@@ -1635,6 +1677,18 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
16351677 ".tmp_source.zig:1:16: error: integer value 300 cannot be implicitly casted to type 'u8'",
16361678 );
16371679
1680 cases.add(
1681 "invalid shift amount error",
1682 \\const x : u8 = 2;
1683 \\fn f() u16 {
1684 \\ return x << 8;
1685 \\}
1686 \\export fn entry() u16 { return f(); }
1687 ,
1688 ".tmp_source.zig:3:14: error: RHS of shift is too large for LHS type",
1689 ".tmp_source.zig:3:17: note: value 8 cannot fit into type u3",
1690 );
1691
16381692 cases.add(
16391693 "incompatible number literals",
16401694 \\const x = 2 == 2.0;
......@@ -1851,6 +1905,416 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
18511905 ".tmp_source.zig:1:15: error: use of undefined value",
18521906 );
18531907
1908 cases.add(
1909 "div on undefined value",
1910 \\comptime {
1911 \\ var a: i64 = undefined;
1912 \\ _ = a / a;
1913 \\}
1914 ,
1915 ".tmp_source.zig:3:9: error: use of undefined value",
1916 );
1917
1918 cases.add(
1919 "div assign on undefined value",
1920 \\comptime {
1921 \\ var a: i64 = undefined;
1922 \\ a /= a;
1923 \\}
1924 ,
1925 ".tmp_source.zig:3:5: error: use of undefined value",
1926 );
1927
1928 cases.add(
1929 "mod on undefined value",
1930 \\comptime {
1931 \\ var a: i64 = undefined;
1932 \\ _ = a % a;
1933 \\}
1934 ,
1935 ".tmp_source.zig:3:9: error: use of undefined value",
1936 );
1937
1938 cases.add(
1939 "mod assign on undefined value",
1940 \\comptime {
1941 \\ var a: i64 = undefined;
1942 \\ a %= a;
1943 \\}
1944 ,
1945 ".tmp_source.zig:3:5: error: use of undefined value",
1946 );
1947
1948 cases.add(
1949 "add on undefined value",
1950 \\comptime {
1951 \\ var a: i64 = undefined;
1952 \\ _ = a + a;
1953 \\}
1954 ,
1955 ".tmp_source.zig:3:9: error: use of undefined value",
1956 );
1957
1958 cases.add(
1959 "add assign on undefined value",
1960 \\comptime {
1961 \\ var a: i64 = undefined;
1962 \\ a += a;
1963 \\}
1964 ,
1965 ".tmp_source.zig:3:5: error: use of undefined value",
1966 );
1967
1968 cases.add(
1969 "add wrap on undefined value",
1970 \\comptime {
1971 \\ var a: i64 = undefined;
1972 \\ _ = a +% a;
1973 \\}
1974 ,
1975 ".tmp_source.zig:3:9: error: use of undefined value",
1976 );
1977
1978 cases.add(
1979 "add wrap assign on undefined value",
1980 \\comptime {
1981 \\ var a: i64 = undefined;
1982 \\ a +%= a;
1983 \\}
1984 ,
1985 ".tmp_source.zig:3:5: error: use of undefined value",
1986 );
1987
1988 cases.add(
1989 "sub on undefined value",
1990 \\comptime {
1991 \\ var a: i64 = undefined;
1992 \\ _ = a - a;
1993 \\}
1994 ,
1995 ".tmp_source.zig:3:9: error: use of undefined value",
1996 );
1997
1998 cases.add(
1999 "sub assign on undefined value",
2000 \\comptime {
2001 \\ var a: i64 = undefined;
2002 \\ a -= a;
2003 \\}
2004 ,
2005 ".tmp_source.zig:3:5: error: use of undefined value",
2006 );
2007
2008 cases.add(
2009 "sub wrap on undefined value",
2010 \\comptime {
2011 \\ var a: i64 = undefined;
2012 \\ _ = a -% a;
2013 \\}
2014 ,
2015 ".tmp_source.zig:3:9: error: use of undefined value",
2016 );
2017
2018 cases.add(
2019 "sub wrap assign on undefined value",
2020 \\comptime {
2021 \\ var a: i64 = undefined;
2022 \\ a -%= a;
2023 \\}
2024 ,
2025 ".tmp_source.zig:3:5: error: use of undefined value",
2026 );
2027
2028 cases.add(
2029 "mult on undefined value",
2030 \\comptime {
2031 \\ var a: i64 = undefined;
2032 \\ _ = a * a;
2033 \\}
2034 ,
2035 ".tmp_source.zig:3:9: error: use of undefined value",
2036 );
2037
2038 cases.add(
2039 "mult assign on undefined value",
2040 \\comptime {
2041 \\ var a: i64 = undefined;
2042 \\ a *= a;
2043 \\}
2044 ,
2045 ".tmp_source.zig:3:5: error: use of undefined value",
2046 );
2047
2048 cases.add(
2049 "mult wrap on undefined value",
2050 \\comptime {
2051 \\ var a: i64 = undefined;
2052 \\ _ = a *% a;
2053 \\}
2054 ,
2055 ".tmp_source.zig:3:9: error: use of undefined value",
2056 );
2057
2058 cases.add(
2059 "mult wrap assign on undefined value",
2060 \\comptime {
2061 \\ var a: i64 = undefined;
2062 \\ a *%= a;
2063 \\}
2064 ,
2065 ".tmp_source.zig:3:5: error: use of undefined value",
2066 );
2067
2068 cases.add(
2069 "shift left on undefined value",
2070 \\comptime {
2071 \\ var a: i64 = undefined;
2072 \\ _ = a << 2;
2073 \\}
2074 ,
2075 ".tmp_source.zig:3:9: error: use of undefined value",
2076 );
2077
2078 cases.add(
2079 "shift left assign on undefined value",
2080 \\comptime {
2081 \\ var a: i64 = undefined;
2082 \\ a <<= 2;
2083 \\}
2084 ,
2085 ".tmp_source.zig:3:5: error: use of undefined value",
2086 );
2087
2088 cases.add(
2089 "shift right on undefined value",
2090 \\comptime {
2091 \\ var a: i64 = undefined;
2092 \\ _ = a >> 2;
2093 \\}
2094 ,
2095 ".tmp_source.zig:3:9: error: use of undefined value",
2096 );
2097
2098 cases.add(
2099 "shift left assign on undefined value",
2100 \\comptime {
2101 \\ var a: i64 = undefined;
2102 \\ a >>= 2;
2103 \\}
2104 ,
2105 ".tmp_source.zig:3:5: error: use of undefined value",
2106 );
2107
2108 cases.add(
2109 "bin and on undefined value",
2110 \\comptime {
2111 \\ var a: i64 = undefined;
2112 \\ _ = a & a;
2113 \\}
2114 ,
2115 ".tmp_source.zig:3:9: error: use of undefined value",
2116 );
2117
2118 cases.add(
2119 "bin and assign on undefined value",
2120 \\comptime {
2121 \\ var a: i64 = undefined;
2122 \\ a &= a;
2123 \\}
2124 ,
2125 ".tmp_source.zig:3:5: error: use of undefined value",
2126 );
2127
2128 cases.add(
2129 "bin or on undefined value",
2130 \\comptime {
2131 \\ var a: i64 = undefined;
2132 \\ _ = a | a;
2133 \\}
2134 ,
2135 ".tmp_source.zig:3:9: error: use of undefined value",
2136 );
2137
2138 cases.add(
2139 "bin or assign on undefined value",
2140 \\comptime {
2141 \\ var a: i64 = undefined;
2142 \\ a |= a;
2143 \\}
2144 ,
2145 ".tmp_source.zig:3:5: error: use of undefined value",
2146 );
2147
2148 cases.add(
2149 "bin xor on undefined value",
2150 \\comptime {
2151 \\ var a: i64 = undefined;
2152 \\ _ = a ^ a;
2153 \\}
2154 ,
2155 ".tmp_source.zig:3:9: error: use of undefined value",
2156 );
2157
2158 cases.add(
2159 "bin xor assign on undefined value",
2160 \\comptime {
2161 \\ var a: i64 = undefined;
2162 \\ a ^= a;
2163 \\}
2164 ,
2165 ".tmp_source.zig:3:5: error: use of undefined value",
2166 );
2167
2168 cases.add(
2169 "equal on undefined value",
2170 \\comptime {
2171 \\ var a: i64 = undefined;
2172 \\ _ = a == a;
2173 \\}
2174 ,
2175 ".tmp_source.zig:3:9: error: use of undefined value",
2176 );
2177
2178 cases.add(
2179 "not equal on undefined value",
2180 \\comptime {
2181 \\ var a: i64 = undefined;
2182 \\ _ = a != a;
2183 \\}
2184 ,
2185 ".tmp_source.zig:3:9: error: use of undefined value",
2186 );
2187
2188 cases.add(
2189 "greater than on undefined value",
2190 \\comptime {
2191 \\ var a: i64 = undefined;
2192 \\ _ = a > a;
2193 \\}
2194 ,
2195 ".tmp_source.zig:3:9: error: use of undefined value",
2196 );
2197
2198 cases.add(
2199 "greater than equal on undefined value",
2200 \\comptime {
2201 \\ var a: i64 = undefined;
2202 \\ _ = a >= a;
2203 \\}
2204 ,
2205 ".tmp_source.zig:3:9: error: use of undefined value",
2206 );
2207
2208 cases.add(
2209 "less than on undefined value",
2210 \\comptime {
2211 \\ var a: i64 = undefined;
2212 \\ _ = a < a;
2213 \\}
2214 ,
2215 ".tmp_source.zig:3:9: error: use of undefined value",
2216 );
2217
2218 cases.add(
2219 "less than equal on undefined value",
2220 \\comptime {
2221 \\ var a: i64 = undefined;
2222 \\ _ = a <= a;
2223 \\}
2224 ,
2225 ".tmp_source.zig:3:9: error: use of undefined value",
2226 );
2227
2228 cases.add(
2229 "and on undefined value",
2230 \\comptime {
2231 \\ var a: bool = undefined;
2232 \\ _ = a and a;
2233 \\}
2234 ,
2235 ".tmp_source.zig:3:9: error: use of undefined value",
2236 );
2237
2238 cases.add(
2239 "or on undefined value",
2240 \\comptime {
2241 \\ var a: bool = undefined;
2242 \\ _ = a or a;
2243 \\}
2244 ,
2245 ".tmp_source.zig:3:9: error: use of undefined value",
2246 );
2247
2248 cases.add(
2249 "negate on undefined value",
2250 \\comptime {
2251 \\ var a: i64 = undefined;
2252 \\ _ = -a;
2253 \\}
2254 ,
2255 ".tmp_source.zig:3:10: error: use of undefined value",
2256 );
2257
2258 cases.add(
2259 "negate wrap on undefined value",
2260 \\comptime {
2261 \\ var a: i64 = undefined;
2262 \\ _ = -%a;
2263 \\}
2264 ,
2265 ".tmp_source.zig:3:11: error: use of undefined value",
2266 );
2267
2268 cases.add(
2269 "bin not on undefined value",
2270 \\comptime {
2271 \\ var a: i64 = undefined;
2272 \\ _ = ~a;
2273 \\}
2274 ,
2275 ".tmp_source.zig:3:10: error: use of undefined value",
2276 );
2277
2278 cases.add(
2279 "bool not on undefined value",
2280 \\comptime {
2281 \\ var a: bool = undefined;
2282 \\ _ = !a;
2283 \\}
2284 ,
2285 ".tmp_source.zig:3:10: error: use of undefined value",
2286 );
2287
2288 cases.add(
2289 "orelse on undefined value",
2290 \\comptime {
2291 \\ var a: ?bool = undefined;
2292 \\ _ = a orelse false;
2293 \\}
2294 ,
2295 ".tmp_source.zig:3:11: error: use of undefined value",
2296 );
2297
2298 cases.add(
2299 "catch on undefined value",
2300 \\comptime {
2301 \\ var a: error!bool = undefined;
2302 \\ _ = a catch |err| false;
2303 \\}
2304 ,
2305 ".tmp_source.zig:3:11: error: use of undefined value",
2306 );
2307
2308 cases.add(
2309 "deref on undefined value",
2310 \\comptime {
2311 \\ var a: *u8 = undefined;
2312 \\ _ = a.*;
2313 \\}
2314 ,
2315 ".tmp_source.zig:3:9: error: use of undefined value",
2316 );
2317
18542318 cases.add(
18552319 "endless loop in function evaluation",
18562320 \\const seventh_fib_number = fibbonaci(7);
......@@ -2086,10 +2550,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
20862550 "convert fixed size array to slice with invalid size",
20872551 \\export fn f() void {
20882552 \\ var array: [5]u8 = undefined;
2089 \\ var foo = ([]const u32)(array)[0];
2553 \\ var foo = @bytesToSlice(u32, array)[0];
20902554 \\}
20912555 ,
2092 ".tmp_source.zig:3:28: error: unable to convert [5]u8 to []const u32: size mismatch",
2556 ".tmp_source.zig:3:15: error: unable to convert [5]u8 to []align(1) const u32: size mismatch",
2557 ".tmp_source.zig:3:29: note: u32 has size 4; remaining bytes: 1",
20932558 );
20942559
20952560 cases.add(
......@@ -2611,17 +3076,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
26113076 ".tmp_source.zig:2:21: error: expected pointer, found 'usize'",
26123077 );
26133078
2614 cases.add(
2615 "too many error values to cast to small integer",
2616 \\const Error = error { A, B, C, D, E, F, G, H };
2617 \\fn foo(e: Error) u2 {
2618 \\ return u2(e);
2619 \\}
2620 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
2621 ,
2622 ".tmp_source.zig:3:14: error: too many error values to fit in 'u2'",
2623 );
2624
26253079 cases.add(
26263080 "asm at compile time",
26273081 \\comptime {
......@@ -3239,18 +3693,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
32393693 ".tmp_source.zig:3:26: note: '*u32' has alignment 4",
32403694 );
32413695
3242 cases.add(
3243 "increase pointer alignment in slice resize",
3244 \\export fn entry() u32 {
3245 \\ var bytes = []u8{0x01, 0x02, 0x03, 0x04};
3246 \\ return ([]u32)(bytes[0..])[0];
3247 \\}
3248 ,
3249 ".tmp_source.zig:3:19: error: cast increases pointer alignment",
3250 ".tmp_source.zig:3:19: note: '[]u8' has alignment 1",
3251 ".tmp_source.zig:3:19: note: '[]u32' has alignment 4",
3252 );
3253
32543696 cases.add(
32553697 "@alignCast expects pointer or slice",
32563698 \\export fn entry() void {
......@@ -3722,22 +4164,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
37224164 ".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'",
37234165 );
37244166
3725 cases.add(
3726 "explicitly casting enum to non tag type",
3727 \\const Small = enum(u2) {
3728 \\ One,
3729 \\ Two,
3730 \\ Three,
3731 \\ Four,
3732 \\};
3733 \\
3734 \\export fn entry() void {
3735 \\ var x = u3(Small.Two);
3736 \\}
3737 ,
3738 ".tmp_source.zig:9:15: error: enum to integer cast to 'u3' instead of its tag type, 'u2'",
3739 );
3740
37414167 cases.add(
37424168 "explicitly casting non tag type to enum",
37434169 \\const Small = enum(u2) {
......@@ -3749,10 +4175,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
37494175 \\
37504176 \\export fn entry() void {
37514177 \\ var y = u3(3);
3752 \\ var x = Small(y);
4178 \\ var x = @intToEnum(Small, y);
37534179 \\}
37544180 ,
3755 ".tmp_source.zig:10:18: error: integer to enum cast from 'u3' instead of its tag type, 'u2'",
4181 ".tmp_source.zig:10:31: error: expected type 'u2', found 'u3'",
37564182 );
37574183
37584184 cases.add(
......@@ -4033,10 +4459,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
40334459 \\ B = 11,
40344460 \\};
40354461 \\export fn entry() void {
4036 \\ var x = Foo(0);
4462 \\ var x = @intToEnum(Foo, 0);
40374463 \\}
40384464 ,
4039 ".tmp_source.zig:6:16: error: enum 'Foo' has no tag matching integer value 0",
4465 ".tmp_source.zig:6:13: error: enum 'Foo' has no tag matching integer value 0",
40404466 ".tmp_source.zig:1:13: note: 'Foo' declared here",
40414467 );
40424468
test/runtime_safety.zig+64-7
......@@ -1,6 +1,63 @@
11const tests = @import("tests.zig");
22
33pub fn addCases(cases: *tests.CompareOutputContext) void {
4 cases.addRuntimeSafety("@intToEnum - no matching tag value",
5 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
6 \\ @import("std").os.exit(126);
7 \\}
8 \\const Foo = enum {
9 \\ A,
10 \\ B,
11 \\ C,
12 \\};
13 \\pub fn main() void {
14 \\ baz(bar(3));
15 \\}
16 \\fn bar(a: u2) Foo {
17 \\ return @intToEnum(Foo, a);
18 \\}
19 \\fn baz(a: Foo) void {}
20 );
21
22 cases.addRuntimeSafety("@floatToInt cannot fit - negative to unsigned",
23 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
24 \\ @import("std").os.exit(126);
25 \\}
26 \\pub fn main() void {
27 \\ baz(bar(-1.1));
28 \\}
29 \\fn bar(a: f32) u8 {
30 \\ return @floatToInt(u8, a);
31 \\}
32 \\fn baz(a: u8) void { }
33 );
34
35 cases.addRuntimeSafety("@floatToInt cannot fit - negative out of range",
36 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
37 \\ @import("std").os.exit(126);
38 \\}
39 \\pub fn main() void {
40 \\ baz(bar(-129.1));
41 \\}
42 \\fn bar(a: f32) i8 {
43 \\ return @floatToInt(i8, a);
44 \\}
45 \\fn baz(a: i8) void { }
46 );
47
48 cases.addRuntimeSafety("@floatToInt cannot fit - positive out of range",
49 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
50 \\ @import("std").os.exit(126);
51 \\}
52 \\pub fn main() void {
53 \\ baz(bar(256.2));
54 \\}
55 \\fn bar(a: f32) u8 {
56 \\ return @floatToInt(u8, a);
57 \\}
58 \\fn baz(a: u8) void { }
59 );
60
461 cases.addRuntimeSafety("calling panic",
562 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
663 \\ @import("std").os.exit(126);
......@@ -175,7 +232,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
175232 \\ if (x.len == 0) return error.Whatever;
176233 \\}
177234 \\fn widenSlice(slice: []align(1) const u8) []align(1) const i32 {
178 \\ return ([]align(1) const i32)(slice);
235 \\ return @bytesToSlice(i32, slice);
179236 \\}
180237 );
181238
......@@ -227,12 +284,12 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
227284 \\pub fn main() void {
228285 \\ _ = bar(9999);
229286 \\}
230 \\fn bar(x: u32) error {
231 \\ return error(x);
287 \\fn bar(x: u16) error {
288 \\ return @intToError(x);
232289 \\}
233290 );
234291
235 cases.addRuntimeSafety("cast integer to non-global error set and no match",
292 cases.addRuntimeSafety("@errSetCast error not present in destination",
236293 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
237294 \\ @import("std").os.exit(126);
238295 \\}
......@@ -242,7 +299,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
242299 \\ _ = foo(Set1.B);
243300 \\}
244301 \\fn foo(set1: Set1) Set2 {
245 \\ return Set2(set1);
302 \\ return @errSetCast(Set2, set1);
246303 \\}
247304 );
248305
......@@ -252,12 +309,12 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
252309 \\}
253310 \\pub fn main() !void {
254311 \\ var array align(4) = []u32{0x11111111, 0x11111111};
255 \\ const bytes = ([]u8)(array[0..]);
312 \\ const bytes = @sliceToBytes(array[0..]);
256313 \\ if (foo(bytes) != 0x11111111) return error.Wrong;
257314 \\}
258315 \\fn foo(bytes: []u8) u32 {
259316 \\ const slice4 = bytes[1..5];
260 \\ const int_slice = ([]u32)(@alignCast(4, slice4));
317 \\ const int_slice = @bytesToSlice(u32, @alignCast(4, slice4));
261318 \\ return int_slice[0];
262319 \\}
263320 );
test/tests.zig+37-45
......@@ -48,13 +48,12 @@ const test_targets = []TestTarget{
4848const max_stdout_size = 1 * 1024 * 1024; // 1 MB
4949
5050pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
51 const cases = b.allocator.create(CompareOutputContext) catch unreachable;
52 cases.* = CompareOutputContext{
51 const cases = b.allocator.create(CompareOutputContext{
5352 .b = b,
5453 .step = b.step("test-compare-output", "Run the compare output tests"),
5554 .test_index = 0,
5655 .test_filter = test_filter,
57 };
56 }) catch unreachable;
5857
5958 compare_output.addCases(cases);
6059
......@@ -62,13 +61,12 @@ pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8) *build
6261}
6362
6463pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
65 const cases = b.allocator.create(CompareOutputContext) catch unreachable;
66 cases.* = CompareOutputContext{
64 const cases = b.allocator.create(CompareOutputContext{
6765 .b = b,
6866 .step = b.step("test-runtime-safety", "Run the runtime safety tests"),
6967 .test_index = 0,
7068 .test_filter = test_filter,
71 };
69 }) catch unreachable;
7270
7371 runtime_safety.addCases(cases);
7472
......@@ -76,13 +74,12 @@ pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8) *build
7674}
7775
7876pub fn addCompileErrorTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
79 const cases = b.allocator.create(CompileErrorContext) catch unreachable;
80 cases.* = CompileErrorContext{
77 const cases = b.allocator.create(CompileErrorContext{
8178 .b = b,
8279 .step = b.step("test-compile-errors", "Run the compile error tests"),
8380 .test_index = 0,
8481 .test_filter = test_filter,
85 };
82 }) catch unreachable;
8683
8784 compile_errors.addCases(cases);
8885
......@@ -90,13 +87,12 @@ pub fn addCompileErrorTests(b: *build.Builder, test_filter: ?[]const u8) *build.
9087}
9188
9289pub fn addBuildExampleTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
93 const cases = b.allocator.create(BuildExamplesContext) catch unreachable;
94 cases.* = BuildExamplesContext{
90 const cases = b.allocator.create(BuildExamplesContext{
9591 .b = b,
9692 .step = b.step("test-build-examples", "Build the examples"),
9793 .test_index = 0,
9894 .test_filter = test_filter,
99 };
95 }) catch unreachable;
10096
10197 build_examples.addCases(cases);
10298
......@@ -104,13 +100,12 @@ pub fn addBuildExampleTests(b: *build.Builder, test_filter: ?[]const u8) *build.
104100}
105101
106102pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
107 const cases = b.allocator.create(CompareOutputContext) catch unreachable;
108 cases.* = CompareOutputContext{
103 const cases = b.allocator.create(CompareOutputContext{
109104 .b = b,
110105 .step = b.step("test-asm-link", "Run the assemble and link tests"),
111106 .test_index = 0,
112107 .test_filter = test_filter,
113 };
108 }) catch unreachable;
114109
115110 assemble_and_link.addCases(cases);
116111
......@@ -118,13 +113,12 @@ pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8) *bui
118113}
119114
120115pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
121 const cases = b.allocator.create(TranslateCContext) catch unreachable;
122 cases.* = TranslateCContext{
116 const cases = b.allocator.create(TranslateCContext{
123117 .b = b,
124118 .step = b.step("test-translate-c", "Run the C transation tests"),
125119 .test_index = 0,
126120 .test_filter = test_filter,
127 };
121 }) catch unreachable;
128122
129123 translate_c.addCases(cases);
130124
......@@ -132,13 +126,12 @@ pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.St
132126}
133127
134128pub fn addGenHTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
135 const cases = b.allocator.create(GenHContext) catch unreachable;
136 cases.* = GenHContext{
129 const cases = b.allocator.create(GenHContext{
137130 .b = b,
138131 .step = b.step("test-gen-h", "Run the C header file generation tests"),
139132 .test_index = 0,
140133 .test_filter = test_filter,
141 };
134 }) catch unreachable;
142135
143136 gen_h.addCases(cases);
144137
......@@ -240,8 +233,7 @@ pub const CompareOutputContext = struct {
240233
241234 pub fn create(context: *CompareOutputContext, exe_path: []const u8, name: []const u8, expected_output: []const u8, cli_args: []const []const u8) *RunCompareOutputStep {
242235 const allocator = context.b.allocator;
243 const ptr = allocator.create(RunCompareOutputStep) catch unreachable;
244 ptr.* = RunCompareOutputStep{
236 const ptr = allocator.create(RunCompareOutputStep{
245237 .context = context,
246238 .exe_path = exe_path,
247239 .name = name,
......@@ -249,7 +241,7 @@ pub const CompareOutputContext = struct {
249241 .test_index = context.test_index,
250242 .step = build.Step.init("RunCompareOutput", allocator, make),
251243 .cli_args = cli_args,
252 };
244 }) catch unreachable;
253245 context.test_index += 1;
254246 return ptr;
255247 }
......@@ -328,14 +320,14 @@ pub const CompareOutputContext = struct {
328320
329321 pub fn create(context: *CompareOutputContext, exe_path: []const u8, name: []const u8) *RuntimeSafetyRunStep {
330322 const allocator = context.b.allocator;
331 const ptr = allocator.create(RuntimeSafetyRunStep) catch unreachable;
332 ptr.* = RuntimeSafetyRunStep{
323 const ptr = allocator.create(RuntimeSafetyRunStep{
333324 .context = context,
334325 .exe_path = exe_path,
335326 .name = name,
336327 .test_index = context.test_index,
337328 .step = build.Step.init("RuntimeSafetyRun", allocator, make),
338 };
329 }) catch unreachable;
330
339331 context.test_index += 1;
340332 return ptr;
341333 }
......@@ -543,15 +535,15 @@ pub const CompileErrorContext = struct {
543535
544536 pub fn create(context: *CompileErrorContext, name: []const u8, case: *const TestCase, build_mode: Mode) *CompileCmpOutputStep {
545537 const allocator = context.b.allocator;
546 const ptr = allocator.create(CompileCmpOutputStep) catch unreachable;
547 ptr.* = CompileCmpOutputStep{
538 const ptr = allocator.create(CompileCmpOutputStep{
548539 .step = build.Step.init("CompileCmpOutput", allocator, make),
549540 .context = context,
550541 .name = name,
551542 .test_index = context.test_index,
552543 .case = case,
553544 .build_mode = build_mode,
554 };
545 }) catch unreachable;
546
555547 context.test_index += 1;
556548 return ptr;
557549 }
......@@ -662,14 +654,14 @@ pub const CompileErrorContext = struct {
662654 }
663655
664656 pub fn create(self: *CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) *TestCase {
665 const tc = self.b.allocator.create(TestCase) catch unreachable;
666 tc.* = TestCase{
657 const tc = self.b.allocator.create(TestCase{
667658 .name = name,
668659 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),
669660 .expected_errors = ArrayList([]const u8).init(self.b.allocator),
670661 .link_libc = false,
671662 .is_exe = false,
672 };
663 }) catch unreachable;
664
673665 tc.addSourceFile(".tmp_source.zig", source);
674666 comptime var arg_i = 0;
675667 inline while (arg_i < expected_lines.len) : (arg_i += 1) {
......@@ -829,14 +821,14 @@ pub const TranslateCContext = struct {
829821
830822 pub fn create(context: *TranslateCContext, name: []const u8, case: *const TestCase) *TranslateCCmpOutputStep {
831823 const allocator = context.b.allocator;
832 const ptr = allocator.create(TranslateCCmpOutputStep) catch unreachable;
833 ptr.* = TranslateCCmpOutputStep{
824 const ptr = allocator.create(TranslateCCmpOutputStep{
834825 .step = build.Step.init("ParseCCmpOutput", allocator, make),
835826 .context = context,
836827 .name = name,
837828 .test_index = context.test_index,
838829 .case = case,
839 };
830 }) catch unreachable;
831
840832 context.test_index += 1;
841833 return ptr;
842834 }
......@@ -936,13 +928,13 @@ pub const TranslateCContext = struct {
936928 }
937929
938930 pub fn create(self: *TranslateCContext, allow_warnings: bool, filename: []const u8, name: []const u8, source: []const u8, expected_lines: ...) *TestCase {
939 const tc = self.b.allocator.create(TestCase) catch unreachable;
940 tc.* = TestCase{
931 const tc = self.b.allocator.create(TestCase{
941932 .name = name,
942933 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),
943934 .expected_lines = ArrayList([]const u8).init(self.b.allocator),
944935 .allow_warnings = allow_warnings,
945 };
936 }) catch unreachable;
937
946938 tc.addSourceFile(filename, source);
947939 comptime var arg_i = 0;
948940 inline while (arg_i < expected_lines.len) : (arg_i += 1) {
......@@ -1023,15 +1015,15 @@ pub const GenHContext = struct {
10231015
10241016 pub fn create(context: *GenHContext, h_path: []const u8, name: []const u8, case: *const TestCase) *GenHCmpOutputStep {
10251017 const allocator = context.b.allocator;
1026 const ptr = allocator.create(GenHCmpOutputStep) catch unreachable;
1027 ptr.* = GenHCmpOutputStep{
1018 const ptr = allocator.create(GenHCmpOutputStep{
10281019 .step = build.Step.init("ParseCCmpOutput", allocator, make),
10291020 .context = context,
10301021 .h_path = h_path,
10311022 .name = name,
10321023 .test_index = context.test_index,
10331024 .case = case,
1034 };
1025 }) catch unreachable;
1026
10351027 context.test_index += 1;
10361028 return ptr;
10371029 }
......@@ -1070,12 +1062,12 @@ pub const GenHContext = struct {
10701062 }
10711063
10721064 pub fn create(self: *GenHContext, filename: []const u8, name: []const u8, source: []const u8, expected_lines: ...) *TestCase {
1073 const tc = self.b.allocator.create(TestCase) catch unreachable;
1074 tc.* = TestCase{
1065 const tc = self.b.allocator.create(TestCase{
10751066 .name = name,
10761067 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),
10771068 .expected_lines = ArrayList([]const u8).init(self.b.allocator),
1078 };
1069 }) catch unreachable;
1070
10791071 tc.addSourceFile(filename, source);
10801072 comptime var arg_i = 0;
10811073 inline while (arg_i < expected_lines.len) : (arg_i += 1) {