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 @@...@@ -1,3 +1,4 @@
1zig-cache/1zig-cache/
2build/2build/
3build-*/3build-*/
4docgen_tmp/
CMakeLists.txt+28-2
...@@ -22,7 +22,7 @@ set(ZIG_VERSION "${ZIG_VERSION_MAJOR}.${ZIG_VERSION_MINOR}.${ZIG_VERSION_PATCH}"...@@ -22,7 +22,7 @@ set(ZIG_VERSION "${ZIG_VERSION_MAJOR}.${ZIG_VERSION_MINOR}.${ZIG_VERSION_PATCH}"
22find_program(GIT_EXE NAMES git)22find_program(GIT_EXE NAMES git)
23if(GIT_EXE)23if(GIT_EXE)
24 execute_process(24 execute_process(
25 COMMAND ${GIT_EXE} name-rev HEAD --tags --name-only --no-undefined --always25 COMMAND ${GIT_EXE} -C ${CMAKE_SOURCE_DIR} name-rev HEAD --tags --name-only --no-undefined --always
26 OUTPUT_VARIABLE ZIG_GIT_REV26 OUTPUT_VARIABLE ZIG_GIT_REV
27 OUTPUT_STRIP_TRAILING_WHITESPACE)27 OUTPUT_STRIP_TRAILING_WHITESPACE)
28 if(ZIG_GIT_REV MATCHES "\\^0$")28 if(ZIG_GIT_REV MATCHES "\\^0$")
...@@ -261,12 +261,15 @@ endif()...@@ -261,12 +261,15 @@ endif()
261set(EMBEDDED_SOFTFLOAT_SOURCES261set(EMBEDDED_SOFTFLOAT_SOURCES
262 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c"262 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c"
263 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c"263 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c"
264 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF16UI.c"
264 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c"265 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF32UI.c"
265 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c"266 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_commonNaNToF64UI.c"
266 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c"267 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f128MToCommonNaN.c"
268 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f16UIToCommonNaN.c"
267 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c"269 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f32UIToCommonNaN.c"
268 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c"270 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_f64UIToCommonNaN.c"
269 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c"271 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNF128M.c"
272 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/s_propagateNaNF16UI.c"
270 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c"273 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/8086/softfloat_raiseFlags.c"
271 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_add.c"274 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_add.c"
272 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_div.c"275 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_div.c"
...@@ -293,8 +296,20 @@ set(EMBEDDED_SOFTFLOAT_SOURCES...@@ -293,8 +296,20 @@ set(EMBEDDED_SOFTFLOAT_SOURCES
293 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c"296 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui32_r_minMag.c"
294 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui64.c"297 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui64.c"
295 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_to_ui64_r_minMag.c"298 "${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"
296 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f32_to_f128M.c"310 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f32_to_f128M.c"
297 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_f128M.c"311 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_f128M.c"
312 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f64_to_f16.c"
298 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_add256M.c"313 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_add256M.c"
299 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addCarryM.c"314 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addCarryM.c"
300 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addComplCarryM.c"315 "${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_addComplCarryM.c"
...@@ -416,7 +431,8 @@ set(ZIG_CPP_SOURCES...@@ -416,7 +431,8 @@ set(ZIG_CPP_SOURCES
416set(ZIG_STD_FILES431set(ZIG_STD_FILES
417 "array_list.zig"432 "array_list.zig"
418 "atomic/index.zig"433 "atomic/index.zig"
419 "atomic/queue.zig"434 "atomic/queue_mpmc.zig"
435 "atomic/queue_mpsc.zig"
420 "atomic/stack.zig"436 "atomic/stack.zig"
421 "base64.zig"437 "base64.zig"
422 "buf_map.zig"438 "buf_map.zig"
...@@ -558,6 +574,7 @@ set(ZIG_STD_FILES...@@ -558,6 +574,7 @@ set(ZIG_STD_FILES
558 "special/compiler_rt/aullrem.zig"574 "special/compiler_rt/aullrem.zig"
559 "special/compiler_rt/comparetf2.zig"575 "special/compiler_rt/comparetf2.zig"
560 "special/compiler_rt/divti3.zig"576 "special/compiler_rt/divti3.zig"
577 "special/compiler_rt/extendXfYf2.zig"
561 "special/compiler_rt/fixuint.zig"578 "special/compiler_rt/fixuint.zig"
562 "special/compiler_rt/fixunsdfdi.zig"579 "special/compiler_rt/fixunsdfdi.zig"
563 "special/compiler_rt/fixunsdfsi.zig"580 "special/compiler_rt/fixunsdfsi.zig"
...@@ -568,8 +585,17 @@ set(ZIG_STD_FILES...@@ -568,8 +585,17 @@ set(ZIG_STD_FILES
568 "special/compiler_rt/fixunstfdi.zig"585 "special/compiler_rt/fixunstfdi.zig"
569 "special/compiler_rt/fixunstfsi.zig"586 "special/compiler_rt/fixunstfsi.zig"
570 "special/compiler_rt/fixunstfti.zig"587 "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"
571 "special/compiler_rt/muloti4.zig"596 "special/compiler_rt/muloti4.zig"
572 "special/compiler_rt/index.zig"597 "special/compiler_rt/index.zig"
598 "special/compiler_rt/truncXfYf2.zig"
573 "special/compiler_rt/udivmod.zig"599 "special/compiler_rt/udivmod.zig"
574 "special/compiler_rt/udivmoddi4.zig"600 "special/compiler_rt/udivmoddi4.zig"
575 "special/compiler_rt/udivmodti4.zig"601 "special/compiler_rt/udivmodti4.zig"
doc/langref.html.in+573-92
...@@ -367,6 +367,11 @@ pub fn main() void {...@@ -367,6 +367,11 @@ pub fn main() void {
367 <td>for ABI compatibility with C</td>367 <td>for ABI compatibility with C</td>
368 </tr>368 </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>
370 <tr>375 <tr>
371 <td><code>f32</code></td>376 <td><code>f32</code></td>
372 <td><code>float</code></td>377 <td><code>float</code></td>
...@@ -654,6 +659,7 @@ fn divide(a: i32, b: i32) i32 {...@@ -654,6 +659,7 @@ fn divide(a: i32, b: i32) i32 {
654 {#header_open|Floats#}659 {#header_open|Floats#}
655 <p>Zig has the following floating point types:</p>660 <p>Zig has the following floating point types:</p>
656 <ul>661 <ul>
662 <li><code>f16</code> - IEEE-754-2008 binary16</li>
657 <li><code>f32</code> - IEEE-754-2008 binary32</li>663 <li><code>f32</code> - IEEE-754-2008 binary32</li>
658 <li><code>f64</code> - IEEE-754-2008 binary64</li>664 <li><code>f64</code> - IEEE-754-2008 binary64</li>
659 <li><code>f128</code> - IEEE-754-2008 binary128</li>665 <li><code>f128</code> - IEEE-754-2008 binary128</li>
...@@ -1456,8 +1462,7 @@ test "pointer array access" {...@@ -1456,8 +1462,7 @@ test "pointer array access" {
1456 // Taking an address of an individual element gives a1462 // Taking an address of an individual element gives a
1457 // pointer to a single item. This kind of pointer1463 // pointer to a single item. This kind of pointer
1458 // does not support pointer arithmetic.1464 // does not support pointer arithmetic.
14591465 var array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
1460 var array = []u8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1461 const ptr = &array[2];1466 const ptr = &array[2];
1462 assert(@typeOf(ptr) == *u8);1467 assert(@typeOf(ptr) == *u8);
14631468
...@@ -1469,7 +1474,7 @@ test "pointer array access" {...@@ -1469,7 +1474,7 @@ test "pointer array access" {
1469test "pointer slicing" {1474test "pointer slicing" {
1470 // In Zig, we prefer using slices over null-terminated pointers.1475 // In Zig, we prefer using slices over null-terminated pointers.
1471 // You can turn an array into a slice using slice syntax:1476 // 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 };
1473 const slice = array[2..4];1478 const slice = array[2..4];
1474 assert(slice.len == 2);1479 assert(slice.len == 2);
14751480
...@@ -1541,13 +1546,13 @@ test "pointer casting" {...@@ -1541,13 +1546,13 @@ test "pointer casting" {
1541 // To convert one pointer type to another, use @ptrCast. This is an unsafe1546 // To convert one pointer type to another, use @ptrCast. This is an unsafe
1542 // operation that Zig cannot protect you against. Use @ptrCast only when other1547 // operation that Zig cannot protect you against. Use @ptrCast only when other
1543 // conversions are not possible.1548 // 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 };
1545 const u32_ptr = @ptrCast(*const u32, &bytes[0]);1550 const u32_ptr = @ptrCast(*const u32, &bytes[0]);
1546 assert(u32_ptr.* == 0x12121212);1551 assert(u32_ptr.* == 0x12121212);
15471552
1548 // Even this example is contrived - there are better ways to do the above than1553 // Even this example is contrived - there are better ways to do the above than
1549 // pointer casting. For example, using a slice narrowing cast:1554 // 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];
1551 assert(u32_value == 0x12121212);1556 assert(u32_value == 0x12121212);
15521557
1553 // And even another way, the most straightforward way to do it:1558 // And even another way, the most straightforward way to do it:
...@@ -1630,13 +1635,13 @@ test "function alignment" {...@@ -1630,13 +1635,13 @@ test "function alignment" {
1630const assert = @import("std").debug.assert;1635const assert = @import("std").debug.assert;
16311636
1632test "pointer alignment safety" {1637test "pointer alignment safety" {
1633 var array align(4) = []u32{0x11111111, 0x11111111};1638 var array align(4) = []u32{ 0x11111111, 0x11111111 };
1634 const bytes = ([]u8)(array[0..]);1639 const bytes = @sliceToBytes(array[0..]);
1635 assert(foo(bytes) == 0x11111111);1640 assert(foo(bytes) == 0x11111111);
1636}1641}
1637fn foo(bytes: []u8) u32 {1642fn foo(bytes: []u8) u32 {
1638 const slice4 = bytes[1..5];1643 const slice4 = bytes[1..5];
1639 const int_slice = ([]u32)(@alignCast(4, slice4));1644 const int_slice = @bytesToSlice(u32, @alignCast(4, slice4));
1640 return int_slice[0];1645 return int_slice[0];
1641}1646}
1642 {#code_end#}1647 {#code_end#}
...@@ -1728,8 +1733,8 @@ test "slice pointer" {...@@ -1728,8 +1733,8 @@ test "slice pointer" {
1728test "slice widening" {1733test "slice widening" {
1729 // Zig supports slice widening and slice narrowing. Cast a slice of u81734 // Zig supports slice widening and slice narrowing. Cast a slice of u8
1730 // to a slice of anything else, and Zig will perform the length conversion.1735 // 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};1736 const array align(@alignOf(u32)) = []u8{ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13 };
1732 const slice = ([]const u32)(array[0..]);1737 const slice = @bytesToSlice(u32, array[0..]);
1733 assert(slice.len == 2);1738 assert(slice.len == 2);
1734 assert(slice[0] == 0x12121212);1739 assert(slice[0] == 0x12121212);
1735 assert(slice[1] == 0x13131313);1740 assert(slice[1] == 0x13131313);
...@@ -1901,9 +1906,9 @@ const Value = enum(u2) {...@@ -1901,9 +1906,9 @@ const Value = enum(u2) {
1901// Now you can cast between u2 and Value.1906// Now you can cast between u2 and Value.
1902// The ordinal value starts from 0, counting up for each member.1907// The ordinal value starts from 0, counting up for each member.
1903test "enum ordinal value" {1908test "enum ordinal value" {
1904 assert(u2(Value.Zero) == 0);1909 assert(@enumToInt(Value.Zero) == 0);
1905 assert(u2(Value.One) == 1);1910 assert(@enumToInt(Value.One) == 1);
1906 assert(u2(Value.Two) == 2);1911 assert(@enumToInt(Value.Two) == 2);
1907}1912}
19081913
1909// You can override the ordinal value for an enum.1914// You can override the ordinal value for an enum.
...@@ -1913,9 +1918,9 @@ const Value2 = enum(u32) {...@@ -1913,9 +1918,9 @@ const Value2 = enum(u32) {
1913 Million = 1000000,1918 Million = 1000000,
1914};1919};
1915test "set enum ordinal value" {1920test "set enum ordinal value" {
1916 assert(u32(Value2.Hundred) == 100);1921 assert(@enumToInt(Value2.Hundred) == 100);
1917 assert(u32(Value2.Thousand) == 1000);1922 assert(@enumToInt(Value2.Thousand) == 1000);
1918 assert(u32(Value2.Million) == 1000000);1923 assert(@enumToInt(Value2.Million) == 1000000);
1919}1924}
19201925
1921// Enums can have methods, the same as structs and unions.1926// Enums can have methods, the same as structs and unions.
...@@ -2356,11 +2361,18 @@ fn eventuallyErrorSequence() error!u32 {...@@ -2356,11 +2361,18 @@ fn eventuallyErrorSequence() error!u32 {
2356 break :blk numbers_left;2361 break :blk numbers_left;
2357 };2362 };
2358}2363}
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
2360test "inline while loop" {2375test "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.
2364 comptime var i = 0;2376 comptime var i = 0;
2365 var sum: usize = 0;2377 var sum: usize = 0;
2366 inline while (i < 3) : (i += 1) {2378 inline while (i < 3) : (i += 1) {
...@@ -2379,6 +2391,16 @@ fn typeNameLength(comptime T: type) usize {...@@ -2379,6 +2391,16 @@ fn typeNameLength(comptime T: type) usize {
2379 return @typeName(T).len;2391 return @typeName(T).len;
2380}2392}
2381 {#code_end#}2393 {#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#}
2382 {#see_also|if|Optionals|Errors|comptime|unreachable#}2404 {#see_also|if|Optionals|Errors|comptime|unreachable#}
2383 {#header_close#}2405 {#header_close#}
2384 {#header_open|for#}2406 {#header_open|for#}
...@@ -2446,15 +2468,20 @@ test "for else" {...@@ -2446,15 +2468,20 @@ test "for else" {
2446 break :blk sum;2468 break :blk sum;
2447 };2469 };
2448}2470}
24492471 {#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
2451test "inline for loop" {2483test "inline for loop" {
2452 const nums = []i32{2, 4, 6};2484 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.
2458 var sum: usize = 0;2485 var sum: usize = 0;
2459 inline for (nums) |i| {2486 inline for (nums) |i| {
2460 const T = switch (i) {2487 const T = switch (i) {
...@@ -2472,6 +2499,16 @@ fn typeNameLength(comptime T: type) usize {...@@ -2472,6 +2499,16 @@ fn typeNameLength(comptime T: type) usize {
2472 return @typeName(T).len;2499 return @typeName(T).len;
2473}2500}
2474 {#code_end#}2501 {#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#}
2475 {#see_also|while|comptime|Arrays|Slices#}2512 {#see_also|while|comptime|Arrays|Slices#}
2476 {#header_close#}2513 {#header_close#}
2477 {#header_open|if#}2514 {#header_open|if#}
...@@ -3542,14 +3579,191 @@ const optional_value: ?i32 = null;...@@ -3542,14 +3579,191 @@ const optional_value: ?i32 = null;
3542 {#header_close#}3579 {#header_close#}
3543 {#header_close#}3580 {#header_close#}
3544 {#header_open|Casting#}3581 {#header_open|Casting#}
3545 <p>TODO: explain implicit vs explicit casting</p>3582 <p>
3546 <p>TODO: resolve peer types builtin</p>3583 A <strong>type cast</strong> converts a value of one type to another.
3547 <p>TODO: truncate builtin</p>3584 Zig has {#link|Implicit Casts#} for conversions that are known to be completely safe and unambiguous,
3548 <p>TODO: bitcast builtin</p>3585 and {#link|Explicit Casts#} for conversions that one would not want to happen on accident.
3549 <p>TODO: int to ptr builtin</p>3586 There is also a third kind of type conversion called {#link|Peer Type Resolution#} for
3550 <p>TODO: ptr to int builtin</p>3587 the case when a result type must be decided given multiple operand types.
3551 <p>TODO: ptrcast builtin</p>3588 </p>
3552 <p>TODO: explain number literals vs concrete types</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#}
3553 {#header_close#}3767 {#header_close#}
35543768
3555 {#header_open|void#}3769 {#header_open|void#}
...@@ -4223,13 +4437,8 @@ pub fn main() void {...@@ -4223,13 +4437,8 @@ pub fn main() void {
4223 task in userland. It does so without introducing another language on top of Zig, such as4437 task in userland. It does so without introducing another language on top of Zig, such as
4224 a macro language or a preprocessor language. It's Zig all the way down.4438 a macro language or a preprocessor language. It's Zig all the way down.
4225 </p>4439 </p>
4226 <p>TODO: suggestion to not use inline unless necessary</p>
4227 {#header_close#}
4228 {#header_close#}4440 {#header_close#}
4229 {#header_open|inline#}4441 {#see_also|inline while|inline for#}
4230 <p>TODO: inline while</p>
4231 <p>TODO: inline for</p>
4232 <p>TODO: suggestion to not use inline unless necessary</p>
4233 {#header_close#}4442 {#header_close#}
4234 {#header_open|Assembly#}4443 {#header_open|Assembly#}
4235 <p>TODO: example of inline assembly</p>4444 <p>TODO: example of inline assembly</p>
...@@ -4651,6 +4860,18 @@ comptime {...@@ -4651,6 +4860,18 @@ comptime {
4651 </p>4860 </p>
4652 {#header_close#}4861 {#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
4654 {#header_open|@cDefine#}4875 {#header_open|@cDefine#}
4655 <pre><code class="zig">@cDefine(comptime name: []u8, value)</code></pre>4876 <pre><code class="zig">@cDefine(comptime name: []u8, value)</code></pre>
4656 <p>4877 <p>
...@@ -4919,12 +5140,23 @@ test "main" {...@@ -4919,12 +5140,23 @@ test "main" {
4919 </p>5140 </p>
4920 {#see_also|@import#}5141 {#see_also|@import#}
4921 {#header_close#}5142 {#header_close#}
4922 {#header_open|@export#}5143
4923 <pre><code class="zig">@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) []const u8</code></pre>5144 {#header_open|@enumToInt#}
5145 <pre><code class="zig">@enumToInt(enum_value: var) var</code></pre>
4924 <p>5146 <p>
4925 Creates a symbol in the output object file.5147 Converts an enumeration value into its integer tag type.
4926 </p>5148 </p>
5149 {#see_also|@intToEnum#}
4927 {#header_close#}5150 {#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
4928 {#header_open|@errorName#}5160 {#header_open|@errorName#}
4929 <pre><code class="zig">@errorName(err: error) []u8</code></pre>5161 <pre><code class="zig">@errorName(err: error) []u8</code></pre>
4930 <p>5162 <p>
...@@ -4941,6 +5173,7 @@ test "main" {...@@ -4941,6 +5173,7 @@ test "main" {
4941 error name table will be generated.5173 error name table will be generated.
4942 </p>5174 </p>
4943 {#header_close#}5175 {#header_close#}
5176
4944 {#header_open|@errorReturnTrace#}5177 {#header_open|@errorReturnTrace#}
4945 <pre><code class="zig">@errorReturnTrace() ?*builtin.StackTrace</code></pre>5178 <pre><code class="zig">@errorReturnTrace() ?*builtin.StackTrace</code></pre>
4946 <p>5179 <p>
...@@ -4949,6 +5182,33 @@ test "main" {...@@ -4949,6 +5182,33 @@ test "main" {
4949 stack trace object. Otherwise returns `null`.5182 stack trace object. Otherwise returns `null`.
4950 </p>5183 </p>
4951 {#header_close#}5184 {#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
4952 {#header_open|@fence#}5212 {#header_open|@fence#}
4953 <pre><code class="zig">@fence(order: AtomicOrder)</code></pre>5213 <pre><code class="zig">@fence(order: AtomicOrder)</code></pre>
4954 <p>5214 <p>
...@@ -4985,8 +5245,12 @@ test "main" {...@@ -4985,8 +5245,12 @@ test "main" {
4985 <pre><code class="zig">@floatToInt(comptime DestType: type, float: var) DestType</code></pre>5245 <pre><code class="zig">@floatToInt(comptime DestType: type, float: var) DestType</code></pre>
4986 <p>5246 <p>
4987 Converts the integer part of a floating point number to the destination type.5247 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.
4989 </p>5248 </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#}
4990 {#header_close#}5254 {#header_close#}
49915255
4992 {#header_open|@frameAddress#}5256 {#header_open|@frameAddress#}
...@@ -5049,8 +5313,36 @@ fn add(a: i32, b: i32) i32 { return a + b; }...@@ -5049,8 +5313,36 @@ fn add(a: i32, b: i32) i32 { return a + b; }
5049 <p>5313 <p>
5050 Converts an integer to another integer while keeping the same numerical value.5314 Converts an integer to another integer while keeping the same numerical value.
5051 Attempting to convert a number which is out of range of the destination type results in5315 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#}.
5053 </p>5328 </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#}
5054 {#header_close#}5346 {#header_close#}
50555347
5056 {#header_open|@intToFloat#}5348 {#header_open|@intToFloat#}
...@@ -5413,12 +5705,6 @@ pub const FloatMode = enum {...@@ -5413,12 +5705,6 @@ pub const FloatMode = enum {
5413 </p>5705 </p>
5414 {#see_also|Compile Variables#}5706 {#see_also|Compile Variables#}
5415 {#header_close#}5707 {#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#}
5422 {#header_open|@shlExact#}5708 {#header_open|@shlExact#}
5423 <pre><code class="zig">@shlExact(value: T, shift_amt: Log2T) T</code></pre>5709 <pre><code class="zig">@shlExact(value: T, shift_amt: Log2T) T</code></pre>
5424 <p>5710 <p>
...@@ -5456,8 +5742,9 @@ pub const FloatMode = enum {...@@ -5456,8 +5742,9 @@ pub const FloatMode = enum {
5456 </p>5742 </p>
5457 {#see_also|@shlExact|@shlWithOverflow#}5743 {#see_also|@shlExact|@shlWithOverflow#}
5458 {#header_close#}5744 {#header_close#}
5745
5459 {#header_open|@sizeOf#}5746 {#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>
5461 <p>5748 <p>
5462 This function returns the number of bytes it takes to store <code>T</code> in memory.5749 This function returns the number of bytes it takes to store <code>T</code> in memory.
5463 </p>5750 </p>
...@@ -5465,6 +5752,15 @@ pub const FloatMode = enum {...@@ -5465,6 +5752,15 @@ pub const FloatMode = enum {
5465 The result is a target-specific compile time constant.5752 The result is a target-specific compile time constant.
5466 </p>5753 </p>
5467 {#header_close#}5754 {#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
5468 {#header_open|@sqrt#}5764 {#header_open|@sqrt#}
5469 <pre><code class="zig">@sqrt(comptime T: type, value: T) T</code></pre>5765 <pre><code class="zig">@sqrt(comptime T: type, value: T) T</code></pre>
5470 <p>5766 <p>
...@@ -5600,10 +5896,17 @@ pub const TypeInfo = union(TypeId) {...@@ -5600,10 +5896,17 @@ pub const TypeInfo = union(TypeId) {
5600 };5896 };
56015897
5602 pub const Pointer = struct {5898 pub const Pointer = struct {
5899 size: Size,
5603 is_const: bool,5900 is_const: bool,
5604 is_volatile: bool,5901 is_volatile: bool,
5605 alignment: u32,5902 alignment: u32,
5606 child: type,5903 child: type,
5904
5905 pub const Size = enum {
5906 One,
5907 Many,
5908 Slice,
5909 };
5607 };5910 };
56085911
5609 pub const Array = struct {5912 pub const Array = struct {
...@@ -5667,7 +5970,7 @@ pub const TypeInfo = union(TypeId) {...@@ -5667,7 +5970,7 @@ pub const TypeInfo = union(TypeId) {
56675970
5668 pub const Union = struct {5971 pub const Union = struct {
5669 layout: ContainerLayout,5972 layout: ContainerLayout,
5670 tag_type: type,5973 tag_type: ?type,
5671 fields: []UnionField,5974 fields: []UnionField,
5672 defs: []Definition,5975 defs: []Definition,
5673 };5976 };
...@@ -5684,20 +5987,20 @@ pub const TypeInfo = union(TypeId) {...@@ -5684,20 +5987,20 @@ pub const TypeInfo = union(TypeId) {
5684 pub const FnArg = struct {5987 pub const FnArg = struct {
5685 is_generic: bool,5988 is_generic: bool,
5686 is_noalias: bool,5989 is_noalias: bool,
5687 arg_type: type,5990 arg_type: ?type,
5688 };5991 };
56895992
5690 pub const Fn = struct {5993 pub const Fn = struct {
5691 calling_convention: CallingConvention,5994 calling_convention: CallingConvention,
5692 is_generic: bool,5995 is_generic: bool,
5693 is_var_args: bool,5996 is_var_args: bool,
5694 return_type: type,5997 return_type: ?type,
5695 async_allocator_type: type,5998 async_allocator_type: ?type,
5696 args: []FnArg,5999 args: []FnArg,
5697 };6000 };
56986001
5699 pub const Promise = struct {6002 pub const Promise = struct {
5700 child: type,6003 child: ?type,
5701 };6004 };
57026005
5703 pub const Definition = struct {6006 pub const Definition = struct {
...@@ -5764,7 +6067,7 @@ pub const TypeInfo = union(TypeId) {...@@ -5764,7 +6067,7 @@ pub const TypeInfo = union(TypeId) {
5764 {#code_begin|syntax#}6067 {#code_begin|syntax#}
5765const Builder = @import("std").build.Builder;6068const Builder = @import("std").build.Builder;
57666069
5767pub fn build(b: &Builder) void {6070pub fn build(b: *Builder) void {
5768 const exe = b.addExecutable("example", "example.zig");6071 const exe = b.addExecutable("example", "example.zig");
5769 exe.setBuildMode(b.standardReleaseOptions());6072 exe.setBuildMode(b.standardReleaseOptions());
5770 b.default_step.dependOn(&exe.step);6073 b.default_step.dependOn(&exe.step);
...@@ -5817,10 +6120,10 @@ pub fn build(b: &Builder) void {...@@ -5817,10 +6120,10 @@ pub fn build(b: &Builder) void {
5817 {#header_open|Undefined Behavior#}6120 {#header_open|Undefined Behavior#}
5818 <p>6121 <p>
5819 Zig has many instances of undefined behavior. If undefined behavior is6122 Zig has many instances of undefined behavior. If undefined behavior is
5820 detected at compile-time, Zig emits an error. Most undefined behavior that6123 detected at compile-time, Zig emits a compile error and refuses to continue.
5821 cannot be detected at compile-time can be detected at runtime. In these cases,6124 Most undefined behavior that cannot be detected at compile-time can be detected
5822 Zig has safety checks. Safety checks can be disabled on a per-block basis6125 at runtime. In these cases, Zig has safety checks. Safety checks can be disabled
5823 with {#link|setRuntimeSafety#}. The {#link|ReleaseFast#}6126 on a per-block basis with {#link|setRuntimeSafety#}. The {#link|ReleaseFast#}
5824 build mode disables all safety checks in order to facilitate optimizations.6127 build mode disables all safety checks in order to facilitate optimizations.
5825 </p>6128 </p>
5826 <p>6129 <p>
...@@ -5841,7 +6144,14 @@ fn assert(ok: bool) void {...@@ -5841,7 +6144,14 @@ fn assert(ok: bool) void {
5841 if (!ok) unreachable; // assertion failure6144 if (!ok) unreachable; // assertion failure
5842}6145}
5843 {#code_end#}6146 {#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#}
5845 {#header_close#}6155 {#header_close#}
5846 {#header_open|Index out of Bounds#}6156 {#header_open|Index out of Bounds#}
5847 <p>At compile-time:</p>6157 <p>At compile-time:</p>
...@@ -5851,7 +6161,16 @@ comptime {...@@ -5851,7 +6161,16 @@ comptime {
5851 const garbage = array[5];6161 const garbage = array[5];
5852}6162}
5853 {#code_end#}6163 {#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#}
5855 {#header_close#}6174 {#header_close#}
5856 {#header_open|Cast Negative Number to Unsigned Integer#}6175 {#header_open|Cast Negative Number to Unsigned Integer#}
5857 <p>At compile-time:</p>6176 <p>At compile-time:</p>
...@@ -5861,10 +6180,18 @@ comptime {...@@ -5861,10 +6180,18 @@ comptime {
5861 const unsigned = @intCast(u32, value);6180 const unsigned = @intCast(u32, value);
5862}6181}
5863 {#code_end#}6182 {#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#}
5865 <p>6193 <p>
5866 If you are trying to obtain the maximum value of an unsigned integer, use <code>@maxValue(T)</code>,6194 To obtain the maximum value of an unsigned integer, use {#link|@maxValue#}.
5867 where <code>T</code> is the integer type, such as <code>u32</code>.
5868 </p>6195 </p>
5869 {#header_close#}6196 {#header_close#}
5870 {#header_open|Cast Truncates Data#}6197 {#header_open|Cast Truncates Data#}
...@@ -5875,11 +6202,18 @@ comptime {...@@ -5875,11 +6202,18 @@ comptime {
5875 const byte = @intCast(u8, spartan_count);6202 const byte = @intCast(u8, spartan_count);
5876}6203}
5877 {#code_end#}6204 {#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#}
5879 <p>6215 <p>
5880 If you are trying to truncate bits, use <code>@truncate(T, value)</code>,6216 To truncate bits, use {#link|@truncate#}.
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.
5883 </p>6217 </p>
5884 {#header_close#}6218 {#header_close#}
5885 {#header_open|Integer Overflow#}6219 {#header_open|Integer Overflow#}
...@@ -5891,9 +6225,9 @@ comptime {...@@ -5891,9 +6225,9 @@ comptime {
5891 <li><code>-</code> (negation)</li>6225 <li><code>-</code> (negation)</li>
5892 <li><code>*</code> (multiplication)</li>6226 <li><code>*</code> (multiplication)</li>
5893 <li><code>/</code> (division)</li>6227 <li><code>/</code> (division)</li>
5894 <li><code>@divTrunc</code> (division)</li>6228 <li>{#link|@divTrunc#} (division)</li>
5895 <li><code>@divFloor</code> (division)</li>6229 <li>{#link|@divFloor#} (division)</li>
5896 <li><code>@divExact</code> (division)</li>6230 <li>{#link|@divExact#} (division)</li>
5897 </ul>6231 </ul>
5898 <p>Example with addition at compile-time:</p>6232 <p>Example with addition at compile-time:</p>
5899 {#code_begin|test_err|operation caused overflow#}6233 {#code_begin|test_err|operation caused overflow#}
...@@ -5902,7 +6236,16 @@ comptime {...@@ -5902,7 +6236,16 @@ comptime {
5902 byte += 1;6236 byte += 1;
5903}6237}
5904 {#code_end#}6238 {#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#}
5906 {#header_close#}6249 {#header_close#}
5907 {#header_open|Standard Library Math Functions#}6250 {#header_open|Standard Library Math Functions#}
5908 <p>These functions provided by the standard library return possible errors.</p>6251 <p>These functions provided by the standard library return possible errors.</p>
...@@ -5937,13 +6280,13 @@ pub fn main() !void {...@@ -5937,13 +6280,13 @@ pub fn main() !void {
5937 occurred, as well as returning the overflowed bits:6280 occurred, as well as returning the overflowed bits:
5938 </p>6281 </p>
5939 <ul>6282 <ul>
5940 <li><code>@addWithOverflow</code></li>6283 <li>{#link|@addWithOverflow#}</li>
5941 <li><code>@subWithOverflow</code></li>6284 <li>{#link|@subWithOverflow#}</li>
5942 <li><code>@mulWithOverflow</code></li>6285 <li>{#link|@mulWithOverflow#}</li>
5943 <li><code>@shlWithOverflow</code></li>6286 <li>{#link|@shlWithOverflow#}</li>
5944 </ul>6287 </ul>
5945 <p>6288 <p>
5946 Example of <code>@addWithOverflow</code>:6289 Example of {#link|@addWithOverflow#}:
5947 </p>6290 </p>
5948 {#code_begin|exe#}6291 {#code_begin|exe#}
5949const warn = @import("std").debug.warn;6292const warn = @import("std").debug.warn;
...@@ -5989,7 +6332,16 @@ comptime {...@@ -5989,7 +6332,16 @@ comptime {
5989 const x = @shlExact(u8(0b01010101), 2);6332 const x = @shlExact(u8(0b01010101), 2);
5990}6333}
5991 {#code_end#}6334 {#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#}
5993 {#header_close#}6345 {#header_close#}
5994 {#header_open|Exact Right Shift Overflow#}6346 {#header_open|Exact Right Shift Overflow#}
5995 <p>At compile-time:</p>6347 <p>At compile-time:</p>
...@@ -5998,7 +6350,16 @@ comptime {...@@ -5998,7 +6350,16 @@ comptime {
5998 const x = @shrExact(u8(0b10101010), 2);6350 const x = @shrExact(u8(0b10101010), 2);
5999}6351}
6000 {#code_end#}6352 {#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#}
6002 {#header_close#}6363 {#header_close#}
6003 {#header_open|Division by Zero#}6364 {#header_open|Division by Zero#}
6004 <p>At compile-time:</p>6365 <p>At compile-time:</p>
...@@ -6009,8 +6370,17 @@ comptime {...@@ -6009,8 +6370,17 @@ comptime {
6009 const c = a / b;6370 const c = a / b;
6010}6371}
6011 {#code_end#}6372 {#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#}
6014 {#header_close#}6384 {#header_close#}
6015 {#header_open|Remainder Division by Zero#}6385 {#header_open|Remainder Division by Zero#}
6016 <p>At compile-time:</p>6386 <p>At compile-time:</p>
...@@ -6021,14 +6391,57 @@ comptime {...@@ -6021,14 +6391,57 @@ comptime {
6021 const c = a % b;6391 const c = a % b;
6022}6392}
6023 {#code_end#}6393 {#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#}
6026 {#header_close#}6405 {#header_close#}
6027 {#header_open|Exact Division Remainder#}6406 {#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#}
6029 {#header_close#}6426 {#header_close#}
6030 {#header_open|Slice Widen Remainder#}6427 {#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#}
6032 {#header_close#}6445 {#header_close#}
6033 {#header_open|Attempt to Unwrap Null#}6446 {#header_open|Attempt to Unwrap Null#}
6034 <p>At compile-time:</p>6447 <p>At compile-time:</p>
...@@ -6038,7 +6451,16 @@ comptime {...@@ -6038,7 +6451,16 @@ comptime {
6038 const number = optional_number.?;6451 const number = optional_number.?;
6039}6452}
6040 {#code_end#}6453 {#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#}
6042 <p>One way to avoid this crash is to test for null instead of assuming non-null, with6464 <p>One way to avoid this crash is to test for null instead of assuming non-null, with
6043 the <code>if</code> expression:</p>6465 the <code>if</code> expression:</p>
6044 {#code_begin|exe|test#}6466 {#code_begin|exe|test#}
...@@ -6053,6 +6475,7 @@ pub fn main() void {...@@ -6053,6 +6475,7 @@ pub fn main() void {
6053 }6475 }
6054}6476}
6055 {#code_end#}6477 {#code_end#}
6478 {#see_also|Optionals#}
6056 {#header_close#}6479 {#header_close#}
6057 {#header_open|Attempt to Unwrap Error#}6480 {#header_open|Attempt to Unwrap Error#}
6058 <p>At compile-time:</p>6481 <p>At compile-time:</p>
...@@ -6065,7 +6488,19 @@ fn getNumberOrFail() !i32 {...@@ -6065,7 +6488,19 @@ fn getNumberOrFail() !i32 {
6065 return error.UnableToReturnNumber;6488 return error.UnableToReturnNumber;
6066}6489}
6067 {#code_end#}6490 {#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#}
6069 <p>One way to avoid this crash is to test for an error instead of assuming a successful result, with6504 <p>One way to avoid this crash is to test for an error instead of assuming a successful result, with
6070 the <code>if</code> expression:</p>6505 the <code>if</code> expression:</p>
6071 {#code_begin|exe#}6506 {#code_begin|exe#}
...@@ -6085,30 +6520,76 @@ fn getNumberOrFail() !i32 {...@@ -6085,30 +6520,76 @@ fn getNumberOrFail() !i32 {
6085 return error.UnableToReturnNumber;6520 return error.UnableToReturnNumber;
6086}6521}
6087 {#code_end#}6522 {#code_end#}
6523 {#see_also|Errors#}
6088 {#header_close#}6524 {#header_close#}
6089 {#header_open|Invalid Error Code#}6525 {#header_open|Invalid Error Code#}
6090 <p>At compile-time:</p>6526 <p>At compile-time:</p>
6091 {#code_begin|test_err|integer value 11 represents no error#}6527 {#code_begin|test_err|integer value 11 represents no error#}
6092comptime {6528comptime {
6093 const err = error.AnError;6529 const err = error.AnError;
6094 const number = u32(err) + 10;6530 const number = @errorToInt(err) + 10;
6095 const invalid_err = error(number);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);
6096}6543}
6097 {#code_end#}6544 {#code_end#}
6098 <p>At runtime crashes with the message <code>invalid error code</code> and a stack trace.</p>
6099 {#header_close#}6545 {#header_close#}
6100 {#header_open|Invalid Enum Cast#}6546 {#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>
6103 {#header_close#}6579 {#header_close#}
6580
6104 {#header_open|Incorrect Pointer Alignment#}6581 {#header_open|Incorrect Pointer Alignment#}
6105 <p>TODO</p>6582 <p>TODO</p>
61066583
6107 {#header_close#}6584 {#header_close#}
6108 {#header_open|Wrong Union Field Access#}6585 {#header_open|Wrong Union Field Access#}
6109 <p>TODO</p>6586 <p>TODO</p>
6587 {#header_close#}
61106588
6589 {#header_open|Out of Bounds Float To Integer Cast#}
6590 <p>TODO</p>
6111 {#header_close#}6591 {#header_close#}
6592
6112 {#header_close#}6593 {#header_close#}
6113 {#header_open|Memory#}6594 {#header_open|Memory#}
6114 <p>TODO: explain no default allocator in zig</p>6595 <p>TODO: explain no default allocator in zig</p>
...@@ -6793,7 +7274,7 @@ hljs.registerLanguage("zig", function(t) {...@@ -6793,7 +7274,7 @@ hljs.registerLanguage("zig", function(t) {
6793 a = t.IR + "\\s*\\(",7274 a = t.IR + "\\s*\\(",
6794 c = {7275 c = {
6795 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",7276 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",
6797 literal: "true false null undefined"7278 literal: "true false null undefined"
6798 },7279 },
6799 n = [e, t.CLCM, t.CBCM, s, r];7280 n = [e, t.CLCM, t.CBCM, s, r];
src-self-hosted/arg.zig+2-2
...@@ -168,7 +168,7 @@ pub const Args = struct {...@@ -168,7 +168,7 @@ pub const Args = struct {
168 }168 }
169169
170 // e.g. --names value1 value2 value3170 // 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 {
172 if (self.flags.get(name)) |entry| {172 if (self.flags.get(name)) |entry| {
173 switch (entry.value) {173 switch (entry.value) {
174 FlagArg.Many => |inner| {174 FlagArg.Many => |inner| {
...@@ -177,7 +177,7 @@ pub const Args = struct {...@@ -177,7 +177,7 @@ pub const Args = struct {
177 else => @panic("attempted to retrieve flag with wrong type"),177 else => @panic("attempted to retrieve flag with wrong type"),
178 }178 }
179 } else {179 } else {
180 return null;180 return []const []const u8{};
181 }181 }
182 }182 }
183};183};
src-self-hosted/errmsg.zig+1-1
...@@ -35,7 +35,7 @@ pub fn createFromParseError(...@@ -35,7 +35,7 @@ pub fn createFromParseError(
35 var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;35 var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;
36 try parse_error.render(&tree.tokens, out_stream);36 try parse_error.render(&tree.tokens, out_stream);
3737
38 const msg = try allocator.construct(Msg{38 const msg = try allocator.create(Msg{
39 .tree = tree,39 .tree = tree,
40 .path = path,40 .path = path,
41 .text = text_buf.toOwnedSlice(),41 .text = text_buf.toOwnedSlice(),
src-self-hosted/main.zig+147-430
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4const event = std.event;
4const os = std.os;5const os = std.os;
5const io = std.io;6const io = std.io;
6const mem = std.mem;7const mem = std.mem;
...@@ -26,15 +27,11 @@ const usage =...@@ -26,15 +27,11 @@ const usage =
26 \\27 \\
27 \\Commands:28 \\Commands:
28 \\29 \\
29 \\ build Build project from build.zig
30 \\ build-exe [source] Create executable from source or object files30 \\ build-exe [source] Create executable from source or object files
31 \\ build-lib [source] Create library from source or object files31 \\ build-lib [source] Create library from source or object files
32 \\ build-obj [source] Create object from source or assembly32 \\ build-obj [source] Create object from source or assembly
33 \\ fmt [source] Parse file and render in canonical zig format33 \\ fmt [source] Parse file and render in canonical zig format
34 \\ run [source] Create executable and run immediately
35 \\ targets List available compilation targets34 \\ targets List available compilation targets
36 \\ test [source] Create and run a test build
37 \\ translate-c [source] Convert c code to zig code
38 \\ version Print version number and exit35 \\ version Print version number and exit
39 \\ zen Print zen of zig and exit36 \\ zen Print zen of zig and exit
40 \\37 \\
...@@ -47,7 +44,10 @@ const Command = struct {...@@ -47,7 +44,10 @@ const Command = struct {
47};44};
4845
49pub fn main() !void {46pub 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
52 var stdout_file = try std.io.getStdOut();52 var stdout_file = try std.io.getStdOut();
53 var stdout_out_stream = std.io.FileOutStream.init(&stdout_file);53 var stdout_out_stream = std.io.FileOutStream.init(&stdout_file);
...@@ -58,18 +58,16 @@ pub fn main() !void {...@@ -58,18 +58,16 @@ pub fn main() !void {
58 stderr = &stderr_out_stream.stream;58 stderr = &stderr_out_stream.stream;
5959
60 const args = try os.argsAlloc(allocator);60 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
63 if (args.len <= 1) {64 if (args.len <= 1) {
65 try stderr.write("expected command argument\n\n");
64 try stderr.write(usage);66 try stderr.write(usage);
65 os.exit(1);67 os.exit(1);
66 }68 }
6769
68 const commands = []Command{70 const commands = []Command{
69 Command{
70 .name = "build",
71 .exec = cmdBuild,
72 },
73 Command{71 Command{
74 .name = "build-exe",72 .name = "build-exe",
75 .exec = cmdBuildExe,73 .exec = cmdBuildExe,
...@@ -86,22 +84,10 @@ pub fn main() !void {...@@ -86,22 +84,10 @@ pub fn main() !void {
86 .name = "fmt",84 .name = "fmt",
87 .exec = cmdFmt,85 .exec = cmdFmt,
88 },86 },
89 Command{
90 .name = "run",
91 .exec = cmdRun,
92 },
93 Command{87 Command{
94 .name = "targets",88 .name = "targets",
95 .exec = cmdTargets,89 .exec = cmdTargets,
96 },90 },
97 Command{
98 .name = "test",
99 .exec = cmdTest,
100 },
101 Command{
102 .name = "translate-c",
103 .exec = cmdTranslateC,
104 },
105 Command{91 Command{
106 .name = "version",92 .name = "version",
107 .exec = cmdVersion,93 .exec = cmdVersion,
...@@ -124,177 +110,15 @@ pub fn main() !void {...@@ -124,177 +110,15 @@ pub fn main() !void {
124110
125 for (commands) |command| {111 for (commands) |command| {
126 if (mem.eql(u8, command.name, args[1])) {112 if (mem.eql(u8, command.name, args[1])) {
127 try command.exec(allocator, args[2..]);113 return command.exec(allocator, args[2..]);
128 return;
129 }114 }
130 }115 }
131116
132 try stderr.print("unknown command: {}\n\n", args[1]);117 try stderr.print("unknown command: {}\n\n", args[1]);
133 try stderr.write(usage);118 try stderr.write(usage);
119 os.exit(1);
134}120}
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
298const usage_build_generic =122const usage_build_generic =
299 \\usage: zig build-exe <options> [file]123 \\usage: zig build-exe <options> [file]
300 \\ zig build-lib <options> [file]124 \\ zig build-lib <options> [file]
...@@ -315,8 +139,11 @@ const usage_build_generic =...@@ -315,8 +139,11 @@ const usage_build_generic =
315 \\ --output-h [file] Override generated header file path139 \\ --output-h [file] Override generated header file path
316 \\ --pkg-begin [name] [path] Make package available to import and push current pkg140 \\ --pkg-begin [name] [path] Make package available to import and push current pkg
317 \\ --pkg-end Pop current pkg141 \\ --pkg-end Pop current pkg
318 \\ --release-fast Build with optimizations on and safety off142 \\ --mode [mode] Set the build mode
319 \\ --release-safe Build with optimizations on and safety on143 \\ 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
320 \\ --static Output will be statically linked147 \\ --static Output will be statically linked
321 \\ --strip Exclude debug symbols148 \\ --strip Exclude debug symbols
322 \\ --target-arch [name] Specify target architecture149 \\ --target-arch [name] Specify target architecture
...@@ -367,6 +194,12 @@ const args_build_generic = []Flag{...@@ -367,6 +194,12 @@ const args_build_generic = []Flag{
367 "off",194 "off",
368 "on",195 "on",
369 }),196 }),
197 Flag.Option("--mode", []const []const u8{
198 "debug",
199 "release-fast",
200 "release-safe",
201 "release-small",
202 }),
370203
371 Flag.ArgMergeN("--assembly", 1),204 Flag.ArgMergeN("--assembly", 1),
372 Flag.Arg1("--cache-dir"),205 Flag.Arg1("--cache-dir"),
...@@ -383,8 +216,6 @@ const args_build_generic = []Flag{...@@ -383,8 +216,6 @@ const args_build_generic = []Flag{
383 // NOTE: Parsed manually after initial check216 // NOTE: Parsed manually after initial check
384 Flag.ArgN("--pkg-begin", 2),217 Flag.ArgN("--pkg-begin", 2),
385 Flag.Bool("--pkg-end"),218 Flag.Bool("--pkg-end"),
386 Flag.Bool("--release-fast"),
387 Flag.Bool("--release-safe"),
388 Flag.Bool("--static"),219 Flag.Bool("--static"),
389 Flag.Bool("--strip"),220 Flag.Bool("--strip"),
390 Flag.Arg1("--target-arch"),221 Flag.Arg1("--target-arch"),
...@@ -431,16 +262,25 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo...@@ -431,16 +262,25 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
431 defer flags.deinit();262 defer flags.deinit();
432263
433 if (flags.present("help")) {264 if (flags.present("help")) {
434 try stderr.write(usage_build_generic);265 try stdout.write(usage_build_generic);
435 os.exit(0);266 os.exit(0);
436 }267 }
437268
438 var build_mode = builtin.Mode.Debug;269 const build_mode = blk: {
439 if (flags.present("release-fast")) {270 if (flags.single("mode")) |mode_flag| {
440 build_mode = builtin.Mode.ReleaseFast;271 if (mem.eql(u8, mode_flag, "debug")) {
441 } else if (flags.present("release-safe")) {272 break :blk builtin.Mode.Debug;
442 build_mode = builtin.Mode.ReleaseSafe;273 } else if (mem.eql(u8, mode_flag, "release-fast")) {
443 }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
445 const color = blk: {285 const color = blk: {
446 if (flags.single("color")) |color_flag| {286 if (flags.single("color")) |color_flag| {
...@@ -456,20 +296,21 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo...@@ -456,20 +296,21 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
456 }296 }
457 };297 };
458298
459 var emit_type = Module.Emit.Binary;299 const emit_type = blk: {
460 if (flags.single("emit")) |emit_flag| {300 if (flags.single("emit")) |emit_flag| {
461 if (mem.eql(u8, emit_flag, "asm")) {301 if (mem.eql(u8, emit_flag, "asm")) {
462 emit_type = Module.Emit.Assembly;302 break :blk Module.Emit.Assembly;
463 } else if (mem.eql(u8, emit_flag, "bin")) {303 } else if (mem.eql(u8, emit_flag, "bin")) {
464 emit_type = Module.Emit.Binary;304 break :blk Module.Emit.Binary;
465 } else if (mem.eql(u8, emit_flag, "llvm-ir")) {305 } else if (mem.eql(u8, emit_flag, "llvm-ir")) {
466 emit_type = Module.Emit.LlvmIr;306 break :blk Module.Emit.LlvmIr;
307 } else unreachable;
467 } else {308 } else {
468 unreachable;309 break :blk Module.Emit.Binary;
469 }310 }
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);
473 defer cur_pkg.deinit();314 defer cur_pkg.deinit();
474315
475 var i: usize = 0;316 var i: usize = 0;
...@@ -482,15 +323,16 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo...@@ -482,15 +323,16 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
482 i += 1;323 i += 1;
483 const new_pkg_path = args[i];324 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);
486 try cur_pkg.children.append(new_cur_pkg);327 try cur_pkg.children.append(new_cur_pkg);
487 cur_pkg = new_cur_pkg;328 cur_pkg = new_cur_pkg;
488 } else if (mem.eql(u8, "--pkg-end", arg_name)) {329 } 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 {
490 try stderr.print("encountered --pkg-end with no matching --pkg-begin\n");333 try stderr.print("encountered --pkg-end with no matching --pkg-begin\n");
491 os.exit(1);334 os.exit(1);
492 }335 }
493 cur_pkg = cur_pkg.parent.?;
494 }336 }
495 }337 }
496338
...@@ -499,43 +341,42 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo...@@ -499,43 +341,42 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
499 os.exit(1);341 os.exit(1);
500 }342 }
501343
502 var in_file: ?[]const u8 = undefined;344 const provided_name = flags.single("name");
503 switch (flags.positionals.len) {345 const root_source_file = switch (flags.positionals.len) {
504 0 => {346 0 => null,
505 try stderr.write("--name [name] not provided and unable to infer\n");347 1 => flags.positionals.at(0),
506 os.exit(1);
507 },
508 1 => {
509 in_file = flags.positionals.at(0);
510 },
511 else => {348 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));
513 os.exit(1);350 os.exit(1);
514 },351 },
515 }352 };
516353
517 const basename = os.path.basename(in_file.?);354 const root_name = if (provided_name) |n| n else blk: {
518 var it = mem.split(basename, ".");355 if (root_source_file) |file| {
519 const root_name = it.next() orelse {356 const basename = os.path.basename(file);
520 try stderr.write("file name cannot be empty\n");357 var it = mem.split(basename, ".");
521 os.exit(1);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 }
522 };363 };
523364
524 const asm_a = flags.many("assembly");365 const assembly_files = flags.many("assembly");
525 const obj_a = flags.many("object");366 const link_objects = 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)) {367 if (root_source_file == null and link_objects.len == 0 and assembly_files.len == 0) {
527 try stderr.write("Expected source file argument or at least one --object or --assembly argument\n");368 try stderr.write("Expected source file argument or at least one --object or --assembly argument\n");
528 os.exit(1);369 os.exit(1);
529 }370 }
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) {
532 try stderr.write("When building an object file, --object arguments are invalid\n");373 try stderr.write("When building an object file, --object arguments are invalid\n");
533 os.exit(1);374 os.exit(1);
534 }375 }
535376
536 const zig_root_source_file = in_file;377 const rel_cache_dir = flags.single("cache-dir") orelse "zig-cache"[0..];
537378 const full_cache_dir = os.path.resolve(allocator, ".", rel_cache_dir) catch {
538 const full_cache_dir = os.path.resolve(allocator, ".", flags.single("cache-dir") orelse "zig-cache"[0..]) catch {379 try stderr.print("invalid cache dir: {}\n", rel_cache_dir);
539 os.exit(1);380 os.exit(1);
540 };381 };
541 defer allocator.free(full_cache_dir);382 defer allocator.free(full_cache_dir);
...@@ -543,10 +384,12 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo...@@ -543,10 +384,12 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
543 const zig_lib_dir = introspect.resolveZigLibDir(allocator) catch os.exit(1);384 const zig_lib_dir = introspect.resolveZigLibDir(allocator) catch os.exit(1);
544 defer allocator.free(zig_lib_dir);385 defer allocator.free(zig_lib_dir);
545386
387 var loop = try event.Loop.init(allocator);
388
546 var module = try Module.create(389 var module = try Module.create(
547 allocator,390 &loop,
548 root_name,391 root_name,
549 zig_root_source_file,392 root_source_file,
550 Target.Native,393 Target.Native,
551 out_type,394 out_type,
552 build_mode,395 build_mode,
...@@ -561,24 +404,21 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo...@@ -561,24 +404,21 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
561404
562 module.is_test = false;405 module.is_test = false;
563406
564 if (flags.single("linker-script")) |linker_script| {407 module.linker_script = flags.single("linker-script");
565 module.linker_script = linker_script;
566 }
567
568 module.each_lib_rpath = flags.present("each-lib-rpath");408 module.each_lib_rpath = flags.present("each-lib-rpath");
569409
570 var clang_argv_buf = ArrayList([]const u8).init(allocator);410 var clang_argv_buf = ArrayList([]const u8).init(allocator);
571 defer clang_argv_buf.deinit();411 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;413 const mllvm_flags = flags.many("mllvm");
579 module.clang_argv = clang_argv_buf.toSliceConst();414 for (mllvm_flags) |mllvm| {
415 try clang_argv_buf.append("-mllvm");
416 try clang_argv_buf.append(mllvm);
580 }417 }
581418
419 module.llvm_argv = mllvm_flags;
420 module.clang_argv = clang_argv_buf.toSliceConst();
421
582 module.strip = flags.present("strip");422 module.strip = flags.present("strip");
583 module.is_static = flags.present("static");423 module.is_static = flags.present("static");
584424
...@@ -610,18 +450,9 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo...@@ -610,18 +450,9 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
610 module.verbose_cimport = flags.present("verbose-cimport");450 module.verbose_cimport = flags.present("verbose-cimport");
611451
612 module.err_color = color;452 module.err_color = color;
613453 module.lib_dirs = flags.many("library-path");
614 if (flags.many("library-path")) |lib_dirs| {454 module.darwin_frameworks = flags.many("framework");
615 module.lib_dirs = lib_dirs;455 module.rpath_list = flags.many("rpath");
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 }
625456
626 if (flags.single("output-h")) |output_h| {457 if (flags.single("output-h")) |output_h| {
627 module.out_h_path = output_h;458 module.out_h_path = output_h;
...@@ -644,41 +475,51 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo...@@ -644,41 +475,51 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
644 }475 }
645476
646 module.emit_file_type = emit_type;477 module.emit_file_type = emit_type;
647 if (flags.many("object")) |objects| {478 module.link_objects = link_objects;
648 module.link_objects = objects;479 module.assembly_files = assembly_files;
649 }480 module.link_out_file = flags.single("out-file");
650 if (flags.many("assembly")) |assembly_files| {
651 module.assembly_files = assembly_files;
652 }
653481
654 try module.build();482 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")) {488async fn processBuildEvents(module: *Module, watch: bool) void {
658 // codegen_print_timing_info(g, stderr);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 }
659 }508 }
660
661 try stderr.print("building {}: {}\n", @tagName(out_type), in_file);
662}509}
663510
664fn cmdBuildExe(allocator: *Allocator, args: []const []const u8) !void {511fn cmdBuildExe(allocator: *Allocator, args: []const []const u8) !void {
665 try buildOutputType(allocator, args, Module.Kind.Exe);512 return buildOutputType(allocator, args, Module.Kind.Exe);
666}513}
667514
668// cmd:build-lib ///////////////////////////////////////////////////////////////////////////////////
669
670fn cmdBuildLib(allocator: *Allocator, args: []const []const u8) !void {515fn cmdBuildLib(allocator: *Allocator, args: []const []const u8) !void {
671 try buildOutputType(allocator, args, Module.Kind.Lib);516 return buildOutputType(allocator, args, Module.Kind.Lib);
672}517}
673518
674// cmd:build-obj ///////////////////////////////////////////////////////////////////////////////////
675
676fn cmdBuildObj(allocator: *Allocator, args: []const []const u8) !void {519fn cmdBuildObj(allocator: *Allocator, args: []const []const u8) !void {
677 try buildOutputType(allocator, args, Module.Kind.Obj);520 return buildOutputType(allocator, args, Module.Kind.Obj);
678}521}
679522
680// cmd:fmt /////////////////////////////////////////////////////////////////////////////////////////
681
682const usage_fmt =523const usage_fmt =
683 \\usage: zig fmt [file]...524 \\usage: zig fmt [file]...
684 \\525 \\
...@@ -707,7 +548,7 @@ const Fmt = struct {...@@ -707,7 +548,7 @@ const Fmt = struct {
707548
708 // file_path must outlive Fmt549 // file_path must outlive Fmt
709 fn addToQueue(self: *Fmt, file_path: []const u8) !void {550 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{
711 .prev = undefined,552 .prev = undefined,
712 .next = undefined,553 .next = undefined,
713 .data = file_path,554 .data = file_path,
...@@ -735,7 +576,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -735,7 +576,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
735 defer flags.deinit();576 defer flags.deinit();
736577
737 if (flags.present("help")) {578 if (flags.present("help")) {
738 try stderr.write(usage_fmt);579 try stdout.write(usage_fmt);
739 os.exit(0);580 os.exit(0);
740 }581 }
741582
...@@ -863,162 +704,16 @@ fn cmdTargets(allocator: *Allocator, args: []const []const u8) !void {...@@ -863,162 +704,16 @@ fn cmdTargets(allocator: *Allocator, args: []const []const u8) !void {
863 }704 }
864}705}
865706
866// cmd:version /////////////////////////////////////////////////////////////////////////////////////
867
868fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void {707fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void {
869 try stdout.print("{}\n", std.cstr.toSliceConst(c.ZIG_VERSION_STRING));708 try stdout.print("{}\n", std.cstr.toSliceConst(c.ZIG_VERSION_STRING));
870}709}
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
883const args_test_spec = []Flag{Flag.Bool("--help")};711const 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
1016fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void {713fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void {
1017 try stderr.write(usage);714 try stdout.write(usage);
1018}715}
1019716
1020// cmd:zen /////////////////////////////////////////////////////////////////////////////////////////
1021
1022const info_zen =717const info_zen =
1023 \\718 \\
1024 \\ * Communicate intent precisely.719 \\ * Communicate intent precisely.
...@@ -1040,8 +735,6 @@ fn cmdZen(allocator: *Allocator, args: []const []const u8) !void {...@@ -1040,8 +735,6 @@ fn cmdZen(allocator: *Allocator, args: []const []const u8) !void {
1040 try stdout.write(info_zen);735 try stdout.write(info_zen);
1041}736}
1042737
1043// cmd:internal ////////////////////////////////////////////////////////////////////////////////////
1044
1045const usage_internal =738const usage_internal =
1046 \\usage: zig internal [subcommand]739 \\usage: zig internal [subcommand]
1047 \\740 \\
...@@ -1095,3 +788,27 @@ fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void {...@@ -1095,3 +788,27 @@ fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void {
1095 std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB),788 std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB),
1096 );789 );
1097}790}
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;...@@ -11,9 +11,11 @@ const warn = std.debug.warn;
11const Token = std.zig.Token;11const Token = std.zig.Token;
12const ArrayList = std.ArrayList;12const ArrayList = std.ArrayList;
13const errmsg = @import("errmsg.zig");13const errmsg = @import("errmsg.zig");
14const ast = std.zig.ast;
15const event = std.event;
1416
15pub const Module = struct {17pub const Module = struct {
16 allocator: *mem.Allocator,18 loop: *event.Loop,
17 name: Buffer,19 name: Buffer,
18 root_src_path: ?[]const u8,20 root_src_path: ?[]const u8,
19 module: llvm.ModuleRef,21 module: llvm.ModuleRef,
...@@ -76,6 +78,52 @@ pub const Module = struct {...@@ -76,6 +78,52 @@ pub const Module = struct {
7678
77 kind: Kind,79 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
79 pub const DarwinVersionMin = union(enum) {127 pub const DarwinVersionMin = union(enum) {
80 None,128 None,
81 MacOS: []const u8,129 MacOS: []const u8,
...@@ -103,31 +151,17 @@ pub const Module = struct {...@@ -103,31 +151,17 @@ pub const Module = struct {
103 LlvmIr,151 LlvmIr,
104 };152 };
105153
106 pub const CliPkg = struct {154 pub fn create(
155 loop: *event.Loop,
107 name: []const u8,156 name: []const u8,
108 path: []const u8,157 root_src_path: ?[]const u8,
109 children: ArrayList(*CliPkg),158 target: *const Target,
110 parent: ?*CliPkg,159 kind: Kind,
111160 build_mode: builtin.Mode,
112 pub fn init(allocator: *mem.Allocator, name: []const u8, path: []const u8, parent: ?*CliPkg) !*CliPkg {161 zig_lib_dir: []const u8,
113 var pkg = try allocator.create(CliPkg);162 cache_dir: []const u8,
114 pkg.name = name;163 ) !*Module {
115 pkg.path = path;164 var name_buffer = try Buffer.init(loop.allocator, name);
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);
131 errdefer name_buffer.deinit();165 errdefer name_buffer.deinit();
132166
133 const context = c.LLVMContextCreate() orelse return error.OutOfMemory;167 const context = c.LLVMContextCreate() orelse return error.OutOfMemory;
...@@ -139,11 +173,12 @@ pub const Module = struct {...@@ -139,11 +173,12 @@ pub const Module = struct {
139 const builder = c.LLVMCreateBuilderInContext(context) orelse return error.OutOfMemory;173 const builder = c.LLVMCreateBuilderInContext(context) orelse return error.OutOfMemory;
140 errdefer c.LLVMDisposeBuilder(builder);174 errdefer c.LLVMDisposeBuilder(builder);
141175
142 const module_ptr = try allocator.create(Module);176 const events = try event.Channel(Event).create(loop, 0);
143 errdefer allocator.destroy(module_ptr);177 errdefer events.destroy();
144178
145 module_ptr.* = Module{179 return loop.allocator.create(Module{
146 .allocator = allocator,180 .loop = loop,
181 .events = events,
147 .name = name_buffer,182 .name = name_buffer,
148 .root_src_path = root_src_path,183 .root_src_path = root_src_path,
149 .module = module,184 .module = module,
...@@ -188,7 +223,7 @@ pub const Module = struct {...@@ -188,7 +223,7 @@ pub const Module = struct {
188 .link_objects = [][]const u8{},223 .link_objects = [][]const u8{},
189 .windows_subsystem_windows = false,224 .windows_subsystem_windows = false,
190 .windows_subsystem_console = false,225 .windows_subsystem_console = false,
191 .link_libs_list = ArrayList(*LinkLib).init(allocator),226 .link_libs_list = ArrayList(*LinkLib).init(loop.allocator),
192 .libc_link_lib = null,227 .libc_link_lib = null,
193 .err_color = errmsg.Color.Auto,228 .err_color = errmsg.Color.Auto,
194 .darwin_frameworks = [][]const u8{},229 .darwin_frameworks = [][]const u8{},
...@@ -196,8 +231,8 @@ pub const Module = struct {...@@ -196,8 +231,8 @@ pub const Module = struct {
196 .test_filters = [][]const u8{},231 .test_filters = [][]const u8{},
197 .test_name_prefix = null,232 .test_name_prefix = null,
198 .emit_file_type = Emit.Binary,233 .emit_file_type = Emit.Binary,
199 };234 .link_out_file = null,
200 return module_ptr;235 });
201 }236 }
202237
203 fn dump(self: *Module) void {238 fn dump(self: *Module) void {
...@@ -205,58 +240,70 @@ pub const Module = struct {...@@ -205,58 +240,70 @@ pub const Module = struct {
205 }240 }
206241
207 pub fn destroy(self: *Module) void {242 pub fn destroy(self: *Module) void {
243 self.events.destroy();
208 c.LLVMDisposeBuilder(self.builder);244 c.LLVMDisposeBuilder(self.builder);
209 c.LLVMDisposeModule(self.module);245 c.LLVMDisposeModule(self.module);
210 c.LLVMContextDispose(self.context);246 c.LLVMContextDispose(self.context);
211 self.name.deinit();247 self.name.deinit();
212248
213 self.allocator.destroy(self);249 self.a().destroy(self);
214 }250 }
215251
216 pub fn build(self: *Module) !void {252 pub fn build(self: *Module) !void {
217 if (self.llvm_argv.len != 0) {253 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{
219 [][]const u8{"zig (LLVM option parsing)"},255 [][]const u8{"zig (LLVM option parsing)"},
220 self.llvm_argv,256 self.llvm_argv,
221 });257 });
222 defer c_compatible_args.deinit();258 defer c_compatible_args.deinit();
259 // TODO this sets global state
223 c.ZigLLVMParseCommandLineOptions(self.llvm_argv.len + 1, c_compatible_args.ptr);260 c.ZigLLVMParseCommandLineOptions(self.llvm_argv.len + 1, c_compatible_args.ptr);
224 }261 }
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 {
226 const root_src_path = self.root_src_path orelse @panic("TODO handle null root src path");279 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| {
228 try printError("unable to get real path '{}': {}", root_src_path, err);281 try printError("unable to get real path '{}': {}", root_src_path, err);
229 return err;282 return err;
230 };283 };
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| {
234 try printError("unable to open '{}': {}", root_src_real_path, err);287 try printError("unable to open '{}': {}", root_src_real_path, err);
235 return err;288 return err;
236 };289 };
237 errdefer self.allocator.free(source_code);290 errdefer self.a().free(source_code);
238
239 warn("====input:====\n");
240
241 warn("{}", source_code);
242
243 warn("====parse:====\n");
244291
245 var tree = try std.zig.parse(self.allocator, source_code);292 var tree = try std.zig.parse(self.a(), source_code);
246 defer tree.deinit();293 defer tree.deinit();
247294
248 var stderr_file = try std.io.getStdErr();295 //var it = tree.root_node.decls.iterator();
249 var stderr_file_out_stream = std.io.FileOutStream.init(&stderr_file);296 //while (it.next()) |decl_ptr| {
250 const out_stream = &stderr_file_out_stream.stream;297 // const decl = decl_ptr.*;
251298 // switch (decl.id) {
252 warn("====fmt:====\n");299 // ast.Node.Comptime => @panic("TODO"),
253 _ = try std.zig.render(self.allocator, out_stream, &tree);300 // ast.Node.VarDecl => @panic("TODO"),
254301 // ast.Node.UseDecl => @panic("TODO"),
255 warn("====ir:====\n");302 // ast.Node.FnDef => @panic("TODO"),
256 warn("TODO\n\n");303 // ast.Node.TestDecl => @panic("TODO"),
257304 // else => unreachable,
258 warn("====llvm ir:====\n");305 // }
259 self.dump();306 //}
260 }307 }
261308
262 pub fn link(self: *Module, out_file: ?[]const u8) !void {309 pub fn link(self: *Module, out_file: ?[]const u8) !void {
...@@ -279,19 +326,22 @@ pub const Module = struct {...@@ -279,19 +326,22 @@ pub const Module = struct {
279 }326 }
280 }327 }
281328
282 const link_lib = try self.allocator.create(LinkLib);329 const link_lib = try self.a().create(LinkLib{
283 link_lib.* = LinkLib{
284 .name = name,330 .name = name,
285 .path = null,331 .path = null,
286 .provided_explicitly = provided_explicitly,332 .provided_explicitly = provided_explicitly,
287 .symbols = ArrayList([]u8).init(self.allocator),333 .symbols = ArrayList([]u8).init(self.a()),
288 };334 });
289 try self.link_libs_list.append(link_lib);335 try self.link_libs_list.append(link_lib);
290 if (is_libc) {336 if (is_libc) {
291 self.libc_link_lib = link_lib;337 self.libc_link_lib = link_lib;
292 }338 }
293 return link_lib;339 return link_lib;
294 }340 }
341
342 fn a(self: Module) *mem.Allocator {
343 return self.loop.allocator;
344 }
295};345};
296346
297fn printError(comptime format: []const u8, args: ...) !void {347fn printError(comptime format: []const u8, args: ...) !void {
src/all_types.hpp+53-1
...@@ -234,6 +234,16 @@ enum RuntimeHintPtr {...@@ -234,6 +234,16 @@ enum RuntimeHintPtr {
234 RuntimeHintPtrNonStack,234 RuntimeHintPtrNonStack,
235};235};
236236
237enum RuntimeHintSliceId {
238 RuntimeHintSliceIdUnknown,
239 RuntimeHintSliceIdLen,
240};
241
242struct RuntimeHintSlice {
243 enum RuntimeHintSliceId id;
244 uint64_t len;
245};
246
237struct ConstGlobalRefs {247struct ConstGlobalRefs {
238 LLVMValueRef llvm_value;248 LLVMValueRef llvm_value;
239 LLVMValueRef llvm_global;249 LLVMValueRef llvm_global;
...@@ -248,6 +258,7 @@ struct ConstExprValue {...@@ -248,6 +258,7 @@ struct ConstExprValue {
248 // populated if special == ConstValSpecialStatic258 // populated if special == ConstValSpecialStatic
249 BigInt x_bigint;259 BigInt x_bigint;
250 BigFloat x_bigfloat;260 BigFloat x_bigfloat;
261 float16_t x_f16;
251 float x_f32;262 float x_f32;
252 double x_f64;263 double x_f64;
253 float128_t x_f128;264 float128_t x_f128;
...@@ -270,6 +281,7 @@ struct ConstExprValue {...@@ -270,6 +281,7 @@ struct ConstExprValue {
270 RuntimeHintErrorUnion rh_error_union;281 RuntimeHintErrorUnion rh_error_union;
271 RuntimeHintOptional rh_maybe;282 RuntimeHintOptional rh_maybe;
272 RuntimeHintPtr rh_ptr;283 RuntimeHintPtr rh_ptr;
284 RuntimeHintSlice rh_slice;
273 } data;285 } data;
274};286};
275287
...@@ -1222,7 +1234,7 @@ struct TypeTableEntry {...@@ -1222,7 +1234,7 @@ struct TypeTableEntry {
12221234
1223 // use these fields to make sure we don't duplicate type table entries for the same type1235 // use these fields to make sure we don't duplicate type table entries for the same type
1224 TypeTableEntry *pointer_parent[2]; // [0 - mut, 1 - const]1236 TypeTableEntry *pointer_parent[2]; // [0 - mut, 1 - const]
1225 TypeTableEntry *maybe_parent;1237 TypeTableEntry *optional_parent;
1226 TypeTableEntry *promise_parent;1238 TypeTableEntry *promise_parent;
1227 TypeTableEntry *promise_frame_parent;1239 TypeTableEntry *promise_frame_parent;
1228 // If we generate a constant name value for this type, we memoize it here.1240 // If we generate a constant name value for this type, we memoize it here.
...@@ -1359,9 +1371,16 @@ enum BuiltinFnId {...@@ -1359,9 +1371,16 @@ enum BuiltinFnId {
1359 BuiltinFnIdTruncate,1371 BuiltinFnIdTruncate,
1360 BuiltinFnIdIntCast,1372 BuiltinFnIdIntCast,
1361 BuiltinFnIdFloatCast,1373 BuiltinFnIdFloatCast,
1374 BuiltinFnIdErrSetCast,
1375 BuiltinFnIdToBytes,
1376 BuiltinFnIdFromBytes,
1362 BuiltinFnIdIntToFloat,1377 BuiltinFnIdIntToFloat,
1363 BuiltinFnIdFloatToInt,1378 BuiltinFnIdFloatToInt,
1364 BuiltinFnIdBoolToInt,1379 BuiltinFnIdBoolToInt,
1380 BuiltinFnIdErrToInt,
1381 BuiltinFnIdIntToErr,
1382 BuiltinFnIdEnumToInt,
1383 BuiltinFnIdIntToEnum,
1365 BuiltinFnIdIntType,1384 BuiltinFnIdIntType,
1366 BuiltinFnIdSetCold,1385 BuiltinFnIdSetCold,
1367 BuiltinFnIdSetRuntimeSafety,1386 BuiltinFnIdSetRuntimeSafety,
...@@ -1416,6 +1435,7 @@ enum PanicMsgId {...@@ -1416,6 +1435,7 @@ enum PanicMsgId {
1416 PanicMsgIdIncorrectAlignment,1435 PanicMsgIdIncorrectAlignment,
1417 PanicMsgIdBadUnionField,1436 PanicMsgIdBadUnionField,
1418 PanicMsgIdBadEnumValue,1437 PanicMsgIdBadEnumValue,
1438 PanicMsgIdFloatToInt,
14191439
1420 PanicMsgIdCount,1440 PanicMsgIdCount,
1421};1441};
...@@ -1579,6 +1599,7 @@ struct CodeGen {...@@ -1579,6 +1599,7 @@ struct CodeGen {
1579 TypeTableEntry *entry_i128;1599 TypeTableEntry *entry_i128;
1580 TypeTableEntry *entry_isize;1600 TypeTableEntry *entry_isize;
1581 TypeTableEntry *entry_usize;1601 TypeTableEntry *entry_usize;
1602 TypeTableEntry *entry_f16;
1582 TypeTableEntry *entry_f32;1603 TypeTableEntry *entry_f32;
1583 TypeTableEntry *entry_f64;1604 TypeTableEntry *entry_f64;
1584 TypeTableEntry *entry_f128;1605 TypeTableEntry *entry_f128;
...@@ -2074,6 +2095,7 @@ enum IrInstructionId {...@@ -2074,6 +2095,7 @@ enum IrInstructionId {
2074 IrInstructionIdIntToPtr,2095 IrInstructionIdIntToPtr,
2075 IrInstructionIdPtrToInt,2096 IrInstructionIdPtrToInt,
2076 IrInstructionIdIntToEnum,2097 IrInstructionIdIntToEnum,
2098 IrInstructionIdEnumToInt,
2077 IrInstructionIdIntToErr,2099 IrInstructionIdIntToErr,
2078 IrInstructionIdErrToInt,2100 IrInstructionIdErrToInt,
2079 IrInstructionIdCheckSwitchProngs,2101 IrInstructionIdCheckSwitchProngs,
...@@ -2119,6 +2141,9 @@ enum IrInstructionId {...@@ -2119,6 +2141,9 @@ enum IrInstructionId {
2119 IrInstructionIdMergeErrRetTraces,2141 IrInstructionIdMergeErrRetTraces,
2120 IrInstructionIdMarkErrRetTracePtr,2142 IrInstructionIdMarkErrRetTracePtr,
2121 IrInstructionIdSqrt,2143 IrInstructionIdSqrt,
2144 IrInstructionIdErrSetCast,
2145 IrInstructionIdToBytes,
2146 IrInstructionIdFromBytes,
2122};2147};
21232148
2124struct IrInstruction {2149struct IrInstruction {
...@@ -2654,6 +2679,26 @@ struct IrInstructionFloatCast {...@@ -2654,6 +2679,26 @@ struct IrInstructionFloatCast {
2654 IrInstruction *target;2679 IrInstruction *target;
2655};2680};
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
2657struct IrInstructionIntToFloat {2702struct IrInstructionIntToFloat {
2658 IrInstruction base;2703 IrInstruction base;
26592704
...@@ -2864,6 +2909,13 @@ struct IrInstructionIntToPtr {...@@ -2864,6 +2909,13 @@ struct IrInstructionIntToPtr {
2864struct IrInstructionIntToEnum {2909struct IrInstructionIntToEnum {
2865 IrInstruction base;2910 IrInstruction base;
28662911
2912 IrInstruction *dest_type;
2913 IrInstruction *target;
2914};
2915
2916struct IrInstructionEnumToInt {
2917 IrInstruction base;
2918
2867 IrInstruction *target;2919 IrInstruction *target;
2868};2920};
28692921
src/analyze.cpp+53-11
...@@ -482,7 +482,7 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)...@@ -482,7 +482,7 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)
482 return return_type->promise_frame_parent;482 return return_type->promise_frame_parent;
483 }483 }
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);
486 TypeTableEntry *result_ptr_type = get_pointer_to_type(g, return_type, false);486 TypeTableEntry *result_ptr_type = get_pointer_to_type(g, return_type, false);
487487
488 ZigList<const char *> field_names = {};488 ZigList<const char *> field_names = {};
...@@ -513,9 +513,9 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)...@@ -513,9 +513,9 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)
513 return entry;513 return entry;
514}514}
515515
516TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {516TypeTableEntry *get_optional_type(CodeGen *g, TypeTableEntry *child_type) {
517 if (child_type->maybe_parent) {517 if (child_type->optional_parent) {
518 TypeTableEntry *entry = child_type->maybe_parent;518 TypeTableEntry *entry = child_type->optional_parent;
519 return entry;519 return entry;
520 } else {520 } else {
521 ensure_complete_type(g, child_type);521 ensure_complete_type(g, child_type);
...@@ -592,7 +592,7 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {...@@ -592,7 +592,7 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
592592
593 entry->data.maybe.child_type = child_type;593 entry->data.maybe.child_type = child_type;
594594
595 child_type->maybe_parent = entry;595 child_type->optional_parent = entry;
596 return entry;596 return entry;
597 }597 }
598}598}
...@@ -1470,6 +1470,17 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -1470,6 +1470,17 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
1470 calling_convention_name(fn_type_id.cc)));1470 calling_convention_name(fn_type_id.cc)));
1471 return g->builtin_types.entry_invalid;1471 return g->builtin_types.entry_invalid;
1472 }1472 }
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
1473 return get_generic_fn_type(g, &fn_type_id);1484 return get_generic_fn_type(g, &fn_type_id);
1474 } else if (param_is_var_args) {1485 } else if (param_is_var_args) {
1475 if (fn_type_id.cc == CallingConventionC) {1486 if (fn_type_id.cc == CallingConventionC) {
...@@ -2307,8 +2318,9 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {...@@ -2307,8 +2318,9 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
2307 return;2318 return;
23082319
2309 if (enum_type->data.enumeration.zero_bits_loop_flag) {2320 if (enum_type->data.enumeration.zero_bits_loop_flag) {
2310 enum_type->data.enumeration.zero_bits_known = true;2321 add_node_error(g, enum_type->data.enumeration.decl_node,
2311 enum_type->data.enumeration.zero_bits_loop_flag = false;2322 buf_sprintf("'%s' depends on itself", buf_ptr(&enum_type->name)));
2323 enum_type->data.enumeration.is_invalid = true;
2312 return;2324 return;
2313 }2325 }
23142326
...@@ -2984,7 +2996,7 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {...@@ -2984,7 +2996,7 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {
2984 return wrong_panic_prototype(g, proto_node, fn_type);2996 return wrong_panic_prototype(g, proto_node, fn_type);
2985 }2997 }
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));
2988 if (fn_type_id->param_info[1].type != optional_ptr_to_stack_trace_type) {3000 if (fn_type_id->param_info[1].type != optional_ptr_to_stack_trace_type) {
2989 return wrong_panic_prototype(g, proto_node, fn_type);3001 return wrong_panic_prototype(g, proto_node, fn_type);
2990 }3002 }
...@@ -3716,6 +3728,7 @@ TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt...@@ -3716,6 +3728,7 @@ TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt
3716}3728}
37173729
3718TypeEnumField *find_enum_field_by_tag(TypeTableEntry *enum_type, const BigInt *tag) {3730TypeEnumField *find_enum_field_by_tag(TypeTableEntry *enum_type, const BigInt *tag) {
3731 assert(enum_type->data.enumeration.zero_bits_known);
3719 for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) {3732 for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) {
3720 TypeEnumField *field = &enum_type->data.enumeration.fields[i];3733 TypeEnumField *field = &enum_type->data.enumeration.fields[i];
3721 if (bigint_cmp(&field->value, tag) == CmpEQ) {3734 if (bigint_cmp(&field->value, tag) == CmpEQ) {
...@@ -4656,6 +4669,13 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {...@@ -4656,6 +4669,13 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
4656 }4669 }
4657 case TypeTableEntryIdFloat:4670 case TypeTableEntryIdFloat:
4658 switch (const_val->type->data.floating.bit_count) {4671 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 }
4659 case 32:4679 case 32:
4660 {4680 {
4661 uint32_t result;4681 uint32_t result;
...@@ -5116,6 +5136,9 @@ void init_const_float(ConstExprValue *const_val, TypeTableEntry *type, double va...@@ -5116,6 +5136,9 @@ void init_const_float(ConstExprValue *const_val, TypeTableEntry *type, double va
5116 bigfloat_init_64(&const_val->data.x_bigfloat, value);5136 bigfloat_init_64(&const_val->data.x_bigfloat, value);
5117 } else if (type->id == TypeTableEntryIdFloat) {5137 } else if (type->id == TypeTableEntryIdFloat) {
5118 switch (type->data.floating.bit_count) {5138 switch (type->data.floating.bit_count) {
5139 case 16:
5140 const_val->data.x_f16 = zig_double_to_f16(value);
5141 break;
5119 case 32:5142 case 32:
5120 const_val->data.x_f32 = value;5143 const_val->data.x_f32 = value;
5121 break;5144 break;
...@@ -5429,6 +5452,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {...@@ -5429,6 +5452,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
5429 case TypeTableEntryIdFloat:5452 case TypeTableEntryIdFloat:
5430 assert(a->type->data.floating.bit_count == b->type->data.floating.bit_count);5453 assert(a->type->data.floating.bit_count == b->type->data.floating.bit_count);
5431 switch (a->type->data.floating.bit_count) {5454 switch (a->type->data.floating.bit_count) {
5455 case 16:
5456 return f16_eq(a->data.x_f16, b->data.x_f16);
5432 case 32:5457 case 32:
5433 return a->data.x_f32 == b->data.x_f32;5458 return a->data.x_f32 == b->data.x_f32;
5434 case 64:5459 case 64:
...@@ -5446,8 +5471,22 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {...@@ -5446,8 +5471,22 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
5446 case TypeTableEntryIdPointer:5471 case TypeTableEntryIdPointer:
5447 case TypeTableEntryIdFn:5472 case TypeTableEntryIdFn:
5448 return const_values_equal_ptr(a, b);5473 return const_values_equal_ptr(a, b);
5449 case TypeTableEntryIdArray:5474 case TypeTableEntryIdArray: {
5450 zig_panic("TODO");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 }
5451 case TypeTableEntryIdStruct:5490 case TypeTableEntryIdStruct:
5452 for (size_t i = 0; i < a->type->data.structure.src_field_count; i += 1) {5491 for (size_t i = 0; i < a->type->data.structure.src_field_count; i += 1) {
5453 ConstExprValue *field_a = &a->data.x_struct.fields[i];5492 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...@@ -5558,7 +5597,7 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, TypeT
5558 return;5597 return;
5559 }5598 }
5560 case ConstPtrSpecialHardCodedAddr:5599 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),
5562 const_val->data.x_ptr.data.hard_coded_addr.addr);5601 const_val->data.x_ptr.data.hard_coded_addr.addr);
5563 return;5602 return;
5564 case ConstPtrSpecialDiscard:5603 case ConstPtrSpecialDiscard:
...@@ -5602,6 +5641,9 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {...@@ -5602,6 +5641,9 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
5602 return;5641 return;
5603 case TypeTableEntryIdFloat:5642 case TypeTableEntryIdFloat:
5604 switch (type_entry->data.floating.bit_count) {5643 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;
5605 case 32:5647 case 32:
5606 buf_appendf(buf, "%f", const_val->data.x_f32);5648 buf_appendf(buf, "%f", const_val->data.x_f32);
5607 return;5649 return;
src/analyze.hpp+1-1
...@@ -24,7 +24,7 @@ TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits);...@@ -24,7 +24,7 @@ TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits);
24TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);24TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);
25TypeTableEntry *get_c_int_type(CodeGen *g, CIntType c_int_type);25TypeTableEntry *get_c_int_type(CodeGen *g, CIntType c_int_type);
26TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id);26TypeTableEntry *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);
28TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size);28TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size);
29TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *ptr_type);29TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *ptr_type);
30TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind,30TypeTableEntry *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) {...@@ -18,6 +18,10 @@ void bigfloat_init_128(BigFloat *dest, float128_t x) {
18 dest->value = x;18 dest->value = x;
19}19}
2020
21void bigfloat_init_16(BigFloat *dest, float16_t x) {
22 f16_to_f128M(x, &dest->value);
23}
24
21void bigfloat_init_32(BigFloat *dest, float x) {25void bigfloat_init_32(BigFloat *dest, float x) {
22 float32_t f32_val;26 float32_t f32_val;
23 memcpy(&f32_val, &x, sizeof(float));27 memcpy(&f32_val, &x, sizeof(float));
...@@ -146,6 +150,10 @@ Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2) {...@@ -146,6 +150,10 @@ Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2) {
146 }150 }
147}151}
148152
153float16_t bigfloat_to_f16(const BigFloat *bigfloat) {
154 return f128M_to_f16(&bigfloat->value);
155}
156
149float bigfloat_to_f32(const BigFloat *bigfloat) {157float bigfloat_to_f32(const BigFloat *bigfloat) {
150 float32_t f32_value = f128M_to_f32(&bigfloat->value);158 float32_t f32_value = f128M_to_f32(&bigfloat->value);
151 float result;159 float result;
src/bigfloat.hpp+2
...@@ -22,6 +22,7 @@ struct BigFloat {...@@ -22,6 +22,7 @@ struct BigFloat {
2222
23struct Buf;23struct Buf;
2424
25void bigfloat_init_16(BigFloat *dest, float16_t x);
25void bigfloat_init_32(BigFloat *dest, float x);26void bigfloat_init_32(BigFloat *dest, float x);
26void bigfloat_init_64(BigFloat *dest, double x);27void bigfloat_init_64(BigFloat *dest, double x);
27void bigfloat_init_128(BigFloat *dest, float128_t x);28void bigfloat_init_128(BigFloat *dest, float128_t x);
...@@ -29,6 +30,7 @@ void bigfloat_init_bigfloat(BigFloat *dest, const BigFloat *x);...@@ -29,6 +30,7 @@ void bigfloat_init_bigfloat(BigFloat *dest, const BigFloat *x);
29void bigfloat_init_bigint(BigFloat *dest, const BigInt *op);30void bigfloat_init_bigint(BigFloat *dest, const BigInt *op);
30int bigfloat_init_buf_base10(BigFloat *dest, const uint8_t *buf_ptr, size_t buf_len);31int bigfloat_init_buf_base10(BigFloat *dest, const uint8_t *buf_ptr, size_t buf_len);
3132
33float16_t bigfloat_to_f16(const BigFloat *bigfloat);
32float bigfloat_to_f32(const BigFloat *bigfloat);34float bigfloat_to_f32(const BigFloat *bigfloat);
33double bigfloat_to_f64(const BigFloat *bigfloat);35double bigfloat_to_f64(const BigFloat *bigfloat);
34float128_t bigfloat_to_f128(const BigFloat *bigfloat);36float128_t bigfloat_to_f128(const BigFloat *bigfloat);
src/bigint.cpp+9-4
...@@ -1683,10 +1683,15 @@ void bigint_incr(BigInt *x) {...@@ -1683,10 +1683,15 @@ void bigint_incr(BigInt *x) {
1683 bigint_init_unsigned(x, 1);1683 bigint_init_unsigned(x, 1);
1684 return;1684 return;
1685 }1685 }
1686 1686
1687 if (x->digit_count == 1 && x->data.digit != UINT64_MAX) {1687 if (x->digit_count == 1) {
1688 x->data.digit += 1;1688 if (x->is_negative && x->data.digit != 0) {
1689 return;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 }
1690 }1695 }
16911696
1692 BigInt copy;1697 BigInt copy;
src/codegen.cpp+89-58
...@@ -17,6 +17,7 @@...@@ -17,6 +17,7 @@
17#include "os.hpp"17#include "os.hpp"
18#include "translate_c.hpp"18#include "translate_c.hpp"
19#include "target.hpp"19#include "target.hpp"
20#include "util.hpp"
20#include "zig_llvm.h"21#include "zig_llvm.h"
2122
22#include <stdio.h>23#include <stdio.h>
...@@ -865,6 +866,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {...@@ -865,6 +866,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
865 return buf_create_from_str("access of inactive union field");866 return buf_create_from_str("access of inactive union field");
866 case PanicMsgIdBadEnumValue:867 case PanicMsgIdBadEnumValue:
867 return buf_create_from_str("invalid enum value");868 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");
868 }871 }
869 zig_unreachable();872 zig_unreachable();
870}873}
...@@ -1644,7 +1647,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, T...@@ -1644,7 +1647,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, T
1644 return trunc_val;1647 return trunc_val;
1645 }1648 }
1646 LLVMValueRef orig_val;1649 LLVMValueRef orig_val;
1647 if (actual_type->data.integral.is_signed) {1650 if (wanted_type->data.integral.is_signed) {
1648 orig_val = LLVMBuildSExt(g->builder, trunc_val, actual_type->type_ref, "");1651 orig_val = LLVMBuildSExt(g->builder, trunc_val, actual_type->type_ref, "");
1649 } else {1652 } else {
1650 orig_val = LLVMBuildZExt(g->builder, trunc_val, actual_type->type_ref, "");1653 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,...@@ -2207,12 +2210,12 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
2207 } else if (type_entry->id == TypeTableEntryIdInt) {2210 } else if (type_entry->id == TypeTableEntryIdInt) {
2208 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, type_entry->data.integral.is_signed);2211 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, type_entry->data.integral.is_signed);
2209 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");2212 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
2210 } else if (type_entry->id == TypeTableEntryIdEnum) {2213 } else if (type_entry->id == TypeTableEntryIdEnum ||
2211 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);2214 type_entry->id == TypeTableEntryIdErrorSet ||
2212 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
2213 } else if (type_entry->id == TypeTableEntryIdErrorSet ||
2214 type_entry->id == TypeTableEntryIdPointer ||2215 type_entry->id == TypeTableEntryIdPointer ||
2215 type_entry->id == TypeTableEntryIdBool)2216 type_entry->id == TypeTableEntryIdBool ||
2217 type_entry->id == TypeTableEntryIdPromise ||
2218 type_entry->id == TypeTableEntryIdFn)
2216 {2219 {
2217 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);2220 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
2218 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");2221 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
...@@ -2509,15 +2512,41 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,...@@ -2509,15 +2512,41 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
2509 } else {2512 } else {
2510 return LLVMBuildUIToFP(g->builder, expr_val, wanted_type->type_ref, "");2513 return LLVMBuildUIToFP(g->builder, expr_val, wanted_type->type_ref, "");
2511 }2514 }
2512 case CastOpFloatToInt:2515 case CastOpFloatToInt: {
2513 assert(wanted_type->id == TypeTableEntryIdInt);2516 assert(wanted_type->id == TypeTableEntryIdInt);
2514 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &cast_instruction->base));2517 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;
2515 if (wanted_type->data.integral.is_signed) {2522 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, "");
2517 } else {2524 } else {
2518 return LLVMBuildFPToUI(g->builder, expr_val, wanted_type->type_ref, "");2525 result = LLVMBuildFPToUI(g->builder, expr_val, wanted_type->type_ref, "");
2519 }2526 }
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 }
2521 case CastOpBoolToInt:2550 case CastOpBoolToInt:
2522 assert(wanted_type->id == TypeTableEntryIdInt);2551 assert(wanted_type->id == TypeTableEntryIdInt);
2523 assert(actual_type->id == TypeTableEntryIdBool);2552 assert(actual_type->id == TypeTableEntryIdBool);
...@@ -2607,8 +2636,25 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable,...@@ -2607,8 +2636,25 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable,
2607 TypeTableEntry *tag_int_type = wanted_type->data.enumeration.tag_int_type;2636 TypeTableEntry *tag_int_type = wanted_type->data.enumeration.tag_int_type;
26082637
2609 LLVMValueRef target_val = ir_llvm_value(g, instruction->target);2638 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),
2611 instruction->target->value.type, tag_int_type, target_val);2640 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;
2612}2658}
26132659
2614static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, IrInstructionIntToErr *instruction) {2660static 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,...@@ -4638,6 +4684,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
4638 case IrInstructionIdIntToFloat:4684 case IrInstructionIdIntToFloat:
4639 case IrInstructionIdFloatToInt:4685 case IrInstructionIdFloatToInt:
4640 case IrInstructionIdBoolToInt:4686 case IrInstructionIdBoolToInt:
4687 case IrInstructionIdErrSetCast:
4688 case IrInstructionIdFromBytes:
4689 case IrInstructionIdToBytes:
4690 case IrInstructionIdEnumToInt:
4641 zig_unreachable();4691 zig_unreachable();
46424692
4643 case IrInstructionIdReturn:4693 case IrInstructionIdReturn:
...@@ -5090,6 +5140,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c...@@ -5090,6 +5140,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
5090 const_val->data.x_err_set->value, false);5140 const_val->data.x_err_set->value, false);
5091 case TypeTableEntryIdFloat:5141 case TypeTableEntryIdFloat:
5092 switch (type_entry->data.floating.bit_count) {5142 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));
5093 case 32:5145 case 32:
5094 return LLVMConstReal(type_entry->type_ref, const_val->data.x_f32);5146 return LLVMConstReal(type_entry->type_ref, const_val->data.x_f32);
5095 case 64:5147 case 64:
...@@ -6056,58 +6108,30 @@ static void define_builtin_types(CodeGen *g) {...@@ -6056,58 +6108,30 @@ static void define_builtin_types(CodeGen *g) {
6056 g->builtin_types.entry_usize = entry;6108 g->builtin_types.entry_usize = entry;
6057 }6109 }
6058 }6110 }
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);6112 auto add_fp_entry = [] (CodeGen *g,
6079 entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),6113 const char *name,
6080 debug_size_in_bits,6114 uint32_t bit_count,
6081 ZigLLVMEncoding_DW_ATE_float());6115 LLVMTypeRef type_ref,
6082 g->builtin_types.entry_f64 = entry;6116 TypeTableEntry **field) {
6083 g->primitive_type_table.put(&entry->name, entry);
6084 }
6085 {
6086 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);6117 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
6087 entry->type_ref = LLVMFP128Type();6118 entry->type_ref = type_ref;
6088 buf_init_from_str(&entry->name, "f128");6119 buf_init_from_str(&entry->name, name);
6089 entry->data.floating.bit_count = 128;6120 entry->data.floating.bit_count = bit_count;
60906121
6091 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);6122 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
6092 entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),6123 entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
6093 debug_size_in_bits,6124 debug_size_in_bits,
6094 ZigLLVMEncoding_DW_ATE_float());6125 ZigLLVMEncoding_DW_ATE_float());
6095 g->builtin_types.entry_f128 = entry;6126 *field = entry;
6096 g->primitive_type_table.put(&entry->name, entry);6127 g->primitive_type_table.put(&entry->name, entry);
6097 }6128 };
6098 {6129 add_fp_entry(g, "f16", 16, LLVMHalfType(), &g->builtin_types.entry_f16);
6099 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);6130 add_fp_entry(g, "f32", 32, LLVMFloatType(), &g->builtin_types.entry_f32);
6100 entry->type_ref = LLVMX86FP80Type();6131 add_fp_entry(g, "f64", 64, LLVMDoubleType(), &g->builtin_types.entry_f64);
6101 buf_init_from_str(&entry->name, "c_longdouble");6132 add_fp_entry(g, "f128", 128, LLVMFP128Type(), &g->builtin_types.entry_f128);
6102 entry->data.floating.bit_count = 80;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 }
6111 {6135 {
6112 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVoid);6136 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVoid);
6113 entry->type_ref = LLVMVoidType();6137 entry->type_ref = LLVMVoidType();
...@@ -6231,6 +6255,10 @@ static void define_builtin_fns(CodeGen *g) {...@@ -6231,6 +6255,10 @@ static void define_builtin_fns(CodeGen *g) {
6231 create_builtin_fn(g, BuiltinFnIdIntToFloat, "intToFloat", 2);6255 create_builtin_fn(g, BuiltinFnIdIntToFloat, "intToFloat", 2);
6232 create_builtin_fn(g, BuiltinFnIdFloatToInt, "floatToInt", 2);6256 create_builtin_fn(g, BuiltinFnIdFloatToInt, "floatToInt", 2);
6233 create_builtin_fn(g, BuiltinFnIdBoolToInt, "boolToInt", 1);6257 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);
6234 create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1);6262 create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1);
6235 create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);6263 create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
6236 create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int6264 create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int
...@@ -6267,6 +6295,9 @@ static void define_builtin_fns(CodeGen *g) {...@@ -6267,6 +6295,9 @@ static void define_builtin_fns(CodeGen *g) {
6267 create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0);6295 create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0);
6268 create_builtin_fn(g, BuiltinFnIdAtomicRmw, "atomicRmw", 5);6296 create_builtin_fn(g, BuiltinFnIdAtomicRmw, "atomicRmw", 5);
6269 create_builtin_fn(g, BuiltinFnIdAtomicLoad, "atomicLoad", 3);6297 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);
6270}6301}
62716302
6272static const char *bool_to_str(bool b) {6303static const char *bool_to_str(bool b) {
...@@ -6538,7 +6569,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {...@@ -6538,7 +6569,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
6538 "\n"6569 "\n"
6539 " pub const Union = struct {\n"6570 " pub const Union = struct {\n"
6540 " layout: ContainerLayout,\n"6571 " layout: ContainerLayout,\n"
6541 " tag_type: type,\n"6572 " tag_type: ?type,\n"
6542 " fields: []UnionField,\n"6573 " fields: []UnionField,\n"
6543 " defs: []Definition,\n"6574 " defs: []Definition,\n"
6544 " };\n"6575 " };\n"
...@@ -6555,20 +6586,20 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {...@@ -6555,20 +6586,20 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
6555 " pub const FnArg = struct {\n"6586 " pub const FnArg = struct {\n"
6556 " is_generic: bool,\n"6587 " is_generic: bool,\n"
6557 " is_noalias: bool,\n"6588 " is_noalias: bool,\n"
6558 " arg_type: type,\n"6589 " arg_type: ?type,\n"
6559 " };\n"6590 " };\n"
6560 "\n"6591 "\n"
6561 " pub const Fn = struct {\n"6592 " pub const Fn = struct {\n"
6562 " calling_convention: CallingConvention,\n"6593 " calling_convention: CallingConvention,\n"
6563 " is_generic: bool,\n"6594 " is_generic: bool,\n"
6564 " is_var_args: bool,\n"6595 " is_var_args: bool,\n"
6565 " return_type: type,\n"6596 " return_type: ?type,\n"
6566 " async_allocator_type: type,\n"6597 " async_allocator_type: ?type,\n"
6567 " args: []FnArg,\n"6598 " args: []FnArg,\n"
6568 " };\n"6599 " };\n"
6569 "\n"6600 "\n"
6570 " pub const Promise = struct {\n"6601 " pub const Promise = struct {\n"
6571 " child: type,\n"6602 " child: ?type,\n"
6572 " };\n"6603 " };\n"
6573 "\n"6604 "\n"
6574 " pub const Definition = struct {\n"6605 " pub const Definition = struct {\n"
src/ir.cpp+943-571
...@@ -11,9 +11,10 @@...@@ -11,9 +11,10 @@
11#include "ir.hpp"11#include "ir.hpp"
12#include "ir_print.hpp"12#include "ir_print.hpp"
13#include "os.hpp"13#include "os.hpp"
14#include "translate_c.hpp"
15#include "range_set.hpp"14#include "range_set.hpp"
16#include "softfloat.hpp"15#include "softfloat.hpp"
16#include "translate_c.hpp"
17#include "util.hpp"
1718
18struct IrExecContext {19struct IrExecContext {
19 ConstExprValue *mem_slot_list;20 ConstExprValue *mem_slot_list;
...@@ -65,12 +66,7 @@ enum ConstCastResultId {...@@ -65,12 +66,7 @@ enum ConstCastResultId {
65 ConstCastResultIdNullWrapPtr,66 ConstCastResultIdNullWrapPtr,
66};67};
6768
68struct ConstCastErrSetMismatch {
69 ZigList<ErrorTableEntry *> missing_errors;
70};
71
72struct ConstCastOnly;69struct ConstCastOnly;
73
74struct ConstCastArg {70struct ConstCastArg {
75 size_t arg_index;71 size_t arg_index;
76 ConstCastOnly *child;72 ConstCastOnly *child;
...@@ -80,15 +76,22 @@ struct ConstCastArgNoAlias {...@@ -80,15 +76,22 @@ struct ConstCastArgNoAlias {
80 size_t arg_index;76 size_t arg_index;
81};77};
8278
79struct ConstCastOptionalMismatch;
80struct ConstCastPointerMismatch;
81struct ConstCastSliceMismatch;
82struct ConstCastErrUnionErrSetMismatch;
83struct ConstCastErrUnionPayloadMismatch;
84struct ConstCastErrSetMismatch;
85
83struct ConstCastOnly {86struct ConstCastOnly {
84 ConstCastResultId id;87 ConstCastResultId id;
85 union {88 union {
86 ConstCastErrSetMismatch error_set;89 ConstCastErrSetMismatch *error_set_mismatch;
87 ConstCastOnly *pointer_child;90 ConstCastPointerMismatch *pointer_mismatch;
88 ConstCastOnly *slice_child;91 ConstCastSliceMismatch *slice_mismatch;
89 ConstCastOnly *optional_child;92 ConstCastOptionalMismatch *optional;
90 ConstCastOnly *error_union_payload;93 ConstCastErrUnionPayloadMismatch *error_union_payload;
91 ConstCastOnly *error_union_error_set;94 ConstCastErrUnionErrSetMismatch *error_union_error_set;
92 ConstCastOnly *return_type;95 ConstCastOnly *return_type;
93 ConstCastOnly *async_allocator_type;96 ConstCastOnly *async_allocator_type;
94 ConstCastOnly *null_wrap_ptr_child;97 ConstCastOnly *null_wrap_ptr_child;
...@@ -97,6 +100,39 @@ struct ConstCastOnly {...@@ -97,6 +100,39 @@ struct ConstCastOnly {
97 } data;100 } data;
98};101};
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
101static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);137static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);
102static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval);138static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval);
...@@ -468,6 +504,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFloatCast *) {...@@ -468,6 +504,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFloatCast *) {
468 return IrInstructionIdFloatCast;504 return IrInstructionIdFloatCast;
469}505}
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
471static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToFloat *) {519static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToFloat *) {
472 return IrInstructionIdIntToFloat;520 return IrInstructionIdIntToFloat;
473}521}
...@@ -588,6 +636,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToEnum *) {...@@ -588,6 +636,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToEnum *) {
588 return IrInstructionIdIntToEnum;636 return IrInstructionIdIntToEnum;
589}637}
590638
639static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumToInt *) {
640 return IrInstructionIdEnumToInt;
641}
642
591static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToErr *) {643static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToErr *) {
592 return IrInstructionIdIntToErr;644 return IrInstructionIdIntToErr;
593}645}
...@@ -1941,6 +1993,37 @@ static IrInstruction *ir_build_float_cast(IrBuilder *irb, Scope *scope, AstNode...@@ -1941,6 +1993,37 @@ static IrInstruction *ir_build_float_cast(IrBuilder *irb, Scope *scope, AstNode
1941 return &instruction->base;1993 return &instruction->base;
1942}1994}
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
1944static IrInstruction *ir_build_int_to_float(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_type, IrInstruction *target) {2027static IrInstruction *ir_build_int_to_float(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_type, IrInstruction *target) {
1945 IrInstructionIntToFloat *instruction = ir_build_instruction<IrInstructionIntToFloat>(irb, scope, source_node);2028 IrInstructionIntToFloat *instruction = ir_build_instruction<IrInstructionIntToFloat>(irb, scope, source_node);
1946 instruction->dest_type = dest_type;2029 instruction->dest_type = dest_type;
...@@ -2335,10 +2418,26 @@ static IrInstruction *ir_build_ptr_to_int(IrBuilder *irb, Scope *scope, AstNode...@@ -2335,10 +2418,26 @@ static IrInstruction *ir_build_ptr_to_int(IrBuilder *irb, Scope *scope, AstNode
2335}2418}
23362419
2337static IrInstruction *ir_build_int_to_enum(IrBuilder *irb, Scope *scope, AstNode *source_node,2420static IrInstruction *ir_build_int_to_enum(IrBuilder *irb, Scope *scope, AstNode *source_node,
2338 IrInstruction *target)2421 IrInstruction *dest_type, IrInstruction *target)
2339{2422{
2340 IrInstructionIntToEnum *instruction = ir_build_instruction<IrInstructionIntToEnum>(2423 IrInstructionIntToEnum *instruction = ir_build_instruction<IrInstructionIntToEnum>(
2341 irb, scope, source_node);2424 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);
2342 instruction->target = target;2441 instruction->target = target;
23432442
2344 ir_ref_instruction(target, irb->current_basic_block);2443 ir_ref_instruction(target, irb->current_basic_block);
...@@ -2946,7 +3045,7 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode...@@ -2946,7 +3045,7 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
29463045
2947 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_field_ptr, return_value);3046 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_field_ptr, return_value);
2948 IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node,3047 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));
2950 // TODO replace replacement_value with @intToPtr(?promise, 0x1) when it doesn't crash zig3049 // TODO replace replacement_value with @intToPtr(?promise, 0x1) when it doesn't crash zig
2951 IrInstruction *replacement_value = irb->exec->coro_handle;3050 IrInstruction *replacement_value = irb->exec->coro_handle;
2952 IrInstruction *maybe_await_handle = ir_build_atomic_rmw(irb, scope, node,3051 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...@@ -4054,6 +4153,46 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
4054 IrInstruction *result = ir_build_float_cast(irb, scope, node, arg0_value, arg1_value);4153 IrInstruction *result = ir_build_float_cast(irb, scope, node, arg0_value, arg1_value);
4055 return ir_lval_wrap(irb, scope, result, lval);4154 return ir_lval_wrap(irb, scope, result, lval);
4056 }4155 }
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 }
4057 case BuiltinFnIdIntToFloat:4196 case BuiltinFnIdIntToFloat:
4058 {4197 {
4059 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);4198 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...@@ -4084,6 +4223,26 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
4084 IrInstruction *result = ir_build_float_to_int(irb, scope, node, arg0_value, arg1_value);4223 IrInstruction *result = ir_build_float_to_int(irb, scope, node, arg0_value, arg1_value);
4085 return ir_lval_wrap(irb, scope, result, lval);4224 return ir_lval_wrap(irb, scope, result, lval);
4086 }4225 }
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 }
4087 case BuiltinFnIdBoolToInt:4246 case BuiltinFnIdBoolToInt:
4088 {4247 {
4089 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);4248 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...@@ -4605,6 +4764,31 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
4605 // this value does not mean anything since we passed non-null values for other arg4764 // this value does not mean anything since we passed non-null values for other arg
4606 AtomicOrderMonotonic);4765 AtomicOrderMonotonic);
4607 }4766 }
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 }
4608 }4792 }
4609 zig_unreachable();4793 zig_unreachable();
4610}4794}
...@@ -6471,7 +6655,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast...@@ -6471,7 +6655,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
6471 ir_build_store_ptr(irb, parent_scope, node, result_ptr_field_ptr, my_result_var_ptr);6655 ir_build_store_ptr(irb, parent_scope, node, result_ptr_field_ptr, my_result_var_ptr);
6472 IrInstruction *save_token = ir_build_coro_save(irb, parent_scope, node, irb->exec->coro_handle);6656 IrInstruction *save_token = ir_build_coro_save(irb, parent_scope, node, irb->exec->coro_handle);
6473 IrInstruction *promise_type_val = ir_build_const_type(irb, parent_scope, node,6657 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));
6475 IrInstruction *maybe_await_handle = ir_build_atomic_rmw(irb, parent_scope, node, 6659 IrInstruction *maybe_await_handle = ir_build_atomic_rmw(irb, parent_scope, node,
6476 promise_type_val, awaiter_field_ptr, nullptr, irb->exec->coro_handle, nullptr,6660 promise_type_val, awaiter_field_ptr, nullptr, irb->exec->coro_handle, nullptr,
6477 AtomicRmwOp_xchg, AtomicOrderSeqCst);6661 AtomicRmwOp_xchg, AtomicOrderSeqCst);
...@@ -6805,7 +6989,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6805,7 +6989,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6805 VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);6989 VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
6806 IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);6990 IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);
6807 IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node,6991 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));
6809 ir_build_var_decl(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value);6993 ir_build_var_decl(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value);
6810 irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var);6994 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...@@ -6928,6 +7112,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6928 IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr);7112 IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr);
6929 ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr);7113 ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr);
6930 }7114 }
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);
6931 ir_build_br(irb, scope, node, check_free_block, const_bool_false);7121 ir_build_br(irb, scope, node, check_free_block, const_bool_false);
69327122
6933 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);7123 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...@@ -6942,6 +7132,14 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6942 incoming_values[1] = const_bool_true;7132 incoming_values[1] = const_bool_true;
6943 IrInstruction *resume_awaiter = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);7133 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
6945 Buf *free_field_name = buf_create_from_str(ASYNC_FREE_FIELD_NAME);7143 Buf *free_field_name = buf_create_from_str(ASYNC_FREE_FIELD_NAME);
6946 IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node,7144 IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node,
6947 ImplicitAllocatorIdLocalVar);7145 ImplicitAllocatorIdLocalVar);
...@@ -6968,9 +7166,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6968,9 +7166,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6968 ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false);7166 ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false);
69697167
6970 ir_set_cursor_at_end_and_append_block(irb, resume_block);7168 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);
6974 ir_build_coro_resume(irb, scope, node, awaiter_handle);7169 ir_build_coro_resume(irb, scope, node, awaiter_handle);
6975 ir_build_br(irb, scope, node, irb->exec->coro_suspend_block, const_bool_false);7170 ir_build_br(irb, scope, node, irb->exec->coro_suspend_block, const_bool_false);
6976 }7171 }
...@@ -7055,6 +7250,11 @@ static bool float_has_fraction(ConstExprValue *const_val) {...@@ -7055,6 +7250,11 @@ static bool float_has_fraction(ConstExprValue *const_val) {
7055 return bigfloat_has_fraction(&const_val->data.x_bigfloat);7250 return bigfloat_has_fraction(&const_val->data.x_bigfloat);
7056 } else if (const_val->type->id == TypeTableEntryIdFloat) {7251 } else if (const_val->type->id == TypeTableEntryIdFloat) {
7057 switch (const_val->type->data.floating.bit_count) {7252 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 }
7058 case 32:7258 case 32:
7059 return floorf(const_val->data.x_f32) != const_val->data.x_f32;7259 return floorf(const_val->data.x_f32) != const_val->data.x_f32;
7060 case 64:7260 case 64:
...@@ -7078,6 +7278,9 @@ static void float_append_buf(Buf *buf, ConstExprValue *const_val) {...@@ -7078,6 +7278,9 @@ static void float_append_buf(Buf *buf, ConstExprValue *const_val) {
7078 bigfloat_append_buf(buf, &const_val->data.x_bigfloat);7278 bigfloat_append_buf(buf, &const_val->data.x_bigfloat);
7079 } else if (const_val->type->id == TypeTableEntryIdFloat) {7279 } else if (const_val->type->id == TypeTableEntryIdFloat) {
7080 switch (const_val->type->data.floating.bit_count) {7280 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;
7081 case 32:7284 case 32:
7082 buf_appendf(buf, "%f", const_val->data.x_f32);7285 buf_appendf(buf, "%f", const_val->data.x_f32);
7083 break;7286 break;
...@@ -7113,6 +7316,17 @@ static void float_init_bigint(BigInt *bigint, ConstExprValue *const_val) {...@@ -7113,6 +7316,17 @@ static void float_init_bigint(BigInt *bigint, ConstExprValue *const_val) {
7113 bigint_init_bigfloat(bigint, &const_val->data.x_bigfloat);7316 bigint_init_bigfloat(bigint, &const_val->data.x_bigfloat);
7114 } else if (const_val->type->id == TypeTableEntryIdFloat) {7317 } else if (const_val->type->id == TypeTableEntryIdFloat) {
7115 switch (const_val->type->data.floating.bit_count) {7318 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 }
7116 case 32:7330 case 32:
7117 if (const_val->data.x_f32 >= 0) {7331 if (const_val->data.x_f32 >= 0) {
7118 bigint_init_unsigned(bigint, (uint64_t)(const_val->data.x_f32));7332 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) {...@@ -7149,6 +7363,9 @@ static void float_init_bigfloat(ConstExprValue *dest_val, BigFloat *bigfloat) {
7149 bigfloat_init_bigfloat(&dest_val->data.x_bigfloat, bigfloat);7363 bigfloat_init_bigfloat(&dest_val->data.x_bigfloat, bigfloat);
7150 } else if (dest_val->type->id == TypeTableEntryIdFloat) {7364 } else if (dest_val->type->id == TypeTableEntryIdFloat) {
7151 switch (dest_val->type->data.floating.bit_count) {7365 switch (dest_val->type->data.floating.bit_count) {
7366 case 16:
7367 dest_val->data.x_f16 = bigfloat_to_f16(bigfloat);
7368 break;
7152 case 32:7369 case 32:
7153 dest_val->data.x_f32 = bigfloat_to_f32(bigfloat);7370 dest_val->data.x_f32 = bigfloat_to_f32(bigfloat);
7154 break;7371 break;
...@@ -7166,11 +7383,39 @@ static void float_init_bigfloat(ConstExprValue *dest_val, BigFloat *bigfloat) {...@@ -7166,11 +7383,39 @@ static void float_init_bigfloat(ConstExprValue *dest_val, BigFloat *bigfloat) {
7166 }7383 }
7167}7384}
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
7169static void float_init_f32(ConstExprValue *dest_val, float x) {7411static void float_init_f32(ConstExprValue *dest_val, float x) {
7170 if (dest_val->type->id == TypeTableEntryIdComptimeFloat) {7412 if (dest_val->type->id == TypeTableEntryIdComptimeFloat) {
7171 bigfloat_init_32(&dest_val->data.x_bigfloat, x);7413 bigfloat_init_32(&dest_val->data.x_bigfloat, x);
7172 } else if (dest_val->type->id == TypeTableEntryIdFloat) {7414 } else if (dest_val->type->id == TypeTableEntryIdFloat) {
7173 switch (dest_val->type->data.floating.bit_count) {7415 switch (dest_val->type->data.floating.bit_count) {
7416 case 16:
7417 dest_val->data.x_f16 = zig_double_to_f16(x);
7418 break;
7174 case 32:7419 case 32:
7175 dest_val->data.x_f32 = x;7420 dest_val->data.x_f32 = x;
7176 break;7421 break;
...@@ -7197,6 +7442,9 @@ static void float_init_f64(ConstExprValue *dest_val, double x) {...@@ -7197,6 +7442,9 @@ static void float_init_f64(ConstExprValue *dest_val, double x) {
7197 bigfloat_init_64(&dest_val->data.x_bigfloat, x);7442 bigfloat_init_64(&dest_val->data.x_bigfloat, x);
7198 } else if (dest_val->type->id == TypeTableEntryIdFloat) {7443 } else if (dest_val->type->id == TypeTableEntryIdFloat) {
7199 switch (dest_val->type->data.floating.bit_count) {7444 switch (dest_val->type->data.floating.bit_count) {
7445 case 16:
7446 dest_val->data.x_f16 = zig_double_to_f16(x);
7447 break;
7200 case 32:7448 case 32:
7201 dest_val->data.x_f32 = x;7449 dest_val->data.x_f32 = x;
7202 break;7450 break;
...@@ -7223,6 +7471,9 @@ static void float_init_f128(ConstExprValue *dest_val, float128_t x) {...@@ -7223,6 +7471,9 @@ static void float_init_f128(ConstExprValue *dest_val, float128_t x) {
7223 bigfloat_init_128(&dest_val->data.x_bigfloat, x);7471 bigfloat_init_128(&dest_val->data.x_bigfloat, x);
7224 } else if (dest_val->type->id == TypeTableEntryIdFloat) {7472 } else if (dest_val->type->id == TypeTableEntryIdFloat) {
7225 switch (dest_val->type->data.floating.bit_count) {7473 switch (dest_val->type->data.floating.bit_count) {
7474 case 16:
7475 dest_val->data.x_f16 = f128M_to_f16(&x);
7476 break;
7226 case 32:7477 case 32:
7227 {7478 {
7228 float32_t f32_val = f128M_to_f32(&x);7479 float32_t f32_val = f128M_to_f32(&x);
...@@ -7253,6 +7504,9 @@ static void float_init_float(ConstExprValue *dest_val, ConstExprValue *src_val)...@@ -7253,6 +7504,9 @@ static void float_init_float(ConstExprValue *dest_val, ConstExprValue *src_val)
7253 float_init_bigfloat(dest_val, &src_val->data.x_bigfloat);7504 float_init_bigfloat(dest_val, &src_val->data.x_bigfloat);
7254 } else if (src_val->type->id == TypeTableEntryIdFloat) {7505 } else if (src_val->type->id == TypeTableEntryIdFloat) {
7255 switch (src_val->type->data.floating.bit_count) {7506 switch (src_val->type->data.floating.bit_count) {
7507 case 16:
7508 float_init_f16(dest_val, src_val->data.x_f16);
7509 break;
7256 case 32:7510 case 32:
7257 float_init_f32(dest_val, src_val->data.x_f32);7511 float_init_f32(dest_val, src_val->data.x_f32);
7258 break;7512 break;
...@@ -7276,6 +7530,14 @@ static Cmp float_cmp(ConstExprValue *op1, ConstExprValue *op2) {...@@ -7276,6 +7530,14 @@ static Cmp float_cmp(ConstExprValue *op1, ConstExprValue *op2) {
7276 return bigfloat_cmp(&op1->data.x_bigfloat, &op2->data.x_bigfloat);7530 return bigfloat_cmp(&op1->data.x_bigfloat, &op2->data.x_bigfloat);
7277 } else if (op1->type->id == TypeTableEntryIdFloat) {7531 } else if (op1->type->id == TypeTableEntryIdFloat) {
7278 switch (op1->type->data.floating.bit_count) {7532 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 }
7279 case 32:7541 case 32:
7280 if (op1->data.x_f32 > op2->data.x_f32) {7542 if (op1->data.x_f32 > op2->data.x_f32) {
7281 return CmpGT;7543 return CmpGT;
...@@ -7313,6 +7575,17 @@ static Cmp float_cmp_zero(ConstExprValue *op) {...@@ -7313,6 +7575,17 @@ static Cmp float_cmp_zero(ConstExprValue *op) {
7313 return bigfloat_cmp_zero(&op->data.x_bigfloat);7575 return bigfloat_cmp_zero(&op->data.x_bigfloat);
7314 } else if (op->type->id == TypeTableEntryIdFloat) {7576 } else if (op->type->id == TypeTableEntryIdFloat) {
7315 switch (op->type->data.floating.bit_count) {7577 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 }
7316 case 32:7589 case 32:
7317 if (op->data.x_f32 < 0.0) {7590 if (op->data.x_f32 < 0.0) {
7318 return CmpLT;7591 return CmpLT;
...@@ -7354,6 +7627,9 @@ static void float_add(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal...@@ -7354,6 +7627,9 @@ static void float_add(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
7354 bigfloat_add(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);7627 bigfloat_add(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
7355 } else if (op1->type->id == TypeTableEntryIdFloat) {7628 } else if (op1->type->id == TypeTableEntryIdFloat) {
7356 switch (op1->type->data.floating.bit_count) {7629 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;
7357 case 32:7633 case 32:
7358 out_val->data.x_f32 = op1->data.x_f32 + op2->data.x_f32;7634 out_val->data.x_f32 = op1->data.x_f32 + op2->data.x_f32;
7359 return;7635 return;
...@@ -7378,6 +7654,9 @@ static void float_sub(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal...@@ -7378,6 +7654,9 @@ static void float_sub(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
7378 bigfloat_sub(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);7654 bigfloat_sub(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
7379 } else if (op1->type->id == TypeTableEntryIdFloat) {7655 } else if (op1->type->id == TypeTableEntryIdFloat) {
7380 switch (op1->type->data.floating.bit_count) {7656 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;
7381 case 32:7660 case 32:
7382 out_val->data.x_f32 = op1->data.x_f32 - op2->data.x_f32;7661 out_val->data.x_f32 = op1->data.x_f32 - op2->data.x_f32;
7383 return;7662 return;
...@@ -7402,6 +7681,9 @@ static void float_mul(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal...@@ -7402,6 +7681,9 @@ static void float_mul(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
7402 bigfloat_mul(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);7681 bigfloat_mul(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
7403 } else if (op1->type->id == TypeTableEntryIdFloat) {7682 } else if (op1->type->id == TypeTableEntryIdFloat) {
7404 switch (op1->type->data.floating.bit_count) {7683 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;
7405 case 32:7687 case 32:
7406 out_val->data.x_f32 = op1->data.x_f32 * op2->data.x_f32;7688 out_val->data.x_f32 = op1->data.x_f32 * op2->data.x_f32;
7407 return;7689 return;
...@@ -7426,6 +7708,9 @@ static void float_div(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal...@@ -7426,6 +7708,9 @@ static void float_div(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
7426 bigfloat_div(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);7708 bigfloat_div(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
7427 } else if (op1->type->id == TypeTableEntryIdFloat) {7709 } else if (op1->type->id == TypeTableEntryIdFloat) {
7428 switch (op1->type->data.floating.bit_count) {7710 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;
7429 case 32:7714 case 32:
7430 out_val->data.x_f32 = op1->data.x_f32 / op2->data.x_f32;7715 out_val->data.x_f32 = op1->data.x_f32 / op2->data.x_f32;
7431 return;7716 return;
...@@ -7450,21 +7735,15 @@ static void float_div_trunc(ConstExprValue *out_val, ConstExprValue *op1, ConstE...@@ -7450,21 +7735,15 @@ static void float_div_trunc(ConstExprValue *out_val, ConstExprValue *op1, ConstE
7450 bigfloat_div_trunc(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);7735 bigfloat_div_trunc(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
7451 } else if (op1->type->id == TypeTableEntryIdFloat) {7736 } else if (op1->type->id == TypeTableEntryIdFloat) {
7452 switch (op1->type->data.floating.bit_count) {7737 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;
7453 case 32:7742 case 32:
7454 out_val->data.x_f32 = op1->data.x_f32 / op2->data.x_f32;7743 out_val->data.x_f32 = truncf(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 }
7460 return;7744 return;
7461 case 64:7745 case 64:
7462 out_val->data.x_f64 = op1->data.x_f64 / op2->data.x_f64;7746 out_val->data.x_f64 = trunc(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 }
7468 return;7747 return;
7469 case 128:7748 case 128:
7470 f128M_div(&op1->data.x_f128, &op2->data.x_f128, &out_val->data.x_f128);7749 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...@@ -7485,6 +7764,10 @@ static void float_div_floor(ConstExprValue *out_val, ConstExprValue *op1, ConstE
7485 bigfloat_div_floor(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);7764 bigfloat_div_floor(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
7486 } else if (op1->type->id == TypeTableEntryIdFloat) {7765 } else if (op1->type->id == TypeTableEntryIdFloat) {
7487 switch (op1->type->data.floating.bit_count) {7766 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;
7488 case 32:7771 case 32:
7489 out_val->data.x_f32 = floorf(op1->data.x_f32 / op2->data.x_f32);7772 out_val->data.x_f32 = floorf(op1->data.x_f32 / op2->data.x_f32);
7490 return;7773 return;
...@@ -7510,6 +7793,9 @@ static void float_rem(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal...@@ -7510,6 +7793,9 @@ static void float_rem(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
7510 bigfloat_rem(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);7793 bigfloat_rem(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
7511 } else if (op1->type->id == TypeTableEntryIdFloat) {7794 } else if (op1->type->id == TypeTableEntryIdFloat) {
7512 switch (op1->type->data.floating.bit_count) {7795 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;
7513 case 32:7799 case 32:
7514 out_val->data.x_f32 = fmodf(op1->data.x_f32, op2->data.x_f32);7800 out_val->data.x_f32 = fmodf(op1->data.x_f32, op2->data.x_f32);
7515 return;7801 return;
...@@ -7527,6 +7813,24 @@ static void float_rem(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal...@@ -7527,6 +7813,24 @@ static void float_rem(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
7527 }7813 }
7528}7814}
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
7530static void float_mod(ConstExprValue *out_val, ConstExprValue *op1, ConstExprValue *op2) {7834static void float_mod(ConstExprValue *out_val, ConstExprValue *op1, ConstExprValue *op2) {
7531 assert(op1->type == op2->type);7835 assert(op1->type == op2->type);
7532 out_val->type = op1->type;7836 out_val->type = op1->type;
...@@ -7534,6 +7838,9 @@ static void float_mod(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal...@@ -7534,6 +7838,9 @@ static void float_mod(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
7534 bigfloat_mod(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);7838 bigfloat_mod(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
7535 } else if (op1->type->id == TypeTableEntryIdFloat) {7839 } else if (op1->type->id == TypeTableEntryIdFloat) {
7536 switch (op1->type->data.floating.bit_count) {7840 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;
7537 case 32:7844 case 32:
7538 out_val->data.x_f32 = fmodf(fmodf(op1->data.x_f32, op2->data.x_f32) + op2->data.x_f32, op2->data.x_f32);7845 out_val->data.x_f32 = fmodf(fmodf(op1->data.x_f32, op2->data.x_f32) + op2->data.x_f32, op2->data.x_f32);
7539 return;7846 return;
...@@ -7541,9 +7848,7 @@ static void float_mod(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal...@@ -7541,9 +7848,7 @@ static void float_mod(ConstExprValue *out_val, ConstExprValue *op1, ConstExprVal
7541 out_val->data.x_f64 = fmod(fmod(op1->data.x_f64, op2->data.x_f64) + op2->data.x_f64, op2->data.x_f64);7848 out_val->data.x_f64 = fmod(fmod(op1->data.x_f64, op2->data.x_f64) + op2->data.x_f64, op2->data.x_f64);
7542 return;7849 return;
7543 case 128:7850 case 128:
7544 f128M_rem(&op1->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);
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);
7547 return;7852 return;
7548 default:7853 default:
7549 zig_unreachable();7854 zig_unreachable();
...@@ -7559,6 +7864,12 @@ static void float_negate(ConstExprValue *out_val, ConstExprValue *op) {...@@ -7559,6 +7864,12 @@ static void float_negate(ConstExprValue *out_val, ConstExprValue *op) {
7559 bigfloat_negate(&out_val->data.x_bigfloat, &op->data.x_bigfloat);7864 bigfloat_negate(&out_val->data.x_bigfloat, &op->data.x_bigfloat);
7560 } else if (op->type->id == TypeTableEntryIdFloat) {7865 } else if (op->type->id == TypeTableEntryIdFloat) {
7561 switch (op->type->data.floating.bit_count) {7866 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 }
7562 case 32:7873 case 32:
7563 out_val->data.x_f32 = -op->data.x_f32;7874 out_val->data.x_f32 = -op->data.x_f32;
7564 return;7875 return;
...@@ -7581,6 +7892,9 @@ static void float_negate(ConstExprValue *out_val, ConstExprValue *op) {...@@ -7581,6 +7892,9 @@ static void float_negate(ConstExprValue *out_val, ConstExprValue *op) {
7581void float_write_ieee597(ConstExprValue *op, uint8_t *buf, bool is_big_endian) {7892void float_write_ieee597(ConstExprValue *op, uint8_t *buf, bool is_big_endian) {
7582 if (op->type->id == TypeTableEntryIdFloat) {7893 if (op->type->id == TypeTableEntryIdFloat) {
7583 switch (op->type->data.floating.bit_count) {7894 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;
7584 case 32:7898 case 32:
7585 memcpy(buf, &op->data.x_f32, 4); // TODO wrong when compiler is big endian7899 memcpy(buf, &op->data.x_f32, 4); // TODO wrong when compiler is big endian
7586 return;7900 return;
...@@ -7601,6 +7915,9 @@ void float_write_ieee597(ConstExprValue *op, uint8_t *buf, bool is_big_endian) {...@@ -7601,6 +7915,9 @@ void float_write_ieee597(ConstExprValue *op, uint8_t *buf, bool is_big_endian) {
7601void float_read_ieee597(ConstExprValue *val, uint8_t *buf, bool is_big_endian) {7915void float_read_ieee597(ConstExprValue *val, uint8_t *buf, bool is_big_endian) {
7602 if (val->type->id == TypeTableEntryIdFloat) {7916 if (val->type->id == TypeTableEntryIdFloat) {
7603 switch (val->type->data.floating.bit_count) {7917 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;
7604 case 32:7921 case 32:
7605 memcpy(&val->data.x_f32, buf, 4); // TODO wrong when compiler is big endian7922 memcpy(&val->data.x_f32, buf, 4); // TODO wrong when compiler is big endian
7606 return;7923 return;
...@@ -7796,9 +8113,10 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry...@@ -7796,9 +8113,10 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
77968113
7797 // * and [*] can do a const-cast-only to ?* and ?[*], respectively8114 // * and [*] can do a const-cast-only to ?* and ?[*], respectively
7798 // but not if there is a mutable parent pointer8115 // but not if there is a mutable parent pointer
8116 // and not if the pointer is zero bits
7799 if (!wanted_is_mutable && wanted_type->id == TypeTableEntryIdOptional &&8117 if (!wanted_is_mutable && wanted_type->id == TypeTableEntryIdOptional &&
7800 wanted_type->data.maybe.child_type->id == TypeTableEntryIdPointer &&8118 wanted_type->data.maybe.child_type->id == TypeTableEntryIdPointer &&
7801 actual_type->id == TypeTableEntryIdPointer)8119 actual_type->id == TypeTableEntryIdPointer && type_has_bits(actual_type))
7802 {8120 {
7803 ConstCastOnly child = types_match_const_cast_only(ira,8121 ConstCastOnly child = types_match_const_cast_only(ira,
7804 wanted_type->data.maybe.child_type, actual_type, source_node, wanted_is_mutable);8122 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...@@ -7824,8 +8142,10 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
7824 actual_type->data.pointer.child_type, source_node, !wanted_type->data.pointer.is_const);8142 actual_type->data.pointer.child_type, source_node, !wanted_type->data.pointer.is_const);
7825 if (child.id != ConstCastResultIdOk) {8143 if (child.id != ConstCastResultIdOk) {
7826 result.id = ConstCastResultIdPointerChild;8144 result.id = ConstCastResultIdPointerChild;
7827 result.data.pointer_child = allocate_nonzero<ConstCastOnly>(1);8145 result.data.pointer_mismatch = allocate_nonzero<ConstCastPointerMismatch>(1);
7828 *result.data.pointer_child = child;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;
7829 }8149 }
7830 return result;8150 return result;
7831 }8151 }
...@@ -7844,8 +8164,10 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry...@@ -7844,8 +8164,10 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
7844 actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const);8164 actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const);
7845 if (child.id != ConstCastResultIdOk) {8165 if (child.id != ConstCastResultIdOk) {
7846 result.id = ConstCastResultIdSliceChild;8166 result.id = ConstCastResultIdSliceChild;
7847 result.data.slice_child = allocate_nonzero<ConstCastOnly>(1);8167 result.data.slice_mismatch = allocate_nonzero<ConstCastSliceMismatch>(1);
7848 *result.data.slice_child = child;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;
7849 }8171 }
7850 return result;8172 return result;
7851 }8173 }
...@@ -7857,8 +8179,10 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry...@@ -7857,8 +8179,10 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
7857 actual_type->data.maybe.child_type, source_node, wanted_is_mutable);8179 actual_type->data.maybe.child_type, source_node, wanted_is_mutable);
7858 if (child.id != ConstCastResultIdOk) {8180 if (child.id != ConstCastResultIdOk) {
7859 result.id = ConstCastResultIdOptionalChild;8181 result.id = ConstCastResultIdOptionalChild;
7860 result.data.optional_child = allocate_nonzero<ConstCastOnly>(1);8182 result.data.optional = allocate_nonzero<ConstCastOptionalMismatch>(1);
7861 *result.data.optional_child = child;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;
7862 }8186 }
7863 return result;8187 return result;
7864 }8188 }
...@@ -7869,16 +8193,20 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry...@@ -7869,16 +8193,20 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
7869 actual_type->data.error_union.payload_type, source_node, wanted_is_mutable);8193 actual_type->data.error_union.payload_type, source_node, wanted_is_mutable);
7870 if (payload_child.id != ConstCastResultIdOk) {8194 if (payload_child.id != ConstCastResultIdOk) {
7871 result.id = ConstCastResultIdErrorUnionPayload;8195 result.id = ConstCastResultIdErrorUnionPayload;
7872 result.data.error_union_payload = allocate_nonzero<ConstCastOnly>(1);8196 result.data.error_union_payload = allocate_nonzero<ConstCastErrUnionPayloadMismatch>(1);
7873 *result.data.error_union_payload = payload_child;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;
7874 return result;8200 return result;
7875 }8201 }
7876 ConstCastOnly error_set_child = types_match_const_cast_only(ira, wanted_type->data.error_union.err_set_type,8202 ConstCastOnly error_set_child = types_match_const_cast_only(ira, wanted_type->data.error_union.err_set_type,
7877 actual_type->data.error_union.err_set_type, source_node, wanted_is_mutable);8203 actual_type->data.error_union.err_set_type, source_node, wanted_is_mutable);
7878 if (error_set_child.id != ConstCastResultIdOk) {8204 if (error_set_child.id != ConstCastResultIdOk) {
7879 result.id = ConstCastResultIdErrorUnionErrorSet;8205 result.id = ConstCastResultIdErrorUnionErrorSet;
7880 result.data.error_union_error_set = allocate_nonzero<ConstCastOnly>(1);8206 result.data.error_union_error_set = allocate_nonzero<ConstCastErrUnionErrSetMismatch>(1);
7881 *result.data.error_union_error_set = error_set_child;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;
7882 return result;8210 return result;
7883 }8211 }
7884 return result;8212 return result;
...@@ -7920,8 +8248,9 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry...@@ -7920,8 +8248,9 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
7920 if (error_entry == nullptr) {8248 if (error_entry == nullptr) {
7921 if (result.id == ConstCastResultIdOk) {8249 if (result.id == ConstCastResultIdOk) {
7922 result.id = ConstCastResultIdErrSet;8250 result.id = ConstCastResultIdErrSet;
8251 result.data.error_set_mismatch = allocate<ConstCastErrSetMismatch>(1);
7923 }8252 }
7924 result.data.error_set.missing_errors.append(contained_error_entry);8253 result.data.error_set_mismatch->missing_errors.append(contained_error_entry);
7925 }8254 }
7926 }8255 }
7927 free(errors);8256 free(errors);
...@@ -8016,325 +8345,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry...@@ -8016,325 +8345,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry
8016 return result;8345 return result;
8017}8346}
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
8338static void update_errors_helper(CodeGen *g, ErrorTableEntry ***errors, size_t *errors_count) {8348static void update_errors_helper(CodeGen *g, ErrorTableEntry ***errors, size_t *errors_count) {
8339 size_t old_errors_count = *errors_count;8349 size_t old_errors_count = *errors_count;
8340 *errors_count = g->errors_by_index.length;8350 *errors_count = g->errors_by_index.length;
...@@ -8881,7 +8891,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod...@@ -8881,7 +8891,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
8881 } else if (prev_inst->value.type->id == TypeTableEntryIdOptional) {8891 } else if (prev_inst->value.type->id == TypeTableEntryIdOptional) {
8882 return prev_inst->value.type;8892 return prev_inst->value.type;
8883 } else {8893 } else {
8884 return get_maybe_type(ira->codegen, prev_inst->value.type);8894 return get_optional_type(ira->codegen, prev_inst->value.type);
8885 }8895 }
8886 } else {8896 } else {
8887 return prev_inst->value.type;8897 return prev_inst->value.type;
...@@ -8909,7 +8919,8 @@ static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_...@@ -8909,7 +8919,8 @@ static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_
8909 }8919 }
8910}8920}
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,
8913 ConstExprValue *other_val, TypeTableEntry *other_type,8924 ConstExprValue *other_val, TypeTableEntry *other_type,
8914 ConstExprValue *const_val, TypeTableEntry *new_type)8925 ConstExprValue *const_val, TypeTableEntry *new_type)
8915{8926{
...@@ -8934,6 +8945,9 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,...@@ -8934,6 +8945,9 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
8934 if (other_val->type->id == TypeTableEntryIdComptimeFloat) {8945 if (other_val->type->id == TypeTableEntryIdComptimeFloat) {
8935 assert(new_type->id == TypeTableEntryIdFloat);8946 assert(new_type->id == TypeTableEntryIdFloat);
8936 switch (new_type->data.floating.bit_count) {8947 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;
8937 case 32:8951 case 32:
8938 const_val->data.x_f32 = bigfloat_to_f32(&other_val->data.x_bigfloat);8952 const_val->data.x_f32 = bigfloat_to_f32(&other_val->data.x_bigfloat);
8939 break;8953 break;
...@@ -8964,6 +8978,9 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,...@@ -8964,6 +8978,9 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
8964 BigFloat bigfloat;8978 BigFloat bigfloat;
8965 bigfloat_init_bigint(&bigfloat, &other_val->data.x_bigint);8979 bigfloat_init_bigint(&bigfloat, &other_val->data.x_bigint);
8966 switch (new_type->data.floating.bit_count) {8980 switch (new_type->data.floating.bit_count) {
8981 case 16:
8982 const_val->data.x_f16 = bigfloat_to_f16(&bigfloat);
8983 break;
8967 case 32:8984 case 32:
8968 const_val->data.x_f32 = bigfloat_to_f32(&bigfloat);8985 const_val->data.x_f32 = bigfloat_to_f32(&bigfloat);
8969 break;8986 break;
...@@ -8981,6 +8998,20 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,...@@ -8981,6 +8998,20 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
8981 }8998 }
8982 case CastOpFloatToInt:8999 case CastOpFloatToInt:
8983 float_init_bigint(&const_val->data.x_bigint, other_val);9000 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
8984 const_val->special = ConstValSpecialStatic;9015 const_val->special = ConstValSpecialStatic;
8985 break;9016 break;
8986 case CastOpBoolToInt:9017 case CastOpBoolToInt:
...@@ -8988,6 +9019,7 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,...@@ -8988,6 +9019,7 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
8988 const_val->special = ConstValSpecialStatic;9019 const_val->special = ConstValSpecialStatic;
8989 break;9020 break;
8990 }9021 }
9022 return true;
8991}9023}
8992static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,9024static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
8993 TypeTableEntry *wanted_type, CastOp cast_op, bool need_alloca)9025 TypeTableEntry *wanted_type, CastOp cast_op, bool need_alloca)
...@@ -8997,8 +9029,11 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -8997,8 +9029,11 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst
8997 {9029 {
8998 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,9030 IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
8999 source_instr->source_node, wanted_type);9031 source_instr->source_node, wanted_type);
9000 eval_const_expr_implicit_cast(cast_op, &value->value, value->value.type,9032 if (!eval_const_expr_implicit_cast(ira, source_instr, cast_op, &value->value, value->value.type,
9001 &result->value, wanted_type);9033 &result->value, wanted_type))
9034 {
9035 return ira->codegen->invalid_instruction;
9036 }
9002 return result;9037 return result;
9003 } else {9038 } else {
9004 IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type, value, cast_op);9039 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) {...@@ -9073,11 +9108,6 @@ static bool is_container(TypeTableEntry *type) {
9073 type->id == TypeTableEntryIdUnion;9108 type->id == TypeTableEntryIdUnion;
9074}9109}
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
9081static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb, IrInstruction *ref_old_instruction) {9111static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb, IrInstruction *ref_old_instruction) {
9082 assert(old_bb);9112 assert(old_bb);
90839113
...@@ -9631,6 +9661,8 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s...@@ -9631,6 +9661,8 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
9631 IrInstruction *result = ir_build_slice(&ira->new_irb, source_instr->scope,9661 IrInstruction *result = ir_build_slice(&ira->new_irb, source_instr->scope,
9632 source_instr->source_node, array_ptr, start, end, false);9662 source_instr->source_node, array_ptr, start, end, false);
9633 result->value.type = wanted_type;9663 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;
9634 ir_add_alloca(ira, result, result->value.type);9666 ir_add_alloca(ira, result, result->value.type);
96359667
9636 return result;9668 return result;
...@@ -9851,7 +9883,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour...@@ -9851,7 +9883,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
9851 }9883 }
98529884
9853 IrInstruction *result = ir_build_int_to_enum(&ira->new_irb, source_instr->scope,9885 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);
9855 result->value.type = wanted_type;9887 result->value.type = wanted_type;
9856 return result;9888 return result;
9857}9889}
...@@ -10063,6 +10095,83 @@ static IrInstruction *ir_analyze_ptr_to_array(IrAnalyze *ira, IrInstruction *sou...@@ -10063,6 +10095,83 @@ static IrInstruction *ir_analyze_ptr_to_array(IrAnalyze *ira, IrInstruction *sou
10063 return result;10095 return result;
10064}10096}
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
10066static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,10175static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
10067 TypeTableEntry *wanted_type, IrInstruction *value)10176 TypeTableEntry *wanted_type, IrInstruction *value)
10068{10177{
...@@ -10073,12 +10182,14 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -10073,12 +10182,14 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10073 return ira->codegen->invalid_instruction;10182 return ira->codegen->invalid_instruction;
10074 }10183 }
1007510184
10076 // explicit match or non-const to const10185 // perfect match or non-const to const
10077 if (types_match_const_cast_only(ira, wanted_type, actual_type, source_node, false).id == ConstCastResultIdOk) {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) {
10078 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);10189 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);
10079 }10190 }
1008010191
10081 // explicit widening conversion10192 // widening conversion
10082 if (wanted_type->id == TypeTableEntryIdInt &&10193 if (wanted_type->id == TypeTableEntryIdInt &&
10083 actual_type->id == TypeTableEntryIdInt &&10194 actual_type->id == TypeTableEntryIdInt &&
10084 wanted_type->data.integral.is_signed == actual_type->data.integral.is_signed &&10195 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...@@ -10095,7 +10206,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10095 return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);10206 return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
10096 }10207 }
1009710208
10098 // explicit float widening conversion10209 // float widening conversion
10099 if (wanted_type->id == TypeTableEntryIdFloat &&10210 if (wanted_type->id == TypeTableEntryIdFloat &&
10100 actual_type->id == TypeTableEntryIdFloat &&10211 actual_type->id == TypeTableEntryIdFloat &&
10101 wanted_type->data.floating.bit_count >= actual_type->data.floating.bit_count)10212 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...@@ -10104,14 +10215,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10104 }10215 }
1010510216
1010610217
10107 // explicit error set cast10218 // cast from [N]T to []const T
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
10115 if (is_slice(wanted_type) && actual_type->id == TypeTableEntryIdArray) {10219 if (is_slice(wanted_type) && actual_type->id == TypeTableEntryIdArray) {
10116 TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;10220 TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
10117 assert(ptr_type->id == TypeTableEntryIdPointer);10221 assert(ptr_type->id == TypeTableEntryIdPointer);
...@@ -10123,7 +10227,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -10123,7 +10227,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10123 }10227 }
10124 }10228 }
1012510229
10126 // explicit cast from &const [N]T to []const T10230 // cast from *const [N]T to []const T
10127 if (is_slice(wanted_type) &&10231 if (is_slice(wanted_type) &&
10128 actual_type->id == TypeTableEntryIdPointer &&10232 actual_type->id == TypeTableEntryIdPointer &&
10129 actual_type->data.pointer.is_const &&10233 actual_type->data.pointer.is_const &&
...@@ -10142,7 +10246,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -10142,7 +10246,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10142 }10246 }
10143 }10247 }
1014410248
10145 // explicit cast from [N]T to &const []const N10249 // cast from [N]T to *const []const T
10146 if (wanted_type->id == TypeTableEntryIdPointer &&10250 if (wanted_type->id == TypeTableEntryIdPointer &&
10147 wanted_type->data.pointer.is_const &&10251 wanted_type->data.pointer.is_const &&
10148 is_slice(wanted_type->data.pointer.child_type) &&10252 is_slice(wanted_type->data.pointer.child_type) &&
...@@ -10167,7 +10271,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -10167,7 +10271,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10167 }10271 }
10168 }10272 }
1016910273
10170 // explicit cast from [N]T to ?[]const N10274 // cast from [N]T to ?[]const T
10171 if (wanted_type->id == TypeTableEntryIdOptional &&10275 if (wanted_type->id == TypeTableEntryIdOptional &&
10172 is_slice(wanted_type->data.maybe.child_type) &&10276 is_slice(wanted_type->data.maybe.child_type) &&
10173 actual_type->id == TypeTableEntryIdArray)10277 actual_type->id == TypeTableEntryIdArray)
...@@ -10191,53 +10295,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -10191,53 +10295,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10191 }10295 }
10192 }10296 }
1019310297
10194 // explicit cast from []T to []u8 or []u8 to []T10298 // *[N]T 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
10241 if (wanted_type->id == TypeTableEntryIdPointer &&10299 if (wanted_type->id == TypeTableEntryIdPointer &&
10242 wanted_type->data.pointer.ptr_len == PtrLenUnknown &&10300 wanted_type->data.pointer.ptr_len == PtrLenUnknown &&
10243 actual_type->id == TypeTableEntryIdPointer &&10301 actual_type->id == TypeTableEntryIdPointer &&
...@@ -10251,7 +10309,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -10251,7 +10309,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10251 return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_type);10309 return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_type);
10252 }10310 }
1025310311
10254 // explicit *[N]T to []T10312 // *[N]T to []T
10255 if (is_slice(wanted_type) &&10313 if (is_slice(wanted_type) &&
10256 actual_type->id == TypeTableEntryIdPointer &&10314 actual_type->id == TypeTableEntryIdPointer &&
10257 actual_type->data.pointer.ptr_len == PtrLenSingle &&10315 actual_type->data.pointer.ptr_len == PtrLenSingle &&
...@@ -10268,7 +10326,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -10268,7 +10326,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10268 }10326 }
1026910327
1027010328
10271 // explicit cast from T to ?T10329 // cast from T to ?T
10272 // note that the *T to ?*T case is handled via the "ConstCastOnly" mechanism10330 // note that the *T to ?*T case is handled via the "ConstCastOnly" mechanism
10273 if (wanted_type->id == TypeTableEntryIdOptional) {10331 if (wanted_type->id == TypeTableEntryIdOptional) {
10274 TypeTableEntry *wanted_child_type = wanted_type->data.maybe.child_type;10332 TypeTableEntry *wanted_child_type = wanted_type->data.maybe.child_type;
...@@ -10300,14 +10358,14 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -10300,14 +10358,14 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10300 }10358 }
10301 }10359 }
1030210360
10303 // explicit cast from null literal to maybe type10361 // cast from null literal to maybe type
10304 if (wanted_type->id == TypeTableEntryIdOptional &&10362 if (wanted_type->id == TypeTableEntryIdOptional &&
10305 actual_type->id == TypeTableEntryIdNull)10363 actual_type->id == TypeTableEntryIdNull)
10306 {10364 {
10307 return ir_analyze_null_to_maybe(ira, source_instr, value, wanted_type);10365 return ir_analyze_null_to_maybe(ira, source_instr, value, wanted_type);
10308 }10366 }
1030910367
10310 // explicit cast from child type of error type to error type10368 // cast from child type of error type to error type
10311 if (wanted_type->id == TypeTableEntryIdErrorUnion) {10369 if (wanted_type->id == TypeTableEntryIdErrorUnion) {
10312 if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type,10370 if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type,
10313 source_node, false).id == ConstCastResultIdOk)10371 source_node, false).id == ConstCastResultIdOk)
...@@ -10324,7 +10382,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -10324,7 +10382,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10324 }10382 }
10325 }10383 }
1032610384
10327 // explicit cast from [N]T to E![]const T10385 // cast from [N]T to E![]const T
10328 if (wanted_type->id == TypeTableEntryIdErrorUnion &&10386 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
10329 is_slice(wanted_type->data.error_union.payload_type) &&10387 is_slice(wanted_type->data.error_union.payload_type) &&
10330 actual_type->id == TypeTableEntryIdArray)10388 actual_type->id == TypeTableEntryIdArray)
...@@ -10348,14 +10406,14 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -10348,14 +10406,14 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10348 }10406 }
10349 }10407 }
1035010408
10351 // explicit cast from error set to error union type10409 // cast from error set to error union type
10352 if (wanted_type->id == TypeTableEntryIdErrorUnion &&10410 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
10353 actual_type->id == TypeTableEntryIdErrorSet)10411 actual_type->id == TypeTableEntryIdErrorSet)
10354 {10412 {
10355 return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type);10413 return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type);
10356 }10414 }
1035710415
10358 // explicit cast from T to E!?T10416 // cast from T to E!?T
10359 if (wanted_type->id == TypeTableEntryIdErrorUnion &&10417 if (wanted_type->id == TypeTableEntryIdErrorUnion &&
10360 wanted_type->data.error_union.payload_type->id == TypeTableEntryIdOptional &&10418 wanted_type->data.error_union.payload_type->id == TypeTableEntryIdOptional &&
10361 actual_type->id != TypeTableEntryIdOptional)10419 actual_type->id != TypeTableEntryIdOptional)
...@@ -10378,8 +10436,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -10378,8 +10436,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10378 }10436 }
10379 }10437 }
1038010438
10381 // explicit cast from number literal to another type10439 // cast from number literal to another type
10382 // explicit cast from number literal to *const integer10440 // cast from number literal to *const integer
10383 if (actual_type->id == TypeTableEntryIdComptimeFloat ||10441 if (actual_type->id == TypeTableEntryIdComptimeFloat ||
10384 actual_type->id == TypeTableEntryIdComptimeInt)10442 actual_type->id == TypeTableEntryIdComptimeInt)
10385 {10443 {
...@@ -10429,7 +10487,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -10429,7 +10487,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10429 }10487 }
10430 }10488 }
1043110489
10432 // explicit cast from typed number to integer or float literal.10490 // cast from typed number to integer or float literal.
10433 // works when the number is known at compile time10491 // works when the number is known at compile time
10434 if (instr_is_comptime(value) &&10492 if (instr_is_comptime(value) &&
10435 ((actual_type->id == TypeTableEntryIdInt && wanted_type->id == TypeTableEntryIdComptimeInt) ||10493 ((actual_type->id == TypeTableEntryIdInt && wanted_type->id == TypeTableEntryIdComptimeInt) ||
...@@ -10438,32 +10496,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -10438,32 +10496,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10438 return ir_analyze_number_to_literal(ira, source_instr, value, wanted_type);10496 return ir_analyze_number_to_literal(ira, source_instr, value, wanted_type);
10439 }10497 }
1044010498
10441 // explicit cast from T!void to integer type which can fit it10499 // cast from union to the enum type of the union
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
10467 if (actual_type->id == TypeTableEntryIdUnion && wanted_type->id == TypeTableEntryIdEnum) {10500 if (actual_type->id == TypeTableEntryIdUnion && wanted_type->id == TypeTableEntryIdEnum) {
10468 type_ensure_zero_bits_known(ira->codegen, actual_type);10501 type_ensure_zero_bits_known(ira->codegen, actual_type);
10469 if (type_is_invalid(actual_type))10502 if (type_is_invalid(actual_type))
...@@ -10474,7 +10507,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -10474,7 +10507,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10474 }10507 }
10475 }10508 }
1047610509
10477 // explicit enum to union which has the enum as the tag type10510 // enum to union which has the enum as the tag type
10478 if (wanted_type->id == TypeTableEntryIdUnion && actual_type->id == TypeTableEntryIdEnum &&10511 if (wanted_type->id == TypeTableEntryIdUnion && actual_type->id == TypeTableEntryIdEnum &&
10479 (wanted_type->data.unionation.decl_node->data.container_decl.auto_enum ||10512 (wanted_type->data.unionation.decl_node->data.container_decl.auto_enum ||
10480 wanted_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr))10513 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...@@ -10485,7 +10518,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10485 }10518 }
10486 }10519 }
1048710520
10488 // explicit enum to &const union which has the enum as the tag type10521 // enum to &const union which has the enum as the tag type
10489 if (actual_type->id == TypeTableEntryIdEnum && wanted_type->id == TypeTableEntryIdPointer) {10522 if (actual_type->id == TypeTableEntryIdEnum && wanted_type->id == TypeTableEntryIdPointer) {
10490 TypeTableEntry *union_type = wanted_type->data.pointer.child_type;10523 TypeTableEntry *union_type = wanted_type->data.pointer.child_type;
10491 if (union_type->data.unionation.decl_node->data.container_decl.auto_enum ||10524 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...@@ -10506,7 +10539,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10506 }10539 }
10507 }10540 }
1050810541
10509 // explicit cast from *T to *[1]T10542 // cast from *T to *[1]T
10510 if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&10543 if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
10511 actual_type->id == TypeTableEntryIdPointer && actual_type->data.pointer.ptr_len == PtrLenSingle)10544 actual_type->id == TypeTableEntryIdPointer && actual_type->data.pointer.ptr_len == PtrLenSingle)
10512 {10545 {
...@@ -10530,7 +10563,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -10530,7 +10563,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10530 }10563 }
10531 }10564 }
1053210565
10533 // explicit cast from T to *T where T is zero bits10566 // cast from T to *T where T is zero bits
10534 if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&10567 if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
10535 types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,10568 types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
10536 actual_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)10569 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...@@ -10545,12 +10578,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10545 }10578 }
1054610579
1054710580
10548 // explicit cast from undefined to anything10581 // cast from undefined to anything
10549 if (actual_type->id == TypeTableEntryIdUndefined) {10582 if (actual_type->id == TypeTableEntryIdUndefined) {
10550 return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type);10583 return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type);
10551 }10584 }
1055210585
10553 // explicit cast from something to const pointer of it10586 // cast from something to const pointer of it
10554 if (!type_requires_comptime(actual_type)) {10587 if (!type_requires_comptime(actual_type)) {
10555 TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);10588 TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);
10556 if (types_match_const_cast_only(ira, wanted_type, const_ptr_actual, source_node, false).id == ConstCastResultIdOk) {10589 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...@@ -10558,10 +10591,11 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10558 }10591 }
10559 }10592 }
1056010593
10561 ir_add_error_node(ira, source_instr->source_node,10594 ErrorMsg *parent_msg = ir_add_error_node(ira, source_instr->source_node,
10562 buf_sprintf("invalid cast from type '%s' to '%s'",10595 buf_sprintf("expected type '%s', found '%s'",
10563 buf_ptr(&actual_type->name),10596 buf_ptr(&wanted_type->name),
10564 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);
10565 return ira->codegen->invalid_instruction;10599 return ira->codegen->invalid_instruction;
10566}10600}
1056710601
...@@ -10578,22 +10612,7 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Typ...@@ -10578,22 +10612,7 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Typ
10578 if (value->value.type->id == TypeTableEntryIdUnreachable)10612 if (value->value.type->id == TypeTableEntryIdUnreachable)
10579 return value;10613 return value;
1058010614
10581 ImplicitCastMatchResult result = ir_types_match_with_implicit_cast(ira, expected_type, value->value.type, value);10615 return ir_analyze_cast(ira, value, expected_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();
10597}10616}
1059810617
10599static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) {10618static 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...@@ -10889,10 +10908,15 @@ static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp
10889 if (casted_op2 == ira->codegen->invalid_instruction)10908 if (casted_op2 == ira->codegen->invalid_instruction)
10890 return ira->codegen->builtin_types.entry_invalid;10909 return ira->codegen->builtin_types.entry_invalid;
1089110910
10892 ConstExprValue *op1_val = &casted_op1->value;10911 if (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2)) {
10893 ConstExprValue *op2_val = &casted_op2->value;
10894 if (op1_val->special != ConstValSpecialRuntime && op2_val->special != ConstValSpecialRuntime) {
10895 ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base);10912 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
10897 assert(casted_op1->value.type->id == TypeTableEntryIdBool);10921 assert(casted_op1->value.type->id == TypeTableEntryIdBool);
10898 assert(casted_op2->value.type->id == TypeTableEntryIdBool);10922 assert(casted_op2->value.type->id == TypeTableEntryIdBool);
...@@ -11042,9 +11066,14 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp...@@ -11042,9 +11066,14 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
11042 }11066 }
11043 }11067 }
1104411068
11045 ConstExprValue *op1_val = &op1->value;11069 if (instr_is_comptime(op1) && instr_is_comptime(op2)) {
11046 ConstExprValue *op2_val = &op2->value;11070 ConstExprValue *op1_val = ir_resolve_const(ira, op1, UndefBad);
11047 if (value_is_comptime(op1_val) && value_is_comptime(op2_val)) {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
11048 bool answer;11077 bool answer;
11049 bool are_equal = op1_val->data.x_err_set->value == op2_val->data.x_err_set->value;11078 bool are_equal = op1_val->data.x_err_set->value == op2_val->data.x_err_set->value;
11050 if (op_id == IrBinOpCmpEq) {11079 if (op_id == IrBinOpCmpEq) {
...@@ -11133,10 +11162,15 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp...@@ -11133,10 +11162,15 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
11133 if (casted_op2 == ira->codegen->invalid_instruction)11162 if (casted_op2 == ira->codegen->invalid_instruction)
11134 return ira->codegen->builtin_types.entry_invalid;11163 return ira->codegen->builtin_types.entry_invalid;
1113511164
11136 ConstExprValue *op1_val = &casted_op1->value;
11137 ConstExprValue *op2_val = &casted_op2->value;
11138 bool one_possible_value = !type_requires_comptime(resolved_type) && !type_has_bits(resolved_type);11165 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
11140 bool answer;11174 bool answer;
11141 if (resolved_type->id == TypeTableEntryIdComptimeFloat || resolved_type->id == TypeTableEntryIdFloat) {11175 if (resolved_type->id == TypeTableEntryIdComptimeFloat || resolved_type->id == TypeTableEntryIdFloat) {
11142 Cmp cmp_result = float_cmp(op1_val, op2_val);11176 Cmp cmp_result = float_cmp(op1_val, op2_val);
...@@ -11164,11 +11198,17 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp...@@ -11164,11 +11198,17 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
11164 if (resolved_type->id == TypeTableEntryIdInt && !resolved_type->data.integral.is_signed) {11198 if (resolved_type->id == TypeTableEntryIdInt && !resolved_type->data.integral.is_signed) {
11165 ConstExprValue *known_left_val;11199 ConstExprValue *known_left_val;
11166 IrBinOp flipped_op_id;11200 IrBinOp flipped_op_id;
11167 if (value_is_comptime(op1_val)) {11201 if (instr_is_comptime(casted_op1)) {
11168 known_left_val = op1_val;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
11169 flipped_op_id = op_id;11206 flipped_op_id = op_id;
11170 } else if (value_is_comptime(op2_val)) {11207 } else if (instr_is_comptime(casted_op2)) {
11171 known_left_val = op2_val;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
11172 if (op_id == IrBinOpCmpLessThan) {11212 if (op_id == IrBinOpCmpLessThan) {
11173 flipped_op_id = IrBinOpCmpGreaterThan;11213 flipped_op_id = IrBinOpCmpGreaterThan;
11174 } else if (op_id == IrBinOpCmpGreaterThan) {11214 } else if (op_id == IrBinOpCmpGreaterThan) {
...@@ -11413,6 +11453,26 @@ static TypeTableEntry *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *...@@ -11413,6 +11453,26 @@ static TypeTableEntry *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *
11413 } else {11453 } else {
11414 TypeTableEntry *shift_amt_type = get_smallest_unsigned_int_type(ira->codegen,11454 TypeTableEntry *shift_amt_type = get_smallest_unsigned_int_type(ira->codegen,
11415 op1->value.type->data.integral.bit_count - 1);11455 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
11417 casted_op2 = ir_implicit_cast(ira, op2, shift_amt_type);11477 casted_op2 = ir_implicit_cast(ira, op2, shift_amt_type);
11418 if (casted_op2 == ira->codegen->invalid_instruction)11478 if (casted_op2 == ira->codegen->invalid_instruction)
...@@ -11420,8 +11480,14 @@ static TypeTableEntry *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *...@@ -11420,8 +11480,14 @@ static TypeTableEntry *ir_analyze_bit_shift(IrAnalyze *ira, IrInstructionBinOp *
11420 }11480 }
1142111481
11422 if (instr_is_comptime(op1) && instr_is_comptime(casted_op2)) {11482 if (instr_is_comptime(op1) && instr_is_comptime(casted_op2)) {
11423 ConstExprValue *op1_val = &op1->value;11483 ConstExprValue *op1_val = ir_resolve_const(ira, op1, UndefBad);
11424 ConstExprValue *op2_val = &casted_op2->value;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
11425 IrInstruction *result_instruction = ir_get_const(ira, &bin_op_instruction->base);11491 IrInstruction *result_instruction = ir_get_const(ira, &bin_op_instruction->base);
11426 ir_link_new_instruction(result_instruction, &bin_op_instruction->base);11492 ir_link_new_instruction(result_instruction, &bin_op_instruction->base);
11427 ConstExprValue *out_val = &result_instruction->value;11493 ConstExprValue *out_val = &result_instruction->value;
...@@ -11500,7 +11566,15 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp...@@ -11500,7 +11566,15 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
11500 if (is_signed_div) {11566 if (is_signed_div) {
11501 bool ok = false;11567 bool ok = false;
11502 if (instr_is_comptime(op1) && instr_is_comptime(op2)) {11568 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) {
11504 // the division by zero error will be caught later, but we don't have a11578 // the division by zero error will be caught later, but we don't have a
11505 // division function ambiguity problem.11579 // division function ambiguity problem.
11506 op_id = IrBinOpDivTrunc;11580 op_id = IrBinOpDivTrunc;
...@@ -11508,8 +11582,8 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp...@@ -11508,8 +11582,8 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
11508 } else {11582 } else {
11509 BigInt trunc_result;11583 BigInt trunc_result;
11510 BigInt floor_result;11584 BigInt floor_result;
11511 bigint_div_trunc(&trunc_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);
11512 bigint_div_floor(&floor_result, &op1->value.data.x_bigint, &op2->value.data.x_bigint);11586 bigint_div_floor(&floor_result, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
11513 if (bigint_cmp(&trunc_result, &floor_result) == CmpEQ) {11587 if (bigint_cmp(&trunc_result, &floor_result) == CmpEQ) {
11514 ok = true;11588 ok = true;
11515 op_id = IrBinOpDivTrunc;11589 op_id = IrBinOpDivTrunc;
...@@ -11530,7 +11604,15 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp...@@ -11530,7 +11604,15 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
11530 if (is_signed_div && (is_int || is_float)) {11604 if (is_signed_div && (is_int || is_float)) {
11531 bool ok = false;11605 bool ok = false;
11532 if (instr_is_comptime(op1) && instr_is_comptime(op2)) {11606 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
11533 if (is_int) {11611 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
11534 if (bigint_cmp_zero(&op2->value.data.x_bigint) == CmpEQ) {11616 if (bigint_cmp_zero(&op2->value.data.x_bigint) == CmpEQ) {
11535 // the division by zero error will be caught later, but we don't11617 // the division by zero error will be caught later, but we don't
11536 // have a remainder function ambiguity problem11618 // have a remainder function ambiguity problem
...@@ -11538,14 +11620,19 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp...@@ -11538,14 +11620,19 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
11538 } else {11620 } else {
11539 BigInt rem_result;11621 BigInt rem_result;
11540 BigInt mod_result;11622 BigInt mod_result;
11541 bigint_rem(&rem_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);
11542 bigint_mod(&mod_result, &op1->value.data.x_bigint, &op2->value.data.x_bigint);11624 bigint_mod(&mod_result, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
11543 ok = bigint_cmp(&rem_result, &mod_result) == CmpEQ;11625 ok = bigint_cmp(&rem_result, &mod_result) == CmpEQ;
11544 }11626 }
11545 } else {11627 } else {
11546 IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, resolved_type);11628 IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, resolved_type);
11547 if (casted_op2 == ira->codegen->invalid_instruction)11629 if (casted_op2 == ira->codegen->invalid_instruction)
11548 return ira->codegen->builtin_types.entry_invalid;11630 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
11549 if (float_cmp_zero(&casted_op2->value) == CmpEQ) {11636 if (float_cmp_zero(&casted_op2->value) == CmpEQ) {
11550 // the division by zero error will be caught later, but we don't11637 // the division by zero error will be caught later, but we don't
11551 // have a remainder function ambiguity problem11638 // have a remainder function ambiguity problem
...@@ -11553,8 +11640,8 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp...@@ -11553,8 +11640,8 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
11553 } else {11640 } else {
11554 ConstExprValue rem_result;11641 ConstExprValue rem_result;
11555 ConstExprValue mod_result;11642 ConstExprValue mod_result;
11556 float_rem(&rem_result, &op1->value, &casted_op2->value);11643 float_rem(&rem_result, op1_val, op2_val);
11557 float_mod(&mod_result, &op1->value, &casted_op2->value);11644 float_mod(&mod_result, op1_val, op2_val);
11558 ok = float_cmp(&rem_result, &mod_result) == CmpEQ;11645 ok = float_cmp(&rem_result, &mod_result) == CmpEQ;
11559 }11646 }
11560 }11647 }
...@@ -11612,8 +11699,13 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp...@@ -11612,8 +11699,13 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
11612 return ira->codegen->builtin_types.entry_invalid;11699 return ira->codegen->builtin_types.entry_invalid;
1161311700
11614 if (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2)) {11701 if (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2)) {
11615 ConstExprValue *op1_val = &casted_op1->value;11702 ConstExprValue *op1_val = ir_resolve_const(ira, casted_op1, UndefBad);
11616 ConstExprValue *op2_val = &casted_op2->value;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
11617 IrInstruction *result_instruction = ir_get_const(ira, &bin_op_instruction->base);11709 IrInstruction *result_instruction = ir_get_const(ira, &bin_op_instruction->base);
11618 ir_link_new_instruction(result_instruction, &bin_op_instruction->base);11710 ir_link_new_instruction(result_instruction, &bin_op_instruction->base);
11619 ConstExprValue *out_val = &result_instruction->value;11711 ConstExprValue *out_val = &result_instruction->value;
...@@ -11788,9 +11880,16 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *...@@ -11788,9 +11880,16 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *
11788 out_val->data.x_ptr.data.base_array.array_val = out_array_val;11880 out_val->data.x_ptr.data.base_array.array_val = out_array_val;
11789 out_val->data.x_ptr.data.base_array.elem_index = 0;11881 out_val->data.x_ptr.data.base_array.elem_index = 0;
11790 }11882 }
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);
11793 expand_undef_array(ira->codegen, op1_array_val);11891 expand_undef_array(ira->codegen, op1_array_val);
11892 expand_undef_array(ira->codegen, op2_array_val);
1179411893
11795 size_t next_index = 0;11894 size_t next_index = 0;
11796 for (size_t i = op1_array_index; i < op1_array_end; i += 1, next_index += 1) {11895 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...@@ -11842,10 +11941,14 @@ static TypeTableEntry *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp
11842 }11941 }
1184311942
11844 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);11943 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
11850 uint64_t i = 0;11953 uint64_t i = 0;
11851 for (uint64_t x = 0; x < mult_amt; x += 1) {11954 for (uint64_t x = 0; x < mult_amt; x += 1) {
...@@ -12243,7 +12346,7 @@ static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,...@@ -12243,7 +12346,7 @@ static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
12243{12346{
12244 if (instruction->optional == IrInstructionErrorReturnTrace::Null) {12347 if (instruction->optional == IrInstructionErrorReturnTrace::Null) {
12245 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);12348 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);
12247 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {12350 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {
12248 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);12351 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
12249 assert(get_codegen_ptr_type(optional_type) != nullptr);12352 assert(get_codegen_ptr_type(optional_type) != nullptr);
...@@ -13172,7 +13275,11 @@ static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp...@@ -13172,7 +13275,11 @@ static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp
13172 // one of the ptr instructions13275 // one of the ptr instructions
1317313276
13174 if (instr_is_comptime(value)) {13277 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);
13176 if (pointee->type == child_type) {13283 if (pointee->type == child_type) {
13177 ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base);13284 ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base);
13178 copy_const_val(out_val, pointee, value->value.data.x_ptr.mut == ConstPtrMutComptimeConst);13285 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...@@ -13221,7 +13328,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
13221 case TypeTableEntryIdPromise:13328 case TypeTableEntryIdPromise:
13222 {13329 {
13223 ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base);13330 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);
13225 return ira->codegen->builtin_types.entry_type;13332 return ira->codegen->builtin_types.entry_type;
13226 }13333 }
13227 case TypeTableEntryIdUnreachable:13334 case TypeTableEntryIdUnreachable:
...@@ -13289,7 +13396,7 @@ static TypeTableEntry *ir_analyze_bin_not(IrAnalyze *ira, IrInstructionUnOp *ins...@@ -13289,7 +13396,7 @@ static TypeTableEntry *ir_analyze_bin_not(IrAnalyze *ira, IrInstructionUnOp *ins
13289 if (expr_type->id == TypeTableEntryIdInt) {13396 if (expr_type->id == TypeTableEntryIdInt) {
13290 if (instr_is_comptime(value)) {13397 if (instr_is_comptime(value)) {
13291 ConstExprValue *target_const_val = ir_resolve_const(ira, value, UndefBad);13398 ConstExprValue *target_const_val = ir_resolve_const(ira, value, UndefBad);
13292 if (!target_const_val)13399 if (target_const_val == nullptr)
13293 return ira->codegen->builtin_types.entry_invalid;13400 return ira->codegen->builtin_types.entry_invalid;
1329413401
13295 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);13402 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...@@ -16045,6 +16152,9 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIn
16045 assert(target->value.type->id == TypeTableEntryIdEnum);16152 assert(target->value.type->id == TypeTableEntryIdEnum);
1604616153
16047 if (instr_is_comptime(target)) {16154 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;
16048 TypeEnumField *field = find_enum_field_by_tag(target->value.type, &target->value.data.x_bigint);16158 TypeEnumField *field = find_enum_field_by_tag(target->value.type, &target->value.data.x_bigint);
16049 ConstExprValue *array_val = create_const_str_lit(ira->codegen, field->name);16159 ConstExprValue *array_val = create_const_str_lit(ira->codegen, field->name);
16050 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);16160 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...@@ -16442,7 +16552,7 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop
16442 true, false, PtrLenUnknown,16552 true, false, PtrLenUnknown,
16443 get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8),16553 get_abi_alignment(ira->codegen, ira->codegen->builtin_types.entry_u8),
16444 0, 0);16554 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));
16446 if (fn_node->is_extern && buf_len(fn_node->lib_name) > 0) {16556 if (fn_node->is_extern && buf_len(fn_node->lib_name) > 0) {
16447 fn_def_fields[6].data.x_optional = create_const_vals(1);16557 fn_def_fields[6].data.x_optional = create_const_vals(1);
16448 ConstExprValue *lib_name = create_const_str_lit(ira->codegen, fn_node->lib_name);16558 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...@@ -16722,16 +16832,20 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
16722 ConstExprValue *fields = create_const_vals(1);16832 ConstExprValue *fields = create_const_vals(1);
16723 result->data.x_struct.fields = fields;16833 result->data.x_struct.fields = fields;
1672416834
16725 // @TODO ?type instead of using @typeOf(undefined) when we have no type.16835 // child: ?type
16726 // child: type
16727 ensure_field_index(result->type, "child", 0);16836 ensure_field_index(result->type, "child", 0);
16728 fields[0].special = ConstValSpecialStatic;16837 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
16731 if (type_entry->data.promise.result_type == nullptr)16840 if (type_entry->data.promise.result_type == nullptr)
16732 fields[0].data.x_type = ira->codegen->builtin_types.entry_undef;16841 fields[0].data.x_optional = nullptr;
16733 else16842 else {
16734 fields[0].data.x_type = type_entry->data.promise.result_type;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
16736 break;16850 break;
16737 }16851 }
...@@ -16872,19 +16986,23 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t...@@ -16872,19 +16986,23 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
16872 fields[0].special = ConstValSpecialStatic;16986 fields[0].special = ConstValSpecialStatic;
16873 fields[0].type = ir_type_info_get_type(ira, "ContainerLayout");16987 fields[0].type = ir_type_info_get_type(ira, "ContainerLayout");
16874 bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.unionation.layout);16988 bigint_init_unsigned(&fields[0].data.x_enum_tag, type_entry->data.unionation.layout);
16875 // tag_type: type16989 // tag_type: ?type
16876 ensure_field_index(result->type, "tag_type", 1);16990 ensure_field_index(result->type, "tag_type", 1);
16877 fields[1].special = ConstValSpecialStatic;16991 fields[1].special = ConstValSpecialStatic;
16878 fields[1].type = ira->codegen->builtin_types.entry_type;16992 fields[1].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
16879 // @TODO ?type instead of using @typeOf(undefined) when we have no type.16993
16880 AstNode *union_decl_node = type_entry->data.unionation.decl_node;16994 AstNode *union_decl_node = type_entry->data.unionation.decl_node;
16881 if (union_decl_node->data.container_decl.auto_enum ||16995 if (union_decl_node->data.container_decl.auto_enum ||
16882 union_decl_node->data.container_decl.init_arg_expr != nullptr)16996 union_decl_node->data.container_decl.init_arg_expr != nullptr)
16883 {16997 {
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;
16885 }17003 }
16886 else17004 else
16887 fields[1].data.x_type = ira->codegen->builtin_types.entry_undef;17005 fields[1].data.x_optional = nullptr;
16888 // fields: []TypeInfo.UnionField17006 // fields: []TypeInfo.UnionField
16889 ensure_field_index(result->type, "fields", 2);17007 ensure_field_index(result->type, "fields", 2);
1689017008
...@@ -16911,9 +17029,9 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t...@@ -16911,9 +17029,9 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
1691117029
16912 ConstExprValue *inner_fields = create_const_vals(3);17030 ConstExprValue *inner_fields = create_const_vals(3);
16913 inner_fields[1].special = ConstValSpecialStatic;17031 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) {
16917 inner_fields[1].data.x_optional = nullptr;17035 inner_fields[1].data.x_optional = nullptr;
16918 } else {17036 } else {
16919 inner_fields[1].data.x_optional = create_const_vals(1);17037 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...@@ -16982,7 +17100,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
1698217100
16983 ConstExprValue *inner_fields = create_const_vals(3);17101 ConstExprValue *inner_fields = create_const_vals(3);
16984 inner_fields[1].special = ConstValSpecialStatic;17102 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
16987 if (!type_has_bits(struct_field->type_entry)) {17105 if (!type_has_bits(struct_field->type_entry)) {
16988 inner_fields[1].data.x_optional = nullptr;17106 inner_fields[1].data.x_optional = nullptr;
...@@ -17022,8 +17140,6 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t...@@ -17022,8 +17140,6 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
17022 ConstExprValue *fields = create_const_vals(6);17140 ConstExprValue *fields = create_const_vals(6);
17023 result->data.x_struct.fields = fields;17141 result->data.x_struct.fields = fields;
1702417142
17025 // @TODO Fix type = undefined with ?type
17026
17027 // calling_convention: TypeInfo.CallingConvention17143 // calling_convention: TypeInfo.CallingConvention
17028 ensure_field_index(result->type, "calling_convention", 0);17144 ensure_field_index(result->type, "calling_convention", 0);
17029 fields[0].special = ConstValSpecialStatic;17145 fields[0].special = ConstValSpecialStatic;
...@@ -17041,22 +17157,32 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t...@@ -17041,22 +17157,32 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
17041 fields[2].special = ConstValSpecialStatic;17157 fields[2].special = ConstValSpecialStatic;
17042 fields[2].type = ira->codegen->builtin_types.entry_bool;17158 fields[2].type = ira->codegen->builtin_types.entry_bool;
17043 fields[2].data.x_bool = type_entry->data.fn.fn_type_id.is_var_args;17159 fields[2].data.x_bool = type_entry->data.fn.fn_type_id.is_var_args;
17044 // return_type: type17160 // return_type: ?type
17045 ensure_field_index(result->type, "return_type", 3);17161 ensure_field_index(result->type, "return_type", 3);
17046 fields[3].special = ConstValSpecialStatic;17162 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);
17048 if (type_entry->data.fn.fn_type_id.return_type == nullptr)17164 if (type_entry->data.fn.fn_type_id.return_type == nullptr)
17049 fields[3].data.x_type = ira->codegen->builtin_types.entry_undef;17165 fields[3].data.x_optional = nullptr;
17050 else17166 else {
17051 fields[3].data.x_type = type_entry->data.fn.fn_type_id.return_type;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 }
17052 // async_allocator_type: type17173 // async_allocator_type: type
17053 ensure_field_index(result->type, "async_allocator_type", 4);17174 ensure_field_index(result->type, "async_allocator_type", 4);
17054 fields[4].special = ConstValSpecialStatic;17175 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);
17056 if (type_entry->data.fn.fn_type_id.async_allocator_type == nullptr)17177 if (type_entry->data.fn.fn_type_id.async_allocator_type == nullptr)
17057 fields[4].data.x_type = ira->codegen->builtin_types.entry_undef;17178 fields[4].data.x_optional = nullptr;
17058 else17179 else {
17059 fields[4].data.x_type = type_entry->data.fn.fn_type_id.async_allocator_type;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 }
17060 // args: []TypeInfo.FnArg17186 // args: []TypeInfo.FnArg
17061 TypeTableEntry *type_info_fn_arg_type = ir_type_info_get_type(ira, "FnArg");17187 TypeTableEntry *type_info_fn_arg_type = ir_type_info_get_type(ira, "FnArg");
17062 size_t fn_arg_count = type_entry->data.fn.fn_type_id.param_count -17188 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...@@ -17090,12 +17216,17 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t
17090 inner_fields[1].type = ira->codegen->builtin_types.entry_bool;17216 inner_fields[1].type = ira->codegen->builtin_types.entry_bool;
17091 inner_fields[1].data.x_bool = fn_param_info->is_noalias;17217 inner_fields[1].data.x_bool = fn_param_info->is_noalias;
17092 inner_fields[2].special = ConstValSpecialStatic;17218 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
17095 if (arg_is_generic)17221 if (arg_is_generic)
17096 inner_fields[2].data.x_type = ira->codegen->builtin_types.entry_undef;17222 inner_fields[2].data.x_optional = nullptr;
17097 else17223 else {
17098 inner_fields[2].data.x_type = fn_param_info->type;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
17100 fn_arg_val->data.x_struct.fields = inner_fields;17231 fn_arg_val->data.x_struct.fields = inner_fields;
17101 fn_arg_val->data.x_struct.parent.id = ConstParentIdArray;17232 fn_arg_val->data.x_struct.parent.id = ConstParentIdArray;
...@@ -17437,7 +17568,7 @@ static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstruct...@@ -17437,7 +17568,7 @@ static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstruct
17437 IrInstruction *result = ir_build_cmpxchg(&ira->new_irb, instruction->base.scope, instruction->base.source_node,17568 IrInstruction *result = ir_build_cmpxchg(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
17438 nullptr, casted_ptr, casted_cmp_value, casted_new_value, nullptr, nullptr, instruction->is_weak,17569 nullptr, casted_ptr, casted_cmp_value, casted_new_value, nullptr, nullptr, instruction->is_weak,
17439 operand_type, success_order, failure_order);17570 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);
17441 ir_link_new_instruction(result, &instruction->base);17572 ir_link_new_instruction(result, &instruction->base);
17442 ir_add_alloca(ira, result, result->value.type);17573 ir_add_alloca(ira, result, result->value.type);
17443 return result->value.type;17574 return result->value.type;
...@@ -17593,6 +17724,137 @@ static TypeTableEntry *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstr...@@ -17593,6 +17724,137 @@ static TypeTableEntry *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstr
17593 return dest_type;17724 return dest_type;
17594}17725}
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
17596static TypeTableEntry *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) {17858static TypeTableEntry *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) {
17597 TypeTableEntry *dest_type = ir_resolve_type(ira, instruction->dest_type->other);17859 TypeTableEntry *dest_type = ir_resolve_type(ira, instruction->dest_type->other);
17598 if (type_is_invalid(dest_type))17860 if (type_is_invalid(dest_type))
...@@ -17627,6 +17889,39 @@ static TypeTableEntry *ir_analyze_instruction_float_to_int(IrAnalyze *ira, IrIns...@@ -17627,6 +17889,39 @@ static TypeTableEntry *ir_analyze_instruction_float_to_int(IrAnalyze *ira, IrIns
17627 return dest_type;17889 return dest_type;
17628}17890}
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
17630static TypeTableEntry *ir_analyze_instruction_bool_to_int(IrAnalyze *ira, IrInstructionBoolToInt *instruction) {17925static TypeTableEntry *ir_analyze_instruction_bool_to_int(IrAnalyze *ira, IrInstructionBoolToInt *instruction) {
17631 IrInstruction *target = instruction->target->other;17926 IrInstruction *target = instruction->target->other;
17632 if (type_is_invalid(target->value.type))17927 if (type_is_invalid(target->value.type))
...@@ -17681,9 +17976,13 @@ static TypeTableEntry *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstruc...@@ -17681,9 +17976,13 @@ static TypeTableEntry *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstruc
17681 if (type_is_invalid(casted_value->value.type))17976 if (type_is_invalid(casted_value->value.type))
17682 return ira->codegen->builtin_types.entry_invalid;17977 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
17685 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);17984 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;
17687 return bool_type;17986 return bool_type;
17688 }17987 }
1768917988
...@@ -18944,7 +19243,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3...@@ -18944,7 +19243,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
18944 old_align_bytes = ptr_type->data.pointer.alignment;19243 old_align_bytes = ptr_type->data.pointer.alignment;
18945 TypeTableEntry *better_ptr_type = adjust_ptr_align(ira->codegen, ptr_type, align_bytes);19244 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);
18948 } else if (target_type->id == TypeTableEntryIdOptional &&19247 } else if (target_type->id == TypeTableEntryIdOptional &&
18949 target_type->data.maybe.child_type->id == TypeTableEntryIdFn)19248 target_type->data.maybe.child_type->id == TypeTableEntryIdFn)
18950 {19249 {
...@@ -18952,7 +19251,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3...@@ -18952,7 +19251,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
18952 old_align_bytes = fn_type_id.alignment;19251 old_align_bytes = fn_type_id.alignment;
18953 fn_type_id.alignment = align_bytes;19252 fn_type_id.alignment = align_bytes;
18954 TypeTableEntry *fn_type = get_fn_type(ira->codegen, &fn_type_id);19253 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);
18956 } else if (is_slice(target_type)) {19255 } else if (is_slice(target_type)) {
18957 TypeTableEntry *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;19256 TypeTableEntry *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;
18958 old_align_bytes = slice_ptr_type->data.pointer.alignment;19257 old_align_bytes = slice_ptr_type->data.pointer.alignment;
...@@ -19713,7 +20012,7 @@ static TypeTableEntry *ir_analyze_instruction_coro_free(IrAnalyze *ira, IrInstru...@@ -19713,7 +20012,7 @@ static TypeTableEntry *ir_analyze_instruction_coro_free(IrAnalyze *ira, IrInstru
19713 instruction->base.source_node, coro_id, coro_handle);20012 instruction->base.source_node, coro_id, coro_handle);
19714 ir_link_new_instruction(result, &instruction->base);20013 ir_link_new_instruction(result, &instruction->base);
19715 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, false);20014 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);
19717 return result->value.type;20016 return result->value.type;
19718}20017}
1971920018
...@@ -19781,7 +20080,7 @@ static TypeTableEntry *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira,...@@ -19781,7 +20080,7 @@ static TypeTableEntry *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira,
19781 instruction->base.source_node, alloc_fn, coro_size);20080 instruction->base.source_node, alloc_fn, coro_size);
19782 ir_link_new_instruction(result, &instruction->base);20081 ir_link_new_instruction(result, &instruction->base);
19783 TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, false);20082 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);
19785 return result->value.type;20084 return result->value.type;
19786}20085}
1978720086
...@@ -20034,6 +20333,9 @@ static TypeTableEntry *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstruction...@@ -20034,6 +20333,9 @@ static TypeTableEntry *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstruction
20034 bigfloat_sqrt(&out_val->data.x_bigfloat, &val->data.x_bigfloat);20333 bigfloat_sqrt(&out_val->data.x_bigfloat, &val->data.x_bigfloat);
20035 } else if (float_type->id == TypeTableEntryIdFloat) {20334 } else if (float_type->id == TypeTableEntryIdFloat) {
20036 switch (float_type->data.floating.bit_count) {20335 switch (float_type->data.floating.bit_count) {
20336 case 16:
20337 out_val->data.x_f16 = f16_sqrt(val->data.x_f16);
20338 break;
20037 case 32:20339 case 32:
20038 out_val->data.x_f32 = sqrtf(val->data.x_f32);20340 out_val->data.x_f32 = sqrtf(val->data.x_f32);
20039 break;20341 break;
...@@ -20054,7 +20356,9 @@ static TypeTableEntry *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstruction...@@ -20054,7 +20356,9 @@ static TypeTableEntry *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstruction
20054 }20356 }
2005520357
20056 assert(float_type->id == TypeTableEntryIdFloat);20358 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) {
20058 ir_add_error(ira, instruction->type, buf_sprintf("compiler TODO: add implementation of sqrt for '%s'", buf_ptr(&float_type->name)));20362 ir_add_error(ira, instruction->type, buf_sprintf("compiler TODO: add implementation of sqrt for '%s'", buf_ptr(&float_type->name)));
20059 return ira->codegen->builtin_types.entry_invalid;20363 return ira->codegen->builtin_types.entry_invalid;
20060 }20364 }
...@@ -20066,13 +20370,63 @@ static TypeTableEntry *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstruction...@@ -20066,13 +20370,63 @@ static TypeTableEntry *ir_analyze_instruction_sqrt(IrAnalyze *ira, IrInstruction
20066 return result->value.type;20370 return result->value.type;
20067}20371}
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
20069static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {20426static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
20070 switch (instruction->id) {20427 switch (instruction->id) {
20071 case IrInstructionIdInvalid:20428 case IrInstructionIdInvalid:
20072 case IrInstructionIdWidenOrShorten:20429 case IrInstructionIdWidenOrShorten:
20073 case IrInstructionIdIntToEnum:
20074 case IrInstructionIdIntToErr:
20075 case IrInstructionIdErrToInt:
20076 case IrInstructionIdStructInit:20430 case IrInstructionIdStructInit:
20077 case IrInstructionIdUnionInit:20431 case IrInstructionIdUnionInit:
20078 case IrInstructionIdStructFieldPtr:20432 case IrInstructionIdStructFieldPtr:
...@@ -20193,6 +20547,12 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -20193,6 +20547,12 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
20193 return ir_analyze_instruction_int_cast(ira, (IrInstructionIntCast *)instruction);20547 return ir_analyze_instruction_int_cast(ira, (IrInstructionIntCast *)instruction);
20194 case IrInstructionIdFloatCast:20548 case IrInstructionIdFloatCast:
20195 return ir_analyze_instruction_float_cast(ira, (IrInstructionFloatCast *)instruction);20549 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);
20196 case IrInstructionIdIntToFloat:20556 case IrInstructionIdIntToFloat:
20197 return ir_analyze_instruction_int_to_float(ira, (IrInstructionIntToFloat *)instruction);20557 return ir_analyze_instruction_int_to_float(ira, (IrInstructionIntToFloat *)instruction);
20198 case IrInstructionIdFloatToInt:20558 case IrInstructionIdFloatToInt:
...@@ -20327,6 +20687,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -20327,6 +20687,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
20327 return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction);20687 return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction);
20328 case IrInstructionIdSqrt:20688 case IrInstructionIdSqrt:
20329 return ir_analyze_instruction_sqrt(ira, (IrInstructionSqrt *)instruction);20689 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);
20330 }20698 }
20331 zig_unreachable();20699 zig_unreachable();
20332}20700}
...@@ -20544,9 +20912,13 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -20544,9 +20912,13 @@ bool ir_has_side_effects(IrInstruction *instruction) {
20544 case IrInstructionIdAtomicLoad:20912 case IrInstructionIdAtomicLoad:
20545 case IrInstructionIdIntCast:20913 case IrInstructionIdIntCast:
20546 case IrInstructionIdFloatCast:20914 case IrInstructionIdFloatCast:
20915 case IrInstructionIdErrSetCast:
20547 case IrInstructionIdIntToFloat:20916 case IrInstructionIdIntToFloat:
20548 case IrInstructionIdFloatToInt:20917 case IrInstructionIdFloatToInt:
20549 case IrInstructionIdBoolToInt:20918 case IrInstructionIdBoolToInt:
20919 case IrInstructionIdFromBytes:
20920 case IrInstructionIdToBytes:
20921 case IrInstructionIdEnumToInt:
20550 return false;20922 return false;
2055120923
20552 case IrInstructionIdAsm:20924 case IrInstructionIdAsm:
src/ir_print.cpp+45
...@@ -664,6 +664,28 @@ static void ir_print_float_cast(IrPrint *irp, IrInstructionFloatCast *instructio...@@ -664,6 +664,28 @@ static void ir_print_float_cast(IrPrint *irp, IrInstructionFloatCast *instructio
664 fprintf(irp->f, ")");664 fprintf(irp->f, ")");
665}665}
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
667static void ir_print_int_to_float(IrPrint *irp, IrInstructionIntToFloat *instruction) {689static void ir_print_int_to_float(IrPrint *irp, IrInstructionIntToFloat *instruction) {
668 fprintf(irp->f, "@intToFloat(");690 fprintf(irp->f, "@intToFloat(");
669 ir_print_other_instruction(irp, instruction->dest_type);691 ir_print_other_instruction(irp, instruction->dest_type);
...@@ -906,6 +928,17 @@ static void ir_print_int_to_ptr(IrPrint *irp, IrInstructionIntToPtr *instruction...@@ -906,6 +928,17 @@ static void ir_print_int_to_ptr(IrPrint *irp, IrInstructionIntToPtr *instruction
906928
907static void ir_print_int_to_enum(IrPrint *irp, IrInstructionIntToEnum *instruction) {929static void ir_print_int_to_enum(IrPrint *irp, IrInstructionIntToEnum *instruction) {
908 fprintf(irp->f, "@intToEnum(");930 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(");
909 ir_print_other_instruction(irp, instruction->target);942 ir_print_other_instruction(irp, instruction->target);
910 fprintf(irp->f, ")");943 fprintf(irp->f, ")");
911}944}
...@@ -1461,6 +1494,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1461,6 +1494,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1461 case IrInstructionIdFloatCast:1494 case IrInstructionIdFloatCast:
1462 ir_print_float_cast(irp, (IrInstructionFloatCast *)instruction);1495 ir_print_float_cast(irp, (IrInstructionFloatCast *)instruction);
1463 break;1496 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;
1464 case IrInstructionIdIntToFloat:1506 case IrInstructionIdIntToFloat:
1465 ir_print_int_to_float(irp, (IrInstructionIntToFloat *)instruction);1507 ir_print_int_to_float(irp, (IrInstructionIntToFloat *)instruction);
1466 break;1508 break;
...@@ -1686,6 +1728,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1686,6 +1728,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1686 case IrInstructionIdAtomicLoad:1728 case IrInstructionIdAtomicLoad:
1687 ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction);1729 ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction);
1688 break;1730 break;
1731 case IrInstructionIdEnumToInt:
1732 ir_print_enum_to_int(irp, (IrInstructionEnumToInt *)instruction);
1733 break;
1689 }1734 }
1690 fprintf(irp->f, "\n");1735 fprintf(irp->f, "\n");
1691}1736}
src/link.cpp+7-4
...@@ -325,10 +325,13 @@ static void construct_linker_job_elf(LinkJob *lj) {...@@ -325,10 +325,13 @@ static void construct_linker_job_elf(LinkJob *lj) {
325 lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));325 lj->args.append((const char *)buf_ptr(g->link_objects.at(i)));
326 }326 }
327327
328 if (g->libc_link_lib == nullptr && (g->out_type == OutTypeExe || g->out_type == OutTypeLib)) {328 if (g->out_type == OutTypeExe || g->out_type == OutTypeLib) {
329 Buf *builtin_o_path = build_o(g, "builtin");329 if (g->libc_link_lib == nullptr) {
330 lj->args.append(buf_ptr(builtin_o_path));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
332 Buf *compiler_rt_o_path = build_compiler_rt(g);335 Buf *compiler_rt_o_path = build_compiler_rt(g);
333 lj->args.append(buf_ptr(compiler_rt_o_path));336 lj->args.append(buf_ptr(compiler_rt_o_path));
334 }337 }
...@@ -554,7 +557,7 @@ static void construct_linker_job_coff(LinkJob *lj) {...@@ -554,7 +557,7 @@ static void construct_linker_job_coff(LinkJob *lj) {
554 lj->args.append(buf_ptr(builtin_o_path));557 lj->args.append(buf_ptr(builtin_o_path));
555 }558 }
556559
557 // msvc compiler_rt is missing some stuff, so we still build it and rely on LinkOnce560 // msvc compiler_rt is missing some stuff, so we still build it and rely on weak linkage
558 Buf *compiler_rt_o_path = build_compiler_rt(g);561 Buf *compiler_rt_o_path = build_compiler_rt(g);
559 lj->args.append(buf_ptr(compiler_rt_o_path));562 lj->args.append(buf_ptr(compiler_rt_o_path));
560 }563 }
src/main.cpp+2
...@@ -924,6 +924,8 @@ int main(int argc, char **argv) {...@@ -924,6 +924,8 @@ int main(int argc, char **argv) {
924 codegen_print_timing_report(g, stdout);924 codegen_print_timing_report(g, stdout);
925 return EXIT_SUCCESS;925 return EXIT_SUCCESS;
926 } else if (cmd == CmdTest) {926 } else if (cmd == CmdTest) {
927 codegen_set_emit_file_type(g, emit_file_type);
928
927 ZigTarget native;929 ZigTarget native;
928 get_native_target(&native);930 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) {...@@ -225,6 +225,11 @@ void os_path_extname(Buf *full_path, Buf *out_basename, Buf *out_extname) {
225}225}
226226
227void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) {227void 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
228 buf_init_from_buf(out_full_path, dirname);233 buf_init_from_buf(out_full_path, dirname);
229 uint8_t c = *(buf_ptr(out_full_path) + buf_len(out_full_path) - 1);234 uint8_t c = *(buf_ptr(out_full_path) + buf_len(out_full_path) - 1);
230 if (!os_is_sep(c))235 if (!os_is_sep(c))
src/tokenizer.cpp+9-2
...@@ -357,12 +357,19 @@ static void end_float_token(Tokenize *t) {...@@ -357,12 +357,19 @@ static void end_float_token(Tokenize *t) {
357 // Mask the sign bit to 0 since always non-negative lex357 // Mask the sign bit to 0 since always non-negative lex
358 const uint64_t exp_mask = 0xffffull << exp_shift;358 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) {
361 f_bits.repr[0] = 0;368 f_bits.repr[0] = 0;
362 f_bits.repr[1] = sig_bits[0] << (shift - 64);369 f_bits.repr[1] = sig_bits[0] << (shift - 64);
363 } else {370 } else {
364 f_bits.repr[0] = sig_bits[0] << shift;371 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));
366 }373 }
367374
368 f_bits.repr[1] &= ~exp_mask;375 f_bits.repr[1] &= ~exp_mask;
src/util.hpp+19
...@@ -31,6 +31,8 @@...@@ -31,6 +31,8 @@
3131
32#endif32#endif
3333
34#include "softfloat.hpp"
35
34#define BREAKPOINT __asm("int $0x03")36#define BREAKPOINT __asm("int $0x03")
3537
36ATTRIBUTE_COLD38ATTRIBUTE_COLD
...@@ -165,4 +167,21 @@ static inline uint8_t log2_u64(uint64_t x) {...@@ -165,4 +167,21 @@ static inline uint8_t log2_u64(uint64_t x) {
165 return (63 - clzll(x));167 return (63 - clzll(x));
166}168}
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
168#endif187#endif
std/atomic/index.zig+5-3
...@@ -1,7 +1,9 @@...@@ -1,7 +1,9 @@
1pub const Stack = @import("stack.zig").Stack;1pub 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
4test "std.atomic" {5test "std.atomic" {
5 _ = @import("stack.zig").Stack;6 _ = @import("stack.zig");
6 _ = @import("queue.zig").Queue;7 _ = @import("queue_mpsc.zig");
8 _ = @import("queue_mpmc.zig");
7}9}
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 {...@@ -117,8 +117,10 @@ fn startPuts(ctx: *Context) u8 {
117 while (put_count != 0) : (put_count -= 1) {117 while (put_count != 0) : (put_count -= 1) {
118 std.os.time.sleep(0, 1); // let the os scheduler be our fuzz118 std.os.time.sleep(0, 1); // let the os scheduler be our fuzz
119 const x = @bitCast(i32, r.random.scalar(u32));119 const x = @bitCast(i32, r.random.scalar(u32));
120 const node = ctx.allocator.create(Stack(i32).Node) catch unreachable;120 const node = ctx.allocator.create(Stack(i32).Node{
121 node.data = x;121 .next = undefined,
122 .data = x,
123 }) catch unreachable;
122 ctx.stack.push(node);124 ctx.stack.push(node);
123 _ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst);125 _ = @atomicRmw(isize, &ctx.put_sum, builtin.AtomicRmwOp.Add, x, AtomicOrder.SeqCst);
124 }126 }
std/build.zig+20-35
...@@ -158,8 +158,7 @@ pub const Builder = struct {...@@ -158,8 +158,7 @@ pub const Builder = struct {
158 }158 }
159159
160 pub fn addTest(self: *Builder, root_src: []const u8) *TestStep {160 pub fn addTest(self: *Builder, root_src: []const u8) *TestStep {
161 const test_step = self.allocator.create(TestStep) catch unreachable;161 const test_step = self.allocator.create(TestStep.init(self, root_src)) catch unreachable;
162 test_step.* = TestStep.init(self, root_src);
163 return test_step;162 return test_step;
164 }163 }
165164
...@@ -191,21 +190,18 @@ pub const Builder = struct {...@@ -191,21 +190,18 @@ pub const Builder = struct {
191 }190 }
192191
193 pub fn addWriteFile(self: *Builder, file_path: []const u8, data: []const u8) *WriteFileStep {192 pub fn addWriteFile(self: *Builder, file_path: []const u8, data: []const u8) *WriteFileStep {
194 const write_file_step = self.allocator.create(WriteFileStep) catch unreachable;193 const write_file_step = self.allocator.create(WriteFileStep.init(self, file_path, data)) catch unreachable;
195 write_file_step.* = WriteFileStep.init(self, file_path, data);
196 return write_file_step;194 return write_file_step;
197 }195 }
198196
199 pub fn addLog(self: *Builder, comptime format: []const u8, args: ...) *LogStep {197 pub fn addLog(self: *Builder, comptime format: []const u8, args: ...) *LogStep {
200 const data = self.fmt(format, args);198 const data = self.fmt(format, args);
201 const log_step = self.allocator.create(LogStep) catch unreachable;199 const log_step = self.allocator.create(LogStep.init(self, data)) catch unreachable;
202 log_step.* = LogStep.init(self, data);
203 return log_step;200 return log_step;
204 }201 }
205202
206 pub fn addRemoveDirTree(self: *Builder, dir_path: []const u8) *RemoveDirStep {203 pub fn addRemoveDirTree(self: *Builder, dir_path: []const u8) *RemoveDirStep {
207 const remove_dir_step = self.allocator.create(RemoveDirStep) catch unreachable;204 const remove_dir_step = self.allocator.create(RemoveDirStep.init(self, dir_path)) catch unreachable;
208 remove_dir_step.* = RemoveDirStep.init(self, dir_path);
209 return remove_dir_step;205 return remove_dir_step;
210 }206 }
211207
...@@ -404,11 +400,10 @@ pub const Builder = struct {...@@ -404,11 +400,10 @@ pub const Builder = struct {
404 }400 }
405401
406 pub fn step(self: *Builder, name: []const u8, description: []const u8) *Step {402 pub fn step(self: *Builder, name: []const u8, description: []const u8) *Step {
407 const step_info = self.allocator.create(TopLevelStep) catch unreachable;403 const step_info = self.allocator.create(TopLevelStep{
408 step_info.* = TopLevelStep{
409 .step = Step.initNoOp(name, self.allocator),404 .step = Step.initNoOp(name, self.allocator),
410 .description = description,405 .description = description,
411 };406 }) catch unreachable;
412 self.top_level_steps.append(step_info) catch unreachable;407 self.top_level_steps.append(step_info) catch unreachable;
413 return &step_info.step;408 return &step_info.step;
414 }409 }
...@@ -598,8 +593,7 @@ pub const Builder = struct {...@@ -598,8 +593,7 @@ pub const Builder = struct {
598 const full_dest_path = os.path.resolve(self.allocator, self.prefix, dest_rel_path) catch unreachable;593 const full_dest_path = os.path.resolve(self.allocator, self.prefix, dest_rel_path) catch unreachable;
599 self.pushInstalledFile(full_dest_path);594 self.pushInstalledFile(full_dest_path);
600595
601 const install_step = self.allocator.create(InstallFileStep) catch unreachable;596 const install_step = self.allocator.create(InstallFileStep.init(self, src_path, full_dest_path)) catch unreachable;
602 install_step.* = InstallFileStep.init(self, src_path, full_dest_path);
603 return install_step;597 return install_step;
604 }598 }
605599
...@@ -837,51 +831,43 @@ pub const LibExeObjStep = struct {...@@ -837,51 +831,43 @@ pub const LibExeObjStep = struct {
837 };831 };
838832
839 pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8, ver: *const Version) *LibExeObjStep {833 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;834 const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Lib, false, ver)) catch unreachable;
841 self.* = initExtraArgs(builder, name, root_src, Kind.Lib, false, ver);
842 return self;835 return self;
843 }836 }
844837
845 pub fn createCSharedLibrary(builder: *Builder, name: []const u8, version: *const Version) *LibExeObjStep {838 pub fn createCSharedLibrary(builder: *Builder, name: []const u8, version: *const Version) *LibExeObjStep {
846 const self = builder.allocator.create(LibExeObjStep) catch unreachable;839 const self = builder.allocator.create(initC(builder, name, Kind.Lib, version, false)) catch unreachable;
847 self.* = initC(builder, name, Kind.Lib, version, false);
848 return self;840 return self;
849 }841 }
850842
851 pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {843 pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
852 const self = builder.allocator.create(LibExeObjStep) catch unreachable;844 const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0))) catch unreachable;
853 self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, builder.version(0, 0, 0));
854 return self;845 return self;
855 }846 }
856847
857 pub fn createCStaticLibrary(builder: *Builder, name: []const u8) *LibExeObjStep {848 pub fn createCStaticLibrary(builder: *Builder, name: []const u8) *LibExeObjStep {
858 const self = builder.allocator.create(LibExeObjStep) catch unreachable;849 const self = builder.allocator.create(initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true)) catch unreachable;
859 self.* = initC(builder, name, Kind.Lib, builder.version(0, 0, 0), true);
860 return self;850 return self;
861 }851 }
862852
863 pub fn createObject(builder: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep {853 pub fn createObject(builder: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep {
864 const self = builder.allocator.create(LibExeObjStep) catch unreachable;854 const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0))) catch unreachable;
865 self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0));
866 return self;855 return self;
867 }856 }
868857
869 pub fn createCObject(builder: *Builder, name: []const u8, src: []const u8) *LibExeObjStep {858 pub fn createCObject(builder: *Builder, name: []const u8, src: []const u8) *LibExeObjStep {
870 const self = builder.allocator.create(LibExeObjStep) catch unreachable;859 const self = builder.allocator.create(initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false)) catch unreachable;
871 self.* = initC(builder, name, Kind.Obj, builder.version(0, 0, 0), false);
872 self.object_src = src;860 self.object_src = src;
873 return self;861 return self;
874 }862 }
875863
876 pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {864 pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
877 const self = builder.allocator.create(LibExeObjStep) catch unreachable;865 const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Exe, false, builder.version(0, 0, 0))) catch unreachable;
878 self.* = initExtraArgs(builder, name, root_src, Kind.Exe, false, builder.version(0, 0, 0));
879 return self;866 return self;
880 }867 }
881868
882 pub fn createCExecutable(builder: *Builder, name: []const u8) *LibExeObjStep {869 pub fn createCExecutable(builder: *Builder, name: []const u8) *LibExeObjStep {
883 const self = builder.allocator.create(LibExeObjStep) catch unreachable;870 const self = builder.allocator.create(initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false)) catch unreachable;
884 self.* = initC(builder, name, Kind.Exe, builder.version(0, 0, 0), false);
885 return self;871 return self;
886 }872 }
887873
...@@ -1748,14 +1734,14 @@ pub const CommandStep = struct {...@@ -1748,14 +1734,14 @@ pub const CommandStep = struct {
17481734
1749 /// ::argv is copied.1735 /// ::argv is copied.
1750 pub fn create(builder: *Builder, cwd: ?[]const u8, env_map: *const BufMap, argv: []const []const u8) *CommandStep {1736 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;1737 const self = builder.allocator.create(CommandStep{
1752 self.* = CommandStep{
1753 .builder = builder,1738 .builder = builder,
1754 .step = Step.init(argv[0], builder.allocator, make),1739 .step = Step.init(argv[0], builder.allocator, make),
1755 .argv = builder.allocator.alloc([]u8, argv.len) catch unreachable,1740 .argv = builder.allocator.alloc([]u8, argv.len) catch unreachable,
1756 .cwd = cwd,1741 .cwd = cwd,
1757 .env_map = env_map,1742 .env_map = env_map,
1758 };1743 }) catch unreachable;
1744
1759 mem.copy([]const u8, self.argv, argv);1745 mem.copy([]const u8, self.argv, argv);
1760 self.step.name = self.argv[0];1746 self.step.name = self.argv[0];
1761 return self;1747 return self;
...@@ -1778,18 +1764,17 @@ const InstallArtifactStep = struct {...@@ -1778,18 +1764,17 @@ const InstallArtifactStep = struct {
1778 const Self = this;1764 const Self = this;
17791765
1780 pub fn create(builder: *Builder, artifact: *LibExeObjStep) *Self {1766 pub fn create(builder: *Builder, artifact: *LibExeObjStep) *Self {
1781 const self = builder.allocator.create(Self) catch unreachable;
1782 const dest_dir = switch (artifact.kind) {1767 const dest_dir = switch (artifact.kind) {
1783 LibExeObjStep.Kind.Obj => unreachable,1768 LibExeObjStep.Kind.Obj => unreachable,
1784 LibExeObjStep.Kind.Exe => builder.exe_dir,1769 LibExeObjStep.Kind.Exe => builder.exe_dir,
1785 LibExeObjStep.Kind.Lib => builder.lib_dir,1770 LibExeObjStep.Kind.Lib => builder.lib_dir,
1786 };1771 };
1787 self.* = Self{1772 const self = builder.allocator.create(Self{
1788 .builder = builder,1773 .builder = builder,
1789 .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),1774 .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),
1790 .artifact = artifact,1775 .artifact = artifact,
1791 .dest_file = os.path.join(builder.allocator, dest_dir, artifact.out_filename) catch unreachable,1776 .dest_file = os.path.join(builder.allocator, dest_dir, artifact.out_filename) catch unreachable,
1792 };1777 }) catch unreachable;
1793 self.step.dependOn(&artifact.step);1778 self.step.dependOn(&artifact.step);
1794 builder.pushInstalledFile(self.dest_file);1779 builder.pushInstalledFile(self.dest_file);
1795 if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) {1780 if (self.artifact.kind == LibExeObjStep.Kind.Lib and !self.artifact.static) {
std/cstr.zig+1-1
...@@ -79,7 +79,7 @@ pub const NullTerminated2DArray = struct {...@@ -79,7 +79,7 @@ pub const NullTerminated2DArray = struct {
79 errdefer allocator.free(buf);79 errdefer allocator.free(buf);
8080
81 var write_index = index_size;81 var write_index = index_size;
82 const index_buf = ([]?[*]u8)(buf);82 const index_buf = @bytesToSlice(?[*]u8, buf);
8383
84 var i: usize = 0;84 var i: usize = 0;
85 for (slices) |slice| {85 for (slices) |slice| {
std/debug/index.zig+5-10
...@@ -249,9 +249,7 @@ fn printSourceAtAddress(debug_info: *ElfStackTrace, out_stream: var, address: us...@@ -249,9 +249,7 @@ fn printSourceAtAddress(debug_info: *ElfStackTrace, out_stream: var, address: us
249pub fn openSelfDebugInfo(allocator: *mem.Allocator) !*ElfStackTrace {249pub fn openSelfDebugInfo(allocator: *mem.Allocator) !*ElfStackTrace {
250 switch (builtin.object_format) {250 switch (builtin.object_format) {
251 builtin.ObjectFormat.elf => {251 builtin.ObjectFormat.elf => {
252 const st = try allocator.create(ElfStackTrace);252 const st = try allocator.create(ElfStackTrace{
253 errdefer allocator.destroy(st);
254 st.* = ElfStackTrace{
255 .self_exe_file = undefined,253 .self_exe_file = undefined,
256 .elf = undefined,254 .elf = undefined,
257 .debug_info = undefined,255 .debug_info = undefined,
...@@ -261,7 +259,8 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !*ElfStackTrace {...@@ -261,7 +259,8 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !*ElfStackTrace {
261 .debug_ranges = null,259 .debug_ranges = null,
262 .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),260 .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
263 .compile_unit_list = ArrayList(CompileUnit).init(allocator),261 .compile_unit_list = ArrayList(CompileUnit).init(allocator),
264 };262 });
263 errdefer allocator.destroy(st);
265 st.self_exe_file = try os.openSelfExe();264 st.self_exe_file = try os.openSelfExe();
266 errdefer st.self_exe_file.close();265 errdefer st.self_exe_file.close();
267266
...@@ -280,11 +279,8 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !*ElfStackTrace {...@@ -280,11 +279,8 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) !*ElfStackTrace {
280 var exe_file = try os.openSelfExe();279 var exe_file = try os.openSelfExe();
281 defer exe_file.close();280 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)) });
284 errdefer allocator.destroy(st);283 errdefer allocator.destroy(st);
285
286 st.* = ElfStackTrace{ .symbol_table = try macho.loadSymbols(allocator, &io.FileInStream.init(&exe_file)) };
287
288 return st;284 return st;
289 },285 },
290 builtin.ObjectFormat.coff => {286 builtin.ObjectFormat.coff => {
...@@ -974,8 +970,7 @@ fn scanAllCompileUnits(st: *ElfStackTrace) !void {...@@ -974,8 +970,7 @@ fn scanAllCompileUnits(st: *ElfStackTrace) !void {
974970
975 try st.self_exe_file.seekTo(compile_unit_pos);971 try st.self_exe_file.seekTo(compile_unit_pos);
976972
977 const compile_unit_die = try st.allocator().create(Die);973 const compile_unit_die = try st.allocator().create(try parseDie(st, abbrev_table, is_64));
978 compile_unit_die.* = try parseDie(st, abbrev_table, is_64);
979974
980 if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;975 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;...@@ -4,6 +4,8 @@ const assert = std.debug.assert;
4const event = this;4const event = this;
5const mem = std.mem;5const mem = std.mem;
6const posix = std.os.posix;6const posix = std.os.posix;
7const AtomicRmwOp = builtin.AtomicRmwOp;
8const AtomicOrder = builtin.AtomicOrder;
79
8pub const TcpServer = struct {10pub const TcpServer = struct {
9 handleRequestFn: async<*mem.Allocator> fn (*TcpServer, *const std.net.Address, *const std.os.File) void,11 handleRequestFn: async<*mem.Allocator> fn (*TcpServer, *const std.net.Address, *const std.os.File) void,
...@@ -93,16 +95,56 @@ pub const TcpServer = struct {...@@ -93,16 +95,56 @@ pub const TcpServer = struct {
9395
94pub const Loop = struct {96pub const Loop = struct {
95 allocator: *mem.Allocator,97 allocator: *mem.Allocator,
96 epollfd: i32,
97 keep_running: bool,98 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 {111 /// The allocator must be thread-safe because we use it for multiplexing
100 const epollfd = try std.os.linuxEpollCreate(std.os.linux.EPOLL_CLOEXEC);112 /// coroutines onto kernel threads.
101 return Loop{113 pub fn init(allocator: *mem.Allocator) !Loop {
114 var self = Loop{
102 .keep_running = true,115 .keep_running = true,
103 .allocator = allocator,116 .allocator = allocator,
104 .epollfd = epollfd,117 .os_data = undefined,
118 .next_tick_queue = std.atomic.QueueMpsc(promise).init(),
105 };119 };
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 }
106 }148 }
107149
108 pub fn addFd(self: *Loop, fd: i32, prom: promise) !void {150 pub fn addFd(self: *Loop, fd: i32, prom: promise) !void {
...@@ -110,11 +152,11 @@ pub const Loop = struct {...@@ -110,11 +152,11 @@ pub const Loop = struct {
110 .events = std.os.linux.EPOLLIN | std.os.linux.EPOLLOUT | std.os.linux.EPOLLET,152 .events = std.os.linux.EPOLLIN | std.os.linux.EPOLLOUT | std.os.linux.EPOLLET,
111 .data = std.os.linux.epoll_data{ .ptr = @ptrToInt(prom) },153 .data = std.os.linux.epoll_data{ .ptr = @ptrToInt(prom) },
112 };154 };
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);
114 }156 }
115157
116 pub fn removeFd(self: *Loop, fd: i32) void {158 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 {};
118 }160 }
119 async fn waitFd(self: *Loop, fd: i32) !void {161 async fn waitFd(self: *Loop, fd: i32) !void {
120 defer self.removeFd(fd);162 defer self.removeFd(fd);
...@@ -126,21 +168,250 @@ pub const Loop = struct {...@@ -126,21 +168,250 @@ pub const Loop = struct {
126 pub fn stop(self: *Loop) void {168 pub fn stop(self: *Loop) void {
127 // TODO make atomic169 // TODO make atomic
128 self.keep_running = false;170 self.keep_running = false;
129 // TODO activate an fd in the epoll set171 // 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);
130 }177 }
131178
132 pub fn run(self: *Loop) void {179 pub fn run(self: *Loop) void {
133 while (self.keep_running) {180 while (self.keep_running) {
134 var events: [16]std.os.linux.epoll_event = undefined;181 // TODO multiplex the next tick queue and the epoll event results onto a thread pool
135 const count = std.os.linuxEpollWait(self.epollfd, events[0..], -1);182 while (self.next_tick_queue.get()) |node| {
136 for (events[0..count]) |ev| {183 resume node.data;
137 const p = @intToPtr(promise, ev.data.ptr);
138 resume p;
139 }184 }
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 => {},
140 }202 }
141 }203 }
142};204};
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
144pub async fn connect(loop: *Loop, _address: *const std.net.Address) !std.os.File {415pub async fn connect(loop: *Loop, _address: *const std.net.Address) !std.os.File {
145 var address = _address.*; // TODO https://github.com/ziglang/zig/issues/733416 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" {...@@ -199,6 +470,7 @@ test "listen on a port, send bytes, receive bytes" {
199 defer cancel p;470 defer cancel p;
200 loop.run();471 loop.run();
201}472}
473
202async fn doAsyncTest(loop: *Loop, address: *const std.net.Address) void {474async fn doAsyncTest(loop: *Loop, address: *const std.net.Address) void {
203 errdefer @panic("test failure");475 errdefer @panic("test failure");
204476
...@@ -211,3 +483,43 @@ async fn doAsyncTest(loop: *Loop, address: *const std.net.Address) void {...@@ -211,3 +483,43 @@ async fn doAsyncTest(loop: *Loop, address: *const std.net.Address) void {
211 assert(mem.eql(u8, msg, "hello from server\n"));483 assert(mem.eql(u8, msg, "hello from server\n"));
212 loop.stop();484 loop.stop();
213}485}
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(...@@ -130,6 +130,9 @@ pub fn formatType(
130 try output(context, "error.");130 try output(context, "error.");
131 return output(context, @errorName(value));131 return output(context, @errorName(value));
132 },132 },
133 builtin.TypeId.Promise => {
134 return format(context, Errors, output, "promise@{x}", @ptrToInt(value));
135 },
133 builtin.TypeId.Pointer => |ptr_info| switch (ptr_info.size) {136 builtin.TypeId.Pointer => |ptr_info| switch (ptr_info.size) {
134 builtin.TypeInfo.Pointer.Size.One => switch (@typeInfo(ptr_info.child)) {137 builtin.TypeInfo.Pointer.Size.One => switch (@typeInfo(ptr_info.child)) {
135 builtin.TypeId.Array => |info| {138 builtin.TypeId.Array => |info| {
...@@ -327,7 +330,7 @@ pub fn formatFloatScientific(...@@ -327,7 +330,7 @@ pub fn formatFloatScientific(
327 comptime Errors: type,330 comptime Errors: type,
328 output: fn (@typeOf(context), []const u8) Errors!void,331 output: fn (@typeOf(context), []const u8) Errors!void,
329) Errors!void {332) Errors!void {
330 var x = f64(value);333 var x = @floatCast(f64, value);
331334
332 // Errol doesn't handle these special cases.335 // Errol doesn't handle these special cases.
333 if (math.signbit(x)) {336 if (math.signbit(x)) {
std/heap.zig+3-3
...@@ -38,6 +38,7 @@ fn cFree(self: *Allocator, old_mem: []u8) void {...@@ -38,6 +38,7 @@ fn cFree(self: *Allocator, old_mem: []u8) void {
38}38}
3939
40/// This allocator makes a syscall directly for every allocation and free.40/// This allocator makes a syscall directly for every allocation and free.
41/// TODO make this thread-safe. The windows implementation will need some atomics.
41pub const DirectAllocator = struct {42pub const DirectAllocator = struct {
42 allocator: Allocator,43 allocator: Allocator,
43 heap_handle: ?HeapHandle,44 heap_handle: ?HeapHandle,
...@@ -221,7 +222,7 @@ pub const ArenaAllocator = struct {...@@ -221,7 +222,7 @@ pub const ArenaAllocator = struct {
221 if (len >= actual_min_size) break;222 if (len >= actual_min_size) break;
222 }223 }
223 const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);224 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)]);
225 const buf_node = &buf_node_slice[0];226 const buf_node = &buf_node_slice[0];
226 buf_node.* = BufNode{227 buf_node.* = BufNode{
227 .data = buf,228 .data = buf,
...@@ -407,8 +408,7 @@ fn testAllocator(allocator: *mem.Allocator) !void {...@@ -407,8 +408,7 @@ fn testAllocator(allocator: *mem.Allocator) !void {
407 var slice = try allocator.alloc(*i32, 100);408 var slice = try allocator.alloc(*i32, 100);
408409
409 for (slice) |*item, i| {410 for (slice) |*item, i| {
410 item.* = try allocator.create(i32);411 item.* = try allocator.create(@intCast(i32, i));
411 item.*.* = @intCast(i32, i);
412 }412 }
413413
414 for (slice) |item, i| {414 for (slice) |item, i| {
std/io.zig+3-5
...@@ -414,14 +414,12 @@ pub const BufferedAtomicFile = struct {...@@ -414,14 +414,12 @@ pub const BufferedAtomicFile = struct {
414414
415 pub fn create(allocator: *mem.Allocator, dest_path: []const u8) !*BufferedAtomicFile {415 pub fn create(allocator: *mem.Allocator, dest_path: []const u8) !*BufferedAtomicFile {
416 // TODO with well defined copy elision we don't need this allocation416 // TODO with well defined copy elision we don't need this allocation
417 var self = try allocator.create(BufferedAtomicFile);417 var self = try allocator.create(BufferedAtomicFile{
418 errdefer allocator.destroy(self);
419
420 self.* = BufferedAtomicFile{
421 .atomic_file = undefined,418 .atomic_file = undefined,
422 .file_stream = undefined,419 .file_stream = undefined,
423 .buffered_stream = undefined,420 .buffered_stream = undefined,
424 };421 });
422 errdefer allocator.destroy(self);
425423
426 self.atomic_file = try os.AtomicFile.init(allocator, dest_path, os.default_file_mode);424 self.atomic_file = try os.AtomicFile.init(allocator, dest_path, os.default_file_mode);
427 errdefer self.atomic_file.deinit();425 errdefer self.atomic_file.deinit();
std/json.zig+1-1
...@@ -180,7 +180,7 @@ pub const StreamingParser = struct {...@@ -180,7 +180,7 @@ pub const StreamingParser = struct {
180 pub fn fromInt(x: var) State {180 pub fn fromInt(x: var) State {
181 debug.assert(x == 0 or x == 1);181 debug.assert(x == 0 or x == 1);
182 const T = @TagType(State);182 const T = @TagType(State);
183 return State(@intCast(T, x));183 return @intToEnum(State, @intCast(T, x));
184 }184 }
185 };185 };
186186
std/linked_list.zig+1-1
...@@ -193,7 +193,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na...@@ -193,7 +193,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
193 /// A pointer to the new node.193 /// A pointer to the new node.
194 pub fn allocateNode(list: *Self, allocator: *Allocator) !*Node {194 pub fn allocateNode(list: *Self, allocator: *Allocator) !*Node {
195 comptime assert(!isIntrusive());195 comptime assert(!isIntrusive());
196 return allocator.create(Node);196 return allocator.create(Node(undefined));
197 }197 }
198198
199 /// Deallocate a node.199 /// Deallocate a node.
std/macho.zig+1-1
...@@ -161,7 +161,7 @@ pub fn loadSymbols(allocator: *mem.Allocator, in: *io.FileInStream) !SymbolTable...@@ -161,7 +161,7 @@ pub fn loadSymbols(allocator: *mem.Allocator, in: *io.FileInStream) !SymbolTable
161}161}
162162
163fn readNoEof(in: *io.FileInStream, comptime T: type, result: []T) !void {163fn readNoEof(in: *io.FileInStream, comptime T: type, result: []T) !void {
164 return in.stream.readNoEof(([]u8)(result));164 return in.stream.readNoEof(@sliceToBytes(result));
165}165}
166fn readOneNoEof(in: *io.FileInStream, comptime T: type, result: *T) !void {166fn readOneNoEof(in: *io.FileInStream, comptime T: type, result: *T) !void {
167 return readNoEof(in, T, (*[1]T)(result)[0..]);167 return readNoEof(in, T, (*[1]T)(result)[0..]);
std/math/copysign.zig+18
...@@ -4,12 +4,22 @@ const assert = std.debug.assert;...@@ -4,12 +4,22 @@ const assert = std.debug.assert;
44
5pub fn copysign(comptime T: type, x: T, y: T) T {5pub fn copysign(comptime T: type, x: T, y: T) T {
6 return switch (T) {6 return switch (T) {
7 f16 => copysign16(x, y),
7 f32 => copysign32(x, y),8 f32 => copysign32(x, y),
8 f64 => copysign64(x, y),9 f64 => copysign64(x, y),
9 else => @compileError("copysign not implemented for " ++ @typeName(T)),10 else => @compileError("copysign not implemented for " ++ @typeName(T)),
10 };11 };
11}12}
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
13fn copysign32(x: f32, y: f32) f32 {23fn copysign32(x: f32, y: f32) f32 {
14 const ux = @bitCast(u32, x);24 const ux = @bitCast(u32, x);
15 const uy = @bitCast(u32, y);25 const uy = @bitCast(u32, y);
...@@ -29,10 +39,18 @@ fn copysign64(x: f64, y: f64) f64 {...@@ -29,10 +39,18 @@ fn copysign64(x: f64, y: f64) f64 {
29}39}
3040
31test "math.copysign" {41test "math.copysign" {
42 assert(copysign(f16, 1.0, 1.0) == copysign16(1.0, 1.0));
32 assert(copysign(f32, 1.0, 1.0) == copysign32(1.0, 1.0));43 assert(copysign(f32, 1.0, 1.0) == copysign32(1.0, 1.0));
33 assert(copysign(f64, 1.0, 1.0) == copysign64(1.0, 1.0));44 assert(copysign(f64, 1.0, 1.0) == copysign64(1.0, 1.0));
34}45}
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
36test "math.copysign32" {54test "math.copysign32" {
37 assert(copysign32(5.0, 1.0) == 5.0);55 assert(copysign32(5.0, 1.0) == 5.0);
38 assert(copysign32(5.0, -1.0) == -5.0);56 assert(copysign32(5.0, -1.0) == -5.0);
std/math/expm1.zig+8
...@@ -20,6 +20,10 @@ pub fn expm1(x: var) @typeOf(x) {...@@ -20,6 +20,10 @@ pub fn expm1(x: var) @typeOf(x) {
2020
21fn expm1_32(x_: f32) f32 {21fn expm1_32(x_: f32) f32 {
22 @setFloatMode(this, builtin.FloatMode.Strict);22 @setFloatMode(this, builtin.FloatMode.Strict);
23
24 if (math.isNan(x_))
25 return math.nan(f32);
26
23 const o_threshold: f32 = 8.8721679688e+01;27 const o_threshold: f32 = 8.8721679688e+01;
24 const ln2_hi: f32 = 6.9313812256e-01;28 const ln2_hi: f32 = 6.9313812256e-01;
25 const ln2_lo: f32 = 9.0580006145e-06;29 const ln2_lo: f32 = 9.0580006145e-06;
...@@ -146,6 +150,10 @@ fn expm1_32(x_: f32) f32 {...@@ -146,6 +150,10 @@ fn expm1_32(x_: f32) f32 {
146150
147fn expm1_64(x_: f64) f64 {151fn expm1_64(x_: f64) f64 {
148 @setFloatMode(this, builtin.FloatMode.Strict);152 @setFloatMode(this, builtin.FloatMode.Strict);
153
154 if (math.isNan(x_))
155 return math.nan(f64);
156
149 const o_threshold: f64 = 7.09782712893383973096e+02;157 const o_threshold: f64 = 7.09782712893383973096e+02;
150 const ln2_hi: f64 = 6.93147180369123816490e-01;158 const ln2_hi: f64 = 6.93147180369123816490e-01;
151 const ln2_lo: f64 = 1.90821492927058770002e-10;159 const ln2_lo: f64 = 1.90821492927058770002e-10;
std/math/fabs.zig+19
...@@ -10,12 +10,19 @@ const assert = std.debug.assert;...@@ -10,12 +10,19 @@ const assert = std.debug.assert;
10pub fn fabs(x: var) @typeOf(x) {10pub fn fabs(x: var) @typeOf(x) {
11 const T = @typeOf(x);11 const T = @typeOf(x);
12 return switch (T) {12 return switch (T) {
13 f16 => fabs16(x),
13 f32 => fabs32(x),14 f32 => fabs32(x),
14 f64 => fabs64(x),15 f64 => fabs64(x),
15 else => @compileError("fabs not implemented for " ++ @typeName(T)),16 else => @compileError("fabs not implemented for " ++ @typeName(T)),
16 };17 };
17}18}
1819
20fn fabs16(x: f16) f16 {
21 var u = @bitCast(u16, x);
22 u &= 0x7FFF;
23 return @bitCast(f16, u);
24}
25
19fn fabs32(x: f32) f32 {26fn fabs32(x: f32) f32 {
20 var u = @bitCast(u32, x);27 var u = @bitCast(u32, x);
21 u &= 0x7FFFFFFF;28 u &= 0x7FFFFFFF;
...@@ -29,10 +36,16 @@ fn fabs64(x: f64) f64 {...@@ -29,10 +36,16 @@ fn fabs64(x: f64) f64 {
29}36}
3037
31test "math.fabs" {38test "math.fabs" {
39 assert(fabs(f16(1.0)) == fabs16(1.0));
32 assert(fabs(f32(1.0)) == fabs32(1.0));40 assert(fabs(f32(1.0)) == fabs32(1.0));
33 assert(fabs(f64(1.0)) == fabs64(1.0));41 assert(fabs(f64(1.0)) == fabs64(1.0));
34}42}
3543
44test "math.fabs16" {
45 assert(fabs16(1.0) == 1.0);
46 assert(fabs16(-1.0) == 1.0);
47}
48
36test "math.fabs32" {49test "math.fabs32" {
37 assert(fabs32(1.0) == 1.0);50 assert(fabs32(1.0) == 1.0);
38 assert(fabs32(-1.0) == 1.0);51 assert(fabs32(-1.0) == 1.0);
...@@ -43,6 +56,12 @@ test "math.fabs64" {...@@ -43,6 +56,12 @@ test "math.fabs64" {
43 assert(fabs64(-1.0) == 1.0);56 assert(fabs64(-1.0) == 1.0);
44}57}
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
46test "math.fabs32.special" {65test "math.fabs32.special" {
47 assert(math.isPositiveInf(fabs(math.inf(f32))));66 assert(math.isPositiveInf(fabs(math.inf(f32))));
48 assert(math.isPositiveInf(fabs(-math.inf(f32))));67 assert(math.isPositiveInf(fabs(-math.inf(f32))));
std/math/floor.zig+50
...@@ -12,12 +12,47 @@ const math = std.math;...@@ -12,12 +12,47 @@ const math = std.math;
12pub fn floor(x: var) @typeOf(x) {12pub fn floor(x: var) @typeOf(x) {
13 const T = @typeOf(x);13 const T = @typeOf(x);
14 return switch (T) {14 return switch (T) {
15 f16 => floor16(x),
15 f32 => floor32(x),16 f32 => floor32(x),
16 f64 => floor64(x),17 f64 => floor64(x),
17 else => @compileError("floor not implemented for " ++ @typeName(T)),18 else => @compileError("floor not implemented for " ++ @typeName(T)),
18 };19 };
19}20}
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
21fn floor32(x: f32) f32 {56fn floor32(x: f32) f32 {
22 var u = @bitCast(u32, x);57 var u = @bitCast(u32, x);
23 const e = @intCast(i32, (u >> 23) & 0xFF) - 0x7F;58 const e = @intCast(i32, (u >> 23) & 0xFF) - 0x7F;
...@@ -84,10 +119,17 @@ fn floor64(x: f64) f64 {...@@ -84,10 +119,17 @@ fn floor64(x: f64) f64 {
84}119}
85120
86test "math.floor" {121test "math.floor" {
122 assert(floor(f16(1.3)) == floor16(1.3));
87 assert(floor(f32(1.3)) == floor32(1.3));123 assert(floor(f32(1.3)) == floor32(1.3));
88 assert(floor(f64(1.3)) == floor64(1.3));124 assert(floor(f64(1.3)) == floor64(1.3));
89}125}
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
91test "math.floor32" {133test "math.floor32" {
92 assert(floor32(1.3) == 1.0);134 assert(floor32(1.3) == 1.0);
93 assert(floor32(-1.3) == -2.0);135 assert(floor32(-1.3) == -2.0);
...@@ -100,6 +142,14 @@ test "math.floor64" {...@@ -100,6 +142,14 @@ test "math.floor64" {
100 assert(floor64(0.2) == 0.0);142 assert(floor64(0.2) == 0.0);
101}143}
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
103test "math.floor32.special" {153test "math.floor32.special" {
104 assert(floor32(0.0) == 0.0);154 assert(floor32(0.0) == 0.0);
105 assert(floor32(-0.0) == -0.0);155 assert(floor32(-0.0) == -0.0);
std/math/index.zig+43-1
...@@ -19,6 +19,18 @@ pub const f32_max = 3.40282346638528859812e+38;...@@ -19,6 +19,18 @@ pub const f32_max = 3.40282346638528859812e+38;
19pub const f32_epsilon = 1.1920928955078125e-07;19pub const f32_epsilon = 1.1920928955078125e-07;
20pub const f32_toint = 1.0 / f32_epsilon;20pub 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
22pub const nan_u32 = u32(0x7F800001);34pub const nan_u32 = u32(0x7F800001);
23pub const nan_f32 = @bitCast(f32, nan_u32);35pub 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 {...@@ -44,6 +56,11 @@ pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) bool {
44pub fn forceEval(value: var) void {56pub fn forceEval(value: var) void {
45 const T = @typeOf(value);57 const T = @typeOf(value);
46 switch (T) {58 switch (T) {
59 f16 => {
60 var x: f16 = undefined;
61 const p = @ptrCast(*volatile f16, &x);
62 p.* = x;
63 },
47 f32 => {64 f32 => {
48 var x: f32 = undefined;65 var x: f32 = undefined;
49 const p = @ptrCast(*volatile f32, &x);66 const p = @ptrCast(*volatile f32, &x);
...@@ -183,6 +200,32 @@ test "math" {...@@ -183,6 +200,32 @@ test "math" {
183 _ = @import("big/index.zig");200 _ = @import("big/index.zig");
184}201}
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
186pub fn min(x: var, y: var) @typeOf(x + y) {229pub fn min(x: var, y: var) @typeOf(x + y) {
187 return if (x < y) x else y;230 return if (x < y) x else y;
188}231}
...@@ -607,4 +650,3 @@ pub fn lossyCast(comptime T: type, value: var) T {...@@ -607,4 +650,3 @@ pub fn lossyCast(comptime T: type, value: var) T {
607 else => @compileError("bad type"),650 else => @compileError("bad type"),
608 }651 }
609}652}
610
std/math/inf.zig+1-1
...@@ -1,9 +1,9 @@...@@ -1,9 +1,9 @@
1const std = @import("../index.zig");1const std = @import("../index.zig");
2const math = std.math;2const math = std.math;
3const assert = std.debug.assert;
43
5pub fn inf(comptime T: type) T {4pub fn inf(comptime T: type) T {
6 return switch (T) {5 return switch (T) {
6 f16 => @bitCast(f16, math.inf_u16),
7 f32 => @bitCast(f32, math.inf_u32),7 f32 => @bitCast(f32, math.inf_u32),
8 f64 => @bitCast(f64, math.inf_u64),8 f64 => @bitCast(f64, math.inf_u64),
9 else => @compileError("inf not implemented for " ++ @typeName(T)),9 else => @compileError("inf not implemented for " ++ @typeName(T)),
std/math/isfinite.zig+8
...@@ -5,6 +5,10 @@ const assert = std.debug.assert;...@@ -5,6 +5,10 @@ const assert = std.debug.assert;
5pub fn isFinite(x: var) bool {5pub fn isFinite(x: var) bool {
6 const T = @typeOf(x);6 const T = @typeOf(x);
7 switch (T) {7 switch (T) {
8 f16 => {
9 const bits = @bitCast(u16, x);
10 return bits & 0x7FFF < 0x7C00;
11 },
8 f32 => {12 f32 => {
9 const bits = @bitCast(u32, x);13 const bits = @bitCast(u32, x);
10 return bits & 0x7FFFFFFF < 0x7F800000;14 return bits & 0x7FFFFFFF < 0x7F800000;
...@@ -20,10 +24,14 @@ pub fn isFinite(x: var) bool {...@@ -20,10 +24,14 @@ pub fn isFinite(x: var) bool {
20}24}
2125
22test "math.isFinite" {26test "math.isFinite" {
27 assert(isFinite(f16(0.0)));
28 assert(isFinite(f16(-0.0)));
23 assert(isFinite(f32(0.0)));29 assert(isFinite(f32(0.0)));
24 assert(isFinite(f32(-0.0)));30 assert(isFinite(f32(-0.0)));
25 assert(isFinite(f64(0.0)));31 assert(isFinite(f64(0.0)));
26 assert(isFinite(f64(-0.0)));32 assert(isFinite(f64(-0.0)));
33 assert(!isFinite(math.inf(f16)));
34 assert(!isFinite(-math.inf(f16)));
27 assert(!isFinite(math.inf(f32)));35 assert(!isFinite(math.inf(f32)));
28 assert(!isFinite(-math.inf(f32)));36 assert(!isFinite(-math.inf(f32)));
29 assert(!isFinite(math.inf(f64)));37 assert(!isFinite(math.inf(f64)));
std/math/isinf.zig+22
...@@ -5,6 +5,10 @@ const assert = std.debug.assert;...@@ -5,6 +5,10 @@ const assert = std.debug.assert;
5pub fn isInf(x: var) bool {5pub fn isInf(x: var) bool {
6 const T = @typeOf(x);6 const T = @typeOf(x);
7 switch (T) {7 switch (T) {
8 f16 => {
9 const bits = @bitCast(u16, x);
10 return bits & 0x7FFF == 0x7C00;
11 },
8 f32 => {12 f32 => {
9 const bits = @bitCast(u32, x);13 const bits = @bitCast(u32, x);
10 return bits & 0x7FFFFFFF == 0x7F800000;14 return bits & 0x7FFFFFFF == 0x7F800000;
...@@ -22,6 +26,9 @@ pub fn isInf(x: var) bool {...@@ -22,6 +26,9 @@ pub fn isInf(x: var) bool {
22pub fn isPositiveInf(x: var) bool {26pub fn isPositiveInf(x: var) bool {
23 const T = @typeOf(x);27 const T = @typeOf(x);
24 switch (T) {28 switch (T) {
29 f16 => {
30 return @bitCast(u16, x) == 0x7C00;
31 },
25 f32 => {32 f32 => {
26 return @bitCast(u32, x) == 0x7F800000;33 return @bitCast(u32, x) == 0x7F800000;
27 },34 },
...@@ -37,6 +44,9 @@ pub fn isPositiveInf(x: var) bool {...@@ -37,6 +44,9 @@ pub fn isPositiveInf(x: var) bool {
37pub fn isNegativeInf(x: var) bool {44pub fn isNegativeInf(x: var) bool {
38 const T = @typeOf(x);45 const T = @typeOf(x);
39 switch (T) {46 switch (T) {
47 f16 => {
48 return @bitCast(u16, x) == 0xFC00;
49 },
40 f32 => {50 f32 => {
41 return @bitCast(u32, x) == 0xFF800000;51 return @bitCast(u32, x) == 0xFF800000;
42 },52 },
...@@ -50,10 +60,14 @@ pub fn isNegativeInf(x: var) bool {...@@ -50,10 +60,14 @@ pub fn isNegativeInf(x: var) bool {
50}60}
5161
52test "math.isInf" {62test "math.isInf" {
63 assert(!isInf(f16(0.0)));
64 assert(!isInf(f16(-0.0)));
53 assert(!isInf(f32(0.0)));65 assert(!isInf(f32(0.0)));
54 assert(!isInf(f32(-0.0)));66 assert(!isInf(f32(-0.0)));
55 assert(!isInf(f64(0.0)));67 assert(!isInf(f64(0.0)));
56 assert(!isInf(f64(-0.0)));68 assert(!isInf(f64(-0.0)));
69 assert(isInf(math.inf(f16)));
70 assert(isInf(-math.inf(f16)));
57 assert(isInf(math.inf(f32)));71 assert(isInf(math.inf(f32)));
58 assert(isInf(-math.inf(f32)));72 assert(isInf(-math.inf(f32)));
59 assert(isInf(math.inf(f64)));73 assert(isInf(math.inf(f64)));
...@@ -61,10 +75,14 @@ test "math.isInf" {...@@ -61,10 +75,14 @@ test "math.isInf" {
61}75}
6276
63test "math.isPositiveInf" {77test "math.isPositiveInf" {
78 assert(!isPositiveInf(f16(0.0)));
79 assert(!isPositiveInf(f16(-0.0)));
64 assert(!isPositiveInf(f32(0.0)));80 assert(!isPositiveInf(f32(0.0)));
65 assert(!isPositiveInf(f32(-0.0)));81 assert(!isPositiveInf(f32(-0.0)));
66 assert(!isPositiveInf(f64(0.0)));82 assert(!isPositiveInf(f64(0.0)));
67 assert(!isPositiveInf(f64(-0.0)));83 assert(!isPositiveInf(f64(-0.0)));
84 assert(isPositiveInf(math.inf(f16)));
85 assert(!isPositiveInf(-math.inf(f16)));
68 assert(isPositiveInf(math.inf(f32)));86 assert(isPositiveInf(math.inf(f32)));
69 assert(!isPositiveInf(-math.inf(f32)));87 assert(!isPositiveInf(-math.inf(f32)));
70 assert(isPositiveInf(math.inf(f64)));88 assert(isPositiveInf(math.inf(f64)));
...@@ -72,10 +90,14 @@ test "math.isPositiveInf" {...@@ -72,10 +90,14 @@ test "math.isPositiveInf" {
72}90}
7391
74test "math.isNegativeInf" {92test "math.isNegativeInf" {
93 assert(!isNegativeInf(f16(0.0)));
94 assert(!isNegativeInf(f16(-0.0)));
75 assert(!isNegativeInf(f32(0.0)));95 assert(!isNegativeInf(f32(0.0)));
76 assert(!isNegativeInf(f32(-0.0)));96 assert(!isNegativeInf(f32(-0.0)));
77 assert(!isNegativeInf(f64(0.0)));97 assert(!isNegativeInf(f64(0.0)));
78 assert(!isNegativeInf(f64(-0.0)));98 assert(!isNegativeInf(f64(-0.0)));
99 assert(!isNegativeInf(math.inf(f16)));
100 assert(isNegativeInf(-math.inf(f16)));
79 assert(!isNegativeInf(math.inf(f32)));101 assert(!isNegativeInf(math.inf(f32)));
80 assert(isNegativeInf(-math.inf(f32)));102 assert(isNegativeInf(-math.inf(f32)));
81 assert(!isNegativeInf(math.inf(f64)));103 assert(!isNegativeInf(math.inf(f64)));
std/math/isnan.zig+6
...@@ -5,6 +5,10 @@ const assert = std.debug.assert;...@@ -5,6 +5,10 @@ const assert = std.debug.assert;
5pub fn isNan(x: var) bool {5pub fn isNan(x: var) bool {
6 const T = @typeOf(x);6 const T = @typeOf(x);
7 switch (T) {7 switch (T) {
8 f16 => {
9 const bits = @bitCast(u16, x);
10 return (bits & 0x7fff) > 0x7c00;
11 },
8 f32 => {12 f32 => {
9 const bits = @bitCast(u32, x);13 const bits = @bitCast(u32, x);
10 return bits & 0x7FFFFFFF > 0x7F800000;14 return bits & 0x7FFFFFFF > 0x7F800000;
...@@ -26,8 +30,10 @@ pub fn isSignalNan(x: var) bool {...@@ -26,8 +30,10 @@ pub fn isSignalNan(x: var) bool {
26}30}
2731
28test "math.isNan" {32test "math.isNan" {
33 assert(isNan(math.nan(f16)));
29 assert(isNan(math.nan(f32)));34 assert(isNan(math.nan(f32)));
30 assert(isNan(math.nan(f64)));35 assert(isNan(math.nan(f64)));
36 assert(!isNan(f16(1.0)));
31 assert(!isNan(f32(1.0)));37 assert(!isNan(f32(1.0)));
32 assert(!isNan(f64(1.0)));38 assert(!isNan(f64(1.0)));
33}39}
std/math/isnormal.zig+9
...@@ -5,6 +5,10 @@ const assert = std.debug.assert;...@@ -5,6 +5,10 @@ const assert = std.debug.assert;
5pub fn isNormal(x: var) bool {5pub fn isNormal(x: var) bool {
6 const T = @typeOf(x);6 const T = @typeOf(x);
7 switch (T) {7 switch (T) {
8 f16 => {
9 const bits = @bitCast(u16, x);
10 return (bits + 1024) & 0x7FFF >= 2048;
11 },
8 f32 => {12 f32 => {
9 const bits = @bitCast(u32, x);13 const bits = @bitCast(u32, x);
10 return (bits + 0x00800000) & 0x7FFFFFFF >= 0x01000000;14 return (bits + 0x00800000) & 0x7FFFFFFF >= 0x01000000;
...@@ -20,8 +24,13 @@ pub fn isNormal(x: var) bool {...@@ -20,8 +24,13 @@ pub fn isNormal(x: var) bool {
20}24}
2125
22test "math.isNormal" {26test "math.isNormal" {
27 assert(!isNormal(math.nan(f16)));
23 assert(!isNormal(math.nan(f32)));28 assert(!isNormal(math.nan(f32)));
24 assert(!isNormal(math.nan(f64)));29 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)));
25 assert(isNormal(f32(1.0)));34 assert(isNormal(f32(1.0)));
26 assert(isNormal(f64(1.0)));35 assert(isNormal(f64(1.0)));
27}36}
std/math/nan.zig+2
...@@ -2,6 +2,7 @@ const math = @import("index.zig");...@@ -2,6 +2,7 @@ const math = @import("index.zig");
22
3pub fn nan(comptime T: type) T {3pub fn nan(comptime T: type) T {
4 return switch (T) {4 return switch (T) {
5 f16 => @bitCast(f16, math.nan_u16),
5 f32 => @bitCast(f32, math.nan_u32),6 f32 => @bitCast(f32, math.nan_u32),
6 f64 => @bitCast(f64, math.nan_u64),7 f64 => @bitCast(f64, math.nan_u64),
7 else => @compileError("nan not implemented for " ++ @typeName(T)),8 else => @compileError("nan not implemented for " ++ @typeName(T)),
...@@ -12,6 +13,7 @@ pub fn nan(comptime T: type) T {...@@ -12,6 +13,7 @@ pub fn nan(comptime T: type) T {
12// representation in the future when required.13// representation in the future when required.
13pub fn snan(comptime T: type) T {14pub fn snan(comptime T: type) T {
14 return switch (T) {15 return switch (T) {
16 f16 => @bitCast(f16, math.nan_u16),
15 f32 => @bitCast(f32, math.nan_u32),17 f32 => @bitCast(f32, math.nan_u32),
16 f64 => @bitCast(f64, math.nan_u64),18 f64 => @bitCast(f64, math.nan_u64),
17 else => @compileError("snan not implemented for " ++ @typeName(T)),19 else => @compileError("snan not implemented for " ++ @typeName(T)),
std/math/signbit.zig+12
...@@ -5,12 +5,18 @@ const assert = std.debug.assert;...@@ -5,12 +5,18 @@ const assert = std.debug.assert;
5pub fn signbit(x: var) bool {5pub fn signbit(x: var) bool {
6 const T = @typeOf(x);6 const T = @typeOf(x);
7 return switch (T) {7 return switch (T) {
8 f16 => signbit16(x),
8 f32 => signbit32(x),9 f32 => signbit32(x),
9 f64 => signbit64(x),10 f64 => signbit64(x),
10 else => @compileError("signbit not implemented for " ++ @typeName(T)),11 else => @compileError("signbit not implemented for " ++ @typeName(T)),
11 };12 };
12}13}
1314
15fn signbit16(x: f16) bool {
16 const bits = @bitCast(u16, x);
17 return bits >> 15 != 0;
18}
19
14fn signbit32(x: f32) bool {20fn signbit32(x: f32) bool {
15 const bits = @bitCast(u32, x);21 const bits = @bitCast(u32, x);
16 return bits >> 31 != 0;22 return bits >> 31 != 0;
...@@ -22,10 +28,16 @@ fn signbit64(x: f64) bool {...@@ -22,10 +28,16 @@ fn signbit64(x: f64) bool {
22}28}
2329
24test "math.signbit" {30test "math.signbit" {
31 assert(signbit(f16(4.0)) == signbit16(4.0));
25 assert(signbit(f32(4.0)) == signbit32(4.0));32 assert(signbit(f32(4.0)) == signbit32(4.0));
26 assert(signbit(f64(4.0)) == signbit64(4.0));33 assert(signbit(f64(4.0)) == signbit64(4.0));
27}34}
2835
36test "math.signbit16" {
37 assert(!signbit16(4.0));
38 assert(signbit16(-3.0));
39}
40
29test "math.signbit32" {41test "math.signbit32" {
30 assert(!signbit32(4.0));42 assert(!signbit32(4.0));
31 assert(signbit32(-3.0));43 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...@@ -31,10 +31,25 @@ pub fn sqrt(x: var) (if (@typeId(@typeOf(x)) == TypeId.Int) @IntType(false, @typ
31}31}
3232
33test "math.sqrt" {33test "math.sqrt" {
34 assert(sqrt(f16(0.0)) == @sqrt(f16, 0.0));
34 assert(sqrt(f32(0.0)) == @sqrt(f32, 0.0));35 assert(sqrt(f32(0.0)) == @sqrt(f32, 0.0));
35 assert(sqrt(f64(0.0)) == @sqrt(f64, 0.0));36 assert(sqrt(f64(0.0)) == @sqrt(f64, 0.0));
36}37}
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
38test "math.sqrt32" {53test "math.sqrt32" {
39 const epsilon = 0.000001;54 const epsilon = 0.000001;
4055
...@@ -63,6 +78,14 @@ test "math.sqrt64" {...@@ -63,6 +78,14 @@ test "math.sqrt64" {
63 assert(math.approxEq(f64, @sqrt(f64, 8942.230469), 94.563367, epsilon));78 assert(math.approxEq(f64, @sqrt(f64, 8942.230469), 94.563367, epsilon));
64}79}
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
66test "math.sqrt32.special" {89test "math.sqrt32.special" {
67 assert(math.isPositiveInf(@sqrt(f32, math.inf(f32))));90 assert(math.isPositiveInf(@sqrt(f32, math.inf(f32))));
68 assert(@sqrt(f32, 0.0) == 0.0);91 assert(@sqrt(f32, 0.0) == 0.0);
std/mem.zig+9-17
...@@ -31,16 +31,8 @@ pub const Allocator = struct {...@@ -31,16 +31,8 @@ pub const Allocator = struct {
31 /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`31 /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`
32 freeFn: fn (self: *Allocator, old_mem: []u8) void,32 freeFn: fn (self: *Allocator, old_mem: []u8) void,
3333
34 /// Call destroy with the result34 /// Call `destroy` with the result
35 pub fn create(self: *Allocator, comptime T: type) !*T {35 pub fn create(self: *Allocator, init: var) Error!*@typeOf(init) {
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) {
44 const T = @typeOf(init);36 const T = @typeOf(init);
45 if (@sizeOf(T) == 0) return &{};37 if (@sizeOf(T) == 0) return &{};
46 const slice = try self.alloc(T, 1);38 const slice = try self.alloc(T, 1);
...@@ -49,7 +41,7 @@ pub const Allocator = struct {...@@ -49,7 +41,7 @@ pub const Allocator = struct {
49 return ptr;41 return ptr;
50 }42 }
5143
52 /// `ptr` should be the return value of `construct` or `create`44 /// `ptr` should be the return value of `create`
53 pub fn destroy(self: *Allocator, ptr: var) void {45 pub fn destroy(self: *Allocator, ptr: var) void {
54 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr));46 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr));
55 self.freeFn(self, non_const_ptr[0..@sizeOf(@typeOf(ptr).Child)]);47 self.freeFn(self, non_const_ptr[0..@sizeOf(@typeOf(ptr).Child)]);
...@@ -70,7 +62,7 @@ pub const Allocator = struct {...@@ -70,7 +62,7 @@ pub const Allocator = struct {
70 for (byte_slice) |*byte| {62 for (byte_slice) |*byte| {
71 byte.* = undefined;63 byte.* = undefined;
72 }64 }
73 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));65 return @bytesToSlice(T, @alignCast(alignment, byte_slice));
74 }66 }
7567
76 pub fn realloc(self: *Allocator, comptime T: type, old_mem: []T, n: usize) ![]T {68 pub fn realloc(self: *Allocator, comptime T: type, old_mem: []T, n: usize) ![]T {
...@@ -86,7 +78,7 @@ pub const Allocator = struct {...@@ -86,7 +78,7 @@ pub const Allocator = struct {
86 return ([*]align(alignment) T)(undefined)[0..0];78 return ([*]align(alignment) T)(undefined)[0..0];
87 }79 }
8880
89 const old_byte_slice = ([]u8)(old_mem);81 const old_byte_slice = @sliceToBytes(old_mem);
90 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;82 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
91 const byte_slice = try self.reallocFn(self, old_byte_slice, byte_count, alignment);83 const byte_slice = try self.reallocFn(self, old_byte_slice, byte_count, alignment);
92 assert(byte_slice.len == byte_count);84 assert(byte_slice.len == byte_count);
...@@ -96,7 +88,7 @@ pub const Allocator = struct {...@@ -96,7 +88,7 @@ pub const Allocator = struct {
96 byte.* = undefined;88 byte.* = undefined;
97 }89 }
98 }90 }
99 return ([]T)(@alignCast(alignment, byte_slice));91 return @bytesToSlice(T, @alignCast(alignment, byte_slice));
100 }92 }
10193
102 /// Reallocate, but `n` must be less than or equal to `old_mem.len`.94 /// Reallocate, but `n` must be less than or equal to `old_mem.len`.
...@@ -118,13 +110,13 @@ pub const Allocator = struct {...@@ -118,13 +110,13 @@ pub const Allocator = struct {
118 // n <= old_mem.len and the multiplication didn't overflow for that operation.110 // n <= old_mem.len and the multiplication didn't overflow for that operation.
119 const byte_count = @sizeOf(T) * n;111 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;
122 assert(byte_slice.len == byte_count);114 assert(byte_slice.len == byte_count);
123 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));115 return @bytesToSlice(T, @alignCast(alignment, byte_slice));
124 }116 }
125117
126 pub fn free(self: *Allocator, memory: var) void {118 pub fn free(self: *Allocator, memory: var) void {
127 const bytes = ([]const u8)(memory);119 const bytes = @sliceToBytes(memory);
128 if (bytes.len == 0) return;120 if (bytes.len == 0) return;
129 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(bytes.ptr));121 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(bytes.ptr));
130 self.freeFn(self, non_const_ptr[0..bytes.len]);122 self.freeFn(self, non_const_ptr[0..bytes.len]);
std/net.zig+1-1
...@@ -68,7 +68,7 @@ pub const Address = struct {...@@ -68,7 +68,7 @@ pub const Address = struct {
6868
69pub fn parseIp4(buf: []const u8) !u32 {69pub fn parseIp4(buf: []const u8) !u32 {
70 var result: u32 = undefined;70 var result: u32 = undefined;
71 const out_ptr = ([]u8)((*[1]u32)(&result)[0..]);71 const out_ptr = @sliceToBytes((*[1]u32)(&result)[0..]);
7272
73 var x: u8 = 0;73 var x: u8 = 0;
74 var index: u8 = 0;74 var index: u8 = 0;
std/os/child_process.zig+5-8
...@@ -85,10 +85,7 @@ pub const ChildProcess = struct {...@@ -85,10 +85,7 @@ pub const ChildProcess = struct {
85 /// First argument in argv is the executable.85 /// First argument in argv is the executable.
86 /// On success must call deinit.86 /// On success must call deinit.
87 pub fn init(argv: []const []const u8, allocator: *mem.Allocator) !*ChildProcess {87 pub fn init(argv: []const []const u8, allocator: *mem.Allocator) !*ChildProcess {
88 const child = try allocator.create(ChildProcess);88 const child = try allocator.create(ChildProcess{
89 errdefer allocator.destroy(child);
90
91 child.* = ChildProcess{
92 .allocator = allocator,89 .allocator = allocator,
93 .argv = argv,90 .argv = argv,
94 .pid = undefined,91 .pid = undefined,
...@@ -109,8 +106,8 @@ pub const ChildProcess = struct {...@@ -109,8 +106,8 @@ pub const ChildProcess = struct {
109 .stdin_behavior = StdIo.Inherit,106 .stdin_behavior = StdIo.Inherit,
110 .stdout_behavior = StdIo.Inherit,107 .stdout_behavior = StdIo.Inherit,
111 .stderr_behavior = StdIo.Inherit,108 .stderr_behavior = StdIo.Inherit,
112 };109 });
113110 errdefer allocator.destroy(child);
114 return child;111 return child;
115 }112 }
116113
...@@ -318,7 +315,7 @@ pub const ChildProcess = struct {...@@ -318,7 +315,7 @@ pub const ChildProcess = struct {
318 // Here we potentially return the fork child's error315 // Here we potentially return the fork child's error
319 // from the parent pid.316 // from the parent pid.
320 if (err_int != @maxValue(ErrInt)) {317 if (err_int != @maxValue(ErrInt)) {
321 return SpawnError(err_int);318 return @errSetCast(SpawnError, @intToError(err_int));
322 }319 }
323320
324 return statusToTerm(status);321 return statusToTerm(status);
...@@ -756,7 +753,7 @@ fn destroyPipe(pipe: *const [2]i32) void {...@@ -756,7 +753,7 @@ fn destroyPipe(pipe: *const [2]i32) void {
756// Child of fork calls this to report an error to the fork parent.753// Child of fork calls this to report an error to the fork parent.
757// Then the child exits.754// Then the child exits.
758fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {755fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {
759 _ = writeIntFd(fd, ErrInt(err));756 _ = writeIntFd(fd, ErrInt(@errorToInt(err)));
760 posix.exit(1);757 posix.exit(1);
761}758}
762759
std/os/index.zig+12-6
...@@ -1805,7 +1805,7 @@ pub fn argsAlloc(allocator: *mem.Allocator) ![]const []u8 {...@@ -1805,7 +1805,7 @@ pub fn argsAlloc(allocator: *mem.Allocator) ![]const []u8 {
1805 const buf = try allocator.alignedAlloc(u8, @alignOf([]u8), total_bytes);1805 const buf = try allocator.alignedAlloc(u8, @alignOf([]u8), total_bytes);
1806 errdefer allocator.free(buf);1806 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]);
1809 const result_contents = buf[slice_list_bytes..];1809 const result_contents = buf[slice_list_bytes..];
1810 mem.copy(u8, result_contents, contents_slice);1810 mem.copy(u8, result_contents, contents_slice);
18111811
...@@ -2468,7 +2468,7 @@ pub const Thread = struct {...@@ -2468,7 +2468,7 @@ pub const Thread = struct {
2468 data: Data,2468 data: Data,
24692469
2470 pub const use_pthreads = is_posix and builtin.link_libc;2470 pub const use_pthreads = is_posix and builtin.link_libc;
2471 const Data = if (use_pthreads)2471 pub const Data = if (use_pthreads)
2472 struct {2472 struct {
2473 handle: c.pthread_t,2473 handle: c.pthread_t,
2474 stack_addr: usize,2474 stack_addr: usize,
...@@ -2582,10 +2582,16 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread...@@ -2582,10 +2582,16 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread
2582 const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) orelse return SpawnThreadError.OutOfMemory;2582 const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) orelse return SpawnThreadError.OutOfMemory;
2583 errdefer assert(windows.HeapFree(heap_handle, 0, bytes_ptr) != 0);2583 errdefer assert(windows.HeapFree(heap_handle, 0, bytes_ptr) != 0);
2584 const bytes = @ptrCast([*]u8, bytes_ptr)[0..byte_count];2584 const bytes = @ptrCast([*]u8, bytes_ptr)[0..byte_count];
2585 const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext) catch unreachable;2585 const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext{
2586 outer_context.inner = context;2586 .thread = Thread{
2587 outer_context.thread.data.heap_handle = heap_handle;2587 .data = Thread.Data{
2588 outer_context.thread.data.alloc_start = bytes_ptr;2588 .heap_handle = heap_handle,
2589 .alloc_start = bytes_ptr,
2590 .handle = undefined,
2591 },
2592 },
2593 .inner = context,
2594 }) catch unreachable;
25892595
2590 const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner);2596 const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner);
2591 outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse {2597 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 {...@@ -79,7 +79,7 @@ pub fn windowsIsCygwinPty(handle: windows.HANDLE) bool {
7979
80 const name_info = @ptrCast(*const windows.FILE_NAME_INFO, &name_info_bytes[0]);80 const name_info = @ptrCast(*const windows.FILE_NAME_INFO, &name_info_bytes[0]);
81 const name_bytes = name_info_bytes[size .. size + usize(name_info.FileNameLength)];81 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);
83 return mem.indexOf(u16, name_wide, []u16{ 'm', 's', 'y', 's', '-' }) != null or83 return mem.indexOf(u16, name_wide, []u16{ 'm', 's', 'y', 's', '-' }) != null or
84 mem.indexOf(u16, name_wide, []u16{ '-', 'p', 't', 'y' }) != null;84 mem.indexOf(u16, name_wide, []u16{ '-', 'p', 't', 'y' }) != null;
85}85}
std/rand/index.zig+2-2
...@@ -116,7 +116,7 @@ pub const Random = struct {...@@ -116,7 +116,7 @@ pub const Random = struct {
116 pub fn floatNorm(r: *Random, comptime T: type) T {116 pub fn floatNorm(r: *Random, comptime T: type) T {
117 const value = ziggurat.next_f64(r, ziggurat.NormDist);117 const value = ziggurat.next_f64(r, ziggurat.NormDist);
118 switch (T) {118 switch (T) {
119 f32 => return f32(value),119 f32 => return @floatCast(f32, value),
120 f64 => return value,120 f64 => return value,
121 else => @compileError("unknown floating point type"),121 else => @compileError("unknown floating point type"),
122 }122 }
...@@ -128,7 +128,7 @@ pub const Random = struct {...@@ -128,7 +128,7 @@ pub const Random = struct {
128 pub fn floatExp(r: *Random, comptime T: type) T {128 pub fn floatExp(r: *Random, comptime T: type) T {
129 const value = ziggurat.next_f64(r, ziggurat.ExpDist);129 const value = ziggurat.next_f64(r, ziggurat.ExpDist);
130 switch (T) {130 switch (T) {
131 f32 => return f32(value),131 f32 => return @floatCast(f32, value),
132 f64 => return value,132 f64 => return value,
133 else => @compileError("unknown floating point type"),133 else => @compileError("unknown floating point type"),
134 }134 }
std/rand/ziggurat.zig+6-2
...@@ -84,12 +84,12 @@ fn ZigTableGen(...@@ -84,12 +84,12 @@ fn ZigTableGen(
8484
85 for (tables.x[2..256]) |*entry, i| {85 for (tables.x[2..256]) |*entry, i| {
86 const last = tables.x[2 + i - 1];86 const last = tables.x[2 + i - 1];
87 *entry = f_inv(v / last + f(last));87 entry.* = f_inv(v / last + f(last));
88 }88 }
89 tables.x[256] = 0;89 tables.x[256] = 0;
9090
91 for (tables.f[0..]) |*entry, i| {91 for (tables.f[0..]) |*entry, i| {
92 *entry = f(tables.x[i]);92 entry.* = f(tables.x[i]);
93 }93 }
9494
95 return tables;95 return tables;
...@@ -160,3 +160,7 @@ test "ziggurant exp dist sanity" {...@@ -160,3 +160,7 @@ test "ziggurant exp dist sanity" {
160 _ = prng.random.floatExp(f64);160 _ = prng.random.floatExp(f64);
161 }161 }
162}162}
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 {...@@ -210,7 +210,9 @@ fn generic_fmod(comptime T: type, x: T, y: T) T {
210}210}
211211
212fn isNan(comptime T: type, bits: T) bool {212fn 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) {
214 return (bits & 0x7fffffff) > 0x7f800000;216 return (bits & 0x7fffffff) > 0x7f800000;
215 } else if (T == u64) {217 } else if (T == u64) {
216 return (bits & (@maxValue(u64) >> 1)) > (u64(0x7ff) << 52);218 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 {...@@ -15,10 +15,31 @@ comptime {
15 @export("__lttf2", @import("comparetf2.zig").__letf2, linkage);15 @export("__lttf2", @import("comparetf2.zig").__letf2, linkage);
16 @export("__netf2", @import("comparetf2.zig").__letf2, linkage);16 @export("__netf2", @import("comparetf2.zig").__letf2, linkage);
17 @export("__gttf2", @import("comparetf2.zig").__getf2, linkage);17 @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);
18 }20 }
1921
20 @export("__unordtf2", @import("comparetf2.zig").__unordtf2, linkage);22 @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
22 @export("__fixunssfsi", @import("fixunssfsi.zig").__fixunssfsi, linkage);43 @export("__fixunssfsi", @import("fixunssfsi.zig").__fixunssfsi, linkage);
23 @export("__fixunssfdi", @import("fixunssfdi.zig").__fixunssfdi, linkage);44 @export("__fixunssfdi", @import("fixunssfdi.zig").__fixunssfdi, linkage);
24 @export("__fixunssfti", @import("fixunssfti.zig").__fixunssfti, linkage);45 @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 {...@@ -858,6 +858,7 @@ pub const Node = struct {
858858
859 pub fn firstToken(self: *FnProto) TokenIndex {859 pub fn firstToken(self: *FnProto) TokenIndex {
860 if (self.visib_token) |visib_token| return visib_token;860 if (self.visib_token) |visib_token| return visib_token;
861 if (self.async_attr) |async_attr| return async_attr.firstToken();
861 if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;862 if (self.extern_export_inline_token) |extern_export_inline_token| return extern_export_inline_token;
862 assert(self.lib_name == null);863 assert(self.lib_name == null);
863 if (self.cc_token) |cc_token| return cc_token;864 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 {...@@ -17,7 +17,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
17 defer stack.deinit();17 defer stack.deinit();
1818
19 const arena = &tree_arena.allocator;19 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{
21 .base = ast.Node{ .id = ast.Node.Id.Root },21 .base = ast.Node{ .id = ast.Node.Id.Root },
22 .decls = ast.Node.Root.DeclList.init(arena),22 .decls = ast.Node.Root.DeclList.init(arena),
23 .doc_comments = null,23 .doc_comments = null,
...@@ -65,14 +65,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -65,14 +65,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
65 Token.Id.Keyword_test => {65 Token.Id.Keyword_test => {
66 stack.append(State.TopLevel) catch unreachable;66 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{
69 .base = ast.Node{ .id = ast.Node.Id.Block },69 .base = ast.Node{ .id = ast.Node.Id.Block },
70 .label = null,70 .label = null,
71 .lbrace = undefined,71 .lbrace = undefined,
72 .statements = ast.Node.Block.StatementList.init(arena),72 .statements = ast.Node.Block.StatementList.init(arena),
73 .rbrace = undefined,73 .rbrace = undefined,
74 });74 });
75 const test_node = try arena.construct(ast.Node.TestDecl{75 const test_node = try arena.create(ast.Node.TestDecl{
76 .base = ast.Node{ .id = ast.Node.Id.TestDecl },76 .base = ast.Node{ .id = ast.Node.Id.TestDecl },
77 .doc_comments = comments,77 .doc_comments = comments,
78 .test_token = token_index,78 .test_token = token_index,
...@@ -109,14 +109,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -109,14 +109,14 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
109 continue;109 continue;
110 },110 },
111 Token.Id.Keyword_comptime => {111 Token.Id.Keyword_comptime => {
112 const block = try arena.construct(ast.Node.Block{112 const block = try arena.create(ast.Node.Block{
113 .base = ast.Node{ .id = ast.Node.Id.Block },113 .base = ast.Node{ .id = ast.Node.Id.Block },
114 .label = null,114 .label = null,
115 .lbrace = undefined,115 .lbrace = undefined,
116 .statements = ast.Node.Block.StatementList.init(arena),116 .statements = ast.Node.Block.StatementList.init(arena),
117 .rbrace = undefined,117 .rbrace = undefined,
118 });118 });
119 const node = try arena.construct(ast.Node.Comptime{119 const node = try arena.create(ast.Node.Comptime{
120 .base = ast.Node{ .id = ast.Node.Id.Comptime },120 .base = ast.Node{ .id = ast.Node.Id.Comptime },
121 .comptime_token = token_index,121 .comptime_token = token_index,
122 .expr = &block.base,122 .expr = &block.base,
...@@ -225,7 +225,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -225,7 +225,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
225 return tree;225 return tree;
226 }226 }
227227
228 const node = try arena.construct(ast.Node.Use{228 const node = try arena.create(ast.Node.Use{
229 .base = ast.Node{ .id = ast.Node.Id.Use },229 .base = ast.Node{ .id = ast.Node.Id.Use },
230 .use_token = token_index,230 .use_token = token_index,
231 .visib_token = ctx.visib_token,231 .visib_token = ctx.visib_token,
...@@ -266,7 +266,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -266,7 +266,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
266 continue;266 continue;
267 },267 },
268 Token.Id.Keyword_fn, Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc, Token.Id.Keyword_async => {268 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{
270 .base = ast.Node{ .id = ast.Node.Id.FnProto },270 .base = ast.Node{ .id = ast.Node.Id.FnProto },
271 .doc_comments = ctx.comments,271 .doc_comments = ctx.comments,
272 .visib_token = ctx.visib_token,272 .visib_token = ctx.visib_token,
...@@ -298,7 +298,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -298,7 +298,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
298 continue;298 continue;
299 },299 },
300 Token.Id.Keyword_async => {300 Token.Id.Keyword_async => {
301 const async_node = try arena.construct(ast.Node.AsyncAttribute{301 const async_node = try arena.create(ast.Node.AsyncAttribute{
302 .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute },302 .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute },
303 .async_token = token_index,303 .async_token = token_index,
304 .allocator_type = null,304 .allocator_type = null,
...@@ -330,7 +330,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -330,7 +330,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
330 },330 },
331 State.TopLevelExternOrField => |ctx| {331 State.TopLevelExternOrField => |ctx| {
332 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |identifier| {332 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{
334 .base = ast.Node{ .id = ast.Node.Id.StructField },334 .base = ast.Node{ .id = ast.Node.Id.StructField },
335 .doc_comments = ctx.comments,335 .doc_comments = ctx.comments,
336 .visib_token = ctx.visib_token,336 .visib_token = ctx.visib_token,
...@@ -375,7 +375,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -375,7 +375,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
375 const token = nextToken(&tok_it, &tree);375 const token = nextToken(&tok_it, &tree);
376 const token_index = token.index;376 const token_index = token.index;
377 const token_ptr = token.ptr;377 const token_ptr = token.ptr;
378 const node = try arena.construct(ast.Node.ContainerDecl{378 const node = try arena.create(ast.Node.ContainerDecl{
379 .base = ast.Node{ .id = ast.Node.Id.ContainerDecl },379 .base = ast.Node{ .id = ast.Node.Id.ContainerDecl },
380 .layout_token = ctx.layout_token,380 .layout_token = ctx.layout_token,
381 .kind_token = switch (token_ptr.id) {381 .kind_token = switch (token_ptr.id) {
...@@ -448,7 +448,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -448,7 +448,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
448 Token.Id.Identifier => {448 Token.Id.Identifier => {
449 switch (tree.tokens.at(container_decl.kind_token).id) {449 switch (tree.tokens.at(container_decl.kind_token).id) {
450 Token.Id.Keyword_struct => {450 Token.Id.Keyword_struct => {
451 const node = try arena.construct(ast.Node.StructField{451 const node = try arena.create(ast.Node.StructField{
452 .base = ast.Node{ .id = ast.Node.Id.StructField },452 .base = ast.Node{ .id = ast.Node.Id.StructField },
453 .doc_comments = comments,453 .doc_comments = comments,
454 .visib_token = null,454 .visib_token = null,
...@@ -464,7 +464,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -464,7 +464,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
464 continue;464 continue;
465 },465 },
466 Token.Id.Keyword_union => {466 Token.Id.Keyword_union => {
467 const node = try arena.construct(ast.Node.UnionTag{467 const node = try arena.create(ast.Node.UnionTag{
468 .base = ast.Node{ .id = ast.Node.Id.UnionTag },468 .base = ast.Node{ .id = ast.Node.Id.UnionTag },
469 .name_token = token_index,469 .name_token = token_index,
470 .type_expr = null,470 .type_expr = null,
...@@ -480,7 +480,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -480,7 +480,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
480 continue;480 continue;
481 },481 },
482 Token.Id.Keyword_enum => {482 Token.Id.Keyword_enum => {
483 const node = try arena.construct(ast.Node.EnumTag{483 const node = try arena.create(ast.Node.EnumTag{
484 .base = ast.Node{ .id = ast.Node.Id.EnumTag },484 .base = ast.Node{ .id = ast.Node.Id.EnumTag },
485 .name_token = token_index,485 .name_token = token_index,
486 .value = null,486 .value = null,
...@@ -562,7 +562,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -562,7 +562,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
562 },562 },
563563
564 State.VarDecl => |ctx| {564 State.VarDecl => |ctx| {
565 const var_decl = try arena.construct(ast.Node.VarDecl{565 const var_decl = try arena.create(ast.Node.VarDecl{
566 .base = ast.Node{ .id = ast.Node.Id.VarDecl },566 .base = ast.Node{ .id = ast.Node.Id.VarDecl },
567 .doc_comments = ctx.comments,567 .doc_comments = ctx.comments,
568 .visib_token = ctx.visib_token,568 .visib_token = ctx.visib_token,
...@@ -660,7 +660,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -660,7 +660,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
660 const token_ptr = token.ptr;660 const token_ptr = token.ptr;
661 switch (token_ptr.id) {661 switch (token_ptr.id) {
662 Token.Id.LBrace => {662 Token.Id.LBrace => {
663 const block = try arena.construct(ast.Node.Block{663 const block = try arena.create(ast.Node.Block{
664 .base = ast.Node{ .id = ast.Node.Id.Block },664 .base = ast.Node{ .id = ast.Node.Id.Block },
665 .label = null,665 .label = null,
666 .lbrace = token_index,666 .lbrace = token_index,
...@@ -712,7 +712,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -712,7 +712,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
712 // TODO: this is a special case. Remove this when #760 is fixed712 // TODO: this is a special case. Remove this when #760 is fixed
713 if (token_ptr.id == Token.Id.Keyword_error) {713 if (token_ptr.id == Token.Id.Keyword_error) {
714 if (tok_it.peek().?.id == Token.Id.LBrace) {714 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{
716 .base = ast.Node{ .id = ast.Node.Id.ErrorType },716 .base = ast.Node{ .id = ast.Node.Id.ErrorType },
717 .token = token_index,717 .token = token_index,
718 });718 });
...@@ -733,7 +733,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -733,7 +733,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
733 if (eatToken(&tok_it, &tree, Token.Id.RParen)) |_| {733 if (eatToken(&tok_it, &tree, Token.Id.RParen)) |_| {
734 continue;734 continue;
735 }735 }
736 const param_decl = try arena.construct(ast.Node.ParamDecl{736 const param_decl = try arena.create(ast.Node.ParamDecl{
737 .base = ast.Node{ .id = ast.Node.Id.ParamDecl },737 .base = ast.Node{ .id = ast.Node.Id.ParamDecl },
738 .comptime_token = null,738 .comptime_token = null,
739 .noalias_token = null,739 .noalias_token = null,
...@@ -819,7 +819,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -819,7 +819,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
819 const token_ptr = token.ptr;819 const token_ptr = token.ptr;
820 switch (token_ptr.id) {820 switch (token_ptr.id) {
821 Token.Id.LBrace => {821 Token.Id.LBrace => {
822 const block = try arena.construct(ast.Node.Block{822 const block = try arena.create(ast.Node.Block{
823 .base = ast.Node{ .id = ast.Node.Id.Block },823 .base = ast.Node{ .id = ast.Node.Id.Block },
824 .label = ctx.label,824 .label = ctx.label,
825 .lbrace = token_index,825 .lbrace = token_index,
...@@ -853,7 +853,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -853,7 +853,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
853 continue;853 continue;
854 },854 },
855 Token.Id.Keyword_suspend => {855 Token.Id.Keyword_suspend => {
856 const node = try arena.construct(ast.Node.Suspend{856 const node = try arena.create(ast.Node.Suspend{
857 .base = ast.Node{ .id = ast.Node.Id.Suspend },857 .base = ast.Node{ .id = ast.Node.Id.Suspend },
858 .label = ctx.label,858 .label = ctx.label,
859 .suspend_token = token_index,859 .suspend_token = token_index,
...@@ -925,7 +925,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -925,7 +925,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
925 }925 }
926 },926 },
927 State.While => |ctx| {927 State.While => |ctx| {
928 const node = try arena.construct(ast.Node.While{928 const node = try arena.create(ast.Node.While{
929 .base = ast.Node{ .id = ast.Node.Id.While },929 .base = ast.Node{ .id = ast.Node.Id.While },
930 .label = ctx.label,930 .label = ctx.label,
931 .inline_token = ctx.inline_token,931 .inline_token = ctx.inline_token,
...@@ -954,7 +954,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -954,7 +954,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
954 continue;954 continue;
955 },955 },
956 State.For => |ctx| {956 State.For => |ctx| {
957 const node = try arena.construct(ast.Node.For{957 const node = try arena.create(ast.Node.For{
958 .base = ast.Node{ .id = ast.Node.Id.For },958 .base = ast.Node{ .id = ast.Node.Id.For },
959 .label = ctx.label,959 .label = ctx.label,
960 .inline_token = ctx.inline_token,960 .inline_token = ctx.inline_token,
...@@ -975,7 +975,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -975,7 +975,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
975 },975 },
976 State.Else => |dest| {976 State.Else => |dest| {
977 if (eatToken(&tok_it, &tree, Token.Id.Keyword_else)) |else_token| {977 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{
979 .base = ast.Node{ .id = ast.Node.Id.Else },979 .base = ast.Node{ .id = ast.Node.Id.Else },
980 .else_token = else_token,980 .else_token = else_token,
981 .payload = null,981 .payload = null,
...@@ -1038,7 +1038,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1038,7 +1038,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1038 continue;1038 continue;
1039 },1039 },
1040 Token.Id.Keyword_defer, Token.Id.Keyword_errdefer => {1040 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{
1042 .base = ast.Node{ .id = ast.Node.Id.Defer },1042 .base = ast.Node{ .id = ast.Node.Id.Defer },
1043 .defer_token = token_index,1043 .defer_token = token_index,
1044 .kind = switch (token_ptr.id) {1044 .kind = switch (token_ptr.id) {
...@@ -1056,7 +1056,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1056,7 +1056,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1056 continue;1056 continue;
1057 },1057 },
1058 Token.Id.LBrace => {1058 Token.Id.LBrace => {
1059 const inner_block = try arena.construct(ast.Node.Block{1059 const inner_block = try arena.create(ast.Node.Block{
1060 .base = ast.Node{ .id = ast.Node.Id.Block },1060 .base = ast.Node{ .id = ast.Node.Id.Block },
1061 .label = null,1061 .label = null,
1062 .lbrace = token_index,1062 .lbrace = token_index,
...@@ -1124,7 +1124,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1124,7 +1124,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1124 continue;1124 continue;
1125 }1125 }
11261126
1127 const node = try arena.construct(ast.Node.AsmOutput{1127 const node = try arena.create(ast.Node.AsmOutput{
1128 .base = ast.Node{ .id = ast.Node.Id.AsmOutput },1128 .base = ast.Node{ .id = ast.Node.Id.AsmOutput },
1129 .lbracket = lbracket_index,1129 .lbracket = lbracket_index,
1130 .symbolic_name = undefined,1130 .symbolic_name = undefined,
...@@ -1178,7 +1178,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1178,7 +1178,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1178 continue;1178 continue;
1179 }1179 }
11801180
1181 const node = try arena.construct(ast.Node.AsmInput{1181 const node = try arena.create(ast.Node.AsmInput{
1182 .base = ast.Node{ .id = ast.Node.Id.AsmInput },1182 .base = ast.Node{ .id = ast.Node.Id.AsmInput },
1183 .lbracket = lbracket_index,1183 .lbracket = lbracket_index,
1184 .symbolic_name = undefined,1184 .symbolic_name = undefined,
...@@ -1243,7 +1243,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1243,7 +1243,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1243 continue;1243 continue;
1244 }1244 }
12451245
1246 const node = try arena.construct(ast.Node.FieldInitializer{1246 const node = try arena.create(ast.Node.FieldInitializer{
1247 .base = ast.Node{ .id = ast.Node.Id.FieldInitializer },1247 .base = ast.Node{ .id = ast.Node.Id.FieldInitializer },
1248 .period_token = undefined,1248 .period_token = undefined,
1249 .name_token = undefined,1249 .name_token = undefined,
...@@ -1332,7 +1332,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1332,7 +1332,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1332 }1332 }
13331333
1334 const comments = try eatDocComments(arena, &tok_it, &tree);1334 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{
1336 .base = ast.Node{ .id = ast.Node.Id.SwitchCase },1336 .base = ast.Node{ .id = ast.Node.Id.SwitchCase },
1337 .items = ast.Node.SwitchCase.ItemList.init(arena),1337 .items = ast.Node.SwitchCase.ItemList.init(arena),
1338 .payload = null,1338 .payload = null,
...@@ -1369,7 +1369,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1369,7 +1369,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1369 const token_index = token.index;1369 const token_index = token.index;
1370 const token_ptr = token.ptr;1370 const token_ptr = token.ptr;
1371 if (token_ptr.id == Token.Id.Keyword_else) {1371 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{
1373 .base = ast.Node{ .id = ast.Node.Id.SwitchElse },1373 .base = ast.Node{ .id = ast.Node.Id.SwitchElse },
1374 .token = token_index,1374 .token = token_index,
1375 });1375 });
...@@ -1468,7 +1468,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1468,7 +1468,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
14681468
1469 State.ExternType => |ctx| {1469 State.ExternType => |ctx| {
1470 if (eatToken(&tok_it, &tree, Token.Id.Keyword_fn)) |fn_token| {1470 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{
1472 .base = ast.Node{ .id = ast.Node.Id.FnProto },1472 .base = ast.Node{ .id = ast.Node.Id.FnProto },
1473 .doc_comments = ctx.comments,1473 .doc_comments = ctx.comments,
1474 .visib_token = null,1474 .visib_token = null,
...@@ -1641,7 +1641,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1641,7 +1641,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1641 continue;1641 continue;
1642 }1642 }
16431643
1644 const node = try arena.construct(ast.Node.Payload{1644 const node = try arena.create(ast.Node.Payload{
1645 .base = ast.Node{ .id = ast.Node.Id.Payload },1645 .base = ast.Node{ .id = ast.Node.Id.Payload },
1646 .lpipe = token_index,1646 .lpipe = token_index,
1647 .error_symbol = undefined,1647 .error_symbol = undefined,
...@@ -1677,7 +1677,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1677,7 +1677,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1677 continue;1677 continue;
1678 }1678 }
16791679
1680 const node = try arena.construct(ast.Node.PointerPayload{1680 const node = try arena.create(ast.Node.PointerPayload{
1681 .base = ast.Node{ .id = ast.Node.Id.PointerPayload },1681 .base = ast.Node{ .id = ast.Node.Id.PointerPayload },
1682 .lpipe = token_index,1682 .lpipe = token_index,
1683 .ptr_token = null,1683 .ptr_token = null,
...@@ -1720,7 +1720,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1720,7 +1720,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1720 continue;1720 continue;
1721 }1721 }
17221722
1723 const node = try arena.construct(ast.Node.PointerIndexPayload{1723 const node = try arena.create(ast.Node.PointerIndexPayload{
1724 .base = ast.Node{ .id = ast.Node.Id.PointerIndexPayload },1724 .base = ast.Node{ .id = ast.Node.Id.PointerIndexPayload },
1725 .lpipe = token_index,1725 .lpipe = token_index,
1726 .ptr_token = null,1726 .ptr_token = null,
...@@ -1754,7 +1754,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1754,7 +1754,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1754 const token_ptr = token.ptr;1754 const token_ptr = token.ptr;
1755 switch (token_ptr.id) {1755 switch (token_ptr.id) {
1756 Token.Id.Keyword_return, Token.Id.Keyword_break, Token.Id.Keyword_continue => {1756 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{
1758 .base = ast.Node{ .id = ast.Node.Id.ControlFlowExpression },1758 .base = ast.Node{ .id = ast.Node.Id.ControlFlowExpression },
1759 .ltoken = token_index,1759 .ltoken = token_index,
1760 .kind = undefined,1760 .kind = undefined,
...@@ -1783,7 +1783,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1783,7 +1783,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1783 continue;1783 continue;
1784 },1784 },
1785 Token.Id.Keyword_try, Token.Id.Keyword_cancel, Token.Id.Keyword_resume => {1785 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{
1787 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },1787 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },
1788 .op_token = token_index,1788 .op_token = token_index,
1789 .op = switch (token_ptr.id) {1789 .op = switch (token_ptr.id) {
...@@ -1817,7 +1817,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1817,7 +1817,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1817 const lhs = opt_ctx.get() orelse continue;1817 const lhs = opt_ctx.get() orelse continue;
18181818
1819 if (eatToken(&tok_it, &tree, Token.Id.Ellipsis3)) |ellipsis3| {1819 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{
1821 .base = ast.Node{ .id = ast.Node.Id.InfixOp },1821 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
1822 .lhs = lhs,1822 .lhs = lhs,
1823 .op_token = ellipsis3,1823 .op_token = ellipsis3,
...@@ -1842,7 +1842,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1842,7 +1842,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1842 const token_index = token.index;1842 const token_index = token.index;
1843 const token_ptr = token.ptr;1843 const token_ptr = token.ptr;
1844 if (tokenIdToAssignment(token_ptr.id)) |ass_id| {1844 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{
1846 .base = ast.Node{ .id = ast.Node.Id.InfixOp },1846 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
1847 .lhs = lhs,1847 .lhs = lhs,
1848 .op_token = token_index,1848 .op_token = token_index,
...@@ -1872,7 +1872,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1872,7 +1872,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1872 const token_index = token.index;1872 const token_index = token.index;
1873 const token_ptr = token.ptr;1873 const token_ptr = token.ptr;
1874 if (tokenIdToUnwrapExpr(token_ptr.id)) |unwrap_id| {1874 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{
1876 .base = ast.Node{ .id = ast.Node.Id.InfixOp },1876 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
1877 .lhs = lhs,1877 .lhs = lhs,
1878 .op_token = token_index,1878 .op_token = token_index,
...@@ -1904,7 +1904,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1904,7 +1904,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1904 const lhs = opt_ctx.get() orelse continue;1904 const lhs = opt_ctx.get() orelse continue;
19051905
1906 if (eatToken(&tok_it, &tree, Token.Id.Keyword_or)) |or_token| {1906 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{
1908 .base = ast.Node{ .id = ast.Node.Id.InfixOp },1908 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
1909 .lhs = lhs,1909 .lhs = lhs,
1910 .op_token = or_token,1910 .op_token = or_token,
...@@ -1928,7 +1928,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1928,7 +1928,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1928 const lhs = opt_ctx.get() orelse continue;1928 const lhs = opt_ctx.get() orelse continue;
19291929
1930 if (eatToken(&tok_it, &tree, Token.Id.Keyword_and)) |and_token| {1930 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{
1932 .base = ast.Node{ .id = ast.Node.Id.InfixOp },1932 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
1933 .lhs = lhs,1933 .lhs = lhs,
1934 .op_token = and_token,1934 .op_token = and_token,
...@@ -1955,7 +1955,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1955,7 +1955,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1955 const token_index = token.index;1955 const token_index = token.index;
1956 const token_ptr = token.ptr;1956 const token_ptr = token.ptr;
1957 if (tokenIdToComparison(token_ptr.id)) |comp_id| {1957 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{
1959 .base = ast.Node{ .id = ast.Node.Id.InfixOp },1959 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
1960 .lhs = lhs,1960 .lhs = lhs,
1961 .op_token = token_index,1961 .op_token = token_index,
...@@ -1982,7 +1982,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -1982,7 +1982,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
1982 const lhs = opt_ctx.get() orelse continue;1982 const lhs = opt_ctx.get() orelse continue;
19831983
1984 if (eatToken(&tok_it, &tree, Token.Id.Pipe)) |pipe| {1984 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{
1986 .base = ast.Node{ .id = ast.Node.Id.InfixOp },1986 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
1987 .lhs = lhs,1987 .lhs = lhs,
1988 .op_token = pipe,1988 .op_token = pipe,
...@@ -2006,7 +2006,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2006,7 +2006,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2006 const lhs = opt_ctx.get() orelse continue;2006 const lhs = opt_ctx.get() orelse continue;
20072007
2008 if (eatToken(&tok_it, &tree, Token.Id.Caret)) |caret| {2008 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{
2010 .base = ast.Node{ .id = ast.Node.Id.InfixOp },2010 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2011 .lhs = lhs,2011 .lhs = lhs,
2012 .op_token = caret,2012 .op_token = caret,
...@@ -2030,7 +2030,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2030,7 +2030,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2030 const lhs = opt_ctx.get() orelse continue;2030 const lhs = opt_ctx.get() orelse continue;
20312031
2032 if (eatToken(&tok_it, &tree, Token.Id.Ampersand)) |ampersand| {2032 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{
2034 .base = ast.Node{ .id = ast.Node.Id.InfixOp },2034 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2035 .lhs = lhs,2035 .lhs = lhs,
2036 .op_token = ampersand,2036 .op_token = ampersand,
...@@ -2057,7 +2057,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2057,7 +2057,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2057 const token_index = token.index;2057 const token_index = token.index;
2058 const token_ptr = token.ptr;2058 const token_ptr = token.ptr;
2059 if (tokenIdToBitShift(token_ptr.id)) |bitshift_id| {2059 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{
2061 .base = ast.Node{ .id = ast.Node.Id.InfixOp },2061 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2062 .lhs = lhs,2062 .lhs = lhs,
2063 .op_token = token_index,2063 .op_token = token_index,
...@@ -2087,7 +2087,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2087,7 +2087,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2087 const token_index = token.index;2087 const token_index = token.index;
2088 const token_ptr = token.ptr;2088 const token_ptr = token.ptr;
2089 if (tokenIdToAddition(token_ptr.id)) |add_id| {2089 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{
2091 .base = ast.Node{ .id = ast.Node.Id.InfixOp },2091 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2092 .lhs = lhs,2092 .lhs = lhs,
2093 .op_token = token_index,2093 .op_token = token_index,
...@@ -2117,7 +2117,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2117,7 +2117,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2117 const token_index = token.index;2117 const token_index = token.index;
2118 const token_ptr = token.ptr;2118 const token_ptr = token.ptr;
2119 if (tokenIdToMultiply(token_ptr.id)) |mult_id| {2119 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{
2121 .base = ast.Node{ .id = ast.Node.Id.InfixOp },2121 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2122 .lhs = lhs,2122 .lhs = lhs,
2123 .op_token = token_index,2123 .op_token = token_index,
...@@ -2145,7 +2145,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2145,7 +2145,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2145 const lhs = opt_ctx.get() orelse continue;2145 const lhs = opt_ctx.get() orelse continue;
21462146
2147 if (tok_it.peek().?.id == Token.Id.Period) {2147 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{
2149 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },2149 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2150 .lhs = lhs,2150 .lhs = lhs,
2151 .op = ast.Node.SuffixOp.Op{ .StructInitializer = ast.Node.SuffixOp.Op.InitList.init(arena) },2151 .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 {...@@ -2164,7 +2164,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2164 continue;2164 continue;
2165 }2165 }
21662166
2167 const node = try arena.construct(ast.Node.SuffixOp{2167 const node = try arena.create(ast.Node.SuffixOp{
2168 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },2168 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2169 .lhs = lhs,2169 .lhs = lhs,
2170 .op = ast.Node.SuffixOp.Op{ .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(arena) },2170 .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 {...@@ -2193,7 +2193,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2193 const lhs = opt_ctx.get() orelse continue;2193 const lhs = opt_ctx.get() orelse continue;
21942194
2195 if (eatToken(&tok_it, &tree, Token.Id.Bang)) |bang| {2195 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{
2197 .base = ast.Node{ .id = ast.Node.Id.InfixOp },2197 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2198 .lhs = lhs,2198 .lhs = lhs,
2199 .op_token = bang,2199 .op_token = bang,
...@@ -2212,7 +2212,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2212,7 +2212,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2212 const token_index = token.index;2212 const token_index = token.index;
2213 const token_ptr = token.ptr;2213 const token_ptr = token.ptr;
2214 if (tokenIdToPrefixOp(token_ptr.id)) |prefix_id| {2214 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{
2216 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },2216 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },
2217 .op_token = token_index,2217 .op_token = token_index,
2218 .op = prefix_id,2218 .op = prefix_id,
...@@ -2222,7 +2222,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2222,7 +2222,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
22222222
2223 // Treat '**' token as two pointer types2223 // Treat '**' token as two pointer types
2224 if (token_ptr.id == Token.Id.AsteriskAsterisk) {2224 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{
2226 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },2226 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },
2227 .op_token = token_index,2227 .op_token = token_index,
2228 .op = prefix_id,2228 .op = prefix_id,
...@@ -2246,7 +2246,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2246,7 +2246,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
22462246
2247 State.SuffixOpExpressionBegin => |opt_ctx| {2247 State.SuffixOpExpressionBegin => |opt_ctx| {
2248 if (eatToken(&tok_it, &tree, Token.Id.Keyword_async)) |async_token| {2248 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{
2250 .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute },2250 .base = ast.Node{ .id = ast.Node.Id.AsyncAttribute },
2251 .async_token = async_token,2251 .async_token = async_token,
2252 .allocator_type = null,2252 .allocator_type = null,
...@@ -2277,7 +2277,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2277,7 +2277,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2277 const token_ptr = token.ptr;2277 const token_ptr = token.ptr;
2278 switch (token_ptr.id) {2278 switch (token_ptr.id) {
2279 Token.Id.LParen => {2279 Token.Id.LParen => {
2280 const node = try arena.construct(ast.Node.SuffixOp{2280 const node = try arena.create(ast.Node.SuffixOp{
2281 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },2281 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2282 .lhs = lhs,2282 .lhs = lhs,
2283 .op = ast.Node.SuffixOp.Op{2283 .op = ast.Node.SuffixOp.Op{
...@@ -2301,7 +2301,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2301,7 +2301,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2301 continue;2301 continue;
2302 },2302 },
2303 Token.Id.LBracket => {2303 Token.Id.LBracket => {
2304 const node = try arena.construct(ast.Node.SuffixOp{2304 const node = try arena.create(ast.Node.SuffixOp{
2305 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },2305 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2306 .lhs = lhs,2306 .lhs = lhs,
2307 .op = ast.Node.SuffixOp.Op{ .ArrayAccess = undefined },2307 .op = ast.Node.SuffixOp.Op{ .ArrayAccess = undefined },
...@@ -2316,7 +2316,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2316,7 +2316,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2316 },2316 },
2317 Token.Id.Period => {2317 Token.Id.Period => {
2318 if (eatToken(&tok_it, &tree, Token.Id.Asterisk)) |asterisk_token| {2318 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{
2320 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },2320 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2321 .lhs = lhs,2321 .lhs = lhs,
2322 .op = ast.Node.SuffixOp.Op.Deref,2322 .op = ast.Node.SuffixOp.Op.Deref,
...@@ -2327,7 +2327,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2327,7 +2327,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2327 continue;2327 continue;
2328 }2328 }
2329 if (eatToken(&tok_it, &tree, Token.Id.QuestionMark)) |question_token| {2329 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{
2331 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },2331 .base = ast.Node{ .id = ast.Node.Id.SuffixOp },
2332 .lhs = lhs,2332 .lhs = lhs,
2333 .op = ast.Node.SuffixOp.Op.UnwrapOptional,2333 .op = ast.Node.SuffixOp.Op.UnwrapOptional,
...@@ -2337,7 +2337,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2337,7 +2337,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2337 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;2337 stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable;
2338 continue;2338 continue;
2339 }2339 }
2340 const node = try arena.construct(ast.Node.InfixOp{2340 const node = try arena.create(ast.Node.InfixOp{
2341 .base = ast.Node{ .id = ast.Node.Id.InfixOp },2341 .base = ast.Node{ .id = ast.Node.Id.InfixOp },
2342 .lhs = lhs,2342 .lhs = lhs,
2343 .op_token = token_index,2343 .op_token = token_index,
...@@ -2397,7 +2397,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2397,7 +2397,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2397 continue;2397 continue;
2398 },2398 },
2399 Token.Id.Keyword_promise => {2399 Token.Id.Keyword_promise => {
2400 const node = try arena.construct(ast.Node.PromiseType{2400 const node = try arena.create(ast.Node.PromiseType{
2401 .base = ast.Node{ .id = ast.Node.Id.PromiseType },2401 .base = ast.Node{ .id = ast.Node.Id.PromiseType },
2402 .promise_token = token.index,2402 .promise_token = token.index,
2403 .result = null,2403 .result = null,
...@@ -2423,7 +2423,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2423,7 +2423,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2423 continue;2423 continue;
2424 },2424 },
2425 Token.Id.LParen => {2425 Token.Id.LParen => {
2426 const node = try arena.construct(ast.Node.GroupedExpression{2426 const node = try arena.create(ast.Node.GroupedExpression{
2427 .base = ast.Node{ .id = ast.Node.Id.GroupedExpression },2427 .base = ast.Node{ .id = ast.Node.Id.GroupedExpression },
2428 .lparen = token.index,2428 .lparen = token.index,
2429 .expr = undefined,2429 .expr = undefined,
...@@ -2441,7 +2441,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2441,7 +2441,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2441 continue;2441 continue;
2442 },2442 },
2443 Token.Id.Builtin => {2443 Token.Id.Builtin => {
2444 const node = try arena.construct(ast.Node.BuiltinCall{2444 const node = try arena.create(ast.Node.BuiltinCall{
2445 .base = ast.Node{ .id = ast.Node.Id.BuiltinCall },2445 .base = ast.Node{ .id = ast.Node.Id.BuiltinCall },
2446 .builtin_token = token.index,2446 .builtin_token = token.index,
2447 .params = ast.Node.BuiltinCall.ParamList.init(arena),2447 .params = ast.Node.BuiltinCall.ParamList.init(arena),
...@@ -2460,7 +2460,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2460,7 +2460,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2460 continue;2460 continue;
2461 },2461 },
2462 Token.Id.LBracket => {2462 Token.Id.LBracket => {
2463 const node = try arena.construct(ast.Node.PrefixOp{2463 const node = try arena.create(ast.Node.PrefixOp{
2464 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },2464 .base = ast.Node{ .id = ast.Node.Id.PrefixOp },
2465 .op_token = token.index,2465 .op_token = token.index,
2466 .op = undefined,2466 .op = undefined,
...@@ -2519,7 +2519,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2519,7 +2519,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2519 continue;2519 continue;
2520 },2520 },
2521 Token.Id.Keyword_fn => {2521 Token.Id.Keyword_fn => {
2522 const fn_proto = try arena.construct(ast.Node.FnProto{2522 const fn_proto = try arena.create(ast.Node.FnProto{
2523 .base = ast.Node{ .id = ast.Node.Id.FnProto },2523 .base = ast.Node{ .id = ast.Node.Id.FnProto },
2524 .doc_comments = null,2524 .doc_comments = null,
2525 .visib_token = null,2525 .visib_token = null,
...@@ -2540,7 +2540,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2540,7 +2540,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2540 continue;2540 continue;
2541 },2541 },
2542 Token.Id.Keyword_nakedcc, Token.Id.Keyword_stdcallcc => {2542 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{
2544 .base = ast.Node{ .id = ast.Node.Id.FnProto },2544 .base = ast.Node{ .id = ast.Node.Id.FnProto },
2545 .doc_comments = null,2545 .doc_comments = null,
2546 .visib_token = null,2546 .visib_token = null,
...@@ -2567,7 +2567,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2567,7 +2567,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2567 continue;2567 continue;
2568 },2568 },
2569 Token.Id.Keyword_asm => {2569 Token.Id.Keyword_asm => {
2570 const node = try arena.construct(ast.Node.Asm{2570 const node = try arena.create(ast.Node.Asm{
2571 .base = ast.Node{ .id = ast.Node.Id.Asm },2571 .base = ast.Node{ .id = ast.Node.Id.Asm },
2572 .asm_token = token.index,2572 .asm_token = token.index,
2573 .volatile_token = null,2573 .volatile_token = null,
...@@ -2629,7 +2629,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2629,7 +2629,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2629 continue;2629 continue;
2630 }2630 }
26312631
2632 const node = try arena.construct(ast.Node.ErrorSetDecl{2632 const node = try arena.create(ast.Node.ErrorSetDecl{
2633 .base = ast.Node{ .id = ast.Node.Id.ErrorSetDecl },2633 .base = ast.Node{ .id = ast.Node.Id.ErrorSetDecl },
2634 .error_token = ctx.error_token,2634 .error_token = ctx.error_token,
2635 .decls = ast.Node.ErrorSetDecl.DeclList.init(arena),2635 .decls = ast.Node.ErrorSetDecl.DeclList.init(arena),
...@@ -2695,7 +2695,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2695,7 +2695,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2695 return tree;2695 return tree;
2696 }2696 }
26972697
2698 const node = try arena.construct(ast.Node.ErrorTag{2698 const node = try arena.create(ast.Node.ErrorTag{
2699 .base = ast.Node{ .id = ast.Node.Id.ErrorTag },2699 .base = ast.Node{ .id = ast.Node.Id.ErrorTag },
2700 .doc_comments = comments,2700 .doc_comments = comments,
2701 .name_token = ident_token_index,2701 .name_token = ident_token_index,
...@@ -3032,7 +3032,7 @@ fn pushDocComment(arena: *mem.Allocator, line_comment: TokenIndex, result: *?*as...@@ -3032,7 +3032,7 @@ fn pushDocComment(arena: *mem.Allocator, line_comment: TokenIndex, result: *?*as
3032 if (result.*) |comment_node| {3032 if (result.*) |comment_node| {
3033 break :blk comment_node;3033 break :blk comment_node;
3034 } else {3034 } else {
3035 const comment_node = try arena.construct(ast.Node.DocComment{3035 const comment_node = try arena.create(ast.Node.DocComment{
3036 .base = ast.Node{ .id = ast.Node.Id.DocComment },3036 .base = ast.Node{ .id = ast.Node.Id.DocComment },
3037 .lines = ast.Node.DocComment.LineList.init(arena),3037 .lines = ast.Node.DocComment.LineList.init(arena),
3038 });3038 });
...@@ -3061,7 +3061,7 @@ fn parseStringLiteral(arena: *mem.Allocator, tok_it: *ast.Tree.TokenList.Iterato...@@ -3061,7 +3061,7 @@ fn parseStringLiteral(arena: *mem.Allocator, tok_it: *ast.Tree.TokenList.Iterato
3061 return &(try createLiteral(arena, ast.Node.StringLiteral, token_index)).base;3061 return &(try createLiteral(arena, ast.Node.StringLiteral, token_index)).base;
3062 },3062 },
3063 Token.Id.MultilineStringLiteralLine => {3063 Token.Id.MultilineStringLiteralLine => {
3064 const node = try arena.construct(ast.Node.MultilineStringLiteral{3064 const node = try arena.create(ast.Node.MultilineStringLiteral{
3065 .base = ast.Node{ .id = ast.Node.Id.MultilineStringLiteral },3065 .base = ast.Node{ .id = ast.Node.Id.MultilineStringLiteral },
3066 .lines = ast.Node.MultilineStringLiteral.LineList.init(arena),3066 .lines = ast.Node.MultilineStringLiteral.LineList.init(arena),
3067 });3067 });
...@@ -3089,7 +3089,7 @@ fn parseStringLiteral(arena: *mem.Allocator, tok_it: *ast.Tree.TokenList.Iterato...@@ -3089,7 +3089,7 @@ fn parseStringLiteral(arena: *mem.Allocator, tok_it: *ast.Tree.TokenList.Iterato
3089fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: *const OptionalCtx, token_ptr: *const Token, token_index: TokenIndex) !bool {3089fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: *const OptionalCtx, token_ptr: *const Token, token_index: TokenIndex) !bool {
3090 switch (token_ptr.id) {3090 switch (token_ptr.id) {
3091 Token.Id.Keyword_suspend => {3091 Token.Id.Keyword_suspend => {
3092 const node = try arena.construct(ast.Node.Suspend{3092 const node = try arena.create(ast.Node.Suspend{
3093 .base = ast.Node{ .id = ast.Node.Id.Suspend },3093 .base = ast.Node{ .id = ast.Node.Id.Suspend },
3094 .label = null,3094 .label = null,
3095 .suspend_token = token_index,3095 .suspend_token = token_index,
...@@ -3103,7 +3103,7 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: *con...@@ -3103,7 +3103,7 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: *con
3103 return true;3103 return true;
3104 },3104 },
3105 Token.Id.Keyword_if => {3105 Token.Id.Keyword_if => {
3106 const node = try arena.construct(ast.Node.If{3106 const node = try arena.create(ast.Node.If{
3107 .base = ast.Node{ .id = ast.Node.Id.If },3107 .base = ast.Node{ .id = ast.Node.Id.If },
3108 .if_token = token_index,3108 .if_token = token_index,
3109 .condition = undefined,3109 .condition = undefined,
...@@ -3144,7 +3144,7 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: *con...@@ -3144,7 +3144,7 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: *con
3144 return true;3144 return true;
3145 },3145 },
3146 Token.Id.Keyword_switch => {3146 Token.Id.Keyword_switch => {
3147 const node = try arena.construct(ast.Node.Switch{3147 const node = try arena.create(ast.Node.Switch{
3148 .base = ast.Node{ .id = ast.Node.Id.Switch },3148 .base = ast.Node{ .id = ast.Node.Id.Switch },
3149 .switch_token = token_index,3149 .switch_token = token_index,
3150 .expr = undefined,3150 .expr = undefined,
...@@ -3166,7 +3166,7 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: *con...@@ -3166,7 +3166,7 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: *con
3166 return true;3166 return true;
3167 },3167 },
3168 Token.Id.Keyword_comptime => {3168 Token.Id.Keyword_comptime => {
3169 const node = try arena.construct(ast.Node.Comptime{3169 const node = try arena.create(ast.Node.Comptime{
3170 .base = ast.Node{ .id = ast.Node.Id.Comptime },3170 .base = ast.Node{ .id = ast.Node.Id.Comptime },
3171 .comptime_token = token_index,3171 .comptime_token = token_index,
3172 .expr = undefined,3172 .expr = undefined,
...@@ -3178,7 +3178,7 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: *con...@@ -3178,7 +3178,7 @@ fn parseBlockExpr(stack: *std.ArrayList(State), arena: *mem.Allocator, ctx: *con
3178 return true;3178 return true;
3179 },3179 },
3180 Token.Id.LBrace => {3180 Token.Id.LBrace => {
3181 const block = try arena.construct(ast.Node.Block{3181 const block = try arena.create(ast.Node.Block{
3182 .base = ast.Node{ .id = ast.Node.Id.Block },3182 .base = ast.Node{ .id = ast.Node.Id.Block },
3183 .label = null,3183 .label = null,
3184 .lbrace = token_index,3184 .lbrace = token_index,
...@@ -3318,7 +3318,7 @@ fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.Node.PrefixOp.Op {...@@ -3318,7 +3318,7 @@ fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.Node.PrefixOp.Op {
3318}3318}
33193319
3320fn createLiteral(arena: *mem.Allocator, comptime T: type, token_index: TokenIndex) !*T {3320fn createLiteral(arena: *mem.Allocator, comptime T: type, token_index: TokenIndex) !*T {
3321 return arena.construct(T{3321 return arena.create(T{
3322 .base = ast.Node{ .id = ast.Node.typeToId(T) },3322 .base = ast.Node{ .id = ast.Node.typeToId(T) },
3323 .token = token_index,3323 .token = token_index,
3324 });3324 });
std/zig/parser_test.zig+9
...@@ -1,3 +1,12 @@...@@ -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
1test "zig fmt: comment to disable/enable zig fmt first" {10test "zig fmt: comment to disable/enable zig fmt first" {
2 try testCanonical(11 try testCanonical(
3 \\// Test trailing comma syntax12 \\// Test trailing comma syntax
test/behavior.zig+3
...@@ -13,6 +13,7 @@ comptime {...@@ -13,6 +13,7 @@ comptime {
13 _ = @import("cases/bugs/656.zig");13 _ = @import("cases/bugs/656.zig");
14 _ = @import("cases/bugs/828.zig");14 _ = @import("cases/bugs/828.zig");
15 _ = @import("cases/bugs/920.zig");15 _ = @import("cases/bugs/920.zig");
16 _ = @import("cases/bugs/1111.zig");
16 _ = @import("cases/byval_arg_var.zig");17 _ = @import("cases/byval_arg_var.zig");
17 _ = @import("cases/cast.zig");18 _ = @import("cases/cast.zig");
18 _ = @import("cases/const_slice_child.zig");19 _ = @import("cases/const_slice_child.zig");
...@@ -34,6 +35,7 @@ comptime {...@@ -34,6 +35,7 @@ comptime {
34 _ = @import("cases/math.zig");35 _ = @import("cases/math.zig");
35 _ = @import("cases/merge_error_sets.zig");36 _ = @import("cases/merge_error_sets.zig");
36 _ = @import("cases/misc.zig");37 _ = @import("cases/misc.zig");
38 _ = @import("cases/optional.zig");
37 _ = @import("cases/namespace_depends_on_compile_var/index.zig");39 _ = @import("cases/namespace_depends_on_compile_var/index.zig");
38 _ = @import("cases/new_stack_call.zig");40 _ = @import("cases/new_stack_call.zig");
39 _ = @import("cases/null.zig");41 _ = @import("cases/null.zig");
...@@ -58,4 +60,5 @@ comptime {...@@ -58,4 +60,5 @@ comptime {
58 _ = @import("cases/var_args.zig");60 _ = @import("cases/var_args.zig");
59 _ = @import("cases/void.zig");61 _ = @import("cases/void.zig");
60 _ = @import("cases/while.zig");62 _ = @import("cases/while.zig");
63 _ = @import("cases/widening.zig");
61}64}
test/cases/align.zig+1-1
...@@ -90,7 +90,7 @@ fn testBytesAlignSlice(b: u8) void {...@@ -90,7 +90,7 @@ fn testBytesAlignSlice(b: u8) void {
90 b,90 b,
91 b,91 b,
92 };92 };
93 const slice = ([]u32)(bytes[0..]);93 const slice: []u32 = @bytesToSlice(u32, bytes[0..]);
94 assert(slice[0] == 0x33333333);94 assert(slice[0] == 0x33333333);
95}95}
9696
test/cases/array.zig+8
...@@ -152,3 +152,11 @@ fn testImplicitCastSingleItemPtr() void {...@@ -152,3 +152,11 @@ fn testImplicitCastSingleItemPtr() void {
152 slice[0] += 1;152 slice[0] += 1;
153 assert(byte == 101);153 assert(byte == 101);
154}154}
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" {...@@ -140,8 +140,8 @@ test "explicit cast from integer to error type" {
140 comptime testCastIntToErr(error.ItBroke);140 comptime testCastIntToErr(error.ItBroke);
141}141}
142fn testCastIntToErr(err: error) void {142fn testCastIntToErr(err: error) void {
143 const x = usize(err);143 const x = @errorToInt(err);
144 const y = error(x);144 const y = @intToError(x);
145 assert(error.ItBroke == y);145 assert(error.ItBroke == y);
146}146}
147147
...@@ -340,11 +340,26 @@ fn testPeerErrorAndArray2(x: u8) error![]const u8 {...@@ -340,11 +340,26 @@ fn testPeerErrorAndArray2(x: u8) error![]const u8 {
340 };340 };
341}341}
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 {
344 const x = i32(1e4);349 const x = i32(1e4);
345 assert(x == 10000);350 assert(x == 10000);
346 const y = @floatToInt(i32, f32(1e4));351 const y = @floatToInt(i32, f32(1e4));
347 assert(y == 10000);352 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);
348}363}
349364
350test "cast u128 to f128 and back" {365test "cast u128 to f128 and back" {
...@@ -372,7 +387,7 @@ test "const slice widen cast" {...@@ -372,7 +387,7 @@ test "const slice widen cast" {
372 0x12,387 0x12,
373 };388 };
374389
375 const u32_value = ([]const u32)(bytes[0..])[0];390 const u32_value = @bytesToSlice(u32, bytes[0..])[0];
376 assert(u32_value == 0x12121212);391 assert(u32_value == 0x12121212);
377392
378 assert(@bitCast(u32, bytes) == 0x12121212);393 assert(@bitCast(u32, bytes) == 0x12121212);
...@@ -406,17 +421,50 @@ test "@intCast comptime_int" {...@@ -406,17 +421,50 @@ test "@intCast comptime_int" {
406}421}
407422
408test "@floatCast comptime_int and comptime_float" {423test "@floatCast comptime_int and comptime_float" {
409 const result = @floatCast(f32, 1234);424 {
410 assert(@typeOf(result) == f32);425 const result = @floatCast(f16, 1234);
411 assert(result == 1234.0);426 assert(@typeOf(result) == f16);
412427 assert(result == 1234.0);
413 const result2 = @floatCast(f32, 1234.0);428 }
414 assert(@typeOf(result) == f32);429 {
415 assert(result == 1234.0);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 }
416}444}
417445
418test "comptime_int @intToFloat" {446test "comptime_int @intToFloat" {
419 const result = @intToFloat(f32, 1234);447 {
420 assert(@typeOf(result) == f32);448 const result = @intToFloat(f16, 1234);
421 assert(result == 1234.0);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);
422}470}
test/cases/coroutines.zig+32-9
...@@ -5,7 +5,10 @@ const assert = std.debug.assert;...@@ -5,7 +5,10 @@ const assert = std.debug.assert;
5var x: i32 = 1;5var x: i32 = 1;
66
7test "create a coroutine and cancel it" {7test "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();
9 comptime assert(@typeOf(p) == promise->void);12 comptime assert(@typeOf(p) == promise->void);
10 cancel p;13 cancel p;
11 assert(x == 2);14 assert(x == 2);
...@@ -17,8 +20,11 @@ async fn simpleAsyncFn() void {...@@ -17,8 +20,11 @@ async fn simpleAsyncFn() void {
17}20}
1821
19test "coroutine suspend, resume, cancel" {22test "coroutine suspend, resume, cancel" {
23 var da = std.heap.DirectAllocator.init();
24 defer da.deinit();
25
20 seq('a');26 seq('a');
21 const p = try async<std.debug.global_allocator> testAsyncSeq();27 const p = try async<&da.allocator> testAsyncSeq();
22 seq('c');28 seq('c');
23 resume p;29 resume p;
24 seq('f');30 seq('f');
...@@ -43,7 +49,10 @@ fn seq(c: u8) void {...@@ -43,7 +49,10 @@ fn seq(c: u8) void {
43}49}
4450
45test "coroutine suspend with block" {51test "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();
47 std.debug.assert(!result);56 std.debug.assert(!result);
48 resume a_promise;57 resume a_promise;
49 std.debug.assert(result);58 std.debug.assert(result);
...@@ -64,8 +73,11 @@ var await_a_promise: promise = undefined;...@@ -64,8 +73,11 @@ var await_a_promise: promise = undefined;
64var await_final_result: i32 = 0;73var await_final_result: i32 = 0;
6574
66test "coroutine await" {75test "coroutine await" {
76 var da = std.heap.DirectAllocator.init();
77 defer da.deinit();
78
67 await_seq('a');79 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;
69 await_seq('f');81 await_seq('f');
70 resume await_a_promise;82 resume await_a_promise;
71 await_seq('i');83 await_seq('i');
...@@ -100,8 +112,11 @@ fn await_seq(c: u8) void {...@@ -100,8 +112,11 @@ fn await_seq(c: u8) void {
100var early_final_result: i32 = 0;112var early_final_result: i32 = 0;
101113
102test "coroutine await early return" {114test "coroutine await early return" {
115 var da = std.heap.DirectAllocator.init();
116 defer da.deinit();
117
103 early_seq('a');118 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;
105 early_seq('f');120 early_seq('f');
106 assert(early_final_result == 1234);121 assert(early_final_result == 1234);
107 assert(std.mem.eql(u8, early_points, "abcdef"));122 assert(std.mem.eql(u8, early_points, "abcdef"));
...@@ -146,7 +161,9 @@ test "async function with dot syntax" {...@@ -146,7 +161,9 @@ test "async function with dot syntax" {
146 suspend;161 suspend;
147 }162 }
148 };163 };
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();
150 cancel p;167 cancel p;
151 assert(S.y == 2);168 assert(S.y == 2);
152}169}
...@@ -157,7 +174,9 @@ test "async fn pointer in a struct field" {...@@ -157,7 +174,9 @@ test "async fn pointer in a struct field" {
157 bar: async<*std.mem.Allocator> fn (*i32) void,174 bar: async<*std.mem.Allocator> fn (*i32) void,
158 };175 };
159 var foo = Foo{ .bar = simpleAsyncFn2 };176 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;
161 assert(data == 2);180 assert(data == 2);
162 cancel p;181 cancel p;
163 assert(data == 4);182 assert(data == 4);
...@@ -169,7 +188,9 @@ async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void {...@@ -169,7 +188,9 @@ async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void {
169}188}
170189
171test "async fn with inferred error set" {190test "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;
173 resume p;194 resume p;
174 cancel p;195 cancel p;
175}196}
...@@ -181,7 +202,9 @@ async fn failing() !void {...@@ -181,7 +202,9 @@ async fn failing() !void {
181test "error return trace across suspend points - early return" {202test "error return trace across suspend points - early return" {
182 const p = nonFailing();203 const p = nonFailing();
183 resume p;204 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);
185 cancel p2;208 cancel p2;
186}209}
187210
test/cases/enum.zig+8-8
...@@ -92,14 +92,14 @@ test "enum to int" {...@@ -92,14 +92,14 @@ test "enum to int" {
92}92}
9393
94fn shouldEqual(n: Number, expected: u3) void {94fn shouldEqual(n: Number, expected: u3) void {
95 assert(u3(n) == expected);95 assert(@enumToInt(n) == expected);
96}96}
9797
98test "int to enum" {98test "int to enum" {
99 testIntToEnumEval(3);99 testIntToEnumEval(3);
100}100}
101fn testIntToEnumEval(x: i32) void {101fn testIntToEnumEval(x: i32) void {
102 assert(IntToEnumNumber(@intCast(u3, x)) == IntToEnumNumber.Three);102 assert(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three);
103}103}
104const IntToEnumNumber = enum {104const IntToEnumNumber = enum {
105 Zero,105 Zero,
...@@ -768,7 +768,7 @@ test "casting enum to its tag type" {...@@ -768,7 +768,7 @@ test "casting enum to its tag type" {
768}768}
769769
770fn testCastEnumToTagType(value: Small2) void {770fn testCastEnumToTagType(value: Small2) void {
771 assert(u2(value) == 1);771 assert(@enumToInt(value) == 1);
772}772}
773773
774const MultipleChoice = enum(u32) {774const MultipleChoice = enum(u32) {
...@@ -784,7 +784,7 @@ test "enum with specified tag values" {...@@ -784,7 +784,7 @@ test "enum with specified tag values" {
784}784}
785785
786fn testEnumWithSpecifiedTagValues(x: MultipleChoice) void {786fn testEnumWithSpecifiedTagValues(x: MultipleChoice) void {
787 assert(u32(x) == 60);787 assert(@enumToInt(x) == 60);
788 assert(1234 == switch (x) {788 assert(1234 == switch (x) {
789 MultipleChoice.A => 1,789 MultipleChoice.A => 1,
790 MultipleChoice.B => 2,790 MultipleChoice.B => 2,
...@@ -811,7 +811,7 @@ test "enum with specified and unspecified tag values" {...@@ -811,7 +811,7 @@ test "enum with specified and unspecified tag values" {
811}811}
812812
813fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {813fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
814 assert(u32(x) == 1000);814 assert(@enumToInt(x) == 1000);
815 assert(1234 == switch (x) {815 assert(1234 == switch (x) {
816 MultipleChoice2.A => 1,816 MultipleChoice2.A => 1,
817 MultipleChoice2.B => 2,817 MultipleChoice2.B => 2,
...@@ -826,8 +826,8 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {...@@ -826,8 +826,8 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
826}826}
827827
828test "cast integer literal to enum" {828test "cast integer literal to enum" {
829 assert(MultipleChoice2(0) == MultipleChoice2.Unspecified1);829 assert(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1);
830 assert(MultipleChoice2(40) == MultipleChoice2.B);830 assert(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B);
831}831}
832832
833const EnumWithOneMember = enum {833const EnumWithOneMember = enum {
...@@ -865,7 +865,7 @@ const EnumWithTagValues = enum(u4) {...@@ -865,7 +865,7 @@ const EnumWithTagValues = enum(u4) {
865 D = 1 << 3,865 D = 1 << 3,
866};866};
867test "enum with tag values don't require parens" {867test "enum with tag values don't require parens" {
868 assert(u4(EnumWithTagValues.C) == 0b0100);868 assert(@enumToInt(EnumWithTagValues.C) == 0b0100);
869}869}
870870
871test "enum with 1 field but explicit tag type should still have the tag type" {871test "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" {...@@ -31,8 +31,8 @@ test "@errorName" {
31}31}
3232
33test "error values" {33test "error values" {
34 const a = i32(error.err1);34 const a = @errorToInt(error.err1);
35 const b = i32(error.err2);35 const b = @errorToInt(error.err2);
36 assert(a != b);36 assert(a != b);
37}37}
3838
...@@ -124,8 +124,8 @@ const Set2 = error{...@@ -124,8 +124,8 @@ const Set2 = error{
124};124};
125125
126fn testExplicitErrorSetCast(set1: Set1) void {126fn testExplicitErrorSetCast(set1: Set1) void {
127 var x = Set2(set1);127 var x = @errSetCast(Set2, set1);
128 var y = Set1(x);128 var y = @errSetCast(Set1, x);
129 assert(y == error.A);129 assert(y == error.A);
130}130}
131131
...@@ -147,14 +147,14 @@ test "syntax: optional operator in front of error union operator" {...@@ -147,14 +147,14 @@ test "syntax: optional operator in front of error union operator" {
147}147}
148148
149test "comptime err to int of error set with only 1 possible value" {149test "comptime err to int of error set with only 1 possible value" {
150 testErrToIntWithOnePossibleValue(error.A, u32(error.A));150 testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));
151 comptime testErrToIntWithOnePossibleValue(error.A, u32(error.A));151 comptime testErrToIntWithOnePossibleValue(error.A, @errorToInt(error.A));
152}152}
153fn testErrToIntWithOnePossibleValue(153fn testErrToIntWithOnePossibleValue(
154 x: error{A},154 x: error{A},
155 comptime value: u32,155 comptime value: u32,
156) void {156) void {
157 if (u32(x) != value) {157 if (@errorToInt(x) != value) {
158 @compileError("bad");158 @compileError("bad");
159 }159 }
160}160}
test/cases/eval.zig+19
...@@ -623,3 +623,22 @@ test "function which returns struct with type field causes implicit comptime" {...@@ -623,3 +623,22 @@ test "function which returns struct with type field causes implicit comptime" {
623 const ty = wrap(i32).T;623 const ty = wrap(i32).T;
624 assert(ty == i32);624 assert(ty == i32);
625}625}
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" {...@@ -6,15 +6,20 @@ test "division" {
6}6}
7fn testDivision() void {7fn testDivision() void {
8 assert(div(u32, 13, 3) == 4);8 assert(div(u32, 13, 3) == 4);
9 assert(div(f16, 1.0, 2.0) == 0.5);
9 assert(div(f32, 1.0, 2.0) == 0.5);10 assert(div(f32, 1.0, 2.0) == 0.5);
1011
11 assert(divExact(u32, 55, 11) == 5);12 assert(divExact(u32, 55, 11) == 5);
12 assert(divExact(i32, -55, 11) == -5);13 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);
13 assert(divExact(f32, 55.0, 11.0) == 5.0);16 assert(divExact(f32, 55.0, 11.0) == 5.0);
14 assert(divExact(f32, -55.0, 11.0) == -5.0);17 assert(divExact(f32, -55.0, 11.0) == -5.0);
1518
16 assert(divFloor(i32, 5, 3) == 1);19 assert(divFloor(i32, 5, 3) == 1);
17 assert(divFloor(i32, -5, 3) == -2);20 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);
18 assert(divFloor(f32, 5.0, 3.0) == 1.0);23 assert(divFloor(f32, 5.0, 3.0) == 1.0);
19 assert(divFloor(f32, -5.0, 3.0) == -2.0);24 assert(divFloor(f32, -5.0, 3.0) == -2.0);
20 assert(divFloor(i32, -0x80000000, -2) == 0x40000000);25 assert(divFloor(i32, -0x80000000, -2) == 0x40000000);
...@@ -24,8 +29,12 @@ fn testDivision() void {...@@ -24,8 +29,12 @@ fn testDivision() void {
2429
25 assert(divTrunc(i32, 5, 3) == 1);30 assert(divTrunc(i32, 5, 3) == 1);
26 assert(divTrunc(i32, -5, 3) == -1);31 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);
27 assert(divTrunc(f32, 5.0, 3.0) == 1.0);34 assert(divTrunc(f32, 5.0, 3.0) == 1.0);
28 assert(divTrunc(f32, -5.0, 3.0) == -1.0);35 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
30 comptime {39 comptime {
31 assert(40 assert(
...@@ -287,6 +296,14 @@ test "quad hex float literal parsing in range" {...@@ -287,6 +296,14 @@ test "quad hex float literal parsing in range" {
287 const d = 0x1.edcbff8ad76ab5bf46463233214fp-435;296 const d = 0x1.edcbff8ad76ab5bf46463233214fp-435;
288}297}
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
290test "hex float literal within range" {307test "hex float literal within range" {
291 const a = 0x1.0p16383;308 const a = 0x1.0p16383;
292 const b = 0x0.1p16387;309 const b = 0x0.1p16387;
...@@ -434,11 +451,28 @@ test "comptime float rem int" {...@@ -434,11 +451,28 @@ test "comptime float rem int" {
434 }451 }
435}452}
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
437test "@sqrt" {469test "@sqrt" {
438 testSqrt(f64, 12.0);470 testSqrt(f64, 12.0);
439 comptime testSqrt(f64, 12.0);471 comptime testSqrt(f64, 12.0);
440 testSqrt(f32, 13.0);472 testSqrt(f32, 13.0);
441 comptime testSqrt(f32, 13.0);473 comptime testSqrt(f32, 13.0);
474 testSqrt(f16, 13.0);
475 comptime testSqrt(f16, 13.0);
442476
443 const x = 14.0;477 const x = 14.0;
444 const y = x * x;478 const y = x * x;
test/cases/misc.zig+8-2
...@@ -53,6 +53,7 @@ test "@IntType builtin" {...@@ -53,6 +53,7 @@ test "@IntType builtin" {
53}53}
5454
55test "floating point primitive bit counts" {55test "floating point primitive bit counts" {
56 assert(f16.bit_count == 16);
56 assert(f32.bit_count == 32);57 assert(f32.bit_count == 32);
57 assert(f64.bit_count == 64);58 assert(f64.bit_count == 64);
58}59}
...@@ -422,14 +423,14 @@ test "cast slice to u8 slice" {...@@ -422,14 +423,14 @@ test "cast slice to u8 slice" {
422 4,423 4,
423 };424 };
424 const big_thing_slice: []i32 = big_thing_array[0..];425 const big_thing_slice: []i32 = big_thing_array[0..];
425 const bytes = ([]u8)(big_thing_slice);426 const bytes = @sliceToBytes(big_thing_slice);
426 assert(bytes.len == 4 * 4);427 assert(bytes.len == 4 * 4);
427 bytes[4] = 0;428 bytes[4] = 0;
428 bytes[5] = 0;429 bytes[5] = 0;
429 bytes[6] = 0;430 bytes[6] = 0;
430 bytes[7] = 0;431 bytes[7] = 0;
431 assert(big_thing_slice[1] == 0);432 assert(big_thing_slice[1] == 0);
432 const big_thing_again = ([]align(1) i32)(bytes);433 const big_thing_again = @bytesToSlice(i32, bytes);
433 assert(big_thing_again[2] == 3);434 assert(big_thing_again[2] == 3);
434 big_thing_again[2] = -1;435 big_thing_again[2] = -1;
435 assert(bytes[8] == @maxValue(u8));436 assert(bytes[8] == @maxValue(u8));
...@@ -701,3 +702,8 @@ test "comptime cast fn to ptr" {...@@ -701,3 +702,8 @@ test "comptime cast fn to ptr" {
701 const addr2 = @ptrCast(*const u8, emptyFn);702 const addr2 = @ptrCast(*const u8, emptyFn);
702 comptime assert(addr1 == addr2);703 comptime assert(addr1 == addr2);
703}704}
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" {...@@ -146,7 +146,7 @@ test "null with default unwrap" {
146146
147test "optional types" {147test "optional types" {
148 comptime {148 comptime {
149 const opt_type_struct = StructWithOptionalType { .t=u8, };149 const opt_type_struct = StructWithOptionalType{ .t = u8 };
150 assert(opt_type_struct.t != null and opt_type_struct.t.? == u8);150 assert(opt_type_struct.t != null and opt_type_struct.t.? == u8);
151 }151 }
152}152}
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" {...@@ -302,7 +302,7 @@ test "packed array 24bits" {
302302
303 var bytes = []u8{0} ** (@sizeOf(FooArray24Bits) + 1);303 var bytes = []u8{0} ** (@sizeOf(FooArray24Bits) + 1);
304 bytes[bytes.len - 1] = 0xaa;304 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];
306 assert(ptr.a == 0);306 assert(ptr.a == 0);
307 assert(ptr.b[0].field == 0);307 assert(ptr.b[0].field == 0);
308 assert(ptr.b[1].field == 0);308 assert(ptr.b[1].field == 0);
...@@ -351,7 +351,7 @@ test "aligned array of packed struct" {...@@ -351,7 +351,7 @@ test "aligned array of packed struct" {
351 }351 }
352352
353 var bytes = []u8{0xbb} ** @sizeOf(FooArrayOfAligned);353 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
356 assert(ptr.a[0].a == 0xbb);356 assert(ptr.a[0].a == 0xbb);
357 assert(ptr.a[0].b == 0xbb);357 assert(ptr.a[0].b == 0xbb);
test/cases/type_info.zig+9-9
...@@ -107,11 +107,11 @@ test "type info: promise info" {...@@ -107,11 +107,11 @@ test "type info: promise info" {
107fn testPromise() void {107fn testPromise() void {
108 const null_promise_info = @typeInfo(promise);108 const null_promise_info = @typeInfo(promise);
109 assert(TypeId(null_promise_info) == TypeId.Promise);109 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
112 const promise_info = @typeInfo(promise->usize);112 const promise_info = @typeInfo(promise->usize);
113 assert(TypeId(promise_info) == TypeId.Promise);113 assert(TypeId(promise_info) == TypeId.Promise);
114 assert(promise_info.Promise.child == usize);114 assert(promise_info.Promise.child.? == usize);
115}115}
116116
117test "type info: error set, error union info" {117test "type info: error set, error union info" {
...@@ -130,7 +130,7 @@ fn testErrorSet() void {...@@ -130,7 +130,7 @@ fn testErrorSet() void {
130 assert(TypeId(error_set_info) == TypeId.ErrorSet);130 assert(TypeId(error_set_info) == TypeId.ErrorSet);
131 assert(error_set_info.ErrorSet.errors.len == 3);131 assert(error_set_info.ErrorSet.errors.len == 3);
132 assert(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First"));132 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
135 const error_union_info = @typeInfo(TestErrorSet!usize);135 const error_union_info = @typeInfo(TestErrorSet!usize);
136 assert(TypeId(error_union_info) == TypeId.ErrorUnion);136 assert(TypeId(error_union_info) == TypeId.ErrorUnion);
...@@ -165,7 +165,7 @@ fn testUnion() void {...@@ -165,7 +165,7 @@ fn testUnion() void {
165 const typeinfo_info = @typeInfo(TypeInfo);165 const typeinfo_info = @typeInfo(TypeInfo);
166 assert(TypeId(typeinfo_info) == TypeId.Union);166 assert(TypeId(typeinfo_info) == TypeId.Union);
167 assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);167 assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
168 assert(typeinfo_info.Union.tag_type == TypeId);168 assert(typeinfo_info.Union.tag_type.? == TypeId);
169 assert(typeinfo_info.Union.fields.len == 25);169 assert(typeinfo_info.Union.fields.len == 25);
170 assert(typeinfo_info.Union.fields[4].enum_field != null);170 assert(typeinfo_info.Union.fields[4].enum_field != null);
171 assert(typeinfo_info.Union.fields[4].enum_field.?.value == 4);171 assert(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
...@@ -179,7 +179,7 @@ fn testUnion() void {...@@ -179,7 +179,7 @@ fn testUnion() void {
179179
180 const notag_union_info = @typeInfo(TestNoTagUnion);180 const notag_union_info = @typeInfo(TestNoTagUnion);
181 assert(TypeId(notag_union_info) == TypeId.Union);181 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);
183 assert(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto);183 assert(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto);
184 assert(notag_union_info.Union.fields.len == 2);184 assert(notag_union_info.Union.fields.len == 2);
185 assert(notag_union_info.Union.fields[0].enum_field == null);185 assert(notag_union_info.Union.fields[0].enum_field == null);
...@@ -191,7 +191,7 @@ fn testUnion() void {...@@ -191,7 +191,7 @@ fn testUnion() void {
191191
192 const extern_union_info = @typeInfo(TestExternUnion);192 const extern_union_info = @typeInfo(TestExternUnion);
193 assert(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern);193 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);
195 assert(extern_union_info.Union.fields[0].enum_field == null);195 assert(extern_union_info.Union.fields[0].enum_field == null);
196 assert(extern_union_info.Union.fields[0].field_type == *c_void);196 assert(extern_union_info.Union.fields[0].field_type == *c_void);
197}197}
...@@ -238,13 +238,13 @@ fn testFunction() void {...@@ -238,13 +238,13 @@ fn testFunction() void {
238 assert(fn_info.Fn.is_generic);238 assert(fn_info.Fn.is_generic);
239 assert(fn_info.Fn.args.len == 2);239 assert(fn_info.Fn.args.len == 2);
240 assert(fn_info.Fn.is_var_args);240 assert(fn_info.Fn.is_var_args);
241 assert(fn_info.Fn.return_type == @typeOf(undefined));241 assert(fn_info.Fn.return_type == null);
242 assert(fn_info.Fn.async_allocator_type == @typeOf(undefined));242 assert(fn_info.Fn.async_allocator_type == null);
243243
244 const test_instance: TestStruct = undefined;244 const test_instance: TestStruct = undefined;
245 const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));245 const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));
246 assert(TypeId(bound_fn_info) == TypeId.BoundFn);246 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);
248}248}
249249
250fn foo(comptime a: usize, b: bool, args: ...) usize {250fn foo(comptime a: usize, b: bool, args: ...) usize {
test/cases/union.zig+2-2
...@@ -126,7 +126,7 @@ const MultipleChoice = union(enum(u32)) {...@@ -126,7 +126,7 @@ const MultipleChoice = union(enum(u32)) {
126test "simple union(enum(u32))" {126test "simple union(enum(u32))" {
127 var x = MultipleChoice.C;127 var x = MultipleChoice.C;
128 assert(x == MultipleChoice.C);128 assert(x == MultipleChoice.C);
129 assert(u32(@TagType(MultipleChoice)(x)) == 60);129 assert(@enumToInt(@TagType(MultipleChoice)(x)) == 60);
130}130}
131131
132const MultipleChoice2 = union(enum(u32)) {132const MultipleChoice2 = union(enum(u32)) {
...@@ -148,7 +148,7 @@ test "union(enum(u32)) with specified and unspecified tag values" {...@@ -148,7 +148,7 @@ test "union(enum(u32)) with specified and unspecified tag values" {
148}148}
149149
150fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: *const MultipleChoice2) void {150fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: *const MultipleChoice2) void {
151 assert(u32(@TagType(MultipleChoice2)(x.*)) == 60);151 assert(@enumToInt(@TagType(MultipleChoice2)(x.*)) == 60);
152 assert(1123 == switch (x.*) {152 assert(1123 == switch (x.*) {
153 MultipleChoice2.A => 1,153 MultipleChoice2.A => 1,
154 MultipleChoice2.B => 2,154 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 @@...@@ -1,6 +1,36 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: *tests.CompileErrorContext) void {3pub 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
4 cases.add(34 cases.add(
5 "use c_void as return type of fn ptr",35 "use c_void as return type of fn ptr",
6 \\export fn entry() void {36 \\export fn entry() void {
...@@ -83,7 +113,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -83,7 +113,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
83 \\ var rule_set = try Foo.init();113 \\ var rule_set = try Foo.init();
84 \\}114 \\}
85 ,115 ,
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'",
87 );117 );
88118
89 cases.add(119 cases.add(
...@@ -105,7 +135,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -105,7 +135,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
105 );135 );
106136
107 cases.add(137 cases.add(
108 "invalid deref on switch target",138 "nested error set mismatch",
109 \\const NextError = error{NextError};139 \\const NextError = error{NextError};
110 \\const OtherError = error{OutOfMemory};140 \\const OtherError = error{OutOfMemory};
111 \\141 \\
...@@ -117,7 +147,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -117,7 +147,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
117 \\ return null;147 \\ return null;
118 \\}148 \\}
119 ,149 ,
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'",
121 ".tmp_source.zig:2:26: note: 'error.OutOfMemory' not a member of destination error set",153 ".tmp_source.zig:2:26: note: 'error.OutOfMemory' not a member of destination error set",
122 );154 );
123155
...@@ -404,10 +436,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -404,10 +436,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
404 \\const Set2 = error {A, C};436 \\const Set2 = error {A, C};
405 \\comptime {437 \\comptime {
406 \\ var x = Set1.B;438 \\ var x = Set1.B;
407 \\ var y = Set2(x);439 \\ var y = @errSetCast(Set2, x);
408 \\}440 \\}
409 ,441 ,
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'",
411 );443 );
412444
413 cases.add(445 cases.add(
...@@ -420,8 +452,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -420,8 +452,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
420 \\ return error.B;452 \\ return error.B;
421 \\}453 \\}
422 ,454 ,
423 ".tmp_source.zig:3:35: error: expected 'SmallErrorSet!i32', found 'error!i32'",455 ".tmp_source.zig:3:35: error: expected type 'SmallErrorSet!i32', found 'error!i32'",
424 ".tmp_source.zig:3:35: note: unable to cast global error set into smaller set",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",
425 );458 );
426459
427 cases.add(460 cases.add(
...@@ -434,8 +467,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -434,8 +467,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
434 \\ return error.B;467 \\ return error.B;
435 \\}468 \\}
436 ,469 ,
437 ".tmp_source.zig:3:31: error: expected 'SmallErrorSet', found 'error'",470 ".tmp_source.zig:3:31: error: expected type 'SmallErrorSet', found 'error'",
438 ".tmp_source.zig:3:31: note: unable to cast global error set into smaller set",471 ".tmp_source.zig:3:31: note: cannot cast global error set into smaller set",
439 );472 );
440473
441 cases.add(474 cases.add(
...@@ -461,31 +494,40 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -461,31 +494,40 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
461 \\ var x: Set2 = set1;494 \\ var x: Set2 = set1;
462 \\}495 \\}
463 ,496 ,
464 ".tmp_source.zig:7:19: error: expected 'Set2', found 'Set1'",497 ".tmp_source.zig:7:19: error: expected type 'Set2', found 'Set1'",
465 ".tmp_source.zig:1:23: note: 'error.B' not a member of destination error set",498 ".tmp_source.zig:1:23: note: 'error.B' not a member of destination error set",
466 );499 );
467500
468 cases.add(501 cases.add(
469 "int to err global invalid number",502 "int to err global invalid number",
470 \\const Set1 = error{A, B};503 \\const Set1 = error{
504 \\ A,
505 \\ B,
506 \\};
471 \\comptime {507 \\comptime {
472 \\ var x: usize = 3;508 \\ var x: u16 = 3;
473 \\ var y = error(x);509 \\ var y = @intToError(x);
474 \\}510 \\}
475 ,511 ,
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",
477 );513 );
478514
479 cases.add(515 cases.add(
480 "int to err non global invalid number",516 "int to err non global invalid number",
481 \\const Set1 = error{A, B};517 \\const Set1 = error{
482 \\const Set2 = error{A, C};518 \\ A,
519 \\ B,
520 \\};
521 \\const Set2 = error{
522 \\ A,
523 \\ C,
524 \\};
483 \\comptime {525 \\comptime {
484 \\ var x = usize(Set1.B);526 \\ var x = @errorToInt(Set1.B);
485 \\ var y = Set2(x);527 \\ var y = @errSetCast(Set2, @intToError(x));
486 \\}528 \\}
487 ,529 ,
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'",
489 );531 );
490532
491 cases.add(533 cases.add(
...@@ -1635,6 +1677,18 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1635,6 +1677,18 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1635 ".tmp_source.zig:1:16: error: integer value 300 cannot be implicitly casted to type 'u8'",1677 ".tmp_source.zig:1:16: error: integer value 300 cannot be implicitly casted to type 'u8'",
1636 );1678 );
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
1638 cases.add(1692 cases.add(
1639 "incompatible number literals",1693 "incompatible number literals",
1640 \\const x = 2 == 2.0;1694 \\const x = 2 == 2.0;
...@@ -1851,6 +1905,416 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1851,6 +1905,416 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1851 ".tmp_source.zig:1:15: error: use of undefined value",1905 ".tmp_source.zig:1:15: error: use of undefined value",
1852 );1906 );
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
1854 cases.add(2318 cases.add(
1855 "endless loop in function evaluation",2319 "endless loop in function evaluation",
1856 \\const seventh_fib_number = fibbonaci(7);2320 \\const seventh_fib_number = fibbonaci(7);
...@@ -2086,10 +2550,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2086,10 +2550,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2086 "convert fixed size array to slice with invalid size",2550 "convert fixed size array to slice with invalid size",
2087 \\export fn f() void {2551 \\export fn f() void {
2088 \\ var array: [5]u8 = undefined;2552 \\ var array: [5]u8 = undefined;
2089 \\ var foo = ([]const u32)(array)[0];2553 \\ var foo = @bytesToSlice(u32, array)[0];
2090 \\}2554 \\}
2091 ,2555 ,
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",
2093 );2558 );
20942559
2095 cases.add(2560 cases.add(
...@@ -2611,17 +3076,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2611,17 +3076,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2611 ".tmp_source.zig:2:21: error: expected pointer, found 'usize'",3076 ".tmp_source.zig:2:21: error: expected pointer, found 'usize'",
2612 );3077 );
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
2625 cases.add(3079 cases.add(
2626 "asm at compile time",3080 "asm at compile time",
2627 \\comptime {3081 \\comptime {
...@@ -3239,18 +3693,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3239,18 +3693,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3239 ".tmp_source.zig:3:26: note: '*u32' has alignment 4",3693 ".tmp_source.zig:3:26: note: '*u32' has alignment 4",
3240 );3694 );
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
3254 cases.add(3696 cases.add(
3255 "@alignCast expects pointer or slice",3697 "@alignCast expects pointer or slice",
3256 \\export fn entry() void {3698 \\export fn entry() void {
...@@ -3722,22 +4164,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3722,22 +4164,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3722 ".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'",4164 ".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'",
3723 );4165 );
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
3741 cases.add(4167 cases.add(
3742 "explicitly casting non tag type to enum",4168 "explicitly casting non tag type to enum",
3743 \\const Small = enum(u2) {4169 \\const Small = enum(u2) {
...@@ -3749,10 +4175,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3749,10 +4175,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3749 \\4175 \\
3750 \\export fn entry() void {4176 \\export fn entry() void {
3751 \\ var y = u3(3);4177 \\ var y = u3(3);
3752 \\ var x = Small(y);4178 \\ var x = @intToEnum(Small, y);
3753 \\}4179 \\}
3754 ,4180 ,
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'",
3756 );4182 );
37574183
3758 cases.add(4184 cases.add(
...@@ -4033,10 +4459,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -4033,10 +4459,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
4033 \\ B = 11,4459 \\ B = 11,
4034 \\};4460 \\};
4035 \\export fn entry() void {4461 \\export fn entry() void {
4036 \\ var x = Foo(0);4462 \\ var x = @intToEnum(Foo, 0);
4037 \\}4463 \\}
4038 ,4464 ,
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",
4040 ".tmp_source.zig:1:13: note: 'Foo' declared here",4466 ".tmp_source.zig:1:13: note: 'Foo' declared here",
4041 );4467 );
40424468
test/runtime_safety.zig+64-7
...@@ -1,6 +1,63 @@...@@ -1,6 +1,63 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: *tests.CompareOutputContext) void {3pub 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
4 cases.addRuntimeSafety("calling panic",61 cases.addRuntimeSafety("calling panic",
5 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {62 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
6 \\ @import("std").os.exit(126);63 \\ @import("std").os.exit(126);
...@@ -175,7 +232,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -175,7 +232,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
175 \\ if (x.len == 0) return error.Whatever;232 \\ if (x.len == 0) return error.Whatever;
176 \\}233 \\}
177 \\fn widenSlice(slice: []align(1) const u8) []align(1) const i32 {234 \\fn widenSlice(slice: []align(1) const u8) []align(1) const i32 {
178 \\ return ([]align(1) const i32)(slice);235 \\ return @bytesToSlice(i32, slice);
179 \\}236 \\}
180 );237 );
181238
...@@ -227,12 +284,12 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -227,12 +284,12 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
227 \\pub fn main() void {284 \\pub fn main() void {
228 \\ _ = bar(9999);285 \\ _ = bar(9999);
229 \\}286 \\}
230 \\fn bar(x: u32) error {287 \\fn bar(x: u16) error {
231 \\ return error(x);288 \\ return @intToError(x);
232 \\}289 \\}
233 );290 );
234291
235 cases.addRuntimeSafety("cast integer to non-global error set and no match",292 cases.addRuntimeSafety("@errSetCast error not present in destination",
236 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {293 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
237 \\ @import("std").os.exit(126);294 \\ @import("std").os.exit(126);
238 \\}295 \\}
...@@ -242,7 +299,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -242,7 +299,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
242 \\ _ = foo(Set1.B);299 \\ _ = foo(Set1.B);
243 \\}300 \\}
244 \\fn foo(set1: Set1) Set2 {301 \\fn foo(set1: Set1) Set2 {
245 \\ return Set2(set1);302 \\ return @errSetCast(Set2, set1);
246 \\}303 \\}
247 );304 );
248305
...@@ -252,12 +309,12 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -252,12 +309,12 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
252 \\}309 \\}
253 \\pub fn main() !void {310 \\pub fn main() !void {
254 \\ var array align(4) = []u32{0x11111111, 0x11111111};311 \\ var array align(4) = []u32{0x11111111, 0x11111111};
255 \\ const bytes = ([]u8)(array[0..]);312 \\ const bytes = @sliceToBytes(array[0..]);
256 \\ if (foo(bytes) != 0x11111111) return error.Wrong;313 \\ if (foo(bytes) != 0x11111111) return error.Wrong;
257 \\}314 \\}
258 \\fn foo(bytes: []u8) u32 {315 \\fn foo(bytes: []u8) u32 {
259 \\ const slice4 = bytes[1..5];316 \\ const slice4 = bytes[1..5];
260 \\ const int_slice = ([]u32)(@alignCast(4, slice4));317 \\ const int_slice = @bytesToSlice(u32, @alignCast(4, slice4));
261 \\ return int_slice[0];318 \\ return int_slice[0];
262 \\}319 \\}
263 );320 );
test/tests.zig+37-45
...@@ -48,13 +48,12 @@ const test_targets = []TestTarget{...@@ -48,13 +48,12 @@ const test_targets = []TestTarget{
48const max_stdout_size = 1 * 1024 * 1024; // 1 MB48const max_stdout_size = 1 * 1024 * 1024; // 1 MB
4949
50pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {50pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
51 const cases = b.allocator.create(CompareOutputContext) catch unreachable;51 const cases = b.allocator.create(CompareOutputContext{
52 cases.* = CompareOutputContext{
53 .b = b,52 .b = b,
54 .step = b.step("test-compare-output", "Run the compare output tests"),53 .step = b.step("test-compare-output", "Run the compare output tests"),
55 .test_index = 0,54 .test_index = 0,
56 .test_filter = test_filter,55 .test_filter = test_filter,
57 };56 }) catch unreachable;
5857
59 compare_output.addCases(cases);58 compare_output.addCases(cases);
6059
...@@ -62,13 +61,12 @@ pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8) *build...@@ -62,13 +61,12 @@ pub fn addCompareOutputTests(b: *build.Builder, test_filter: ?[]const u8) *build
62}61}
6362
64pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {63pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
65 const cases = b.allocator.create(CompareOutputContext) catch unreachable;64 const cases = b.allocator.create(CompareOutputContext{
66 cases.* = CompareOutputContext{
67 .b = b,65 .b = b,
68 .step = b.step("test-runtime-safety", "Run the runtime safety tests"),66 .step = b.step("test-runtime-safety", "Run the runtime safety tests"),
69 .test_index = 0,67 .test_index = 0,
70 .test_filter = test_filter,68 .test_filter = test_filter,
71 };69 }) catch unreachable;
7270
73 runtime_safety.addCases(cases);71 runtime_safety.addCases(cases);
7472
...@@ -76,13 +74,12 @@ pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8) *build...@@ -76,13 +74,12 @@ pub fn addRuntimeSafetyTests(b: *build.Builder, test_filter: ?[]const u8) *build
76}74}
7775
78pub fn addCompileErrorTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {76pub fn addCompileErrorTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
79 const cases = b.allocator.create(CompileErrorContext) catch unreachable;77 const cases = b.allocator.create(CompileErrorContext{
80 cases.* = CompileErrorContext{
81 .b = b,78 .b = b,
82 .step = b.step("test-compile-errors", "Run the compile error tests"),79 .step = b.step("test-compile-errors", "Run the compile error tests"),
83 .test_index = 0,80 .test_index = 0,
84 .test_filter = test_filter,81 .test_filter = test_filter,
85 };82 }) catch unreachable;
8683
87 compile_errors.addCases(cases);84 compile_errors.addCases(cases);
8885
...@@ -90,13 +87,12 @@ pub fn addCompileErrorTests(b: *build.Builder, test_filter: ?[]const u8) *build....@@ -90,13 +87,12 @@ pub fn addCompileErrorTests(b: *build.Builder, test_filter: ?[]const u8) *build.
90}87}
9188
92pub fn addBuildExampleTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {89pub fn addBuildExampleTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
93 const cases = b.allocator.create(BuildExamplesContext) catch unreachable;90 const cases = b.allocator.create(BuildExamplesContext{
94 cases.* = BuildExamplesContext{
95 .b = b,91 .b = b,
96 .step = b.step("test-build-examples", "Build the examples"),92 .step = b.step("test-build-examples", "Build the examples"),
97 .test_index = 0,93 .test_index = 0,
98 .test_filter = test_filter,94 .test_filter = test_filter,
99 };95 }) catch unreachable;
10096
101 build_examples.addCases(cases);97 build_examples.addCases(cases);
10298
...@@ -104,13 +100,12 @@ pub fn addBuildExampleTests(b: *build.Builder, test_filter: ?[]const u8) *build....@@ -104,13 +100,12 @@ pub fn addBuildExampleTests(b: *build.Builder, test_filter: ?[]const u8) *build.
104}100}
105101
106pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {102pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
107 const cases = b.allocator.create(CompareOutputContext) catch unreachable;103 const cases = b.allocator.create(CompareOutputContext{
108 cases.* = CompareOutputContext{
109 .b = b,104 .b = b,
110 .step = b.step("test-asm-link", "Run the assemble and link tests"),105 .step = b.step("test-asm-link", "Run the assemble and link tests"),
111 .test_index = 0,106 .test_index = 0,
112 .test_filter = test_filter,107 .test_filter = test_filter,
113 };108 }) catch unreachable;
114109
115 assemble_and_link.addCases(cases);110 assemble_and_link.addCases(cases);
116111
...@@ -118,13 +113,12 @@ pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8) *bui...@@ -118,13 +113,12 @@ pub fn addAssembleAndLinkTests(b: *build.Builder, test_filter: ?[]const u8) *bui
118}113}
119114
120pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {115pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
121 const cases = b.allocator.create(TranslateCContext) catch unreachable;116 const cases = b.allocator.create(TranslateCContext{
122 cases.* = TranslateCContext{
123 .b = b,117 .b = b,
124 .step = b.step("test-translate-c", "Run the C transation tests"),118 .step = b.step("test-translate-c", "Run the C transation tests"),
125 .test_index = 0,119 .test_index = 0,
126 .test_filter = test_filter,120 .test_filter = test_filter,
127 };121 }) catch unreachable;
128122
129 translate_c.addCases(cases);123 translate_c.addCases(cases);
130124
...@@ -132,13 +126,12 @@ pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.St...@@ -132,13 +126,12 @@ pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.St
132}126}
133127
134pub fn addGenHTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {128pub fn addGenHTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
135 const cases = b.allocator.create(GenHContext) catch unreachable;129 const cases = b.allocator.create(GenHContext{
136 cases.* = GenHContext{
137 .b = b,130 .b = b,
138 .step = b.step("test-gen-h", "Run the C header file generation tests"),131 .step = b.step("test-gen-h", "Run the C header file generation tests"),
139 .test_index = 0,132 .test_index = 0,
140 .test_filter = test_filter,133 .test_filter = test_filter,
141 };134 }) catch unreachable;
142135
143 gen_h.addCases(cases);136 gen_h.addCases(cases);
144137
...@@ -240,8 +233,7 @@ pub const CompareOutputContext = struct {...@@ -240,8 +233,7 @@ pub const CompareOutputContext = struct {
240233
241 pub fn create(context: *CompareOutputContext, exe_path: []const u8, name: []const u8, expected_output: []const u8, cli_args: []const []const u8) *RunCompareOutputStep {234 pub fn create(context: *CompareOutputContext, exe_path: []const u8, name: []const u8, expected_output: []const u8, cli_args: []const []const u8) *RunCompareOutputStep {
242 const allocator = context.b.allocator;235 const allocator = context.b.allocator;
243 const ptr = allocator.create(RunCompareOutputStep) catch unreachable;236 const ptr = allocator.create(RunCompareOutputStep{
244 ptr.* = RunCompareOutputStep{
245 .context = context,237 .context = context,
246 .exe_path = exe_path,238 .exe_path = exe_path,
247 .name = name,239 .name = name,
...@@ -249,7 +241,7 @@ pub const CompareOutputContext = struct {...@@ -249,7 +241,7 @@ pub const CompareOutputContext = struct {
249 .test_index = context.test_index,241 .test_index = context.test_index,
250 .step = build.Step.init("RunCompareOutput", allocator, make),242 .step = build.Step.init("RunCompareOutput", allocator, make),
251 .cli_args = cli_args,243 .cli_args = cli_args,
252 };244 }) catch unreachable;
253 context.test_index += 1;245 context.test_index += 1;
254 return ptr;246 return ptr;
255 }247 }
...@@ -328,14 +320,14 @@ pub const CompareOutputContext = struct {...@@ -328,14 +320,14 @@ pub const CompareOutputContext = struct {
328320
329 pub fn create(context: *CompareOutputContext, exe_path: []const u8, name: []const u8) *RuntimeSafetyRunStep {321 pub fn create(context: *CompareOutputContext, exe_path: []const u8, name: []const u8) *RuntimeSafetyRunStep {
330 const allocator = context.b.allocator;322 const allocator = context.b.allocator;
331 const ptr = allocator.create(RuntimeSafetyRunStep) catch unreachable;323 const ptr = allocator.create(RuntimeSafetyRunStep{
332 ptr.* = RuntimeSafetyRunStep{
333 .context = context,324 .context = context,
334 .exe_path = exe_path,325 .exe_path = exe_path,
335 .name = name,326 .name = name,
336 .test_index = context.test_index,327 .test_index = context.test_index,
337 .step = build.Step.init("RuntimeSafetyRun", allocator, make),328 .step = build.Step.init("RuntimeSafetyRun", allocator, make),
338 };329 }) catch unreachable;
330
339 context.test_index += 1;331 context.test_index += 1;
340 return ptr;332 return ptr;
341 }333 }
...@@ -543,15 +535,15 @@ pub const CompileErrorContext = struct {...@@ -543,15 +535,15 @@ pub const CompileErrorContext = struct {
543535
544 pub fn create(context: *CompileErrorContext, name: []const u8, case: *const TestCase, build_mode: Mode) *CompileCmpOutputStep {536 pub fn create(context: *CompileErrorContext, name: []const u8, case: *const TestCase, build_mode: Mode) *CompileCmpOutputStep {
545 const allocator = context.b.allocator;537 const allocator = context.b.allocator;
546 const ptr = allocator.create(CompileCmpOutputStep) catch unreachable;538 const ptr = allocator.create(CompileCmpOutputStep{
547 ptr.* = CompileCmpOutputStep{
548 .step = build.Step.init("CompileCmpOutput", allocator, make),539 .step = build.Step.init("CompileCmpOutput", allocator, make),
549 .context = context,540 .context = context,
550 .name = name,541 .name = name,
551 .test_index = context.test_index,542 .test_index = context.test_index,
552 .case = case,543 .case = case,
553 .build_mode = build_mode,544 .build_mode = build_mode,
554 };545 }) catch unreachable;
546
555 context.test_index += 1;547 context.test_index += 1;
556 return ptr;548 return ptr;
557 }549 }
...@@ -662,14 +654,14 @@ pub const CompileErrorContext = struct {...@@ -662,14 +654,14 @@ pub const CompileErrorContext = struct {
662 }654 }
663655
664 pub fn create(self: *CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) *TestCase {656 pub fn create(self: *CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) *TestCase {
665 const tc = self.b.allocator.create(TestCase) catch unreachable;657 const tc = self.b.allocator.create(TestCase{
666 tc.* = TestCase{
667 .name = name,658 .name = name,
668 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),659 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),
669 .expected_errors = ArrayList([]const u8).init(self.b.allocator),660 .expected_errors = ArrayList([]const u8).init(self.b.allocator),
670 .link_libc = false,661 .link_libc = false,
671 .is_exe = false,662 .is_exe = false,
672 };663 }) catch unreachable;
664
673 tc.addSourceFile(".tmp_source.zig", source);665 tc.addSourceFile(".tmp_source.zig", source);
674 comptime var arg_i = 0;666 comptime var arg_i = 0;
675 inline while (arg_i < expected_lines.len) : (arg_i += 1) {667 inline while (arg_i < expected_lines.len) : (arg_i += 1) {
...@@ -829,14 +821,14 @@ pub const TranslateCContext = struct {...@@ -829,14 +821,14 @@ pub const TranslateCContext = struct {
829821
830 pub fn create(context: *TranslateCContext, name: []const u8, case: *const TestCase) *TranslateCCmpOutputStep {822 pub fn create(context: *TranslateCContext, name: []const u8, case: *const TestCase) *TranslateCCmpOutputStep {
831 const allocator = context.b.allocator;823 const allocator = context.b.allocator;
832 const ptr = allocator.create(TranslateCCmpOutputStep) catch unreachable;824 const ptr = allocator.create(TranslateCCmpOutputStep{
833 ptr.* = TranslateCCmpOutputStep{
834 .step = build.Step.init("ParseCCmpOutput", allocator, make),825 .step = build.Step.init("ParseCCmpOutput", allocator, make),
835 .context = context,826 .context = context,
836 .name = name,827 .name = name,
837 .test_index = context.test_index,828 .test_index = context.test_index,
838 .case = case,829 .case = case,
839 };830 }) catch unreachable;
831
840 context.test_index += 1;832 context.test_index += 1;
841 return ptr;833 return ptr;
842 }834 }
...@@ -936,13 +928,13 @@ pub const TranslateCContext = struct {...@@ -936,13 +928,13 @@ pub const TranslateCContext = struct {
936 }928 }
937929
938 pub fn create(self: *TranslateCContext, allow_warnings: bool, filename: []const u8, name: []const u8, source: []const u8, expected_lines: ...) *TestCase {930 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;931 const tc = self.b.allocator.create(TestCase{
940 tc.* = TestCase{
941 .name = name,932 .name = name,
942 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),933 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),
943 .expected_lines = ArrayList([]const u8).init(self.b.allocator),934 .expected_lines = ArrayList([]const u8).init(self.b.allocator),
944 .allow_warnings = allow_warnings,935 .allow_warnings = allow_warnings,
945 };936 }) catch unreachable;
937
946 tc.addSourceFile(filename, source);938 tc.addSourceFile(filename, source);
947 comptime var arg_i = 0;939 comptime var arg_i = 0;
948 inline while (arg_i < expected_lines.len) : (arg_i += 1) {940 inline while (arg_i < expected_lines.len) : (arg_i += 1) {
...@@ -1023,15 +1015,15 @@ pub const GenHContext = struct {...@@ -1023,15 +1015,15 @@ pub const GenHContext = struct {
10231015
1024 pub fn create(context: *GenHContext, h_path: []const u8, name: []const u8, case: *const TestCase) *GenHCmpOutputStep {1016 pub fn create(context: *GenHContext, h_path: []const u8, name: []const u8, case: *const TestCase) *GenHCmpOutputStep {
1025 const allocator = context.b.allocator;1017 const allocator = context.b.allocator;
1026 const ptr = allocator.create(GenHCmpOutputStep) catch unreachable;1018 const ptr = allocator.create(GenHCmpOutputStep{
1027 ptr.* = GenHCmpOutputStep{
1028 .step = build.Step.init("ParseCCmpOutput", allocator, make),1019 .step = build.Step.init("ParseCCmpOutput", allocator, make),
1029 .context = context,1020 .context = context,
1030 .h_path = h_path,1021 .h_path = h_path,
1031 .name = name,1022 .name = name,
1032 .test_index = context.test_index,1023 .test_index = context.test_index,
1033 .case = case,1024 .case = case,
1034 };1025 }) catch unreachable;
1026
1035 context.test_index += 1;1027 context.test_index += 1;
1036 return ptr;1028 return ptr;
1037 }1029 }
...@@ -1070,12 +1062,12 @@ pub const GenHContext = struct {...@@ -1070,12 +1062,12 @@ pub const GenHContext = struct {
1070 }1062 }
10711063
1072 pub fn create(self: *GenHContext, filename: []const u8, name: []const u8, source: []const u8, expected_lines: ...) *TestCase {1064 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;1065 const tc = self.b.allocator.create(TestCase{
1074 tc.* = TestCase{
1075 .name = name,1066 .name = name,
1076 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),1067 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),
1077 .expected_lines = ArrayList([]const u8).init(self.b.allocator),1068 .expected_lines = ArrayList([]const u8).init(self.b.allocator),
1078 };1069 }) catch unreachable;
1070
1079 tc.addSourceFile(filename, source);1071 tc.addSourceFile(filename, source);
1080 comptime var arg_i = 0;1072 comptime var arg_i = 0;
1081 inline while (arg_i < expected_lines.len) : (arg_i += 1) {1073 inline while (arg_i < expected_lines.len) : (arg_i += 1) {