authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-27 14:11:29-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-27 16:10:48-07:00
logd399f8a489dd2ae62fae9b805778bfdc697a969b
tree60df6836102786a1e665dfc92d815a27d6f8c352
parentb5b634e4e8a2a1fe32fba50ccd175257b4213936
parentf6c934677315665c140151b8dd28a56f948205e2

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


122 files changed, 15962 insertions(+), 3861 deletions(-)

CMakeLists.txt+9-8
...@@ -434,13 +434,12 @@ set(ZIG_STAGE2_SOURCES...@@ -434,13 +434,12 @@ set(ZIG_STAGE2_SOURCES
434 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/log10.zig"434 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/log10.zig"
435 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/log2.zig"435 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/log2.zig"
436 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/modti3.zig"436 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/modti3.zig"
437 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulXi3.zig"
437 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/muldf3.zig"438 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/muldf3.zig"
438 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/muldi3.zig"
439 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulf3.zig"439 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulf3.zig"
440 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulo.zig"440 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulo.zig"
441 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulsf3.zig"441 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulsf3.zig"
442 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/multf3.zig"442 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/multf3.zig"
443 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/multi3.zig"
444 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulxf3.zig"443 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulxf3.zig"
445 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/negXi2.zig"444 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/negXi2.zig"
446 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/negv.zig"445 "${CMAKE_SOURCE_DIR}/lib/compiler_rt/negv.zig"
...@@ -569,6 +568,7 @@ set(ZIG_STAGE2_SOURCES...@@ -569,6 +568,7 @@ set(ZIG_STAGE2_SOURCES
569 "${CMAKE_SOURCE_DIR}/src/clang_options_data.zig"568 "${CMAKE_SOURCE_DIR}/src/clang_options_data.zig"
570 "${CMAKE_SOURCE_DIR}/src/codegen.zig"569 "${CMAKE_SOURCE_DIR}/src/codegen.zig"
571 "${CMAKE_SOURCE_DIR}/src/codegen/c.zig"570 "${CMAKE_SOURCE_DIR}/src/codegen/c.zig"
571 "${CMAKE_SOURCE_DIR}/src/codegen/c/type.zig"
572 "${CMAKE_SOURCE_DIR}/src/codegen/llvm.zig"572 "${CMAKE_SOURCE_DIR}/src/codegen/llvm.zig"
573 "${CMAKE_SOURCE_DIR}/src/codegen/llvm/bindings.zig"573 "${CMAKE_SOURCE_DIR}/src/codegen/llvm/bindings.zig"
574 "${CMAKE_SOURCE_DIR}/src/glibc.zig"574 "${CMAKE_SOURCE_DIR}/src/glibc.zig"
...@@ -612,7 +612,6 @@ set(ZIG_STAGE2_SOURCES...@@ -612,7 +612,6 @@ set(ZIG_STAGE2_SOURCES
612 "${CMAKE_SOURCE_DIR}/src/link/tapi.zig"612 "${CMAKE_SOURCE_DIR}/src/link/tapi.zig"
613 "${CMAKE_SOURCE_DIR}/src/link/tapi/Tokenizer.zig"613 "${CMAKE_SOURCE_DIR}/src/link/tapi/Tokenizer.zig"
614 "${CMAKE_SOURCE_DIR}/src/link/tapi/parse.zig"614 "${CMAKE_SOURCE_DIR}/src/link/tapi/parse.zig"
615 "${CMAKE_SOURCE_DIR}/src/link/tapi/parse/test.zig"
616 "${CMAKE_SOURCE_DIR}/src/link/tapi/yaml.zig"615 "${CMAKE_SOURCE_DIR}/src/link/tapi/yaml.zig"
617 "${CMAKE_SOURCE_DIR}/src/main.zig"616 "${CMAKE_SOURCE_DIR}/src/main.zig"
618 "${CMAKE_SOURCE_DIR}/src/mingw.zig"617 "${CMAKE_SOURCE_DIR}/src/mingw.zig"
...@@ -748,10 +747,11 @@ set(BUILD_ZIG2_ARGS...@@ -748,10 +747,11 @@ set(BUILD_ZIG2_ARGS
748 build-exe src/main.zig -ofmt=c -lc747 build-exe src/main.zig -ofmt=c -lc
749 -OReleaseSmall748 -OReleaseSmall
750 --name zig2 -femit-bin="${ZIG2_C_SOURCE}"749 --name zig2 -femit-bin="${ZIG2_C_SOURCE}"
751 --pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}" --pkg-end750 --mod "build_options::${ZIG_CONFIG_ZIG_OUT}"
751 --deps build_options
752 -target "${HOST_TARGET_TRIPLE}"752 -target "${HOST_TARGET_TRIPLE}"
753)753)
754 754
755add_custom_command(755add_custom_command(
756 OUTPUT "${ZIG2_C_SOURCE}"756 OUTPUT "${ZIG2_C_SOURCE}"
757 COMMAND zig1 ${BUILD_ZIG2_ARGS}757 COMMAND zig1 ${BUILD_ZIG2_ARGS}
...@@ -765,10 +765,11 @@ set(BUILD_COMPILER_RT_ARGS...@@ -765,10 +765,11 @@ set(BUILD_COMPILER_RT_ARGS
765 build-obj lib/compiler_rt.zig -ofmt=c765 build-obj lib/compiler_rt.zig -ofmt=c
766 -OReleaseSmall766 -OReleaseSmall
767 --name compiler_rt -femit-bin="${ZIG_COMPILER_RT_C_SOURCE}"767 --name compiler_rt -femit-bin="${ZIG_COMPILER_RT_C_SOURCE}"
768 --pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}" --pkg-end768 --mod "build_options::${ZIG_CONFIG_ZIG_OUT}"
769 --deps build_options
769 -target "${HOST_TARGET_TRIPLE}"770 -target "${HOST_TARGET_TRIPLE}"
770)771)
771 772
772add_custom_command(773add_custom_command(
773 OUTPUT "${ZIG_COMPILER_RT_C_SOURCE}"774 OUTPUT "${ZIG_COMPILER_RT_C_SOURCE}"
774 COMMAND zig1 ${BUILD_COMPILER_RT_ARGS}775 COMMAND zig1 ${BUILD_COMPILER_RT_ARGS}
...@@ -782,7 +783,7 @@ set_target_properties(zig2 PROPERTIES...@@ -782,7 +783,7 @@ set_target_properties(zig2 PROPERTIES
782 COMPILE_FLAGS ${ZIG2_COMPILE_FLAGS}783 COMPILE_FLAGS ${ZIG2_COMPILE_FLAGS}
783 LINK_FLAGS ${ZIG2_LINK_FLAGS}784 LINK_FLAGS ${ZIG2_LINK_FLAGS}
784)785)
785target_include_directories(zig2 PUBLIC "${CMAKE_SOURCE_DIR}/lib")786target_include_directories(zig2 PUBLIC "${CMAKE_SOURCE_DIR}/stage1")
786target_link_libraries(zig2 LINK_PUBLIC zigcpp)787target_link_libraries(zig2 LINK_PUBLIC zigcpp)
787788
788if(MSVC)789if(MSVC)
build.zig+7
...@@ -118,8 +118,11 @@ pub fn build(b: *std.Build) !void {...@@ -118,8 +118,11 @@ pub fn build(b: *std.Build) !void {
118 ".gz",118 ".gz",
119 ".z.0",119 ".z.0",
120 ".z.9",120 ".z.9",
121 ".zstd.3",
122 ".zstd.19",
121 "rfc1951.txt",123 "rfc1951.txt",
122 "rfc1952.txt",124 "rfc1952.txt",
125 "rfc8478.txt",
123 // exclude files from lib/std/compress/deflate/testdata126 // exclude files from lib/std/compress/deflate/testdata
124 ".expect",127 ".expect",
125 ".expect-noinput",128 ".expect-noinput",
...@@ -513,8 +516,12 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {...@@ -513,8 +516,12 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
513 run_opt.addArg("-o");516 run_opt.addArg("-o");
514 run_opt.addFileSourceArg(.{ .path = "stage1/zig1.wasm" });517 run_opt.addFileSourceArg(.{ .path = "stage1/zig1.wasm" });
515518
519 const copy_zig_h = b.addWriteFiles();
520 copy_zig_h.addCopyFileToSource(.{ .path = "lib/zig.h" }, "stage1/zig.h");
521
516 const update_zig1_step = b.step("update-zig1", "Update stage1/zig1.wasm");522 const update_zig1_step = b.step("update-zig1", "Update stage1/zig1.wasm");
517 update_zig1_step.dependOn(&run_opt.step);523 update_zig1_step.dependOn(&run_opt.step);
524 update_zig1_step.dependOn(&copy_zig_h.step);
518}525}
519526
520fn addCompilerStep(527fn addCompilerStep(
ci/x86_64-windows-debug.ps1+2-1
...@@ -87,7 +87,8 @@ CheckLastExitCode...@@ -87,7 +87,8 @@ CheckLastExitCode
87 -OReleaseSmall `87 -OReleaseSmall `
88 --name compiler_rt `88 --name compiler_rt `
89 -femit-bin="compiler_rt-x86_64-windows-msvc.c" `89 -femit-bin="compiler_rt-x86_64-windows-msvc.c" `
90 --pkg-begin build_options config.zig --pkg-end `90 --mod build_options::config.zig `
91 --deps build_options `
91 -target x86_64-windows-msvc92 -target x86_64-windows-msvc
92CheckLastExitCode93CheckLastExitCode
9394
ci/x86_64-windows-release.ps1+2-1
...@@ -87,7 +87,8 @@ CheckLastExitCode...@@ -87,7 +87,8 @@ CheckLastExitCode
87 -OReleaseSmall `87 -OReleaseSmall `
88 --name compiler_rt `88 --name compiler_rt `
89 -femit-bin="compiler_rt-x86_64-windows-msvc.c" `89 -femit-bin="compiler_rt-x86_64-windows-msvc.c" `
90 --pkg-begin build_options config.zig --pkg-end `90 --mod build_options::config.zig `
91 --deps build_options `
91 -target x86_64-windows-msvc92 -target x86_64-windows-msvc
92CheckLastExitCode93CheckLastExitCode
9394
lib/compiler_rt.zig+142-133
...@@ -3,64 +3,34 @@ const builtin = @import("builtin");...@@ -3,64 +3,34 @@ const builtin = @import("builtin");
3pub const panic = @import("compiler_rt/common.zig").panic;3pub const panic = @import("compiler_rt/common.zig").panic;
44
5comptime {5comptime {
6 _ = @import("compiler_rt/addf3.zig");6 // Integer routines
7 _ = @import("compiler_rt/addhf3.zig");7 _ = @import("compiler_rt/count0bits.zig");
8 _ = @import("compiler_rt/addsf3.zig");8 _ = @import("compiler_rt/parity.zig");
9 _ = @import("compiler_rt/adddf3.zig");9 _ = @import("compiler_rt/popcount.zig");
10 _ = @import("compiler_rt/addtf3.zig");10 _ = @import("compiler_rt/bswap.zig");
11 _ = @import("compiler_rt/addxf3.zig");11 _ = @import("compiler_rt/cmp.zig");
12
13 _ = @import("compiler_rt/subhf3.zig");
14 _ = @import("compiler_rt/subsf3.zig");
15 _ = @import("compiler_rt/subdf3.zig");
16 _ = @import("compiler_rt/subtf3.zig");
17 _ = @import("compiler_rt/subxf3.zig");
18
19 _ = @import("compiler_rt/mulf3.zig");
20 _ = @import("compiler_rt/mulhf3.zig");
21 _ = @import("compiler_rt/mulsf3.zig");
22 _ = @import("compiler_rt/muldf3.zig");
23 _ = @import("compiler_rt/multf3.zig");
24 _ = @import("compiler_rt/mulxf3.zig");
25
26 _ = @import("compiler_rt/powiXf2.zig");
27 _ = @import("compiler_rt/mulc3.zig");
28 _ = @import("compiler_rt/mulhc3.zig");
29 _ = @import("compiler_rt/mulsc3.zig");
30 _ = @import("compiler_rt/muldc3.zig");
31 _ = @import("compiler_rt/mulxc3.zig");
32 _ = @import("compiler_rt/multc3.zig");
3312
34 _ = @import("compiler_rt/divc3.zig");13 _ = @import("compiler_rt/shift.zig");
35 _ = @import("compiler_rt/divhc3.zig");14 _ = @import("compiler_rt/negXi2.zig");
36 _ = @import("compiler_rt/divsc3.zig");15 _ = @import("compiler_rt/int.zig");
37 _ = @import("compiler_rt/divdc3.zig");16 _ = @import("compiler_rt/mulXi3.zig");
38 _ = @import("compiler_rt/divxc3.zig");17 _ = @import("compiler_rt/divti3.zig");
39 _ = @import("compiler_rt/divtc3.zig");18 _ = @import("compiler_rt/udivti3.zig");
19 _ = @import("compiler_rt/modti3.zig");
20 _ = @import("compiler_rt/umodti3.zig");
4021
41 _ = @import("compiler_rt/neghf2.zig");22 _ = @import("compiler_rt/absv.zig");
42 _ = @import("compiler_rt/negsf2.zig");23 _ = @import("compiler_rt/absvsi2.zig");
43 _ = @import("compiler_rt/negdf2.zig");24 _ = @import("compiler_rt/absvdi2.zig");
44 _ = @import("compiler_rt/negtf2.zig");25 _ = @import("compiler_rt/absvti2.zig");
45 _ = @import("compiler_rt/negxf2.zig");26 _ = @import("compiler_rt/negv.zig");
4627
47 _ = @import("compiler_rt/comparef.zig");28 _ = @import("compiler_rt/addo.zig");
48 _ = @import("compiler_rt/cmphf2.zig");29 _ = @import("compiler_rt/subo.zig");
49 _ = @import("compiler_rt/cmpsf2.zig");30 _ = @import("compiler_rt/mulo.zig");
50 _ = @import("compiler_rt/cmpdf2.zig");
51 _ = @import("compiler_rt/cmptf2.zig");
52 _ = @import("compiler_rt/cmpxf2.zig");
53 _ = @import("compiler_rt/gehf2.zig");
54 _ = @import("compiler_rt/gesf2.zig");
55 _ = @import("compiler_rt/gedf2.zig");
56 _ = @import("compiler_rt/gexf2.zig");
57 _ = @import("compiler_rt/getf2.zig");
58 _ = @import("compiler_rt/unordhf2.zig");
59 _ = @import("compiler_rt/unordsf2.zig");
60 _ = @import("compiler_rt/unorddf2.zig");
61 _ = @import("compiler_rt/unordxf2.zig");
62 _ = @import("compiler_rt/unordtf2.zig");
6331
32 // Float routines
33 // conversion
64 _ = @import("compiler_rt/extendf.zig");34 _ = @import("compiler_rt/extendf.zig");
65 _ = @import("compiler_rt/extendhfsf2.zig");35 _ = @import("compiler_rt/extendhfsf2.zig");
66 _ = @import("compiler_rt/extendhfdf2.zig");36 _ = @import("compiler_rt/extendhfdf2.zig");
...@@ -85,37 +55,37 @@ comptime {...@@ -85,37 +55,37 @@ comptime {
85 _ = @import("compiler_rt/trunctfdf2.zig");55 _ = @import("compiler_rt/trunctfdf2.zig");
86 _ = @import("compiler_rt/trunctfxf2.zig");56 _ = @import("compiler_rt/trunctfxf2.zig");
8757
88 _ = @import("compiler_rt/divhf3.zig");58 _ = @import("compiler_rt/float_to_int.zig");
89 _ = @import("compiler_rt/divsf3.zig");59 _ = @import("compiler_rt/fixhfsi.zig");
90 _ = @import("compiler_rt/divdf3.zig");60 _ = @import("compiler_rt/fixhfdi.zig");
91 _ = @import("compiler_rt/divxf3.zig");61 _ = @import("compiler_rt/fixhfti.zig");
92 _ = @import("compiler_rt/divtf3.zig");62 _ = @import("compiler_rt/fixsfsi.zig");
93 _ = @import("compiler_rt/sin.zig");63 _ = @import("compiler_rt/fixsfdi.zig");
94 _ = @import("compiler_rt/cos.zig");64 _ = @import("compiler_rt/fixsfti.zig");
95 _ = @import("compiler_rt/sincos.zig");65 _ = @import("compiler_rt/fixdfsi.zig");
96 _ = @import("compiler_rt/ceil.zig");66 _ = @import("compiler_rt/fixdfdi.zig");
97 _ = @import("compiler_rt/exp.zig");67 _ = @import("compiler_rt/fixdfti.zig");
98 _ = @import("compiler_rt/exp2.zig");68 _ = @import("compiler_rt/fixtfsi.zig");
99 _ = @import("compiler_rt/fabs.zig");69 _ = @import("compiler_rt/fixtfdi.zig");
100 _ = @import("compiler_rt/floor.zig");70 _ = @import("compiler_rt/fixtfti.zig");
101 _ = @import("compiler_rt/fma.zig");71 _ = @import("compiler_rt/fixxfsi.zig");
102 _ = @import("compiler_rt/fmax.zig");72 _ = @import("compiler_rt/fixxfdi.zig");
103 _ = @import("compiler_rt/fmin.zig");73 _ = @import("compiler_rt/fixxfti.zig");
104 _ = @import("compiler_rt/fmod.zig");74 _ = @import("compiler_rt/fixunshfsi.zig");
105 _ = @import("compiler_rt/log.zig");75 _ = @import("compiler_rt/fixunshfdi.zig");
106 _ = @import("compiler_rt/log10.zig");76 _ = @import("compiler_rt/fixunshfti.zig");
107 _ = @import("compiler_rt/log2.zig");77 _ = @import("compiler_rt/fixunssfsi.zig");
108 _ = @import("compiler_rt/round.zig");78 _ = @import("compiler_rt/fixunssfdi.zig");
109 _ = @import("compiler_rt/sqrt.zig");79 _ = @import("compiler_rt/fixunssfti.zig");
110 _ = @import("compiler_rt/tan.zig");80 _ = @import("compiler_rt/fixunsdfsi.zig");
111 _ = @import("compiler_rt/trunc.zig");81 _ = @import("compiler_rt/fixunsdfdi.zig");
112 _ = @import("compiler_rt/divti3.zig");82 _ = @import("compiler_rt/fixunsdfti.zig");
113 _ = @import("compiler_rt/modti3.zig");83 _ = @import("compiler_rt/fixunstfsi.zig");
114 _ = @import("compiler_rt/multi3.zig");84 _ = @import("compiler_rt/fixunstfdi.zig");
115 _ = @import("compiler_rt/udivti3.zig");85 _ = @import("compiler_rt/fixunstfti.zig");
116 _ = @import("compiler_rt/udivmodei4.zig");86 _ = @import("compiler_rt/fixunsxfsi.zig");
117 _ = @import("compiler_rt/udivmodti4.zig");87 _ = @import("compiler_rt/fixunsxfdi.zig");
118 _ = @import("compiler_rt/umodti3.zig");88 _ = @import("compiler_rt/fixunsxfti.zig");
11989
120 _ = @import("compiler_rt/int_to_float.zig");90 _ = @import("compiler_rt/int_to_float.zig");
121 _ = @import("compiler_rt/floatsihf.zig");91 _ = @import("compiler_rt/floatsihf.zig");
...@@ -149,60 +119,99 @@ comptime {...@@ -149,60 +119,99 @@ comptime {
149 _ = @import("compiler_rt/floatuntitf.zig");119 _ = @import("compiler_rt/floatuntitf.zig");
150 _ = @import("compiler_rt/floatuntixf.zig");120 _ = @import("compiler_rt/floatuntixf.zig");
151121
152 _ = @import("compiler_rt/float_to_int.zig");122 // comparison
153 _ = @import("compiler_rt/fixhfsi.zig");123 _ = @import("compiler_rt/comparef.zig");
154 _ = @import("compiler_rt/fixhfdi.zig");124 _ = @import("compiler_rt/cmphf2.zig");
155 _ = @import("compiler_rt/fixhfti.zig");125 _ = @import("compiler_rt/cmpsf2.zig");
156 _ = @import("compiler_rt/fixsfsi.zig");126 _ = @import("compiler_rt/cmpdf2.zig");
157 _ = @import("compiler_rt/fixsfdi.zig");127 _ = @import("compiler_rt/cmptf2.zig");
158 _ = @import("compiler_rt/fixsfti.zig");128 _ = @import("compiler_rt/cmpxf2.zig");
159 _ = @import("compiler_rt/fixdfsi.zig");129 _ = @import("compiler_rt/unordhf2.zig");
160 _ = @import("compiler_rt/fixdfdi.zig");130 _ = @import("compiler_rt/unordsf2.zig");
161 _ = @import("compiler_rt/fixdfti.zig");131 _ = @import("compiler_rt/unorddf2.zig");
162 _ = @import("compiler_rt/fixtfsi.zig");132 _ = @import("compiler_rt/unordxf2.zig");
163 _ = @import("compiler_rt/fixtfdi.zig");133 _ = @import("compiler_rt/unordtf2.zig");
164 _ = @import("compiler_rt/fixtfti.zig");134 _ = @import("compiler_rt/gehf2.zig");
165 _ = @import("compiler_rt/fixxfsi.zig");135 _ = @import("compiler_rt/gesf2.zig");
166 _ = @import("compiler_rt/fixxfdi.zig");136 _ = @import("compiler_rt/gedf2.zig");
167 _ = @import("compiler_rt/fixxfti.zig");137 _ = @import("compiler_rt/gexf2.zig");
168 _ = @import("compiler_rt/fixunshfsi.zig");138 _ = @import("compiler_rt/getf2.zig");
169 _ = @import("compiler_rt/fixunshfdi.zig");
170 _ = @import("compiler_rt/fixunshfti.zig");
171 _ = @import("compiler_rt/fixunssfsi.zig");
172 _ = @import("compiler_rt/fixunssfdi.zig");
173 _ = @import("compiler_rt/fixunssfti.zig");
174 _ = @import("compiler_rt/fixunsdfsi.zig");
175 _ = @import("compiler_rt/fixunsdfdi.zig");
176 _ = @import("compiler_rt/fixunsdfti.zig");
177 _ = @import("compiler_rt/fixunstfsi.zig");
178 _ = @import("compiler_rt/fixunstfdi.zig");
179 _ = @import("compiler_rt/fixunstfti.zig");
180 _ = @import("compiler_rt/fixunsxfsi.zig");
181 _ = @import("compiler_rt/fixunsxfdi.zig");
182 _ = @import("compiler_rt/fixunsxfti.zig");
183139
184 _ = @import("compiler_rt/count0bits.zig");140 // arithmetic
185 _ = @import("compiler_rt/parity.zig");141 _ = @import("compiler_rt/addf3.zig");
186 _ = @import("compiler_rt/popcount.zig");142 _ = @import("compiler_rt/addhf3.zig");
187 _ = @import("compiler_rt/bswap.zig");143 _ = @import("compiler_rt/addsf3.zig");
188 _ = @import("compiler_rt/int.zig");144 _ = @import("compiler_rt/adddf3.zig");
189 _ = @import("compiler_rt/shift.zig");145 _ = @import("compiler_rt/addtf3.zig");
146 _ = @import("compiler_rt/addxf3.zig");
190147
191 _ = @import("compiler_rt/negXi2.zig");148 _ = @import("compiler_rt/subhf3.zig");
149 _ = @import("compiler_rt/subsf3.zig");
150 _ = @import("compiler_rt/subdf3.zig");
151 _ = @import("compiler_rt/subtf3.zig");
152 _ = @import("compiler_rt/subxf3.zig");
192153
193 _ = @import("compiler_rt/muldi3.zig");154 _ = @import("compiler_rt/mulf3.zig");
155 _ = @import("compiler_rt/mulhf3.zig");
156 _ = @import("compiler_rt/mulsf3.zig");
157 _ = @import("compiler_rt/muldf3.zig");
158 _ = @import("compiler_rt/multf3.zig");
159 _ = @import("compiler_rt/mulxf3.zig");
194160
195 _ = @import("compiler_rt/absv.zig");161 _ = @import("compiler_rt/divhf3.zig");
196 _ = @import("compiler_rt/absvsi2.zig");162 _ = @import("compiler_rt/divsf3.zig");
197 _ = @import("compiler_rt/absvdi2.zig");163 _ = @import("compiler_rt/divdf3.zig");
198 _ = @import("compiler_rt/absvti2.zig");164 _ = @import("compiler_rt/divxf3.zig");
165 _ = @import("compiler_rt/divtf3.zig");
199166
200 _ = @import("compiler_rt/negv.zig");167 _ = @import("compiler_rt/neghf2.zig");
201 _ = @import("compiler_rt/addo.zig");168 _ = @import("compiler_rt/negsf2.zig");
202 _ = @import("compiler_rt/subo.zig");169 _ = @import("compiler_rt/negdf2.zig");
203 _ = @import("compiler_rt/mulo.zig");170 _ = @import("compiler_rt/negtf2.zig");
204 _ = @import("compiler_rt/cmp.zig");171 _ = @import("compiler_rt/negxf2.zig");
172
173 // other
174 _ = @import("compiler_rt/powiXf2.zig");
175 _ = @import("compiler_rt/mulc3.zig");
176 _ = @import("compiler_rt/mulhc3.zig");
177 _ = @import("compiler_rt/mulsc3.zig");
178 _ = @import("compiler_rt/muldc3.zig");
179 _ = @import("compiler_rt/mulxc3.zig");
180 _ = @import("compiler_rt/multc3.zig");
181
182 _ = @import("compiler_rt/divc3.zig");
183 _ = @import("compiler_rt/divhc3.zig");
184 _ = @import("compiler_rt/divsc3.zig");
185 _ = @import("compiler_rt/divdc3.zig");
186 _ = @import("compiler_rt/divxc3.zig");
187 _ = @import("compiler_rt/divtc3.zig");
188
189 // Math routines. Alphabetically sorted.
190 _ = @import("compiler_rt/ceil.zig");
191 _ = @import("compiler_rt/cos.zig");
192 _ = @import("compiler_rt/exp.zig");
193 _ = @import("compiler_rt/exp2.zig");
194 _ = @import("compiler_rt/fabs.zig");
195 _ = @import("compiler_rt/floor.zig");
196 _ = @import("compiler_rt/fma.zig");
197 _ = @import("compiler_rt/fmax.zig");
198 _ = @import("compiler_rt/fmin.zig");
199 _ = @import("compiler_rt/fmod.zig");
200 _ = @import("compiler_rt/log.zig");
201 _ = @import("compiler_rt/log10.zig");
202 _ = @import("compiler_rt/log2.zig");
203 _ = @import("compiler_rt/round.zig");
204 _ = @import("compiler_rt/sin.zig");
205 _ = @import("compiler_rt/sincos.zig");
206 _ = @import("compiler_rt/sqrt.zig");
207 _ = @import("compiler_rt/tan.zig");
208 _ = @import("compiler_rt/trunc.zig");
209
210 // BigInt. Alphabetically sorted.
211 _ = @import("compiler_rt/udivmodei4.zig");
212 _ = @import("compiler_rt/udivmodti4.zig");
205213
214 // extra
206 _ = @import("compiler_rt/os_version_check.zig");215 _ = @import("compiler_rt/os_version_check.zig");
207 _ = @import("compiler_rt/emutls.zig");216 _ = @import("compiler_rt/emutls.zig");
208 _ = @import("compiler_rt/arm.zig");217 _ = @import("compiler_rt/arm.zig");
lib/compiler_rt/README.md+1-1
...@@ -331,7 +331,7 @@ Integer and Float Operations...@@ -331,7 +331,7 @@ Integer and Float Operations
331| ✓ | __negdf2 | f64 | ∅ | f64 | .. |331| ✓ | __negdf2 | f64 | ∅ | f64 | .. |
332| ✓ | __negtf2 | f128 | ∅ | f128 | .. |332| ✓ | __negtf2 | f128 | ∅ | f128 | .. |
333| ✓ | __negxf2 | f80 | ∅ | f80 | .. |333| ✓ | __negxf2 | f80 | ∅ | f80 | .. |
334| | | | | | **Floating point raised to integer power** |334| | | | | | **Other** |
335| ✓ | __powihf2 | f16 | i32 | f16 | `a ^ b` |335| ✓ | __powihf2 | f16 | i32 | f16 | `a ^ b` |
336| ✓ | __powisf2 | f32 | i32 | f32 | .. |336| ✓ | __powisf2 | f32 | i32 | f32 | .. |
337| ✓ | __powidf2 | f64 | i32 | f64 | .. |337| ✓ | __powidf2 | f64 | i32 | f64 | .. |
lib/compiler_rt/common.zig+18
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const native_endian = builtin.cpu.arch.endian();
34
4pub const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak;5pub const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak;
5/// Determines the symbol's visibility to other objects.6/// Determines the symbol's visibility to other objects.
...@@ -221,3 +222,20 @@ pub inline fn fneg(a: anytype) @TypeOf(a) {...@@ -221,3 +222,20 @@ pub inline fn fneg(a: anytype) @TypeOf(a) {
221 const negated = @bitCast(U, a) ^ sign_bit_mask;222 const negated = @bitCast(U, a) ^ sign_bit_mask;
222 return @bitCast(F, negated);223 return @bitCast(F, negated);
223}224}
225
226/// Allows to access underlying bits as two equally sized lower and higher
227/// signed or unsigned integers.
228pub fn HalveInt(comptime T: type, comptime signed_half: bool) type {
229 return extern union {
230 pub const bits = @divExact(@typeInfo(T).Int.bits, 2);
231 pub const HalfTU = std.meta.Int(.unsigned, bits);
232 pub const HalfTS = std.meta.Int(.signed, bits);
233 pub const HalfT = if (signed_half) HalfTS else HalfTU;
234
235 all: T,
236 s: if (native_endian == .Little)
237 extern struct { low: HalfT, high: HalfT }
238 else
239 extern struct { high: HalfT, low: HalfT },
240 };
241}
lib/compiler_rt/int.zig-57
...@@ -16,7 +16,6 @@ pub const panic = common.panic;...@@ -16,7 +16,6 @@ pub const panic = common.panic;
16comptime {16comptime {
17 @export(__divmodti4, .{ .name = "__divmodti4", .linkage = common.linkage, .visibility = common.visibility });17 @export(__divmodti4, .{ .name = "__divmodti4", .linkage = common.linkage, .visibility = common.visibility });
18 @export(__udivmoddi4, .{ .name = "__udivmoddi4", .linkage = common.linkage, .visibility = common.visibility });18 @export(__udivmoddi4, .{ .name = "__udivmoddi4", .linkage = common.linkage, .visibility = common.visibility });
19 @export(__mulsi3, .{ .name = "__mulsi3", .linkage = common.linkage, .visibility = common.visibility });
20 @export(__divmoddi4, .{ .name = "__divmoddi4", .linkage = common.linkage, .visibility = common.visibility });19 @export(__divmoddi4, .{ .name = "__divmoddi4", .linkage = common.linkage, .visibility = common.visibility });
21 if (common.want_aeabi) {20 if (common.want_aeabi) {
22 @export(__aeabi_idiv, .{ .name = "__aeabi_idiv", .linkage = common.linkage, .visibility = common.visibility });21 @export(__aeabi_idiv, .{ .name = "__aeabi_idiv", .linkage = common.linkage, .visibility = common.visibility });
...@@ -663,59 +662,3 @@ fn test_one_umodsi3(a: u32, b: u32, expected_r: u32) !void {...@@ -663,59 +662,3 @@ fn test_one_umodsi3(a: u32, b: u32, expected_r: u32) !void {
663 const r: u32 = __umodsi3(a, b);662 const r: u32 = __umodsi3(a, b);
664 try testing.expect(r == expected_r);663 try testing.expect(r == expected_r);
665}664}
666
667pub fn __mulsi3(a: i32, b: i32) callconv(.C) i32 {
668 var ua = @bitCast(u32, a);
669 var ub = @bitCast(u32, b);
670 var r: u32 = 0;
671
672 while (ua > 0) {
673 if ((ua & 1) != 0) r +%= ub;
674 ua >>= 1;
675 ub <<= 1;
676 }
677
678 return @bitCast(i32, r);
679}
680
681fn test_one_mulsi3(a: i32, b: i32, result: i32) !void {
682 try testing.expectEqual(result, __mulsi3(a, b));
683}
684
685test "mulsi3" {
686 try test_one_mulsi3(0, 0, 0);
687 try test_one_mulsi3(0, 1, 0);
688 try test_one_mulsi3(1, 0, 0);
689 try test_one_mulsi3(0, 10, 0);
690 try test_one_mulsi3(10, 0, 0);
691 try test_one_mulsi3(0, maxInt(i32), 0);
692 try test_one_mulsi3(maxInt(i32), 0, 0);
693 try test_one_mulsi3(0, -1, 0);
694 try test_one_mulsi3(-1, 0, 0);
695 try test_one_mulsi3(0, -10, 0);
696 try test_one_mulsi3(-10, 0, 0);
697 try test_one_mulsi3(0, minInt(i32), 0);
698 try test_one_mulsi3(minInt(i32), 0, 0);
699 try test_one_mulsi3(1, 1, 1);
700 try test_one_mulsi3(1, 10, 10);
701 try test_one_mulsi3(10, 1, 10);
702 try test_one_mulsi3(1, maxInt(i32), maxInt(i32));
703 try test_one_mulsi3(maxInt(i32), 1, maxInt(i32));
704 try test_one_mulsi3(1, -1, -1);
705 try test_one_mulsi3(1, -10, -10);
706 try test_one_mulsi3(-10, 1, -10);
707 try test_one_mulsi3(1, minInt(i32), minInt(i32));
708 try test_one_mulsi3(minInt(i32), 1, minInt(i32));
709 try test_one_mulsi3(46340, 46340, 2147395600);
710 try test_one_mulsi3(-46340, 46340, -2147395600);
711 try test_one_mulsi3(46340, -46340, -2147395600);
712 try test_one_mulsi3(-46340, -46340, 2147395600);
713 try test_one_mulsi3(4194303, 8192, @truncate(i32, 34359730176));
714 try test_one_mulsi3(-4194303, 8192, @truncate(i32, -34359730176));
715 try test_one_mulsi3(4194303, -8192, @truncate(i32, -34359730176));
716 try test_one_mulsi3(-4194303, -8192, @truncate(i32, 34359730176));
717 try test_one_mulsi3(8192, 4194303, @truncate(i32, 34359730176));
718 try test_one_mulsi3(-8192, 4194303, @truncate(i32, -34359730176));
719 try test_one_mulsi3(8192, -4194303, @truncate(i32, -34359730176));
720 try test_one_mulsi3(-8192, -4194303, @truncate(i32, 34359730176));
721}
lib/compiler_rt/mulXi3.zig created+101
...@@ -0,0 +1,101 @@
1const builtin = @import("builtin");
2const std = @import("std");
3const testing = std.testing;
4const common = @import("common.zig");
5const native_endian = builtin.cpu.arch.endian();
6
7pub const panic = common.panic;
8
9comptime {
10 @export(__mulsi3, .{ .name = "__mulsi3", .linkage = common.linkage, .visibility = common.visibility });
11 if (common.want_aeabi) {
12 @export(__aeabi_lmul, .{ .name = "__aeabi_lmul", .linkage = common.linkage, .visibility = common.visibility });
13 } else {
14 @export(__muldi3, .{ .name = "__muldi3", .linkage = common.linkage, .visibility = common.visibility });
15 }
16 if (common.want_windows_v2u64_abi) {
17 @export(__multi3_windows_x86_64, .{ .name = "__multi3", .linkage = common.linkage, .visibility = common.visibility });
18 } else {
19 @export(__multi3, .{ .name = "__multi3", .linkage = common.linkage, .visibility = common.visibility });
20 }
21}
22
23pub fn __mulsi3(a: i32, b: i32) callconv(.C) i32 {
24 var ua = @bitCast(u32, a);
25 var ub = @bitCast(u32, b);
26 var r: u32 = 0;
27
28 while (ua > 0) {
29 if ((ua & 1) != 0) r +%= ub;
30 ua >>= 1;
31 ub <<= 1;
32 }
33
34 return @bitCast(i32, r);
35}
36
37pub fn __muldi3(a: i64, b: i64) callconv(.C) i64 {
38 return mulX(i64, a, b);
39}
40
41fn __aeabi_lmul(a: i64, b: i64) callconv(.AAPCS) i64 {
42 return mulX(i64, a, b);
43}
44
45inline fn mulX(comptime T: type, a: T, b: T) T {
46 const word_t = common.HalveInt(T, false);
47 const x = word_t{ .all = a };
48 const y = word_t{ .all = b };
49 var r = switch (T) {
50 i64, i128 => word_t{ .all = muldXi(word_t.HalfT, x.s.low, y.s.low) },
51 else => unreachable,
52 };
53 r.s.high +%= x.s.high *% y.s.low +% x.s.low *% y.s.high;
54 return r.all;
55}
56
57fn DoubleInt(comptime T: type) type {
58 return switch (T) {
59 u32 => i64,
60 u64 => i128,
61 i32 => i64,
62 i64 => i128,
63 else => unreachable,
64 };
65}
66
67fn muldXi(comptime T: type, a: T, b: T) DoubleInt(T) {
68 const DT = DoubleInt(T);
69 const word_t = common.HalveInt(DT, false);
70 const bits_in_word_2 = @sizeOf(T) * 8 / 2;
71 const lower_mask = (~@as(T, 0)) >> bits_in_word_2;
72
73 var r: word_t = undefined;
74 r.s.low = (a & lower_mask) *% (b & lower_mask);
75 var t: T = r.s.low >> bits_in_word_2;
76 r.s.low &= lower_mask;
77 t += (a >> bits_in_word_2) *% (b & lower_mask);
78 r.s.low +%= (t & lower_mask) << bits_in_word_2;
79 r.s.high = t >> bits_in_word_2;
80 t = r.s.low >> bits_in_word_2;
81 r.s.low &= lower_mask;
82 t +%= (b >> bits_in_word_2) *% (a & lower_mask);
83 r.s.low +%= (t & lower_mask) << bits_in_word_2;
84 r.s.high +%= t >> bits_in_word_2;
85 r.s.high +%= (a >> bits_in_word_2) *% (b >> bits_in_word_2);
86 return r.all;
87}
88
89pub fn __multi3(a: i128, b: i128) callconv(.C) i128 {
90 return mulX(i128, a, b);
91}
92
93const v2u64 = @Vector(2, u64);
94
95fn __multi3_windows_x86_64(a: v2u64, b: v2u64) callconv(.C) v2u64 {
96 return @bitCast(v2u64, mulX(i128, @bitCast(i128, a), @bitCast(i128, b)));
97}
98
99test {
100 _ = @import("mulXi3_test.zig");
101}
lib/compiler_rt/mulXi3_test.zig created+147
...@@ -0,0 +1,147 @@
1const std = @import("std");
2const testing = std.testing;
3const mulXi3 = @import("mulXi3.zig");
4const maxInt = std.math.maxInt;
5const minInt = std.math.minInt;
6
7fn test_one_mulsi3(a: i32, b: i32, result: i32) !void {
8 try testing.expectEqual(result, mulXi3.__mulsi3(a, b));
9}
10
11fn test__muldi3(a: i64, b: i64, expected: i64) !void {
12 const x = mulXi3.__muldi3(a, b);
13 try testing.expect(x == expected);
14}
15
16fn test__multi3(a: i128, b: i128, expected: i128) !void {
17 const x = mulXi3.__multi3(a, b);
18 try testing.expect(x == expected);
19}
20
21test "mulsi3" {
22 try test_one_mulsi3(0, 0, 0);
23 try test_one_mulsi3(0, 1, 0);
24 try test_one_mulsi3(1, 0, 0);
25 try test_one_mulsi3(0, 10, 0);
26 try test_one_mulsi3(10, 0, 0);
27 try test_one_mulsi3(0, maxInt(i32), 0);
28 try test_one_mulsi3(maxInt(i32), 0, 0);
29 try test_one_mulsi3(0, -1, 0);
30 try test_one_mulsi3(-1, 0, 0);
31 try test_one_mulsi3(0, -10, 0);
32 try test_one_mulsi3(-10, 0, 0);
33 try test_one_mulsi3(0, minInt(i32), 0);
34 try test_one_mulsi3(minInt(i32), 0, 0);
35 try test_one_mulsi3(1, 1, 1);
36 try test_one_mulsi3(1, 10, 10);
37 try test_one_mulsi3(10, 1, 10);
38 try test_one_mulsi3(1, maxInt(i32), maxInt(i32));
39 try test_one_mulsi3(maxInt(i32), 1, maxInt(i32));
40 try test_one_mulsi3(1, -1, -1);
41 try test_one_mulsi3(1, -10, -10);
42 try test_one_mulsi3(-10, 1, -10);
43 try test_one_mulsi3(1, minInt(i32), minInt(i32));
44 try test_one_mulsi3(minInt(i32), 1, minInt(i32));
45 try test_one_mulsi3(46340, 46340, 2147395600);
46 try test_one_mulsi3(-46340, 46340, -2147395600);
47 try test_one_mulsi3(46340, -46340, -2147395600);
48 try test_one_mulsi3(-46340, -46340, 2147395600);
49 try test_one_mulsi3(4194303, 8192, @truncate(i32, 34359730176));
50 try test_one_mulsi3(-4194303, 8192, @truncate(i32, -34359730176));
51 try test_one_mulsi3(4194303, -8192, @truncate(i32, -34359730176));
52 try test_one_mulsi3(-4194303, -8192, @truncate(i32, 34359730176));
53 try test_one_mulsi3(8192, 4194303, @truncate(i32, 34359730176));
54 try test_one_mulsi3(-8192, 4194303, @truncate(i32, -34359730176));
55 try test_one_mulsi3(8192, -4194303, @truncate(i32, -34359730176));
56 try test_one_mulsi3(-8192, -4194303, @truncate(i32, 34359730176));
57}
58
59test "muldi3" {
60 try test__muldi3(0, 0, 0);
61 try test__muldi3(0, 1, 0);
62 try test__muldi3(1, 0, 0);
63 try test__muldi3(0, 10, 0);
64 try test__muldi3(10, 0, 0);
65 try test__muldi3(0, 81985529216486895, 0);
66 try test__muldi3(81985529216486895, 0, 0);
67
68 try test__muldi3(0, -1, 0);
69 try test__muldi3(-1, 0, 0);
70 try test__muldi3(0, -10, 0);
71 try test__muldi3(-10, 0, 0);
72 try test__muldi3(0, -81985529216486895, 0);
73 try test__muldi3(-81985529216486895, 0, 0);
74
75 try test__muldi3(1, 1, 1);
76 try test__muldi3(1, 10, 10);
77 try test__muldi3(10, 1, 10);
78 try test__muldi3(1, 81985529216486895, 81985529216486895);
79 try test__muldi3(81985529216486895, 1, 81985529216486895);
80
81 try test__muldi3(1, -1, -1);
82 try test__muldi3(1, -10, -10);
83 try test__muldi3(-10, 1, -10);
84 try test__muldi3(1, -81985529216486895, -81985529216486895);
85 try test__muldi3(-81985529216486895, 1, -81985529216486895);
86
87 try test__muldi3(3037000499, 3037000499, 9223372030926249001);
88 try test__muldi3(-3037000499, 3037000499, -9223372030926249001);
89 try test__muldi3(3037000499, -3037000499, -9223372030926249001);
90 try test__muldi3(-3037000499, -3037000499, 9223372030926249001);
91
92 try test__muldi3(4398046511103, 2097152, 9223372036852678656);
93 try test__muldi3(-4398046511103, 2097152, -9223372036852678656);
94 try test__muldi3(4398046511103, -2097152, -9223372036852678656);
95 try test__muldi3(-4398046511103, -2097152, 9223372036852678656);
96
97 try test__muldi3(2097152, 4398046511103, 9223372036852678656);
98 try test__muldi3(-2097152, 4398046511103, -9223372036852678656);
99 try test__muldi3(2097152, -4398046511103, -9223372036852678656);
100 try test__muldi3(-2097152, -4398046511103, 9223372036852678656);
101}
102
103test "multi3" {
104 try test__multi3(0, 0, 0);
105 try test__multi3(0, 1, 0);
106 try test__multi3(1, 0, 0);
107 try test__multi3(0, 10, 0);
108 try test__multi3(10, 0, 0);
109 try test__multi3(0, 81985529216486895, 0);
110 try test__multi3(81985529216486895, 0, 0);
111
112 try test__multi3(0, -1, 0);
113 try test__multi3(-1, 0, 0);
114 try test__multi3(0, -10, 0);
115 try test__multi3(-10, 0, 0);
116 try test__multi3(0, -81985529216486895, 0);
117 try test__multi3(-81985529216486895, 0, 0);
118
119 try test__multi3(1, 1, 1);
120 try test__multi3(1, 10, 10);
121 try test__multi3(10, 1, 10);
122 try test__multi3(1, 81985529216486895, 81985529216486895);
123 try test__multi3(81985529216486895, 1, 81985529216486895);
124
125 try test__multi3(1, -1, -1);
126 try test__multi3(1, -10, -10);
127 try test__multi3(-10, 1, -10);
128 try test__multi3(1, -81985529216486895, -81985529216486895);
129 try test__multi3(-81985529216486895, 1, -81985529216486895);
130
131 try test__multi3(3037000499, 3037000499, 9223372030926249001);
132 try test__multi3(-3037000499, 3037000499, -9223372030926249001);
133 try test__multi3(3037000499, -3037000499, -9223372030926249001);
134 try test__multi3(-3037000499, -3037000499, 9223372030926249001);
135
136 try test__multi3(4398046511103, 2097152, 9223372036852678656);
137 try test__multi3(-4398046511103, 2097152, -9223372036852678656);
138 try test__multi3(4398046511103, -2097152, -9223372036852678656);
139 try test__multi3(-4398046511103, -2097152, 9223372036852678656);
140
141 try test__multi3(2097152, 4398046511103, 9223372036852678656);
142 try test__multi3(-2097152, 4398046511103, -9223372036852678656);
143 try test__multi3(2097152, -4398046511103, -9223372036852678656);
144 try test__multi3(-2097152, -4398046511103, 9223372036852678656);
145
146 try test__multi3(0x00000000000000B504F333F9DE5BE000, 0x000000000000000000B504F333F9DE5B, 0x7FFFFFFFFFFFF328DF915DA296E8A000);
147}
lib/compiler_rt/muldi3.zig deleted-71
...@@ -1,71 +0,0 @@
1//! Ported from
2//! https://github.com/llvm/llvm-project/blob/llvmorg-9.0.0/compiler-rt/lib/builtins/muldi3.c
3
4const std = @import("std");
5const builtin = @import("builtin");
6const native_endian = builtin.cpu.arch.endian();
7const common = @import("common.zig");
8
9pub const panic = common.panic;
10
11comptime {
12 if (common.want_aeabi) {
13 @export(__aeabi_lmul, .{ .name = "__aeabi_lmul", .linkage = common.linkage, .visibility = common.visibility });
14 } else {
15 @export(__muldi3, .{ .name = "__muldi3", .linkage = common.linkage, .visibility = common.visibility });
16 }
17}
18
19pub fn __muldi3(a: i64, b: i64) callconv(.C) i64 {
20 return mul(a, b);
21}
22
23fn __aeabi_lmul(a: i64, b: i64) callconv(.AAPCS) i64 {
24 return mul(a, b);
25}
26
27inline fn mul(a: i64, b: i64) i64 {
28 const x = dwords{ .all = a };
29 const y = dwords{ .all = b };
30 var r = dwords{ .all = muldsi3(x.s.low, y.s.low) };
31 r.s.high +%= x.s.high *% y.s.low +% x.s.low *% y.s.high;
32 return r.all;
33}
34
35const dwords = extern union {
36 all: i64,
37 s: switch (native_endian) {
38 .Little => extern struct {
39 low: u32,
40 high: u32,
41 },
42 .Big => extern struct {
43 high: u32,
44 low: u32,
45 },
46 },
47};
48
49fn muldsi3(a: u32, b: u32) i64 {
50 const bits_in_word_2 = @sizeOf(i32) * 8 / 2;
51 const lower_mask = (~@as(u32, 0)) >> bits_in_word_2;
52
53 var r: dwords = undefined;
54 r.s.low = (a & lower_mask) *% (b & lower_mask);
55 var t: u32 = r.s.low >> bits_in_word_2;
56 r.s.low &= lower_mask;
57 t += (a >> bits_in_word_2) *% (b & lower_mask);
58 r.s.low +%= (t & lower_mask) << bits_in_word_2;
59 r.s.high = t >> bits_in_word_2;
60 t = r.s.low >> bits_in_word_2;
61 r.s.low &= lower_mask;
62 t +%= (b >> bits_in_word_2) *% (a & lower_mask);
63 r.s.low +%= (t & lower_mask) << bits_in_word_2;
64 r.s.high +%= t >> bits_in_word_2;
65 r.s.high +%= (a >> bits_in_word_2) *% (b >> bits_in_word_2);
66 return r.all;
67}
68
69test {
70 _ = @import("muldi3_test.zig");
71}
lib/compiler_rt/muldi3_test.zig deleted-51
...@@ -1,51 +0,0 @@
1const __muldi3 = @import("muldi3.zig").__muldi3;
2const testing = @import("std").testing;
3
4fn test__muldi3(a: i64, b: i64, expected: i64) !void {
5 const x = __muldi3(a, b);
6 try testing.expect(x == expected);
7}
8
9test "muldi3" {
10 try test__muldi3(0, 0, 0);
11 try test__muldi3(0, 1, 0);
12 try test__muldi3(1, 0, 0);
13 try test__muldi3(0, 10, 0);
14 try test__muldi3(10, 0, 0);
15 try test__muldi3(0, 81985529216486895, 0);
16 try test__muldi3(81985529216486895, 0, 0);
17
18 try test__muldi3(0, -1, 0);
19 try test__muldi3(-1, 0, 0);
20 try test__muldi3(0, -10, 0);
21 try test__muldi3(-10, 0, 0);
22 try test__muldi3(0, -81985529216486895, 0);
23 try test__muldi3(-81985529216486895, 0, 0);
24
25 try test__muldi3(1, 1, 1);
26 try test__muldi3(1, 10, 10);
27 try test__muldi3(10, 1, 10);
28 try test__muldi3(1, 81985529216486895, 81985529216486895);
29 try test__muldi3(81985529216486895, 1, 81985529216486895);
30
31 try test__muldi3(1, -1, -1);
32 try test__muldi3(1, -10, -10);
33 try test__muldi3(-10, 1, -10);
34 try test__muldi3(1, -81985529216486895, -81985529216486895);
35 try test__muldi3(-81985529216486895, 1, -81985529216486895);
36
37 try test__muldi3(3037000499, 3037000499, 9223372030926249001);
38 try test__muldi3(-3037000499, 3037000499, -9223372030926249001);
39 try test__muldi3(3037000499, -3037000499, -9223372030926249001);
40 try test__muldi3(-3037000499, -3037000499, 9223372030926249001);
41
42 try test__muldi3(4398046511103, 2097152, 9223372036852678656);
43 try test__muldi3(-4398046511103, 2097152, -9223372036852678656);
44 try test__muldi3(4398046511103, -2097152, -9223372036852678656);
45 try test__muldi3(-4398046511103, -2097152, 9223372036852678656);
46
47 try test__muldi3(2097152, 4398046511103, 9223372036852678656);
48 try test__muldi3(-2097152, 4398046511103, -9223372036852678656);
49 try test__muldi3(2097152, -4398046511103, -9223372036852678656);
50 try test__muldi3(-2097152, -4398046511103, 9223372036852678656);
51}
lib/compiler_rt/multi3.zig deleted-75
...@@ -1,75 +0,0 @@
1//! Ported from git@github.com:llvm-project/llvm-project-20170507.git
2//! ae684fad6d34858c014c94da69c15e7774a633c3
3//! 2018-08-13
4
5const std = @import("std");
6const builtin = @import("builtin");
7const native_endian = builtin.cpu.arch.endian();
8const common = @import("common.zig");
9
10pub const panic = common.panic;
11
12comptime {
13 if (common.want_windows_v2u64_abi) {
14 @export(__multi3_windows_x86_64, .{ .name = "__multi3", .linkage = common.linkage, .visibility = common.visibility });
15 } else {
16 @export(__multi3, .{ .name = "__multi3", .linkage = common.linkage, .visibility = common.visibility });
17 }
18}
19
20pub fn __multi3(a: i128, b: i128) callconv(.C) i128 {
21 return mul(a, b);
22}
23
24const v2u64 = @Vector(2, u64);
25
26fn __multi3_windows_x86_64(a: v2u64, b: v2u64) callconv(.C) v2u64 {
27 return @bitCast(v2u64, mul(@bitCast(i128, a), @bitCast(i128, b)));
28}
29
30inline fn mul(a: i128, b: i128) i128 {
31 const x = twords{ .all = a };
32 const y = twords{ .all = b };
33 var r = twords{ .all = mulddi3(x.s.low, y.s.low) };
34 r.s.high +%= x.s.high *% y.s.low +% x.s.low *% y.s.high;
35 return r.all;
36}
37
38fn mulddi3(a: u64, b: u64) i128 {
39 const bits_in_dword_2 = (@sizeOf(i64) * 8) / 2;
40 const lower_mask = ~@as(u64, 0) >> bits_in_dword_2;
41 var r: twords = undefined;
42 r.s.low = (a & lower_mask) *% (b & lower_mask);
43 var t: u64 = r.s.low >> bits_in_dword_2;
44 r.s.low &= lower_mask;
45 t +%= (a >> bits_in_dword_2) *% (b & lower_mask);
46 r.s.low +%= (t & lower_mask) << bits_in_dword_2;
47 r.s.high = t >> bits_in_dword_2;
48 t = r.s.low >> bits_in_dword_2;
49 r.s.low &= lower_mask;
50 t +%= (b >> bits_in_dword_2) *% (a & lower_mask);
51 r.s.low +%= (t & lower_mask) << bits_in_dword_2;
52 r.s.high +%= t >> bits_in_dword_2;
53 r.s.high +%= (a >> bits_in_dword_2) *% (b >> bits_in_dword_2);
54 return r.all;
55}
56
57const twords = extern union {
58 all: i128,
59 s: S,
60
61 const S = if (native_endian == .Little)
62 extern struct {
63 low: u64,
64 high: u64,
65 }
66 else
67 extern struct {
68 high: u64,
69 low: u64,
70 };
71};
72
73test {
74 _ = @import("multi3_test.zig");
75}
lib/compiler_rt/multi3_test.zig deleted-53
...@@ -1,53 +0,0 @@
1const __multi3 = @import("multi3.zig").__multi3;
2const testing = @import("std").testing;
3
4fn test__multi3(a: i128, b: i128, expected: i128) !void {
5 const x = __multi3(a, b);
6 try testing.expect(x == expected);
7}
8
9test "multi3" {
10 try test__multi3(0, 0, 0);
11 try test__multi3(0, 1, 0);
12 try test__multi3(1, 0, 0);
13 try test__multi3(0, 10, 0);
14 try test__multi3(10, 0, 0);
15 try test__multi3(0, 81985529216486895, 0);
16 try test__multi3(81985529216486895, 0, 0);
17
18 try test__multi3(0, -1, 0);
19 try test__multi3(-1, 0, 0);
20 try test__multi3(0, -10, 0);
21 try test__multi3(-10, 0, 0);
22 try test__multi3(0, -81985529216486895, 0);
23 try test__multi3(-81985529216486895, 0, 0);
24
25 try test__multi3(1, 1, 1);
26 try test__multi3(1, 10, 10);
27 try test__multi3(10, 1, 10);
28 try test__multi3(1, 81985529216486895, 81985529216486895);
29 try test__multi3(81985529216486895, 1, 81985529216486895);
30
31 try test__multi3(1, -1, -1);
32 try test__multi3(1, -10, -10);
33 try test__multi3(-10, 1, -10);
34 try test__multi3(1, -81985529216486895, -81985529216486895);
35 try test__multi3(-81985529216486895, 1, -81985529216486895);
36
37 try test__multi3(3037000499, 3037000499, 9223372030926249001);
38 try test__multi3(-3037000499, 3037000499, -9223372030926249001);
39 try test__multi3(3037000499, -3037000499, -9223372030926249001);
40 try test__multi3(-3037000499, -3037000499, 9223372030926249001);
41
42 try test__multi3(4398046511103, 2097152, 9223372036852678656);
43 try test__multi3(-4398046511103, 2097152, -9223372036852678656);
44 try test__multi3(4398046511103, -2097152, -9223372036852678656);
45 try test__multi3(-4398046511103, -2097152, 9223372036852678656);
46
47 try test__multi3(2097152, 4398046511103, 9223372036852678656);
48 try test__multi3(-2097152, 4398046511103, -9223372036852678656);
49 try test__multi3(2097152, -4398046511103, -9223372036852678656);
50 try test__multi3(-2097152, -4398046511103, 9223372036852678656);
51
52 try test__multi3(0x00000000000000B504F333F9DE5BE000, 0x000000000000000000B504F333F9DE5B, 0x7FFFFFFFFFFFF328DF915DA296E8A000);
53}
lib/compiler_rt/shift.zig+24-40
...@@ -1,7 +1,6 @@...@@ -1,7 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const Log2Int = std.math.Log2Int;3const Log2Int = std.math.Log2Int;
4const native_endian = builtin.cpu.arch.endian();
5const common = @import("common.zig");4const common = @import("common.zig");
65
7pub const panic = common.panic;6pub const panic = common.panic;
...@@ -27,39 +26,24 @@ comptime {...@@ -27,39 +26,24 @@ comptime {
27 }26 }
28}27}
2928
30fn Dwords(comptime T: type, comptime signed_half: bool) type {
31 return extern union {
32 const bits = @divExact(@typeInfo(T).Int.bits, 2);
33 const HalfTU = std.meta.Int(.unsigned, bits);
34 const HalfTS = std.meta.Int(.signed, bits);
35 const HalfT = if (signed_half) HalfTS else HalfTU;
36
37 all: T,
38 s: if (native_endian == .Little)
39 extern struct { low: HalfT, high: HalfT }
40 else
41 extern struct { high: HalfT, low: HalfT },
42 };
43}
44
45// Arithmetic shift left: shift in 0 from right to left29// Arithmetic shift left: shift in 0 from right to left
46// Precondition: 0 <= b < bits_in_dword30// Precondition: 0 <= b < bits_in_dword
47inline fn ashlXi3(comptime T: type, a: T, b: i32) T {31inline fn ashlXi3(comptime T: type, a: T, b: i32) T {
48 const dwords = Dwords(T, false);32 const word_t = common.HalveInt(T, false);
49 const S = Log2Int(dwords.HalfT);33 const S = Log2Int(word_t.HalfT);
5034
51 const input = dwords{ .all = a };35 const input = word_t{ .all = a };
52 var output: dwords = undefined;36 var output: word_t = undefined;
5337
54 if (b >= dwords.bits) {38 if (b >= word_t.bits) {
55 output.s.low = 0;39 output.s.low = 0;
56 output.s.high = input.s.low << @intCast(S, b - dwords.bits);40 output.s.high = input.s.low << @intCast(S, b - word_t.bits);
57 } else if (b == 0) {41 } else if (b == 0) {
58 return a;42 return a;
59 } else {43 } else {
60 output.s.low = input.s.low << @intCast(S, b);44 output.s.low = input.s.low << @intCast(S, b);
61 output.s.high = input.s.high << @intCast(S, b);45 output.s.high = input.s.high << @intCast(S, b);
62 output.s.high |= input.s.low >> @intCast(S, dwords.bits - b);46 output.s.high |= input.s.low >> @intCast(S, word_t.bits - b);
63 }47 }
6448
65 return output.all;49 return output.all;
...@@ -68,24 +52,24 @@ inline fn ashlXi3(comptime T: type, a: T, b: i32) T {...@@ -68,24 +52,24 @@ inline fn ashlXi3(comptime T: type, a: T, b: i32) T {
68// Arithmetic shift right: shift in 1 from left to right52// Arithmetic shift right: shift in 1 from left to right
69// Precondition: 0 <= b < T.bit_count53// Precondition: 0 <= b < T.bit_count
70inline fn ashrXi3(comptime T: type, a: T, b: i32) T {54inline fn ashrXi3(comptime T: type, a: T, b: i32) T {
71 const dwords = Dwords(T, true);55 const word_t = common.HalveInt(T, true);
72 const S = Log2Int(dwords.HalfT);56 const S = Log2Int(word_t.HalfT);
7357
74 const input = dwords{ .all = a };58 const input = word_t{ .all = a };
75 var output: dwords = undefined;59 var output: word_t = undefined;
7660
77 if (b >= dwords.bits) {61 if (b >= word_t.bits) {
78 output.s.high = input.s.high >> (dwords.bits - 1);62 output.s.high = input.s.high >> (word_t.bits - 1);
79 output.s.low = input.s.high >> @intCast(S, b - dwords.bits);63 output.s.low = input.s.high >> @intCast(S, b - word_t.bits);
80 } else if (b == 0) {64 } else if (b == 0) {
81 return a;65 return a;
82 } else {66 } else {
83 output.s.high = input.s.high >> @intCast(S, b);67 output.s.high = input.s.high >> @intCast(S, b);
84 output.s.low = input.s.high << @intCast(S, dwords.bits - b);68 output.s.low = input.s.high << @intCast(S, word_t.bits - b);
85 // Avoid sign-extension here69 // Avoid sign-extension here
86 output.s.low |= @bitCast(70 output.s.low |= @bitCast(
87 dwords.HalfT,71 word_t.HalfT,
88 @bitCast(dwords.HalfTU, input.s.low) >> @intCast(S, b),72 @bitCast(word_t.HalfTU, input.s.low) >> @intCast(S, b),
89 );73 );
90 }74 }
9175
...@@ -95,20 +79,20 @@ inline fn ashrXi3(comptime T: type, a: T, b: i32) T {...@@ -95,20 +79,20 @@ inline fn ashrXi3(comptime T: type, a: T, b: i32) T {
95// Logical shift right: shift in 0 from left to right79// Logical shift right: shift in 0 from left to right
96// Precondition: 0 <= b < T.bit_count80// Precondition: 0 <= b < T.bit_count
97inline fn lshrXi3(comptime T: type, a: T, b: i32) T {81inline fn lshrXi3(comptime T: type, a: T, b: i32) T {
98 const dwords = Dwords(T, false);82 const word_t = common.HalveInt(T, false);
99 const S = Log2Int(dwords.HalfT);83 const S = Log2Int(word_t.HalfT);
10084
101 const input = dwords{ .all = a };85 const input = word_t{ .all = a };
102 var output: dwords = undefined;86 var output: word_t = undefined;
10387
104 if (b >= dwords.bits) {88 if (b >= word_t.bits) {
105 output.s.high = 0;89 output.s.high = 0;
106 output.s.low = input.s.high >> @intCast(S, b - dwords.bits);90 output.s.low = input.s.high >> @intCast(S, b - word_t.bits);
107 } else if (b == 0) {91 } else if (b == 0) {
108 return a;92 return a;
109 } else {93 } else {
110 output.s.high = input.s.high >> @intCast(S, b);94 output.s.high = input.s.high >> @intCast(S, b);
111 output.s.low = input.s.high << @intCast(S, dwords.bits - b);95 output.s.low = input.s.high << @intCast(S, word_t.bits - b);
112 output.s.low |= input.s.low >> @intCast(S, b);96 output.s.low |= input.s.low >> @intCast(S, b);
113 }97 }
11498
lib/docs/main.js+89-91
...@@ -106,7 +106,7 @@ const NAV_MODES = {...@@ -106,7 +106,7 @@ const NAV_MODES = {
106 // empty array means refers to the package itself106 // empty array means refers to the package itself
107 declNames: [],107 declNames: [],
108 // these will be all types, except the last one may be a type or a decl108 // these will be all types, except the last one may be a type or a decl
109 declObjs: [], 109 declObjs: [],
110 // (a, b, c, d) comptime call; result is the value the docs refer to110 // (a, b, c, d) comptime call; result is the value the docs refer to
111 callName: null,111 callName: null,
112 };112 };
...@@ -200,7 +200,7 @@ const NAV_MODES = {...@@ -200,7 +200,7 @@ const NAV_MODES = {
200 case NAV_MODES.GUIDES:200 case NAV_MODES.GUIDES:
201 document.title = "[G] " + curNav.activeGuide + suffix;201 document.title = "[G] " + curNav.activeGuide + suffix;
202 return;202 return;
203 } 203 }
204 }204 }
205205
206 function isDecl(x) {206 function isDecl(x) {
...@@ -401,7 +401,7 @@ const NAV_MODES = {...@@ -401,7 +401,7 @@ const NAV_MODES = {
401 domGuideSwitch.classList.add("active");401 domGuideSwitch.classList.add("active");
402 domApiSwitch.classList.remove("active");402 domApiSwitch.classList.remove("active");
403 domDocs.classList.add("hidden");403 domDocs.classList.add("hidden");
404 domGuides.classList.remove("hidden"); 404 domGuides.classList.remove("hidden");
405 domApiMenu.classList.add("hidden");405 domApiMenu.classList.add("hidden");
406406
407 // sidebar guides list407 // sidebar guides list
...@@ -422,7 +422,7 @@ const NAV_MODES = {...@@ -422,7 +422,7 @@ const NAV_MODES = {
422 if (list.length > 0) {422 if (list.length > 0) {
423 domGuidesMenu.classList.remove("hidden");423 domGuidesMenu.classList.remove("hidden");
424 }424 }
425 425
426 // main content426 // main content
427 const activeGuide = zigAnalysis.guides[curNav.activeGuide];427 const activeGuide = zigAnalysis.guides[curNav.activeGuide];
428 if (activeGuide == undefined) {428 if (activeGuide == undefined) {
...@@ -454,7 +454,7 @@ const NAV_MODES = {...@@ -454,7 +454,7 @@ const NAV_MODES = {
454454
455 Happy writing!455 Happy writing!
456 `);456 `);
457 } else { 457 } else {
458 domGuides.innerHTML = markdown(activeGuide);458 domGuides.innerHTML = markdown(activeGuide);
459 }459 }
460 }460 }
...@@ -467,7 +467,7 @@ const NAV_MODES = {...@@ -467,7 +467,7 @@ const NAV_MODES = {
467 domDocs.classList.remove("hidden");467 domDocs.classList.remove("hidden");
468 domApiMenu.classList.remove("hidden");468 domApiMenu.classList.remove("hidden");
469 domGuidesMenu.classList.add("hidden");469 domGuidesMenu.classList.add("hidden");
470 470
471 domStatus.classList.add("hidden");471 domStatus.classList.add("hidden");
472 domFnProto.classList.add("hidden");472 domFnProto.classList.add("hidden");
473 domSectParams.classList.add("hidden");473 domSectParams.classList.add("hidden");
...@@ -537,9 +537,9 @@ const NAV_MODES = {...@@ -537,9 +537,9 @@ const NAV_MODES = {
537 currentType = childDecl;537 currentType = childDecl;
538 curNav.declObjs.push(currentType);538 curNav.declObjs.push(currentType);
539 }539 }
540 540
541 541
542 542
543 window.x = currentType;543 window.x = currentType;
544544
545 renderNav();545 renderNav();
...@@ -586,15 +586,15 @@ const NAV_MODES = {...@@ -586,15 +586,15 @@ const NAV_MODES = {
586 switch (curNav.mode) {586 switch (curNav.mode) {
587 case NAV_MODES.API:587 case NAV_MODES.API:
588 case NAV_MODES.API_INTERNAL:588 case NAV_MODES.API_INTERNAL:
589 return renderApi();589 return renderApi();
590 case NAV_MODES.GUIDES:590 case NAV_MODES.GUIDES:
591 return renderGuides();591 return renderGuides();
592 default:592 default:
593 throw "?";593 throw "?";
594 } 594 }
595 }595 }
596596
597 597
598 function renderDocTest(decl) {598 function renderDocTest(decl) {
599 if (!decl.decltest) return;599 if (!decl.decltest) return;
600 const astNode = getAstNode(decl.decltest);600 const astNode = getAstNode(decl.decltest);
...@@ -651,7 +651,7 @@ const NAV_MODES = {...@@ -651,7 +651,7 @@ const NAV_MODES = {
651 wantLink: true,651 wantLink: true,
652 fnDecl,652 fnDecl,
653 });653 });
654 654
655 domFnSourceLink.innerHTML = "[<a target=\"_blank\" href=\"" + sourceFileLink(fnDecl) + "\">src</a>]";655 domFnSourceLink.innerHTML = "[<a target=\"_blank\" href=\"" + sourceFileLink(fnDecl) + "\">src</a>]";
656656
657 let docsSource = null;657 let docsSource = null;
...@@ -895,7 +895,7 @@ const NAV_MODES = {...@@ -895,7 +895,7 @@ const NAV_MODES = {
895895
896 function navLink(pkgNames, declNames, callName) {896 function navLink(pkgNames, declNames, callName) {
897 let base = curNav.mode;897 let base = curNav.mode;
898 898
899 if (pkgNames.length === 0 && declNames.length === 0) {899 if (pkgNames.length === 0 && declNames.length === 0) {
900 return base;900 return base;
901 } else if (declNames.length === 0 && callName == null) {901 } else if (declNames.length === 0 && callName == null) {
...@@ -919,18 +919,18 @@ const NAV_MODES = {...@@ -919,18 +919,18 @@ const NAV_MODES = {
919919
920 function findDeclNavLink(declName) {920 function findDeclNavLink(declName) {
921 if (curNav.declObjs.length == 0) return null;921 if (curNav.declObjs.length == 0) return null;
922 const curFile = getAstNode(curNav.declObjs[curNav.declObjs.length-1].src).file;922 const curFile = getAstNode(curNav.declObjs[curNav.declObjs.length - 1].src).file;
923 923
924 for (let i = curNav.declObjs.length -1; i >= 0; i--) {924 for (let i = curNav.declObjs.length - 1; i >= 0; i--) {
925 const curDecl = curNav.declObjs[i];925 const curDecl = curNav.declObjs[i];
926 const curDeclName = curNav.declNames[i-1];926 const curDeclName = curNav.declNames[i - 1];
927 if (curDeclName == declName) {927 if (curDeclName == declName) {
928 const declPath = curNav.declNames.slice(0,i);928 const declPath = curNav.declNames.slice(0, i);
929 return navLink(curNav.pkgNames, declPath);929 return navLink(curNav.pkgNames, declPath);
930 } 930 }
931931
932 if (findSubDecl(curDecl, declName) != null) { 932 if (findSubDecl(curDecl, declName) != null) {
933 const declPath = curNav.declNames.slice(0,i).concat([declName]);933 const declPath = curNav.declNames.slice(0, i).concat([declName]);
934 return navLink(curNav.pkgNames, declPath);934 return navLink(curNav.pkgNames, declPath);
935 }935 }
936 }936 }
...@@ -1366,10 +1366,6 @@ const NAV_MODES = {...@@ -1366,10 +1366,6 @@ const NAV_MODES = {
1366 payloadHtml += "truncate";1366 payloadHtml += "truncate";
1367 break;1367 break;
1368 }1368 }
1369 case "align_cast": {
1370 payloadHtml += "alignCast";
1371 break;
1372 }
1373 case "has_decl": {1369 case "has_decl": {
1374 payloadHtml += "hasDecl";1370 payloadHtml += "hasDecl";
1375 break;1371 break;
...@@ -1700,15 +1696,15 @@ const NAV_MODES = {...@@ -1700,15 +1696,15 @@ const NAV_MODES = {
1700 }1696 }
1701 case "declRef": {1697 case "declRef": {
1702 const name = getDecl(expr.declRef).name;1698 const name = getDecl(expr.declRef).name;
1703 1699
1704 if (opts.wantHtml) {1700 if (opts.wantHtml) {
1705 let payloadHtml = "";1701 let payloadHtml = "";
1706 if (opts.wantLink) {1702 if (opts.wantLink) {
1707 payloadHtml += '<a href="'+ findDeclNavLink(name) +'">'; 1703 payloadHtml += '<a href="' + findDeclNavLink(name) + '">';
1708 }1704 }
1709 payloadHtml +=1705 payloadHtml +=
1710 '<span class="tok-kw" style="color:lightblue;">' +1706 '<span class="tok-kw" style="color:lightblue;">' +
1711 name +1707 name +
1712 "</span>";1708 "</span>";
1713 if (opts.wantLink) payloadHtml += "</a>";1709 if (opts.wantLink) payloadHtml += "</a>";
1714 return payloadHtml;1710 return payloadHtml;
...@@ -1728,12 +1724,12 @@ const NAV_MODES = {...@@ -1728,12 +1724,12 @@ const NAV_MODES = {
1728 if ("string" in expr.refPath[i]) {1724 if ("string" in expr.refPath[i]) {
1729 component = expr.refPath[i].string;1725 component = expr.refPath[i].string;
1730 } else {1726 } else {
1731 component = exprName(expr.refPath[i], {...opts, wantLink: false});1727 component = exprName(expr.refPath[i], { ...opts, wantLink: false });
1732 if (opts.wantLink && "declRef" in expr.refPath[i]) {1728 if (opts.wantLink && "declRef" in expr.refPath[i]) {
1733 url += "." + getDecl(expr.refPath[i].declRef).name;1729 url += "." + getDecl(expr.refPath[i].declRef).name;
1734 component = '<a href="'+ url +'">' +1730 component = '<a href="' + url + '">' +
1735 component +1731 component +
1736 "</a>"; 1732 "</a>";
1737 }1733 }
1738 }1734 }
1739 name += "." + component;1735 name += "." + component;
...@@ -1792,12 +1788,12 @@ const NAV_MODES = {...@@ -1792,12 +1788,12 @@ const NAV_MODES = {
1792 name = "struct { ";1788 name = "struct { ";
1793 }1789 }
1794 }1790 }
1795 if (structObj.fields.length > 1 && opts.wantHtml) {name += "</br>";}1791 if (structObj.fields.length > 1 && opts.wantHtml) { name += "</br>"; }
1796 let indent = "";1792 let indent = "";
1797 if (structObj.fields.length > 1 && opts.wantHtml) {1793 if (structObj.fields.length > 1 && opts.wantHtml) {
1798 indent = "&nbsp;&nbsp;&nbsp;&nbsp;"1794 indent = "&nbsp;&nbsp;&nbsp;&nbsp;"
1799 }1795 }
1800 if (opts.indent) {1796 if (opts.indent && structObj.fields.length > 1) {
1801 indent = opts.indent + indent;1797 indent = opts.indent + indent;
1802 }1798 }
1803 let structNode = getAstNode(structObj.src);1799 let structNode = getAstNode(structObj.src);
...@@ -1808,7 +1804,7 @@ const NAV_MODES = {...@@ -1808,7 +1804,7 @@ const NAV_MODES = {
1808 field_end += " ";1804 field_end += " ";
1809 }1805 }
18101806
1811 for(let i = 0; i < structObj.fields.length; i += 1) {1807 for (let i = 0; i < structObj.fields.length; i += 1) {
1812 let fieldNode = getAstNode(structNode.fields[i]);1808 let fieldNode = getAstNode(structNode.fields[i]);
1813 let fieldName = fieldNode.name;1809 let fieldName = fieldNode.name;
1814 let html = indent;1810 let html = indent;
...@@ -1817,17 +1813,17 @@ const NAV_MODES = {...@@ -1817,17 +1813,17 @@ const NAV_MODES = {
1817 }1813 }
18181814
1819 let fieldTypeExpr = structObj.fields[i];1815 let fieldTypeExpr = structObj.fields[i];
1820 if(!structObj.is_tuple) {1816 if (!structObj.is_tuple) {
1821 html += ": ";1817 html += ": ";
1822 }1818 }
18231819
1824 html += exprName(fieldTypeExpr, {...opts, indent: indent});1820 html += exprName(fieldTypeExpr, { ...opts, indent: indent });
18251821
1826 html += field_end;1822 html += field_end;
18271823
1828 name += html;1824 name += html;
1829 }1825 }
1830 if (opts.indent) {1826 if (opts.indent && structObj.fields.length > 1) {
1831 name += opts.indent;1827 name += opts.indent;
1832 }1828 }
1833 name += "}";1829 name += "}";
...@@ -1850,7 +1846,7 @@ const NAV_MODES = {...@@ -1850,7 +1846,7 @@ const NAV_MODES = {
1850 if (enumObj.nonexhaustive) {1846 if (enumObj.nonexhaustive) {
1851 fields_len += 1;1847 fields_len += 1;
1852 }1848 }
1853 if (fields_len > 1 && opts.wantHtml) {name += "</br>";}1849 if (fields_len > 1 && opts.wantHtml) { name += "</br>"; }
1854 let indent = "";1850 let indent = "";
1855 if (fields_len > 1) {1851 if (fields_len > 1) {
1856 if (opts.wantHtml) {1852 if (opts.wantHtml) {
...@@ -1868,10 +1864,10 @@ const NAV_MODES = {...@@ -1868,10 +1864,10 @@ const NAV_MODES = {
1868 } else {1864 } else {
1869 field_end += " ";1865 field_end += " ";
1870 }1866 }
1871 for(let i = 0; i < enumNode.fields.length; i += 1) {1867 for (let i = 0; i < enumNode.fields.length; i += 1) {
1872 let fieldNode = getAstNode(enumNode.fields[i]);1868 let fieldNode = getAstNode(enumNode.fields[i]);
1873 let fieldName = fieldNode.name;1869 let fieldName = fieldNode.name;
1874 let html = indent + escapeHtml(fieldName);1870 let html = indent + escapeHtml(fieldName);
18751871
1876 html += field_end;1872 html += field_end;
18771873
...@@ -1895,16 +1891,16 @@ const NAV_MODES = {...@@ -1895,16 +1891,16 @@ const NAV_MODES = {
1895 name = "union";1891 name = "union";
1896 }1892 }
1897 if (unionObj.auto_tag) {1893 if (unionObj.auto_tag) {
1898 if (opts.wantHtml) {1894 if (opts.wantHtml) {
1899 name += " (<span class='tok-kw'>enum</span>";1895 name += " (<span class='tok-kw'>enum</span>";
1900 } else {1896 } else {
1901 name += " (enum";1897 name += " (enum";
1902 }1898 }
1903 if (unionObj.tag) {1899 if (unionObj.tag) {
1904 name += "(" + exprName(unionObj.tag, opts) + "))";1900 name += "(" + exprName(unionObj.tag, opts) + "))";
1905 } else {1901 } else {
1906 name += ")";1902 name += ")";
1907 }1903 }
1908 } else if (unionObj.tag) {1904 } else if (unionObj.tag) {
1909 name += " (" + exprName(unionObj.tag, opts) + ")";1905 name += " (" + exprName(unionObj.tag, opts) + ")";
1910 }1906 }
...@@ -1926,7 +1922,7 @@ const NAV_MODES = {...@@ -1926,7 +1922,7 @@ const NAV_MODES = {
1926 } else {1922 } else {
1927 field_end += " ";1923 field_end += " ";
1928 }1924 }
1929 for(let i = 0; i < unionObj.fields.length; i += 1) {1925 for (let i = 0; i < unionObj.fields.length; i += 1) {
1930 let fieldNode = getAstNode(unionNode.fields[i]);1926 let fieldNode = getAstNode(unionNode.fields[i]);
1931 let fieldName = fieldNode.name;1927 let fieldName = fieldNode.name;
1932 let html = indent + escapeHtml(fieldName);1928 let html = indent + escapeHtml(fieldName);
...@@ -1934,7 +1930,7 @@ const NAV_MODES = {...@@ -1934,7 +1930,7 @@ const NAV_MODES = {
1934 let fieldTypeExpr = unionObj.fields[i];1930 let fieldTypeExpr = unionObj.fields[i];
1935 html += ": ";1931 html += ": ";
19361932
1937 html += exprName(fieldTypeExpr, {...opts, indent: indent});1933 html += exprName(fieldTypeExpr, { ...opts, indent: indent });
19381934
1939 html += field_end;1935 html += field_end;
19401936
...@@ -2163,7 +2159,7 @@ const NAV_MODES = {...@@ -2163,7 +2159,7 @@ const NAV_MODES = {
2163 opts.fnDecl = null;2159 opts.fnDecl = null;
2164 opts.linkFnNameDecl = null;2160 opts.linkFnNameDecl = null;
2165 let payloadHtml = "";2161 let payloadHtml = "";
2166 if (opts.addParensIfFnSignature && fnObj.src == 0){2162 if (opts.addParensIfFnSignature && fnObj.src == 0) {
2167 payloadHtml += "(";2163 payloadHtml += "(";
2168 }2164 }
2169 if (opts.wantHtml) {2165 if (opts.wantHtml) {
...@@ -2179,7 +2175,7 @@ const NAV_MODES = {...@@ -2179,7 +2175,7 @@ const NAV_MODES = {
2179 if (linkFnNameDecl) {2175 if (linkFnNameDecl) {
2180 payloadHtml +=2176 payloadHtml +=
2181 '<a href="' + linkFnNameDecl + '">' +2177 '<a href="' + linkFnNameDecl + '">' +
2182 escapeHtml(fnDecl.name) +2178 escapeHtml(fnDecl.name) +
2183 "</a>";2179 "</a>";
2184 } else {2180 } else {
2185 payloadHtml += escapeHtml(fnDecl.name);2181 payloadHtml += escapeHtml(fnDecl.name);
...@@ -2198,7 +2194,7 @@ const NAV_MODES = {...@@ -2198,7 +2194,7 @@ const NAV_MODES = {
2198 fields = fnNode.fields;2194 fields = fnNode.fields;
2199 isVarArgs = fnNode.varArgs;2195 isVarArgs = fnNode.varArgs;
2200 }2196 }
2201 2197
2202 for (let i = 0; i < fnObj.params.length; i += 1) {2198 for (let i = 0; i < fnObj.params.length; i += 1) {
2203 if (i != 0) {2199 if (i != 0) {
2204 payloadHtml += ", ";2200 payloadHtml += ", ";
...@@ -2251,13 +2247,13 @@ const NAV_MODES = {...@@ -2251,13 +2247,13 @@ const NAV_MODES = {
2251 } else if ("typeOf" in value) {2247 } else if ("typeOf" in value) {
2252 payloadHtml += exprName(value, opts);2248 payloadHtml += exprName(value, opts);
2253 } else if ("typeOf_peer" in value) {2249 } else if ("typeOf_peer" in value) {
2254 payloadHtml += exprName(value, opts);2250 payloadHtml += exprName(value, opts);
2255 } else if ("declRef" in value) {2251 } else if ("declRef" in value) {
2256 payloadHtml += exprName(value, opts);2252 payloadHtml += exprName(value, opts);
2257 } else if ("call" in value) {2253 } else if ("call" in value) {
2258 payloadHtml += exprName(value, opts);2254 payloadHtml += exprName(value, opts);
2259 } else if ("refPath" in value) {2255 } else if ("refPath" in value) {
2260 payloadHtml += exprName(value, opts);2256 payloadHtml += exprName(value, opts);
2261 } else if ("type" in value) {2257 } else if ("type" in value) {
2262 payloadHtml += exprName(value, opts);2258 payloadHtml += exprName(value, opts);
2263 //payloadHtml += '<span class="tok-kw">' + name + "</span>";2259 //payloadHtml += '<span class="tok-kw">' + name + "</span>";
...@@ -2301,7 +2297,7 @@ const NAV_MODES = {...@@ -2301,7 +2297,7 @@ const NAV_MODES = {
2301 }2297 }
2302 if (fnObj.ret != null) {2298 if (fnObj.ret != null) {
2303 payloadHtml += exprName(fnObj.ret, {2299 payloadHtml += exprName(fnObj.ret, {
2304 ...opts, 2300 ...opts,
2305 addParensIfFnSignature: true,2301 addParensIfFnSignature: true,
2306 });2302 });
2307 } else if (opts.wantHtml) {2303 } else if (opts.wantHtml) {
...@@ -2310,7 +2306,7 @@ const NAV_MODES = {...@@ -2310,7 +2306,7 @@ const NAV_MODES = {
2310 payloadHtml += "anytype";2306 payloadHtml += "anytype";
2311 }2307 }
23122308
2313 if (opts.addParensIfFnSignature && fnObj.src == 0){2309 if (opts.addParensIfFnSignature && fnObj.src == 0) {
2314 payloadHtml += ")";2310 payloadHtml += ")";
2315 }2311 }
2316 return payloadHtml;2312 return payloadHtml;
...@@ -2353,7 +2349,7 @@ const NAV_MODES = {...@@ -2353,7 +2349,7 @@ const NAV_MODES = {
2353 ) {2349 ) {
2354 name = "std";2350 name = "std";
2355 } else {2351 } else {
2356 name = exprName({ type: typeObj }, {wantHtml: false, wantLink: false});2352 name = exprName({ type: typeObj }, { wantHtml: false, wantLink: false });
2357 }2353 }
2358 if (name != null && name != "") {2354 if (name != null && name != "") {
2359 domHdrName.innerText =2355 domHdrName.innerText =
...@@ -2644,10 +2640,10 @@ const NAV_MODES = {...@@ -2644,10 +2640,10 @@ const NAV_MODES = {
2644 }2640 }
26452641
2646 function sourceFileLink(decl) {2642 function sourceFileLink(decl) {
2647 const srcNode = getAstNode(decl.src);2643 const srcNode = getAstNode(decl.src);
2648 return sourceFileUrlTemplate.2644 return sourceFileUrlTemplate.
2649 replace("{{file}}", zigAnalysis.files[srcNode.file]).2645 replace("{{file}}", zigAnalysis.files[srcNode.file]).
2650 replace("{{line}}", srcNode.line + 1);2646 replace("{{line}}", srcNode.line + 1);
2651 }2647 }
26522648
2653 function renderContainer(container) {2649 function renderContainer(container) {
...@@ -2783,8 +2779,8 @@ const NAV_MODES = {...@@ -2783,8 +2779,8 @@ const NAV_MODES = {
2783 if (short != docs) {2779 if (short != docs) {
2784 short = markdown(short);2780 short = markdown(short);
2785 var long = markdown(docs);2781 var long = markdown(docs);
2786 tdDesc.innerHTML = 2782 tdDesc.innerHTML =
2787 "<div class=\"expand\" ><span class=\"button\" onclick=\"toggleExpand(event)\"></span><div class=\"sum-less\">" + short + "</div>" + "<div class=\"sum-more\">" + long + "</div></details>";2783 "<div class=\"expand\" ><span class=\"button\" onclick=\"toggleExpand(event)\"></span><div class=\"sum-less\">" + short + "</div>" + "<div class=\"sum-more\">" + long + "</div></details>";
2788 }2784 }
2789 else {2785 else {
2790 tdDesc.innerHTML = markdown(short);2786 tdDesc.innerHTML = markdown(short);
...@@ -2818,10 +2814,10 @@ const NAV_MODES = {...@@ -2818,10 +2814,10 @@ const NAV_MODES = {
2818 html += ' = <span class="tok-number">' + fieldName + "</span>";2814 html += ' = <span class="tok-number">' + fieldName + "</span>";
2819 } else {2815 } else {
2820 let fieldTypeExpr = container.fields[i];2816 let fieldTypeExpr = container.fields[i];
2821 if(container.kind ==! typeKinds.Struct || !container.is_tuple) {2817 if (container.kind !== typeKinds.Struct || !container.is_tuple) {
2822 html += ": ";2818 html += ": ";
2823 }2819 }
2824 html += exprName(fieldTypeExpr, {wantHtml:true, wantLink:true});2820 html += exprName(fieldTypeExpr, { wantHtml: true, wantLink: true });
2825 let tsn = typeShorthandName(fieldTypeExpr);2821 let tsn = typeShorthandName(fieldTypeExpr);
2826 if (tsn) {2822 if (tsn) {
2827 html += "<span> (" + tsn + ")</span>";2823 html += "<span> (" + tsn + ")</span>";
...@@ -3007,8 +3003,8 @@ const NAV_MODES = {...@@ -3007,8 +3003,8 @@ const NAV_MODES = {
3007 throw new Error("No type 'type' found");3003 throw new Error("No type 'type' found");
3008 }3004 }
30093005
3010 3006
3011 function updateCurNav() { 3007 function updateCurNav() {
3012 curNav = {3008 curNav = {
3013 mode: NAV_MODES.API,3009 mode: NAV_MODES.API,
3014 pkgNames: [],3010 pkgNames: [],
...@@ -3021,7 +3017,7 @@ const NAV_MODES = {...@@ -3021,7 +3017,7 @@ const NAV_MODES = {
30213017
3022 const mode = location.hash.substring(0, 3);3018 const mode = location.hash.substring(0, 3);
3023 let query = location.hash.substring(3);3019 let query = location.hash.substring(3);
3024 3020
3025 const DEFAULT_HASH = NAV_MODES.API + zigAnalysis.packages[zigAnalysis.rootPkg].name;3021 const DEFAULT_HASH = NAV_MODES.API + zigAnalysis.packages[zigAnalysis.rootPkg].name;
3026 switch (mode) {3022 switch (mode) {
3027 case NAV_MODES.API:3023 case NAV_MODES.API:
...@@ -3037,7 +3033,7 @@ const NAV_MODES = {...@@ -3037,7 +3033,7 @@ const NAV_MODES = {
3037 nonSearchPart = query.substring(0, qpos);3033 nonSearchPart = query.substring(0, qpos);
3038 curNavSearch = decodeURIComponent(query.substring(qpos + 1));3034 curNavSearch = decodeURIComponent(query.substring(qpos + 1));
3039 }3035 }
3040 3036
3041 let parts = nonSearchPart.split(":");3037 let parts = nonSearchPart.split(":");
3042 if (parts[0] == "") {3038 if (parts[0] == "") {
3043 location.hash = DEFAULT_HASH;3039 location.hash = DEFAULT_HASH;
...@@ -3059,14 +3055,14 @@ const NAV_MODES = {...@@ -3059,14 +3055,14 @@ const NAV_MODES = {
30593055
3060 curNav.mode = mode;3056 curNav.mode = mode;
3061 curNav.activeGuide = query;3057 curNav.activeGuide = query;
3062 3058
3063 return;3059 return;
3064 default:3060 default:
3065 location.hash = DEFAULT_HASH;3061 location.hash = DEFAULT_HASH;
3066 return;3062 return;
3067 }3063 }
3068 }3064 }
3069 3065
3070 function onHashChange() {3066 function onHashChange() {
3071 updateCurNav();3067 updateCurNav();
3072 if (domSearch.value !== curNavSearch) {3068 if (domSearch.value !== curNavSearch) {
...@@ -3103,7 +3099,7 @@ const NAV_MODES = {...@@ -3103,7 +3099,7 @@ const NAV_MODES = {
3103 if (!callee.generic_ret) return null;3099 if (!callee.generic_ret) return null;
3104 resolvedGenericRet = resolveValue({ expr: callee.generic_ret });3100 resolvedGenericRet = resolveValue({ expr: callee.generic_ret });
3105 }3101 }
3106 3102
3107 if ("type" in resolvedGenericRet.expr) {3103 if ("type" in resolvedGenericRet.expr) {
3108 parentType = getType(resolvedGenericRet.expr.type);3104 parentType = getType(resolvedGenericRet.expr.type);
3109 }3105 }
...@@ -3248,7 +3244,7 @@ const NAV_MODES = {...@@ -3248,7 +3244,7 @@ const NAV_MODES = {
3248 });3244 });
3249 }3245 }
32503246
3251 function shortDesc(docs){3247 function shortDesc(docs) {
3252 const trimmed_docs = docs.trim();3248 const trimmed_docs = docs.trim();
3253 let index = trimmed_docs.indexOf("\n\n");3249 let index = trimmed_docs.indexOf("\n\n");
3254 let cut = false;3250 let cut = false;
...@@ -3319,14 +3315,16 @@ const NAV_MODES = {...@@ -3319,14 +3315,16 @@ const NAV_MODES = {
3319 } else if (line.text.startsWith("#")) {3315 } else if (line.text.startsWith("#")) {
3320 line.type = "h1";3316 line.type = "h1";
3321 line.text = line.text.substr(1);3317 line.text = line.text.substr(1);
3322 } else if (line.text.startsWith("-")) {3318 } else if (line.text.match(/^-[ \t]+.*$/)) {
3323 line.type = "ul";3319 // line starts with a hyphen, followed by spaces or tabs
3324 line.text = line.text.substr(1);3320 const match = line.text.match(/^-[ \t]+/);
3325 } else if (line.text.match(/^\d+\..*$/)) {
3326 // if line starts with {number}{dot}
3327 const match = line.text.match(/(\d+)\./);
3328 line.type = "ul";3321 line.type = "ul";
3329 line.text = line.text.substr(match[0].length);3322 line.text = line.text.substr(match[0].length);
3323 } else if (line.text.match(/^\d+\.[ \t]+.*$/)) {
3324 // line starts with {number}{dot}{spaces or tabs}
3325 const match = line.text.match(/(\d+)\.[ \t]+/);
3326 line.type = "ol";
3327 line.text = line.text.substr(match[0].length);
3330 line.ordered_number = Number(match[1].length);3328 line.ordered_number = Number(match[1].length);
3331 } else if (line.text == "```") {3329 } else if (line.text == "```") {
3332 line.type = "skip";3330 line.type = "skip";
...@@ -3536,7 +3534,7 @@ const NAV_MODES = {...@@ -3536,7 +3534,7 @@ const NAV_MODES = {
3536 case "ul":3534 case "ul":
3537 case "ol":3535 case "ol":
3538 if (3536 if (
3539 !previousLineIs("ul", line_no) ||3537 !previousLineIs(line.type, line_no) ||
3540 getPreviousLineIndent(line_no) < line.indent3538 getPreviousLineIndent(line_no) < line.indent
3541 ) {3539 ) {
3542 html += "<" + line.type + ">\n";3540 html += "<" + line.type + ">\n";
...@@ -3545,7 +3543,7 @@ const NAV_MODES = {...@@ -3545,7 +3543,7 @@ const NAV_MODES = {
3545 html += "<li>" + markdownInlines(line.text) + "</li>\n";3543 html += "<li>" + markdownInlines(line.text) + "</li>\n";
35463544
3547 if (3545 if (
3548 !nextLineIs("ul", line_no) ||3546 !nextLineIs(line.type, line_no) ||
3549 getNextLineIndent(line_no) < line.indent3547 getNextLineIndent(line_no) < line.indent
3550 ) {3548 ) {
3551 html += "</" + line.type + ">\n";3549 html += "</" + line.type + ">\n";
...@@ -4067,4 +4065,4 @@ function toggleExpand(event) {...@@ -4067,4 +4065,4 @@ function toggleExpand(event) {
4067 if (!parent.open && parent.getBoundingClientRect().top < 0) {4065 if (!parent.open && parent.getBoundingClientRect().top < 0) {
4068 parent.parentElement.parentElement.scrollIntoView(true);4066 parent.parentElement.parentElement.scrollIntoView(true);
4069 }4067 }
4070}
\ No newline at end of file
4068}
lib/std/Build.zig+4-11
...@@ -37,7 +37,7 @@ pub const FmtStep = @import("Build/FmtStep.zig");...@@ -37,7 +37,7 @@ pub const FmtStep = @import("Build/FmtStep.zig");
37pub const InstallArtifactStep = @import("Build/InstallArtifactStep.zig");37pub const InstallArtifactStep = @import("Build/InstallArtifactStep.zig");
38pub const InstallDirStep = @import("Build/InstallDirStep.zig");38pub const InstallDirStep = @import("Build/InstallDirStep.zig");
39pub const InstallFileStep = @import("Build/InstallFileStep.zig");39pub const InstallFileStep = @import("Build/InstallFileStep.zig");
40pub const InstallRawStep = @import("Build/InstallRawStep.zig");40pub const ObjCopyStep = @import("Build/ObjCopyStep.zig");
41pub const CompileStep = @import("Build/CompileStep.zig");41pub const CompileStep = @import("Build/CompileStep.zig");
42pub const LogStep = @import("Build/LogStep.zig");42pub const LogStep = @import("Build/LogStep.zig");
43pub const OptionsStep = @import("Build/OptionsStep.zig");43pub const OptionsStep = @import("Build/OptionsStep.zig");
...@@ -1254,11 +1254,8 @@ pub fn installLibFile(self: *Build, src_path: []const u8, dest_rel_path: []const...@@ -1254,11 +1254,8 @@ pub fn installLibFile(self: *Build, src_path: []const u8, dest_rel_path: []const
1254 self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .lib, dest_rel_path).step);1254 self.getInstallStep().dependOn(&self.addInstallFileWithDir(.{ .path = src_path }, .lib, dest_rel_path).step);
1255}1255}
12561256
1257/// Output format (BIN vs Intel HEX) determined by filename1257pub fn addObjCopy(b: *Build, source: FileSource, options: ObjCopyStep.Options) *ObjCopyStep {
1258pub fn installRaw(self: *Build, artifact: *CompileStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep {1258 return ObjCopyStep.create(b, source, options);
1259 const raw = self.addInstallRaw(artifact, dest_filename, options);
1260 self.getInstallStep().dependOn(&raw.step);
1261 return raw;
1262}1259}
12631260
1264///`dest_rel_path` is relative to install prefix path1261///`dest_rel_path` is relative to install prefix path
...@@ -1280,10 +1277,6 @@ pub fn addInstallHeaderFile(b: *Build, src_path: []const u8, dest_rel_path: []co...@@ -1280,10 +1277,6 @@ pub fn addInstallHeaderFile(b: *Build, src_path: []const u8, dest_rel_path: []co
1280 return b.addInstallFileWithDir(.{ .path = src_path }, .header, dest_rel_path);1277 return b.addInstallFileWithDir(.{ .path = src_path }, .header, dest_rel_path);
1281}1278}
12821279
1283pub fn addInstallRaw(self: *Build, artifact: *CompileStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep {
1284 return InstallRawStep.create(self, artifact, dest_filename, options);
1285}
1286
1287pub fn addInstallFileWithDir(1280pub fn addInstallFileWithDir(
1288 self: *Build,1281 self: *Build,
1289 source: FileSource,1282 source: FileSource,
...@@ -1771,7 +1764,7 @@ test {...@@ -1771,7 +1764,7 @@ test {
1771 _ = InstallArtifactStep;1764 _ = InstallArtifactStep;
1772 _ = InstallDirStep;1765 _ = InstallDirStep;
1773 _ = InstallFileStep;1766 _ = InstallFileStep;
1774 _ = InstallRawStep;1767 _ = ObjCopyStep;
1775 _ = CompileStep;1768 _ = CompileStep;
1776 _ = LogStep;1769 _ = LogStep;
1777 _ = OptionsStep;1770 _ = OptionsStep;
lib/std/Build/CompileStep.zig+121-25
...@@ -21,7 +21,7 @@ const VcpkgRoot = std.Build.VcpkgRoot;...@@ -21,7 +21,7 @@ const VcpkgRoot = std.Build.VcpkgRoot;
21const InstallDir = std.Build.InstallDir;21const InstallDir = std.Build.InstallDir;
22const InstallArtifactStep = std.Build.InstallArtifactStep;22const InstallArtifactStep = std.Build.InstallArtifactStep;
23const GeneratedFile = std.Build.GeneratedFile;23const GeneratedFile = std.Build.GeneratedFile;
24const InstallRawStep = std.Build.InstallRawStep;24const ObjCopyStep = std.Build.ObjCopyStep;
25const EmulatableRunStep = std.Build.EmulatableRunStep;25const EmulatableRunStep = std.Build.EmulatableRunStep;
26const CheckObjectStep = std.Build.CheckObjectStep;26const CheckObjectStep = std.Build.CheckObjectStep;
27const RunStep = std.Build.RunStep;27const RunStep = std.Build.RunStep;
...@@ -432,10 +432,6 @@ pub fn install(self: *CompileStep) void {...@@ -432,10 +432,6 @@ pub fn install(self: *CompileStep) void {
432 self.builder.installArtifact(self);432 self.builder.installArtifact(self);
433}433}
434434
435pub fn installRaw(self: *CompileStep, dest_filename: []const u8, options: InstallRawStep.CreateOptions) *InstallRawStep {
436 return self.builder.installRaw(self, dest_filename, options);
437}
438
439pub fn installHeader(a: *CompileStep, src_path: []const u8, dest_rel_path: []const u8) void {435pub fn installHeader(a: *CompileStep, src_path: []const u8, dest_rel_path: []const u8) void {
440 const install_file = a.builder.addInstallHeaderFile(src_path, dest_rel_path);436 const install_file = a.builder.addInstallHeaderFile(src_path, dest_rel_path);
441 a.builder.getInstallStep().dependOn(&install_file.step);437 a.builder.getInstallStep().dependOn(&install_file.step);
...@@ -458,6 +454,7 @@ pub fn installConfigHeader(...@@ -458,6 +454,7 @@ pub fn installConfigHeader(
458 options.install_dir,454 options.install_dir,
459 dest_rel_path,455 dest_rel_path,
460 );456 );
457 install_file.step.dependOn(&config_header.step);
461 cs.builder.getInstallStep().dependOn(&install_file.step);458 cs.builder.getInstallStep().dependOn(&install_file.step);
462 cs.installed_headers.append(&install_file.step) catch @panic("OOM");459 cs.installed_headers.append(&install_file.step) catch @panic("OOM");
463}460}
...@@ -506,6 +503,18 @@ pub fn installLibraryHeaders(a: *CompileStep, l: *CompileStep) void {...@@ -506,6 +503,18 @@ pub fn installLibraryHeaders(a: *CompileStep, l: *CompileStep) void {
506 a.installed_headers.appendSlice(l.installed_headers.items) catch @panic("OOM");503 a.installed_headers.appendSlice(l.installed_headers.items) catch @panic("OOM");
507}504}
508505
506pub fn addObjCopy(cs: *CompileStep, options: ObjCopyStep.Options) *ObjCopyStep {
507 var copy = options;
508 if (copy.basename == null) {
509 if (options.format) |f| {
510 copy.basename = cs.builder.fmt("{s}.{s}", .{ cs.name, @tagName(f) });
511 } else {
512 copy.basename = cs.name;
513 }
514 }
515 return cs.builder.addObjCopy(cs.getOutputSource(), copy);
516}
517
509/// Deprecated: use `std.Build.addRunArtifact`518/// Deprecated: use `std.Build.addRunArtifact`
510/// This function will run in the context of the package that created the executable,519/// This function will run in the context of the package that created the executable,
511/// which is undesirable when running an executable provided by a dependency package.520/// which is undesirable when running an executable provided by a dependency package.
...@@ -955,7 +964,10 @@ pub fn addFrameworkPath(self: *CompileStep, dir_path: []const u8) void {...@@ -955,7 +964,10 @@ pub fn addFrameworkPath(self: *CompileStep, dir_path: []const u8) void {
955/// package's module table using `name`.964/// package's module table using `name`.
956pub fn addModule(cs: *CompileStep, name: []const u8, module: *Module) void {965pub fn addModule(cs: *CompileStep, name: []const u8, module: *Module) void {
957 cs.modules.put(cs.builder.dupe(name), module) catch @panic("OOM");966 cs.modules.put(cs.builder.dupe(name), module) catch @panic("OOM");
958 cs.addRecursiveBuildDeps(module);967
968 var done = std.AutoHashMap(*Module, void).init(cs.builder.allocator);
969 defer done.deinit();
970 cs.addRecursiveBuildDeps(module, &done) catch @panic("OOM");
959}971}
960972
961/// Adds a module to be used with `@import` without exposing it in the current973/// Adds a module to be used with `@import` without exposing it in the current
...@@ -969,10 +981,12 @@ pub fn addOptions(cs: *CompileStep, module_name: []const u8, options: *OptionsSt...@@ -969,10 +981,12 @@ pub fn addOptions(cs: *CompileStep, module_name: []const u8, options: *OptionsSt
969 addModule(cs, module_name, options.createModule());981 addModule(cs, module_name, options.createModule());
970}982}
971983
972fn addRecursiveBuildDeps(cs: *CompileStep, module: *Module) void {984fn addRecursiveBuildDeps(cs: *CompileStep, module: *Module, done: *std.AutoHashMap(*Module, void)) !void {
985 if (done.contains(module)) return;
986 try done.put(module, {});
973 module.source_file.addStepDependencies(&cs.step);987 module.source_file.addStepDependencies(&cs.step);
974 for (module.dependencies.values()) |dep| {988 for (module.dependencies.values()) |dep| {
975 cs.addRecursiveBuildDeps(dep);989 try cs.addRecursiveBuildDeps(dep, done);
976 }990 }
977}991}
978992
...@@ -1031,22 +1045,110 @@ fn linkLibraryOrObject(self: *CompileStep, other: *CompileStep) void {...@@ -1031,22 +1045,110 @@ fn linkLibraryOrObject(self: *CompileStep, other: *CompileStep) void {
1031fn appendModuleArgs(1045fn appendModuleArgs(
1032 cs: *CompileStep,1046 cs: *CompileStep,
1033 zig_args: *ArrayList([]const u8),1047 zig_args: *ArrayList([]const u8),
1034 name: []const u8,
1035 module: *Module,
1036) error{OutOfMemory}!void {1048) error{OutOfMemory}!void {
1037 try zig_args.append("--pkg-begin");1049 // First, traverse the whole dependency graph and give every module a unique name, ideally one
1038 try zig_args.append(name);1050 // named after what it's called somewhere in the graph. It will help here to have both a mapping
1039 try zig_args.append(module.builder.pathFromRoot(module.source_file.getPath(module.builder)));1051 // from module to name and a set of all the currently-used names.
1052 var mod_names = std.AutoHashMap(*Module, []const u8).init(cs.builder.allocator);
1053 var names = std.StringHashMap(void).init(cs.builder.allocator);
1054
1055 var to_name = std.ArrayList(struct {
1056 name: []const u8,
1057 mod: *Module,
1058 }).init(cs.builder.allocator);
1059 {
1060 var it = cs.modules.iterator();
1061 while (it.next()) |kv| {
1062 // While we're traversing the root dependencies, let's make sure that no module names
1063 // have colons in them, since the CLI forbids it. We handle this for transitive
1064 // dependencies further down.
1065 if (std.mem.indexOfScalar(u8, kv.key_ptr.*, ':') != null) {
1066 @panic("Module names cannot contain colons");
1067 }
1068 try to_name.append(.{
1069 .name = kv.key_ptr.*,
1070 .mod = kv.value_ptr.*,
1071 });
1072 }
1073 }
1074
1075 while (to_name.popOrNull()) |dep| {
1076 if (mod_names.contains(dep.mod)) continue;
1077
1078 // We'll use this buffer to store the name we decide on
1079 var buf = try cs.builder.allocator.alloc(u8, dep.name.len + 32);
1080 // First, try just the exposed dependency name
1081 std.mem.copy(u8, buf, dep.name);
1082 var name = buf[0..dep.name.len];
1083 var n: usize = 0;
1084 while (names.contains(name)) {
1085 // If that failed, append an incrementing number to the end
1086 name = std.fmt.bufPrint(buf, "{s}{}", .{ dep.name, n }) catch unreachable;
1087 n += 1;
1088 }
1089
1090 try mod_names.put(dep.mod, name);
1091 try names.put(name, {});
10401092
1093 var it = dep.mod.dependencies.iterator();
1094 while (it.next()) |kv| {
1095 // Same colon-in-name check as above, but for transitive dependencies.
1096 if (std.mem.indexOfScalar(u8, kv.key_ptr.*, ':') != null) {
1097 @panic("Module names cannot contain colons");
1098 }
1099 try to_name.append(.{
1100 .name = kv.key_ptr.*,
1101 .mod = kv.value_ptr.*,
1102 });
1103 }
1104 }
1105
1106 // Since the module names given to the CLI are based off of the exposed names, we already know
1107 // that none of the CLI names have colons in them, so there's no need to check that explicitly.
1108
1109 // Every module in the graph is now named; output their definitions
1041 {1110 {
1042 const keys = module.dependencies.keys();1111 var it = mod_names.iterator();
1043 for (module.dependencies.values(), 0..) |sub_module, i| {1112 while (it.next()) |kv| {
1044 const sub_name = keys[i];1113 const mod = kv.key_ptr.*;
1045 try cs.appendModuleArgs(zig_args, sub_name, sub_module);1114 const name = kv.value_ptr.*;
1115
1116 const deps_str = try constructDepString(cs.builder.allocator, mod_names, mod.dependencies);
1117 const src = mod.builder.pathFromRoot(mod.source_file.getPath(mod.builder));
1118 try zig_args.append("--mod");
1119 try zig_args.append(try std.fmt.allocPrint(cs.builder.allocator, "{s}:{s}:{s}", .{ name, deps_str, src }));
1046 }1120 }
1047 }1121 }
10481122
1049 try zig_args.append("--pkg-end");1123 // Lastly, output the root dependencies
1124 const deps_str = try constructDepString(cs.builder.allocator, mod_names, cs.modules);
1125 if (deps_str.len > 0) {
1126 try zig_args.append("--deps");
1127 try zig_args.append(deps_str);
1128 }
1129}
1130
1131fn constructDepString(
1132 allocator: std.mem.Allocator,
1133 mod_names: std.AutoHashMap(*Module, []const u8),
1134 deps: std.StringArrayHashMap(*Module),
1135) ![]const u8 {
1136 var deps_str = std.ArrayList(u8).init(allocator);
1137 var it = deps.iterator();
1138 while (it.next()) |kv| {
1139 const expose = kv.key_ptr.*;
1140 const name = mod_names.get(kv.value_ptr.*).?;
1141 if (std.mem.eql(u8, expose, name)) {
1142 try deps_str.writer().print("{s},", .{name});
1143 } else {
1144 try deps_str.writer().print("{s}={s},", .{ expose, name });
1145 }
1146 }
1147 if (deps_str.items.len > 0) {
1148 return deps_str.items[0 .. deps_str.items.len - 1]; // omit trailing comma
1149 } else {
1150 return "";
1151 }
1050}1152}
10511153
1052fn make(step: *Step) !void {1154fn make(step: *Step) !void {
...@@ -1573,13 +1675,7 @@ fn make(step: *Step) !void {...@@ -1573,13 +1675,7 @@ fn make(step: *Step) !void {
1573 try zig_args.append("--test-no-exec");1675 try zig_args.append("--test-no-exec");
1574 }1676 }
15751677
1576 {1678 try self.appendModuleArgs(&zig_args);
1577 const keys = self.modules.keys();
1578 for (self.modules.values(), 0..) |module, i| {
1579 const name = keys[i];
1580 try self.appendModuleArgs(&zig_args, name, module);
1581 }
1582 }
15831679
1584 for (self.include_dirs.items) |include_dir| {1680 for (self.include_dirs.items) |include_dir| {
1585 switch (include_dir) {1681 switch (include_dir) {
lib/std/Build/EmulatableRunStep.zig+2-2
...@@ -26,7 +26,7 @@ builder: *std.Build,...@@ -26,7 +26,7 @@ builder: *std.Build,
26exe: *CompileStep,26exe: *CompileStep,
2727
28/// Set this to `null` to ignore the exit code for the purpose of determining a successful execution28/// Set this to `null` to ignore the exit code for the purpose of determining a successful execution
29expected_exit_code: ?u8 = 0,29expected_term: ?std.ChildProcess.Term = .{ .Exited = 0 },
3030
31/// Override this field to modify the environment31/// Override this field to modify the environment
32env_map: ?*EnvMap,32env_map: ?*EnvMap,
...@@ -131,7 +131,7 @@ fn make(step: *Step) !void {...@@ -131,7 +131,7 @@ fn make(step: *Step) !void {
131 try RunStep.runCommand(131 try RunStep.runCommand(
132 argv_list.items,132 argv_list.items,
133 self.builder,133 self.builder,
134 self.expected_exit_code,134 self.expected_term,
135 self.stdout_action,135 self.stdout_action,
136 self.stderr_action,136 self.stderr_action,
137 .Inherit,137 .Inherit,
lib/std/Build/InstallRawStep.zig deleted-110
...@@ -1,110 +0,0 @@
1//! TODO: Rename this to ObjCopyStep now that it invokes the `zig objcopy`
2//! subcommand rather than containing an implementation directly.
3
4const std = @import("std");
5const InstallRawStep = @This();
6
7const Allocator = std.mem.Allocator;
8const ArenaAllocator = std.heap.ArenaAllocator;
9const ArrayListUnmanaged = std.ArrayListUnmanaged;
10const File = std.fs.File;
11const InstallDir = std.Build.InstallDir;
12const CompileStep = std.Build.CompileStep;
13const Step = std.Build.Step;
14const elf = std.elf;
15const fs = std.fs;
16const io = std.io;
17const sort = std.sort;
18
19pub const base_id = .install_raw;
20
21pub const RawFormat = enum {
22 bin,
23 hex,
24};
25
26step: Step,
27builder: *std.Build,
28artifact: *CompileStep,
29dest_dir: InstallDir,
30dest_filename: []const u8,
31options: CreateOptions,
32output_file: std.Build.GeneratedFile,
33
34pub const CreateOptions = struct {
35 format: ?RawFormat = null,
36 dest_dir: ?InstallDir = null,
37 only_section: ?[]const u8 = null,
38 pad_to: ?u64 = null,
39};
40
41pub fn create(
42 builder: *std.Build,
43 artifact: *CompileStep,
44 dest_filename: []const u8,
45 options: CreateOptions,
46) *InstallRawStep {
47 const self = builder.allocator.create(InstallRawStep) catch @panic("OOM");
48 self.* = InstallRawStep{
49 .step = Step.init(.install_raw, builder.fmt("install raw binary {s}", .{artifact.step.name}), builder.allocator, make),
50 .builder = builder,
51 .artifact = artifact,
52 .dest_dir = if (options.dest_dir) |d| d else switch (artifact.kind) {
53 .obj => unreachable,
54 .@"test" => unreachable,
55 .exe, .test_exe => .bin,
56 .lib => unreachable,
57 },
58 .dest_filename = dest_filename,
59 .options = options,
60 .output_file = std.Build.GeneratedFile{ .step = &self.step },
61 };
62 self.step.dependOn(&artifact.step);
63
64 builder.pushInstalledFile(self.dest_dir, dest_filename);
65 return self;
66}
67
68pub fn getOutputSource(self: *const InstallRawStep) std.Build.FileSource {
69 return std.Build.FileSource{ .generated = &self.output_file };
70}
71
72fn make(step: *Step) !void {
73 const self = @fieldParentPtr(InstallRawStep, "step", step);
74 const b = self.builder;
75
76 if (self.artifact.target.getObjectFormat() != .elf) {
77 std.debug.print("InstallRawStep only works with ELF format.\n", .{});
78 return error.InvalidObjectFormat;
79 }
80
81 const full_src_path = self.artifact.getOutputSource().getPath(b);
82 const full_dest_path = b.getInstallPath(self.dest_dir, self.dest_filename);
83 self.output_file.path = full_dest_path;
84
85 try fs.cwd().makePath(b.getInstallPath(self.dest_dir, ""));
86
87 var argv_list = std.ArrayList([]const u8).init(b.allocator);
88 try argv_list.appendSlice(&.{ b.zig_exe, "objcopy" });
89
90 if (self.options.only_section) |only_section| {
91 try argv_list.appendSlice(&.{ "-j", only_section });
92 }
93 if (self.options.pad_to) |pad_to| {
94 try argv_list.appendSlice(&.{
95 "--pad-to",
96 b.fmt("{d}", .{pad_to}),
97 });
98 }
99 if (self.options.format) |format| switch (format) {
100 .bin => try argv_list.appendSlice(&.{ "-O", "binary" }),
101 .hex => try argv_list.appendSlice(&.{ "-O", "hex" }),
102 };
103
104 try argv_list.appendSlice(&.{ full_src_path, full_dest_path });
105 _ = try self.builder.execFromStep(argv_list.items, &self.step);
106}
107
108test {
109 std.testing.refAllDecls(InstallRawStep);
110}
lib/std/Build/ObjCopyStep.zig created+138
...@@ -0,0 +1,138 @@
1const std = @import("std");
2const ObjCopyStep = @This();
3
4const Allocator = std.mem.Allocator;
5const ArenaAllocator = std.heap.ArenaAllocator;
6const ArrayListUnmanaged = std.ArrayListUnmanaged;
7const File = std.fs.File;
8const InstallDir = std.Build.InstallDir;
9const CompileStep = std.Build.CompileStep;
10const Step = std.Build.Step;
11const elf = std.elf;
12const fs = std.fs;
13const io = std.io;
14const sort = std.sort;
15
16pub const base_id: Step.Id = .objcopy;
17
18pub const RawFormat = enum {
19 bin,
20 hex,
21};
22
23step: Step,
24builder: *std.Build,
25file_source: std.Build.FileSource,
26basename: []const u8,
27output_file: std.Build.GeneratedFile,
28
29format: ?RawFormat,
30only_section: ?[]const u8,
31pad_to: ?u64,
32
33pub const Options = struct {
34 basename: ?[]const u8 = null,
35 format: ?RawFormat = null,
36 only_section: ?[]const u8 = null,
37 pad_to: ?u64 = null,
38};
39
40pub fn create(
41 builder: *std.Build,
42 file_source: std.Build.FileSource,
43 options: Options,
44) *ObjCopyStep {
45 const self = builder.allocator.create(ObjCopyStep) catch @panic("OOM");
46 self.* = ObjCopyStep{
47 .step = Step.init(
48 base_id,
49 builder.fmt("objcopy {s}", .{file_source.getDisplayName()}),
50 builder.allocator,
51 make,
52 ),
53 .builder = builder,
54 .file_source = file_source,
55 .basename = options.basename orelse file_source.getDisplayName(),
56 .output_file = std.Build.GeneratedFile{ .step = &self.step },
57
58 .format = options.format,
59 .only_section = options.only_section,
60 .pad_to = options.pad_to,
61 };
62 file_source.addStepDependencies(&self.step);
63 return self;
64}
65
66pub fn getOutputSource(self: *const ObjCopyStep) std.Build.FileSource {
67 return .{ .generated = &self.output_file };
68}
69
70fn make(step: *Step) !void {
71 const self = @fieldParentPtr(ObjCopyStep, "step", step);
72 const b = self.builder;
73
74 var man = b.cache.obtain();
75 defer man.deinit();
76
77 // Random bytes to make ObjCopyStep unique. Refresh this with new random
78 // bytes when ObjCopyStep implementation is modified incompatibly.
79 man.hash.add(@as(u32, 0xe18b7baf));
80
81 const full_src_path = self.file_source.getPath(b);
82 _ = try man.addFile(full_src_path, null);
83 man.hash.addOptionalBytes(self.only_section);
84 man.hash.addOptional(self.pad_to);
85 man.hash.addOptional(self.format);
86
87 if (man.hit() catch |err| failWithCacheError(man, err)) {
88 // Cache hit, skip subprocess execution.
89 const digest = man.final();
90 self.output_file.path = try b.cache_root.join(b.allocator, &.{
91 "o", &digest, self.basename,
92 });
93 return;
94 }
95
96 const digest = man.final();
97 const full_dest_path = try b.cache_root.join(b.allocator, &.{ "o", &digest, self.basename });
98 const cache_path = "o" ++ fs.path.sep_str ++ digest;
99 b.cache_root.handle.makePath(cache_path) catch |err| {
100 std.debug.print("unable to make path {s}: {s}\n", .{ cache_path, @errorName(err) });
101 return err;
102 };
103
104 var argv = std.ArrayList([]const u8).init(b.allocator);
105 try argv.appendSlice(&.{ b.zig_exe, "objcopy" });
106
107 if (self.only_section) |only_section| {
108 try argv.appendSlice(&.{ "-j", only_section });
109 }
110 if (self.pad_to) |pad_to| {
111 try argv.appendSlice(&.{ "--pad-to", b.fmt("{d}", .{pad_to}) });
112 }
113 if (self.format) |format| switch (format) {
114 .bin => try argv.appendSlice(&.{ "-O", "binary" }),
115 .hex => try argv.appendSlice(&.{ "-O", "hex" }),
116 };
117
118 try argv.appendSlice(&.{ full_src_path, full_dest_path });
119 _ = try self.builder.execFromStep(argv.items, &self.step);
120
121 self.output_file.path = full_dest_path;
122 try man.writeManifest();
123}
124
125/// TODO consolidate this with the same function in RunStep?
126/// Also properly deal with concurrency (see open PR)
127fn failWithCacheError(man: std.Build.Cache.Manifest, err: anyerror) noreturn {
128 const i = man.failed_file_index orelse failWithSimpleError(err);
129 const pp = man.files.items[i].prefixed_path orelse failWithSimpleError(err);
130 const prefix = man.cache.prefixes()[pp.prefix].path orelse "";
131 std.debug.print("{s}: {s}/{s}\n", .{ @errorName(err), prefix, pp.sub_path });
132 std.process.exit(1);
133}
134
135fn failWithSimpleError(err: anyerror) noreturn {
136 std.debug.print("{s}\n", .{@errorName(err)});
137 std.process.exit(1);
138}
lib/std/Build/RunStep.zig+55-28
...@@ -35,7 +35,7 @@ stderr_action: StdIoAction = .inherit,...@@ -35,7 +35,7 @@ stderr_action: StdIoAction = .inherit,
35stdin_behavior: std.ChildProcess.StdIo = .Inherit,35stdin_behavior: std.ChildProcess.StdIo = .Inherit,
3636
37/// Set this to `null` to ignore the exit code for the purpose of determining a successful execution37/// Set this to `null` to ignore the exit code for the purpose of determining a successful execution
38expected_exit_code: ?u8 = 0,38expected_term: ?std.ChildProcess.Term = .{ .Exited = 0 },
3939
40/// Print the command before running it40/// Print the command before running it
41print: bool,41print: bool,
...@@ -290,7 +290,7 @@ fn make(step: *Step) !void {...@@ -290,7 +290,7 @@ fn make(step: *Step) !void {
290 try runCommand(290 try runCommand(
291 argv_list.items,291 argv_list.items,
292 self.builder,292 self.builder,
293 self.expected_exit_code,293 self.expected_term,
294 self.stdout_action,294 self.stdout_action,
295 self.stderr_action,295 self.stderr_action,
296 self.stdin_behavior,296 self.stdin_behavior,
...@@ -304,10 +304,55 @@ fn make(step: *Step) !void {...@@ -304,10 +304,55 @@ fn make(step: *Step) !void {
304 }304 }
305}305}
306306
307fn formatTerm(
308 term: ?std.ChildProcess.Term,
309 comptime fmt: []const u8,
310 options: std.fmt.FormatOptions,
311 writer: anytype,
312) !void {
313 _ = fmt;
314 _ = options;
315 if (term) |t| switch (t) {
316 .Exited => |code| try writer.print("exited with code {}", .{code}),
317 .Signal => |sig| try writer.print("terminated with signal {}", .{sig}),
318 .Stopped => |sig| try writer.print("stopped with signal {}", .{sig}),
319 .Unknown => |code| try writer.print("terminated for unknown reason with code {}", .{code}),
320 } else {
321 try writer.writeAll("exited with any code");
322 }
323}
324fn fmtTerm(term: ?std.ChildProcess.Term) std.fmt.Formatter(formatTerm) {
325 return .{ .data = term };
326}
327
328fn termMatches(expected: ?std.ChildProcess.Term, actual: std.ChildProcess.Term) bool {
329 return if (expected) |e| switch (e) {
330 .Exited => |expected_code| switch (actual) {
331 .Exited => |actual_code| expected_code == actual_code,
332 else => false,
333 },
334 .Signal => |expected_sig| switch (actual) {
335 .Signal => |actual_sig| expected_sig == actual_sig,
336 else => false,
337 },
338 .Stopped => |expected_sig| switch (actual) {
339 .Stopped => |actual_sig| expected_sig == actual_sig,
340 else => false,
341 },
342 .Unknown => |expected_code| switch (actual) {
343 .Unknown => |actual_code| expected_code == actual_code,
344 else => false,
345 },
346 } else switch (actual) {
347 .Exited => true,
348 else => false,
349 };
350}
351
307pub fn runCommand(352pub fn runCommand(
308 argv: []const []const u8,353 argv: []const []const u8,
309 builder: *std.Build,354 builder: *std.Build,
310 expected_exit_code: ?u8,355 expected_term: ?std.ChildProcess.Term,
311 stdout_action: StdIoAction,356 stdout_action: StdIoAction,
312 stderr_action: StdIoAction,357 stderr_action: StdIoAction,
313 stdin_behavior: std.ChildProcess.StdIo,358 stdin_behavior: std.ChildProcess.StdIo,
...@@ -369,32 +414,14 @@ pub fn runCommand(...@@ -369,32 +414,14 @@ pub fn runCommand(
369 return err;414 return err;
370 };415 };
371416
372 switch (term) {417 if (!termMatches(expected_term, term)) {
373 .Exited => |code| blk: {418 if (builder.prominent_compile_errors) {
374 const expected_code = expected_exit_code orelse break :blk;419 std.debug.print("Run step {} (expected {})\n", .{ fmtTerm(term), fmtTerm(expected_term) });
375420 } else {
376 if (code != expected_code) {421 std.debug.print("The following command {} (expected {}):\n", .{ fmtTerm(term), fmtTerm(expected_term) });
377 if (builder.prominent_compile_errors) {
378 std.debug.print("Run step exited with error code {} (expected {})\n", .{
379 code,
380 expected_code,
381 });
382 } else {
383 std.debug.print("The following command exited with error code {} (expected {}):\n", .{
384 code,
385 expected_code,
386 });
387 printCmd(cwd, argv);
388 }
389
390 return error.UnexpectedExitCode;
391 }
392 },
393 else => {
394 std.debug.print("The following command terminated unexpectedly:\n", .{});
395 printCmd(cwd, argv);422 printCmd(cwd, argv);
396 return error.UncleanExit;423 }
397 },424 return error.UnexpectedExit;
398 }425 }
399426
400 switch (stderr_action) {427 switch (stderr_action) {
lib/std/Build/Step.zig+2-2
...@@ -21,7 +21,7 @@ pub const Id = enum {...@@ -21,7 +21,7 @@ pub const Id = enum {
21 check_file,21 check_file,
22 check_object,22 check_object,
23 config_header,23 config_header,
24 install_raw,24 objcopy,
25 options,25 options,
26 custom,26 custom,
2727
...@@ -42,7 +42,7 @@ pub const Id = enum {...@@ -42,7 +42,7 @@ pub const Id = enum {
42 .check_file => Build.CheckFileStep,42 .check_file => Build.CheckFileStep,
43 .check_object => Build.CheckObjectStep,43 .check_object => Build.CheckObjectStep,
44 .config_header => Build.ConfigHeaderStep,44 .config_header => Build.ConfigHeaderStep,
45 .install_raw => Build.InstallRawStep,45 .objcopy => Build.ObjCopyStep,
46 .options => Build.OptionsStep,46 .options => Build.OptionsStep,
47 .custom => @compileError("no type available for custom step"),47 .custom => @compileError("no type available for custom step"),
48 };48 };
lib/std/Build/WriteFileStep.zig+173-71
...@@ -1,55 +1,117 @@...@@ -1,55 +1,117 @@
1const std = @import("../std.zig");1//! WriteFileStep is primarily used to create a directory in an appropriate
2const Step = std.Build.Step;2//! location inside the local cache which has a set of files that have either
3const fs = std.fs;3//! been generated during the build, or are copied from the source package.
4const ArrayList = std.ArrayList;4//!
55//! However, this step has an additional capability of writing data to paths
6const WriteFileStep = @This();6//! relative to the package root, effectively mutating the package's source
77//! files. Be careful with the latter functionality; it should not be used
8pub const base_id = .write_file;8//! during the normal build process, but as a utility run by a developer with
9//! intention to update source files, which will then be committed to version
10//! control.
911
10step: Step,12step: Step,
11builder: *std.Build,13builder: *std.Build,
12files: std.TailQueue(File),14/// The elements here are pointers because we need stable pointers for the
15/// GeneratedFile field.
16files: std.ArrayListUnmanaged(*File),
17output_source_files: std.ArrayListUnmanaged(OutputSourceFile),
18
19pub const base_id = .write_file;
1320
14pub const File = struct {21pub const File = struct {
15 source: std.Build.GeneratedFile,22 generated_file: std.Build.GeneratedFile,
16 basename: []const u8,23 sub_path: []const u8,
24 contents: Contents,
25};
26
27pub const OutputSourceFile = struct {
28 contents: Contents,
29 sub_path: []const u8,
30};
31
32pub const Contents = union(enum) {
17 bytes: []const u8,33 bytes: []const u8,
34 copy: std.Build.FileSource,
18};35};
1936
20pub fn init(builder: *std.Build) WriteFileStep {37pub fn init(builder: *std.Build) WriteFileStep {
21 return WriteFileStep{38 return .{
22 .builder = builder,39 .builder = builder,
23 .step = Step.init(.write_file, "writefile", builder.allocator, make),40 .step = Step.init(.write_file, "writefile", builder.allocator, make),
24 .files = .{},41 .files = .{},
42 .output_source_files = .{},
25 };43 };
26}44}
2745
28pub fn add(self: *WriteFileStep, basename: []const u8, bytes: []const u8) void {46pub fn add(wf: *WriteFileStep, sub_path: []const u8, bytes: []const u8) void {
29 const node = self.builder.allocator.create(std.TailQueue(File).Node) catch @panic("unhandled error");47 const gpa = wf.builder.allocator;
30 node.* = .{48 const file = gpa.create(File) catch @panic("OOM");
31 .data = .{49 file.* = .{
32 .source = std.Build.GeneratedFile{ .step = &self.step },50 .generated_file = .{ .step = &wf.step },
33 .basename = self.builder.dupePath(basename),51 .sub_path = wf.builder.dupePath(sub_path),
34 .bytes = self.builder.dupe(bytes),52 .contents = .{ .bytes = wf.builder.dupe(bytes) },
35 },53 };
54 wf.files.append(gpa, file) catch @panic("OOM");
55}
56
57/// Place the file into the generated directory within the local cache,
58/// along with all the rest of the files added to this step. The parameter
59/// here is the destination path relative to the local cache directory
60/// associated with this WriteFileStep. It may be a basename, or it may
61/// include sub-directories, in which case this step will ensure the
62/// required sub-path exists.
63/// This is the option expected to be used most commonly with `addCopyFile`.
64pub fn addCopyFile(wf: *WriteFileStep, source: std.Build.FileSource, sub_path: []const u8) void {
65 const gpa = wf.builder.allocator;
66 const file = gpa.create(File) catch @panic("OOM");
67 file.* = .{
68 .generated_file = .{ .step = &wf.step },
69 .sub_path = wf.builder.dupePath(sub_path),
70 .contents = .{ .copy = source },
36 };71 };
72 wf.files.append(gpa, file) catch @panic("OOM");
73}
3774
38 self.files.append(node);75/// A path relative to the package root.
76/// Be careful with this because it updates source files. This should not be
77/// used as part of the normal build process, but as a utility occasionally
78/// run by a developer with intent to modify source files and then commit
79/// those changes to version control.
80/// A file added this way is not available with `getFileSource`.
81pub fn addCopyFileToSource(wf: *WriteFileStep, source: std.Build.FileSource, sub_path: []const u8) void {
82 wf.output_source_files.append(wf.builder.allocator, .{
83 .contents = .{ .copy = source },
84 .sub_path = sub_path,
85 }) catch @panic("OOM");
39}86}
4087
41/// Gets a file source for the given basename. If the file does not exist, returns `null`.88/// Gets a file source for the given sub_path. If the file does not exist, returns `null`.
42pub fn getFileSource(step: *WriteFileStep, basename: []const u8) ?std.Build.FileSource {89pub fn getFileSource(wf: *WriteFileStep, sub_path: []const u8) ?std.Build.FileSource {
43 var it = step.files.first;90 for (wf.files.items) |file| {
44 while (it) |node| : (it = node.next) {91 if (std.mem.eql(u8, file.sub_path, sub_path)) {
45 if (std.mem.eql(u8, node.data.basename, basename))92 return .{ .generated = &file.generated_file };
46 return std.Build.FileSource{ .generated = &node.data.source };93 }
47 }94 }
48 return null;95 return null;
49}96}
5097
51fn make(step: *Step) !void {98fn make(step: *Step) !void {
52 const self = @fieldParentPtr(WriteFileStep, "step", step);99 const wf = @fieldParentPtr(WriteFileStep, "step", step);
100
101 // Writing to source files is kind of an extra capability of this
102 // WriteFileStep - arguably it should be a different step. But anyway here
103 // it is, it happens unconditionally and does not interact with the other
104 // files here.
105 for (wf.output_source_files.items) |output_source_file| {
106 const basename = fs.path.basename(output_source_file.sub_path);
107 if (fs.path.dirname(output_source_file.sub_path)) |dirname| {
108 var dir = try wf.builder.build_root.handle.makeOpenPath(dirname, .{});
109 defer dir.close();
110 try writeFile(wf, dir, output_source_file.contents, basename);
111 } else {
112 try writeFile(wf, wf.builder.build_root.handle, output_source_file.contents, basename);
113 }
114 }
53115
54 // The cache is used here not really as a way to speed things up - because writing116 // The cache is used here not really as a way to speed things up - because writing
55 // the data to a file would probably be very fast - but as a way to find a canonical117 // the data to a file would probably be very fast - but as a way to find a canonical
...@@ -58,56 +120,96 @@ fn make(step: *Step) !void {...@@ -58,56 +120,96 @@ fn make(step: *Step) !void {
58 // If, for example, a hard-coded path was used as the location to put WriteFileStep120 // If, for example, a hard-coded path was used as the location to put WriteFileStep
59 // files, then two WriteFileSteps executing in parallel might clobber each other.121 // files, then two WriteFileSteps executing in parallel might clobber each other.
60122
61 // TODO port the cache system from the compiler to zig std lib. Until then123 var man = wf.builder.cache.obtain();
62 // we directly construct the path, and no "cache hit" detection happens;124 defer man.deinit();
63 // the files are always written.125
64 // Note there is similar code over in ConfigHeaderStep.
65 const Hasher = std.crypto.auth.siphash.SipHash128(1, 3);
66 // Random bytes to make WriteFileStep unique. Refresh this with126 // Random bytes to make WriteFileStep unique. Refresh this with
67 // new random bytes when WriteFileStep implementation is modified127 // new random bytes when WriteFileStep implementation is modified
68 // in a non-backwards-compatible way.128 // in a non-backwards-compatible way.
69 var hash = Hasher.init("eagVR1dYXoE7ARDP");129 man.hash.add(@as(u32, 0xd767ee59));
70130
71 {131 for (wf.files.items) |file| {
72 var it = self.files.first;132 man.hash.addBytes(file.sub_path);
73 while (it) |node| : (it = node.next) {133 switch (file.contents) {
74 hash.update(node.data.basename);134 .bytes => |bytes| {
75 hash.update(node.data.bytes);135 man.hash.addBytes(bytes);
76 hash.update("|");136 },
137 .copy => |file_source| {
138 _ = try man.addFile(file_source.getPath(wf.builder), null);
139 },
77 }140 }
78 }141 }
79 var digest: [16]u8 = undefined;142
80 hash.final(&digest);143 if (man.hit() catch |err| failWithCacheError(man, err)) {
81 var hash_basename: [digest.len * 2]u8 = undefined;144 // Cache hit, skip writing file data.
82 _ = std.fmt.bufPrint(145 const digest = man.final();
83 &hash_basename,146 for (wf.files.items) |file| {
84 "{s}",147 file.generated_file.path = try wf.builder.cache_root.join(
85 .{std.fmt.fmtSliceHexLower(&digest)},148 wf.builder.allocator,
86 ) catch unreachable;149 &.{ "o", &digest, file.sub_path },
87150 );
88 const output_dir = try self.builder.cache_root.join(self.builder.allocator, &.{151 }
89 "o", &hash_basename,152 return;
90 });153 }
91 var dir = fs.cwd().makeOpenPath(output_dir, .{}) catch |err| {154
92 std.debug.print("unable to make path {s}: {s}\n", .{ output_dir, @errorName(err) });155 const digest = man.final();
156 const cache_path = "o" ++ fs.path.sep_str ++ digest;
157
158 var cache_dir = wf.builder.cache_root.handle.makeOpenPath(cache_path, .{}) catch |err| {
159 std.debug.print("unable to make path {s}: {s}\n", .{ cache_path, @errorName(err) });
93 return err;160 return err;
94 };161 };
95 defer dir.close();162 defer cache_dir.close();
96 {163
97 var it = self.files.first;164 for (wf.files.items) |file| {
98 while (it) |node| : (it = node.next) {165 const basename = fs.path.basename(file.sub_path);
99 dir.writeFile(node.data.basename, node.data.bytes) catch |err| {166 if (fs.path.dirname(file.sub_path)) |dirname| {
100 std.debug.print("unable to write {s} into {s}: {s}\n", .{167 var dir = try wf.builder.cache_root.handle.makeOpenPath(dirname, .{});
101 node.data.basename,168 defer dir.close();
102 output_dir,169 try writeFile(wf, dir, file.contents, basename);
103 @errorName(err),170 } else {
104 });171 try writeFile(wf, cache_dir, file.contents, basename);
105 return err;
106 };
107 node.data.source.path = try fs.path.join(
108 self.builder.allocator,
109 &[_][]const u8{ output_dir, node.data.basename },
110 );
111 }172 }
173
174 file.generated_file.path = try wf.builder.cache_root.join(
175 wf.builder.allocator,
176 &.{ cache_path, file.sub_path },
177 );
112 }178 }
179
180 try man.writeManifest();
113}181}
182
183fn writeFile(wf: *WriteFileStep, dir: fs.Dir, contents: Contents, basename: []const u8) !void {
184 // TODO after landing concurrency PR, improve error reporting here
185 switch (contents) {
186 .bytes => |bytes| return dir.writeFile(basename, bytes),
187 .copy => |file_source| {
188 const source_path = file_source.getPath(wf.builder);
189 const prev_status = try fs.Dir.updateFile(fs.cwd(), source_path, dir, basename, .{});
190 _ = prev_status; // TODO logging (affected by open PR regarding concurrency)
191 },
192 }
193}
194
195/// TODO consolidate this with the same function in RunStep?
196/// Also properly deal with concurrency (see open PR)
197fn failWithCacheError(man: std.Build.Cache.Manifest, err: anyerror) noreturn {
198 const i = man.failed_file_index orelse failWithSimpleError(err);
199 const pp = man.files.items[i].prefixed_path orelse failWithSimpleError(err);
200 const prefix = man.cache.prefixes()[pp.prefix].path orelse "";
201 std.debug.print("{s}: {s}/{s}\n", .{ @errorName(err), prefix, pp.sub_path });
202 std.process.exit(1);
203}
204
205fn failWithSimpleError(err: anyerror) noreturn {
206 std.debug.print("{s}\n", .{@errorName(err)});
207 std.process.exit(1);
208}
209
210const std = @import("../std.zig");
211const Step = std.Build.Step;
212const fs = std.fs;
213const ArrayList = std.ArrayList;
214
215const WriteFileStep = @This();
lib/std/RingBuffer.zig created+136
...@@ -0,0 +1,136 @@
1//! This ring buffer stores read and write indices while being able to utilise
2//! the full backing slice by incrementing the indices modulo twice the slice's
3//! length and reducing indices modulo the slice's length on slice access. This
4//! means that whether the ring buffer if full or empty can be distinguished by
5//! looking at the difference between the read and write indices without adding
6//! an extra boolean flag or having to reserve a slot in the buffer.
7//!
8//! This ring buffer has not been implemented with thread safety in mind, and
9//! therefore should not be assumed to be suitable for use cases involving
10//! separate reader and writer threads.
11
12const Allocator = @import("std").mem.Allocator;
13const assert = @import("std").debug.assert;
14
15const RingBuffer = @This();
16
17data: []u8,
18read_index: usize,
19write_index: usize,
20
21pub const Error = error{Full};
22
23/// Allocate a new `RingBuffer`; `deinit()` should be called to free the buffer.
24pub fn init(allocator: Allocator, capacity: usize) Allocator.Error!RingBuffer {
25 const bytes = try allocator.alloc(u8, capacity);
26 return RingBuffer{
27 .data = bytes,
28 .write_index = 0,
29 .read_index = 0,
30 };
31}
32
33/// Free the data backing a `RingBuffer`; must be passed the same `Allocator` as
34/// `init()`.
35pub fn deinit(self: *RingBuffer, allocator: Allocator) void {
36 allocator.free(self.data);
37 self.* = undefined;
38}
39
40/// Returns `index` modulo the length of the backing slice.
41pub fn mask(self: RingBuffer, index: usize) usize {
42 return index % self.data.len;
43}
44
45/// Returns `index` modulo twice the length of the backing slice.
46pub fn mask2(self: RingBuffer, index: usize) usize {
47 return index % (2 * self.data.len);
48}
49
50/// Write `byte` into the ring buffer. Returns `error.Full` if the ring
51/// buffer is full.
52pub fn write(self: *RingBuffer, byte: u8) Error!void {
53 if (self.isFull()) return error.Full;
54 self.writeAssumeCapacity(byte);
55}
56
57/// Write `byte` into the ring buffer. If the ring buffer is full, the
58/// oldest byte is overwritten.
59pub fn writeAssumeCapacity(self: *RingBuffer, byte: u8) void {
60 self.data[self.mask(self.write_index)] = byte;
61 self.write_index = self.mask2(self.write_index + 1);
62}
63
64/// Write `bytes` into the ring buffer. Returns `error.Full` if the ring
65/// buffer does not have enough space, without writing any data.
66pub fn writeSlice(self: *RingBuffer, bytes: []const u8) Error!void {
67 if (self.len() + bytes.len > self.data.len) return error.Full;
68 self.writeSliceAssumeCapacity(bytes);
69}
70
71/// Write `bytes` into the ring buffer. If there is not enough space, older
72/// bytes will be overwritten.
73pub fn writeSliceAssumeCapacity(self: *RingBuffer, bytes: []const u8) void {
74 for (bytes) |b| self.writeAssumeCapacity(b);
75}
76
77/// Consume a byte from the ring buffer and return it. Returns `null` if the
78/// ring buffer is empty.
79pub fn read(self: *RingBuffer) ?u8 {
80 if (self.isEmpty()) return null;
81 return self.readAssumeLength();
82}
83
84/// Consume a byte from the ring buffer and return it; asserts that the buffer
85/// is not empty.
86pub fn readAssumeLength(self: *RingBuffer) u8 {
87 assert(!self.isEmpty());
88 const byte = self.data[self.mask(self.read_index)];
89 self.read_index = self.mask2(self.read_index + 1);
90 return byte;
91}
92
93/// Returns `true` if the ring buffer is empty and `false` otherwise.
94pub fn isEmpty(self: RingBuffer) bool {
95 return self.write_index == self.read_index;
96}
97
98/// Returns `true` if the ring buffer is full and `false` otherwise.
99pub fn isFull(self: RingBuffer) bool {
100 return self.mask2(self.write_index + self.data.len) == self.read_index;
101}
102
103/// Returns the length
104pub fn len(self: RingBuffer) usize {
105 const wrap_offset = 2 * self.data.len * @boolToInt(self.write_index < self.read_index);
106 const adjusted_write_index = self.write_index + wrap_offset;
107 return adjusted_write_index - self.read_index;
108}
109
110/// A `Slice` represents a region of a ring buffer. The region is split into two
111/// sections as the ring buffer data will not be contiguous if the desired
112/// region wraps to the start of the backing slice.
113pub const Slice = struct {
114 first: []u8,
115 second: []u8,
116};
117
118/// Returns a `Slice` for the region of the ring buffer starting at
119/// `self.mask(start_unmasked)` with the specified length.
120pub fn sliceAt(self: RingBuffer, start_unmasked: usize, length: usize) Slice {
121 assert(length <= self.data.len);
122 const slice1_start = self.mask(start_unmasked);
123 const slice1_end = @min(self.data.len, slice1_start + length);
124 const slice1 = self.data[slice1_start..slice1_end];
125 const slice2 = self.data[0 .. length - slice1.len];
126 return Slice{
127 .first = slice1,
128 .second = slice2,
129 };
130}
131
132/// Returns a `Slice` for the last `length` bytes written to the ring buffer.
133/// Does not check that any bytes have been written into the region.
134pub fn sliceLast(self: RingBuffer, length: usize) Slice {
135 return self.sliceAt(self.write_index + self.data.len - length, length);
136}
lib/std/child_process.zig+33-24
...@@ -197,6 +197,32 @@ pub const ChildProcess = struct {...@@ -197,6 +197,32 @@ pub const ChildProcess = struct {
197 stderr: []u8,197 stderr: []u8,
198 };198 };
199199
200 /// Collect the output from the process's stdout and stderr. Will return once all output
201 /// has been collected. This does not mean that the process has ended. `wait` should still
202 /// be called to wait for and clean up the process.
203 ///
204 /// The process must be started with stdout_behavior and stderr_behavior == .Pipe
205 pub fn collectOutput(
206 child: ChildProcess,
207 stdout: *std.ArrayList(u8),
208 stderr: *std.ArrayList(u8),
209 max_output_bytes: usize,
210 ) !void {
211 debug.assert(child.stdout_behavior == .Pipe);
212 debug.assert(child.stderr_behavior == .Pipe);
213 if (builtin.os.tag == .haiku) {
214 const stdout_in = child.stdout.?.reader();
215 const stderr_in = child.stderr.?.reader();
216
217 try stdout_in.readAllArrayList(stdout, max_output_bytes);
218 try stderr_in.readAllArrayList(stderr, max_output_bytes);
219 } else if (builtin.os.tag == .windows) {
220 try collectOutputWindows(child, stdout, stderr, max_output_bytes);
221 } else {
222 try collectOutputPosix(child, stdout, stderr, max_output_bytes);
223 }
224 }
225
200 fn collectOutputPosix(226 fn collectOutputPosix(
201 child: ChildProcess,227 child: ChildProcess,
202 stdout: *std.ArrayList(u8),228 stdout: *std.ArrayList(u8),
...@@ -297,8 +323,12 @@ pub const ChildProcess = struct {...@@ -297,8 +323,12 @@ pub const ChildProcess = struct {
297 }323 }
298 }324 }
299325
300 fn collectOutputWindows(child: ChildProcess, outs: [2]*std.ArrayList(u8), max_output_bytes: usize) !void {326 fn collectOutputWindows(child: ChildProcess, stdout: *std.ArrayList(u8), stderr: *std.ArrayList(u8), max_output_bytes: usize) !void {
301 const bump_amt = 512;327 const bump_amt = 512;
328 const outs = [_]*std.ArrayList(u8){
329 stdout,
330 stderr,
331 };
302 const handles = [_]windows.HANDLE{332 const handles = [_]windows.HANDLE{
303 child.stdout.?.handle,333 child.stdout.?.handle,
304 child.stderr.?.handle,334 child.stderr.?.handle,
...@@ -391,24 +421,6 @@ pub const ChildProcess = struct {...@@ -391,24 +421,6 @@ pub const ChildProcess = struct {
391 child.env_map = args.env_map;421 child.env_map = args.env_map;
392 child.expand_arg0 = args.expand_arg0;422 child.expand_arg0 = args.expand_arg0;
393423
394 try child.spawn();
395
396 if (builtin.os.tag == .haiku) {
397 const stdout_in = child.stdout.?.reader();
398 const stderr_in = child.stderr.?.reader();
399
400 const stdout = try stdout_in.readAllAlloc(args.allocator, args.max_output_bytes);
401 errdefer args.allocator.free(stdout);
402 const stderr = try stderr_in.readAllAlloc(args.allocator, args.max_output_bytes);
403 errdefer args.allocator.free(stderr);
404
405 return ExecResult{
406 .term = try child.wait(),
407 .stdout = stdout,
408 .stderr = stderr,
409 };
410 }
411
412 var stdout = std.ArrayList(u8).init(args.allocator);424 var stdout = std.ArrayList(u8).init(args.allocator);
413 var stderr = std.ArrayList(u8).init(args.allocator);425 var stderr = std.ArrayList(u8).init(args.allocator);
414 errdefer {426 errdefer {
...@@ -416,11 +428,8 @@ pub const ChildProcess = struct {...@@ -416,11 +428,8 @@ pub const ChildProcess = struct {
416 stderr.deinit();428 stderr.deinit();
417 }429 }
418430
419 if (builtin.os.tag == .windows) {431 try child.spawn();
420 try collectOutputWindows(child, [_]*std.ArrayList(u8){ &stdout, &stderr }, args.max_output_bytes);432 try child.collectOutput(&stdout, &stderr, args.max_output_bytes);
421 } else {
422 try collectOutputPosix(child, &stdout, &stderr, args.max_output_bytes);
423 }
424433
425 return ExecResult{434 return ExecResult{
426 .term = try child.wait(),435 .term = try child.wait(),
lib/std/compress.zig+2
...@@ -6,6 +6,7 @@ pub const lzma = @import("compress/lzma.zig");...@@ -6,6 +6,7 @@ pub const lzma = @import("compress/lzma.zig");
6pub const lzma2 = @import("compress/lzma2.zig");6pub const lzma2 = @import("compress/lzma2.zig");
7pub const xz = @import("compress/xz.zig");7pub const xz = @import("compress/xz.zig");
8pub const zlib = @import("compress/zlib.zig");8pub const zlib = @import("compress/zlib.zig");
9pub const zstd = @import("compress/zstandard.zig");
910
10pub fn HashedReader(11pub fn HashedReader(
11 comptime ReaderType: anytype,12 comptime ReaderType: anytype,
...@@ -44,4 +45,5 @@ test {...@@ -44,4 +45,5 @@ test {
44 _ = lzma2;45 _ = lzma2;
45 _ = xz;46 _ = xz;
46 _ = zlib;47 _ = zlib;
48 _ = zstd;
47}49}
lib/std/compress/testdata/rfc8478.txt created+3027
...@@ -0,0 +1,3027 @@
1
2
3
4
5
6
7Internet Engineering Task Force (IETF) Y. Collet
8Request for Comments: 8478 M. Kucherawy, Ed.
9Category: Informational Facebook
10ISSN: 2070-1721 October 2018
11
12
13 Zstandard Compression and the application/zstd Media Type
14
15Abstract
16
17 Zstandard, or "zstd" (pronounced "zee standard"), is a data
18 compression mechanism. This document describes the mechanism and
19 registers a media type and content encoding to be used when
20 transporting zstd-compressed content via Multipurpose Internet Mail
21 Extensions (MIME).
22
23 Despite use of the word "standard" as part of its name, readers are
24 advised that this document is not an Internet Standards Track
25 specification; it is being published for informational purposes only.
26
27Status of This Memo
28
29 This document is not an Internet Standards Track specification; it is
30 published for informational purposes.
31
32 This document is a product of the Internet Engineering Task Force
33 (IETF). It represents the consensus of the IETF community. It has
34 received public review and has been approved for publication by the
35 Internet Engineering Steering Group (IESG). Not all documents
36 approved by the IESG are candidates for any level of Internet
37 Standard; see Section 2 of RFC 7841.
38
39 Information about the current status of this document, any errata,
40 and how to provide feedback on it may be obtained at
41 https://www.rfc-editor.org/info/rfc8478.
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58Collet & Kucherawy Informational [Page 1]
59
60RFC 8478 application/zstd October 2018
61
62
63Copyright Notice
64
65 Copyright (c) 2018 IETF Trust and the persons identified as the
66 document authors. All rights reserved.
67
68 This document is subject to BCP 78 and the IETF Trust's Legal
69 Provisions Relating to IETF Documents
70 (https://trustee.ietf.org/license-info) in effect on the date of
71 publication of this document. Please review these documents
72 carefully, as they describe your rights and restrictions with respect
73 to this document. Code Components extracted from this document must
74 include Simplified BSD License text as described in Section 4.e of
75 the Trust Legal Provisions and are provided without warranty as
76 described in the Simplified BSD License.
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114Collet & Kucherawy Informational [Page 2]
115
116RFC 8478 application/zstd October 2018
117
118
119Table of Contents
120
121 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4
122 2. Definitions . . . . . . . . . . . . . . . . . . . . . . . . . 4
123 3. Compression Algorithm . . . . . . . . . . . . . . . . . . . . 5
124 3.1. Frames . . . . . . . . . . . . . . . . . . . . . . . . . 6
125 3.1.1. Zstandard Frames . . . . . . . . . . . . . . . . . . 6
126 3.1.1.1. Frame Header . . . . . . . . . . . . . . . . . . 7
127 3.1.1.2. Blocks . . . . . . . . . . . . . . . . . . . . . 12
128 3.1.1.3. Compressed Blocks . . . . . . . . . . . . . . . . 14
129 3.1.1.4. Sequence Execution . . . . . . . . . . . . . . . 28
130 3.1.1.5. Repeat Offsets . . . . . . . . . . . . . . . . . 29
131 3.1.2. Skippable Frames . . . . . . . . . . . . . . . . . . 30
132 4. Entropy Encoding . . . . . . . . . . . . . . . . . . . . . . 30
133 4.1. FSE . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
134 4.1.1. FSE Table Description . . . . . . . . . . . . . . . . 31
135 4.2. Huffman Coding . . . . . . . . . . . . . . . . . . . . . 34
136 4.2.1. Huffman Tree Description . . . . . . . . . . . . . . 35
137 4.2.1.1. Huffman Tree Header . . . . . . . . . . . . . . . 36
138 4.2.1.2. FSE Compression of Huffman Weights . . . . . . . 37
139 4.2.1.3. Conversion from Weights to Huffman Prefix Codes . 38
140 4.2.2. Huffman-Coded Streams . . . . . . . . . . . . . . . . 39
141 5. Dictionary Format . . . . . . . . . . . . . . . . . . . . . . 40
142 6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 42
143 6.1. The 'application/zstd' Media Type . . . . . . . . . . . . 42
144 6.2. Content Encoding . . . . . . . . . . . . . . . . . . . . 43
145 6.3. Dictionaries . . . . . . . . . . . . . . . . . . . . . . 43
146 7. Security Considerations . . . . . . . . . . . . . . . . . . . 43
147 8. Implementation Status . . . . . . . . . . . . . . . . . . . . 44
148 9. References . . . . . . . . . . . . . . . . . . . . . . . . . 45
149 9.1. Normative References . . . . . . . . . . . . . . . . . . 45
150 9.2. Informative References . . . . . . . . . . . . . . . . . 45
151 Appendix A. Decoding Tables for Predefined Codes . . . . . . . . 46
152 A.1. Literal Length Code Table . . . . . . . . . . . . . . . . 46
153 A.2. Match Length Code Table . . . . . . . . . . . . . . . . . 49
154 A.3. Offset Code Table . . . . . . . . . . . . . . . . . . . . 52
155 Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 53
156 Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 54
157
158
159
160
161
162
163
164
165
166
167
168
169
170Collet & Kucherawy Informational [Page 3]
171
172RFC 8478 application/zstd October 2018
173
174
1751. Introduction
176
177 Zstandard, or "zstd" (pronounced "zee standard"), is a data
178 compression mechanism, akin to gzip [RFC1952].
179
180 Despite use of the word "standard" as part of its name, readers are
181 advised that this document is not an Internet Standards Track
182 specification; it is being published for informational purposes only.
183
184 This document describes the Zstandard format. Also, to enable the
185 transport of a data object compressed with Zstandard, this document
186 registers a media type that can be used to identify such content when
187 it is used in a payload encoded using Multipurpose Internet Mail
188 Extensions (MIME).
189
1902. Definitions
191
192 Some terms used elsewhere in this document are defined here for
193 clarity.
194
195 uncompressed: Describes an arbitrary set of bytes in their original
196 form, prior to being subjected to compression.
197
198 compress, compression: The act of processing a set of bytes via the
199 compression mechanism described here.
200
201 compressed: Describes the result of passing a set of bytes through
202 this mechanism. The original input has thus been compressed.
203
204 decompress, decompression: The act of processing a set of bytes
205 through the inverse of the compression mechanism described here,
206 in an attempt to recover the original set of bytes prior to
207 compression.
208
209 decompressed: Describes the result of passing a set of bytes through
210 the reverse of this mechanism. When this is successful, the
211 decompressed payload and the uncompressed payload are
212 indistinguishable.
213
214 encode: The process of translating data from one form to another;
215 this may include compression or it may refer to other translations
216 done as part of this specification.
217
218 decode: The reverse of "encode"; describes a process of reversing a
219 prior encoding to recover the original content.
220
221
222
223
224
225
226Collet & Kucherawy Informational [Page 4]
227
228RFC 8478 application/zstd October 2018
229
230
231 frame: Content compressed by Zstandard is transformed into a
232 Zstandard frame. Multiple frames can be appended into a single
233 file or stream. A frame is completely independent, has a defined
234 beginning and end, and has a set of parameters that tells the
235 decoder how to decompress it.
236
237 block: A frame encapsulates one or multiple blocks. Each block
238 contains arbitrary content, which is described by its header, and
239 has a guaranteed maximum content size that depends upon frame
240 parameters. Unlike frames, each block depends on previous blocks
241 for proper decoding. However, each block can be decompressed
242 without waiting for its successor, allowing streaming operations.
243
244 natural order: A sequence or ordering of objects or values that is
245 typical of that type of object or value. A set of unique
246 integers, for example, is in "natural order" if when progressing
247 from one element in the set or sequence to the next, there is
248 never a decrease in value.
249
250 The naming convention for identifiers within the specification is
251 Mixed_Case_With_Underscores. Identifiers inside square brackets
252 indicate that the identifier is optional in the presented context.
253
2543. Compression Algorithm
255
256 This section describes the Zstandard algorithm.
257
258 The purpose of this document is to define a lossless compressed data
259 format that is a) independent of the CPU type, operating system, file
260 system, and character set and b) is suitable for file compression and
261 pipe and streaming compression, using the Zstandard algorithm. The
262 text of the specification assumes a basic background in programming
263 at the level of bits and other primitive data representations.
264
265 The data can be produced or consumed, even for an arbitrarily long
266 sequentially presented input data stream, using only an a priori
267 bounded amount of intermediate storage, and hence can be used in data
268 communications. The format uses the Zstandard compression method,
269 and an optional xxHash-64 checksum method [XXHASH], for detection of
270 data corruption.
271
272 The data format defined by this specification does not attempt to
273 allow random access to compressed data.
274
275 Unless otherwise indicated below, a compliant compressor must produce
276 data sets that conform to the specifications presented here.
277 However, it does not need to support all options.
278
279
280
281
282Collet & Kucherawy Informational [Page 5]
283
284RFC 8478 application/zstd October 2018
285
286
287 A compliant decompressor must be able to decompress at least one
288 working set of parameters that conforms to the specifications
289 presented here. It may also ignore informative fields, such as the
290 checksum. Whenever it does not support a parameter defined in the
291 compressed stream, it must produce a non-ambiguous error code and
292 associated error message explaining which parameter is unsupported.
293
294 This specification is intended for use by implementers of software to
295 compress data into Zstandard format and/or decompress data from
296 Zstandard format. The Zstandard format is supported by an open
297 source reference implementation, written in portable C, and available
298 at [ZSTD].
299
3003.1. Frames
301
302 Zstandard compressed data is made up of one or more frames. Each
303 frame is independent and can be decompressed independently of other
304 frames. The decompressed content of multiple concatenated frames is
305 the concatenation of each frame's decompressed content.
306
307 There are two frame formats defined for Zstandard: Zstandard frames
308 and skippable frames. Zstandard frames contain compressed data,
309 while skippable frames contain custom user metadata.
310
3113.1.1. Zstandard Frames
312
313 The structure of a single Zstandard frame is as follows:
314
315 +--------------------+------------+
316 | Magic_Number | 4 bytes |
317 +--------------------+------------+
318 | Frame_Header | 2-14 bytes |
319 +--------------------+------------+
320 | Data_Block | n bytes |
321 +--------------------+------------+
322 | [More Data_Blocks] | |
323 +--------------------+------------+
324 | [Content_Checksum] | 0-4 bytes |
325 +--------------------+------------+
326
327 Magic_Number: 4 bytes, little-endian format. Value: 0xFD2FB528.
328
329 Frame_Header: 2 to 14 bytes, detailed in Section 3.1.1.1.
330
331 Data_Block: Detailed in Section 3.1.1.2. This is where data
332 appears.
333
334
335
336
337
338Collet & Kucherawy Informational [Page 6]
339
340RFC 8478 application/zstd October 2018
341
342
343 Content_Checksum: An optional 32-bit checksum, only present if
344 Content_Checksum_Flag is set. The content checksum is the result
345 of the XXH64() hash function [XXHASH] digesting the original
346 (decoded) data as input, and a seed of zero. The low 4 bytes of
347 the checksum are stored in little-endian format.
348
349 The magic number was selected to be less probable to find at the
350 beginning of an arbitrary file. It avoids trivial patterns (0x00,
351 0xFF, repeated bytes, increasing bytes, etc.), contains byte values
352 outside of ASCII range, and doesn't map into UTF-8 space, all of
353 which reduce the likelihood of its appearance at the top of a text
354 file.
355
3563.1.1.1. Frame Header
357
358 The frame header has a variable size, with a minimum of 2 bytes and
359 up to 14 bytes depending on optional parameters. The structure of
360 Frame_Header is as follows:
361
362 +-------------------------+-----------+
363 | Frame_Header_Descriptor | 1 byte |
364 +-------------------------+-----------+
365 | [Window_Descriptor] | 0-1 byte |
366 +-------------------------+-----------+
367 | [Dictionary_ID] | 0-4 bytes |
368 +-------------------------+-----------+
369 | [Frame_Content_Size] | 0-8 bytes |
370 +-------------------------+-----------+
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394Collet & Kucherawy Informational [Page 7]
395
396RFC 8478 application/zstd October 2018
397
398
3993.1.1.1.1. Frame_Header_Descriptor
400
401 The first header's byte is called the Frame_Header_Descriptor. It
402 describes which other fields are present. Decoding this byte is
403 enough to tell the size of Frame_Header.
404
405 +------------+-------------------------+
406 | Bit Number | Field Name |
407 +------------+-------------------------+
408 | 7-6 | Frame_Content_Size_Flag |
409 +------------+-------------------------+
410 | 5 | Single_Segment_Flag |
411 +------------+-------------------------+
412 | 4 | (unused) |
413 +------------+-------------------------+
414 | 3 | (reserved) |
415 +------------+-------------------------+
416 | 2 | Content_Checksum_Flag |
417 +------------+-------------------------+
418 | 1-0 | Dictionary_ID_Flag |
419 +------------+-------------------------+
420
421 In this table, bit 7 is the highest bit, while bit 0 is the lowest
422 one.
423
4243.1.1.1.1.1. Frame_Content_Size_Flag
425
426 This is a 2-bit flag (equivalent to Frame_Header_Descriptor right-
427 shifted 6 bits) specifying whether Frame_Content_Size (the
428 decompressed data size) is provided within the header. Flag_Value
429 provides FCS_Field_Size, which is the number of bytes used by
430 Frame_Content_Size according to the following table:
431
432 +----------------+--------+---+---+---+
433 | Flag_Value | 0 | 1 | 2 | 3 |
434 +----------------+--------+---+---+---+
435 | FCS_Field_Size | 0 or 1 | 2 | 4 | 8 |
436 +----------------+--------+---+---+---+
437
438 When Flag_Value is 0, FCS_Field_Size depends on Single_Segment_Flag:
439 If Single_Segment_Flag is set, FCS_Field_Size is 1. Otherwise,
440 FCS_Field_Size is 0; Frame_Content_Size is not provided.
441
442
443
444
445
446
447
448
449
450Collet & Kucherawy Informational [Page 8]
451
452RFC 8478 application/zstd October 2018
453
454
4553.1.1.1.1.2. Single_Segment_Flag
456
457 If this flag is set, data must be regenerated within a single
458 continuous memory segment.
459
460 In this case, Window_Descriptor byte is skipped, but
461 Frame_Content_Size is necessarily present. As a consequence, the
462 decoder must allocate a memory segment of size equal or larger than
463 Frame_Content_Size.
464
465 In order to protect the decoder from unreasonable memory
466 requirements, a decoder is allowed to reject a compressed frame that
467 requests a memory size beyond the decoder's authorized range.
468
469 For broader compatibility, decoders are recommended to support memory
470 sizes of at least 8 MB. This is only a recommendation; each decoder
471 is free to support higher or lower limits, depending on local
472 limitations.
473
4743.1.1.1.1.3. Unused Bit
475
476 A decoder compliant with this specification version shall not
477 interpret this bit. It might be used in a future version, to signal
478 a property that is not mandatory to properly decode the frame. An
479 encoder compliant with this specification must set this bit to zero.
480
4813.1.1.1.1.4. Reserved Bit
482
483 This bit is reserved for some future feature. Its value must be
484 zero. A decoder compliant with this specification version must
485 ensure it is not set. This bit may be used in a future revision, to
486 signal a feature that must be interpreted to decode the frame
487 correctly.
488
4893.1.1.1.1.5. Content_Checksum_Flag
490
491 If this flag is set, a 32-bit Content_Checksum will be present at the
492 frame's end. See the description of Content_Checksum above.
493
494
495
496
497
498
499
500
501
502
503
504
505
506Collet & Kucherawy Informational [Page 9]
507
508RFC 8478 application/zstd October 2018
509
510
5113.1.1.1.1.6. Dictionary_ID_Flag
512
513 This is a 2-bit flag (= Frame_Header_Descriptor & 0x3) indicating
514 whether a dictionary ID is provided within the header. It also
515 specifies the size of this field as DID_Field_Size:
516
517 +----------------+---+---+---+---+
518 | Flag_Value | 0 | 1 | 2 | 3 |
519 +----------------+---+---+---+---+
520 | DID_Field_Size | 0 | 1 | 2 | 4 |
521 +----------------+---+---+---+---+
522
5233.1.1.1.2. Window Descriptor
524
525 This provides guarantees about the minimum memory buffer required to
526 decompress a frame. This information is important for decoders to
527 allocate enough memory.
528
529 The Window_Descriptor byte is optional. When Single_Segment_Flag is
530 set, Window_Descriptor is not present. In this case, Window_Size is
531 Frame_Content_Size, which can be any value from 0 to 2^64-1 bytes (16
532 ExaBytes).
533
534 +------------+----------+----------+
535 | Bit Number | 7-3 | 2-0 |
536 +------------+----------+----------+
537 | Field Name | Exponent | Mantissa |
538 +------------+----------+----------+
539
540 The minimum memory buffer size is called Window_Size. It is
541 described by the following formulae:
542
543 windowLog = 10 + Exponent;
544 windowBase = 1 << windowLog;
545 windowAdd = (windowBase / 8) * Mantissa;
546 Window_Size = windowBase + windowAdd;
547
548 The minimum Window_Size is 1 KB. The maximum Window_Size is (1<<41)
549 + 7*(1<<38) bytes, which is 3.75 TB.
550
551 In general, larger Window_Size values tend to improve the compression
552 ratio, but at the cost of increased memory usage.
553
554 To properly decode compressed data, a decoder will need to allocate a
555 buffer of at least Window_Size bytes.
556
557
558
559
560
561
562Collet & Kucherawy Informational [Page 10]
563
564RFC 8478 application/zstd October 2018
565
566
567 In order to protect decoders from unreasonable memory requirements, a
568 decoder is allowed to reject a compressed frame that requests a
569 memory size beyond decoder's authorized range.
570
571 For improved interoperability, it's recommended for decoders to
572 support values of Window_Size up to 8 MB and for encoders not to
573 generate frames requiring a Window_Size larger than 8 MB. It's
574 merely a recommendation though, and decoders are free to support
575 larger or lower limits, depending on local limitations.
576
5773.1.1.1.3. Dictionary_ID
578
579 This is a variable size field, which contains the ID of the
580 dictionary required to properly decode the frame. This field is
581 optional. When it's not present, it's up to the decoder to know
582 which dictionary to use.
583
584 Dictionary_ID field size is provided by DID_Field_Size.
585 DID_Field_Size is directly derived from the value of
586 Dictionary_ID_Flag. One byte can represent an ID 0-255; 2 bytes can
587 represent an ID 0-65535; 4 bytes can represent an ID 0-4294967295.
588 Format is little-endian.
589
590 It is permitted to represent a small ID (for example, 13) with a
591 large 4-byte dictionary ID, even if it is less efficient.
592
593 Within private environments, any dictionary ID can be used. However,
594 for frames and dictionaries distributed in public space,
595 Dictionary_ID must be attributed carefully. The following ranges are
596 reserved for use only with dictionaries that have been registered
597 with IANA (see Section 6.3):
598
599 low range: <= 32767
600 high range: >= (1 << 31)
601
602 Any other value for Dictionary_ID can be used by private arrangement
603 between participants.
604
605 Any payload presented for decompression that references an
606 unregistered reserved dictionary ID results in an error.
607
608
609
610
611
612
613
614
615
616
617
618Collet & Kucherawy Informational [Page 11]
619
620RFC 8478 application/zstd October 2018
621
622
6233.1.1.1.4. Frame Content Size
624
625 This is the original (uncompressed) size. This information is
626 optional. Frame_Content_Size uses a variable number of bytes,
627 provided by FCS_Field_Size. FCS_Field_Size is provided by the value
628 of Frame_Content_Size_Flag. FCS_Field_Size can be equal to 0 (not
629 present), 1, 2, 4, or 8 bytes.
630
631 +----------------+--------------+
632 | FCS Field Size | Range |
633 +----------------+--------------+
634 | 0 | unknown |
635 +----------------+--------------+
636 | 1 | 0 - 255 |
637 +----------------+--------------+
638 | 2 | 256 - 65791 |
639 +----------------+--------------+
640 | 4 | 0 - 2^32 - 1 |
641 +----------------+--------------+
642 | 8 | 0 - 2^64 - 1 |
643 +----------------+--------------+
644
645 Frame_Content_Size format is little-endian. When FCS_Field_Size is
646 1, 4, or 8 bytes, the value is read directly. When FCS_Field_Size is
647 2, the offset of 256 is added. It's allowed to represent a small
648 size (for example 18) using any compatible variant.
649
6503.1.1.2. Blocks
651
652 After Magic_Number and Frame_Header, there are some number of blocks.
653 Each frame must have at least 1 block, but there is no upper limit on
654 the number of blocks per frame.
655
656 The structure of a block is as follows:
657
658 +--------------+---------------+
659 | Block_Header | Block_Content |
660 +--------------+---------------+
661 | 3 bytes | n bytes |
662 +--------------+---------------+
663
664
665
666
667
668
669
670
671
672
673
674Collet & Kucherawy Informational [Page 12]
675
676RFC 8478 application/zstd October 2018
677
678
679 Block_Header uses 3 bytes, written using little-endian convention.
680 It contains three fields:
681
682 +------------+------------+------------+
683 | Last_Block | Block_Type | Block_Size |
684 +------------+------------+------------+
685 | bit 0 | bits 1-2 | bits 3-23 |
686 +------------+------------+------------+
687
6883.1.1.2.1. Last_Block
689
690 The lowest bit (Last_Block) signals whether this block is the last
691 one. The frame will end after this last block. It may be followed
692 by an optional Content_Checksum (see Section 3.1.1).
693
6943.1.1.2.2. Block_Type
695
696 The next 2 bits represent the Block_Type. There are four block
697 types:
698
699 +-----------+------------------+
700 | Value | Block_Type |
701 +-----------+------------------+
702 | 0 | Raw_Block |
703 +-----------+------------------+
704 | 1 | RLE_Block |
705 +-----------+------------------+
706 | 2 | Compressed_Block |
707 +-----------+------------------+
708 | 3 | Reserved |
709 +-----------+------------------+
710
711 Raw_Block: This is an uncompressed block. Block_Content contains
712 Block_Size bytes.
713
714 RLE_Block: This is a single byte, repeated Block_Size times.
715 Block_Content consists of a single byte. On the decompression
716 side, this byte must be repeated Block_Size times.
717
718 Compressed_Block: This is a compressed block as described in
719 Section 3.1.1.3. Block_Size is the length of Block_Content,
720 namely the compressed data. The decompressed size is not known,
721 but its maximum possible value is guaranteed (see below).
722
723 Reserved: This is not a block. This value cannot be used with the
724 current specification. If such a value is present, it is
725 considered to be corrupt data.
726
727
728
729
730Collet & Kucherawy Informational [Page 13]
731
732RFC 8478 application/zstd October 2018
733
734
7353.1.1.2.3. Block_Size
736
737 The upper 21 bits of Block_Header represent the Block_Size.
738 Block_Size is the size of the block excluding the header. A block
739 can contain any number of bytes (even zero), up to
740 Block_Maximum_Decompressed_Size, which is the smallest of:
741
742 o Window_Size
743
744 o 128 KB
745
746 A Compressed_Block has the extra restriction that Block_Size is
747 always strictly less than the decompressed size. If this condition
748 cannot be respected, the block must be sent uncompressed instead
749 (i.e., treated as a Raw_Block).
750
7513.1.1.3. Compressed Blocks
752
753 To decompress a compressed block, the compressed size must be
754 provided from the Block_Size field within Block_Header.
755
756 A compressed block consists of two sections: a Literals
757 Section (Section 3.1.1.3.1) and a
758 Sequences_Section (Section 3.1.1.3.2). The results of the two
759 sections are then combined to produce the decompressed data in
760 Sequence Execution (Section 3.1.1.4).
761
762 To decode a compressed block, the following elements are necessary:
763
764 o Previous decoded data, up to a distance of Window_Size, or the
765 beginning of the Frame, whichever is smaller. Single_Segment_Flag
766 will be set in the latter case.
767
768 o List of "recent offsets" from the previous Compressed_Block.
769
770 o The previous Huffman tree, required by Treeless_Literals_Block
771 type.
772
773 o Previous Finite State Entropy (FSE) decoding tables, required by
774 Repeat_Mode, for each symbol type (literals lengths, match
775 lengths, offsets).
776
777 Note that decoding tables are not always from the previous
778 Compressed_Block:
779
780 o Every decoding table can come from a dictionary.
781
782
783
784
785
786Collet & Kucherawy Informational [Page 14]
787
788RFC 8478 application/zstd October 2018
789
790
791 o The Huffman tree comes from the previous
792 Compressed_Literals_Block.
793
7943.1.1.3.1. Literals_Section_Header
795
796 All literals are regrouped in the first part of the block. They can
797 be decoded first and then copied during Sequence Execution (see
798 Section 3.1.1.4), or they can be decoded on the flow during Sequence
799 Execution.
800
801 Literals can be stored uncompressed or compressed using Huffman
802 prefix codes. When compressed, an optional tree description can be
803 present, followed by 1 or 4 streams.
804
805 +----------------------------+
806 | Literals_Section_Header |
807 +----------------------------+
808 | [Huffman_Tree_Description] |
809 +----------------------------+
810 | [Jump_Table] |
811 +----------------------------+
812 | Stream_1 |
813 +----------------------------+
814 | [Stream_2] |
815 +----------------------------+
816 | [Stream_3] |
817 +----------------------------+
818 | [Stream_4] |
819 +----------------------------+
820
8213.1.1.3.1.1. Literals_Section_Header
822
823 This field describes how literals are packed. It's a byte-aligned
824 variable-size bit field, ranging from 1 to 5 bytes, using little-
825 endian convention.
826
827 +---------------------+-----------+
828 | Literals_Block_Type | 2 bits |
829 +---------------------+-----------+
830 | Size_Format | 1-2 bits |
831 +---------------------+-----------+
832 | Regenerated_Size | 5-20 bits |
833 +---------------------+-----------+
834 | [Compressed_Size] | 0-18 bits |
835 +---------------------+-----------+
836
837 In this representation, bits at the top are the lowest bits.
838
839
840
841
842Collet & Kucherawy Informational [Page 15]
843
844RFC 8478 application/zstd October 2018
845
846
847 The Literals_Block_Type field uses the two lowest bits of the first
848 byte, describing four different block types:
849
850 +---------------------------+-------+
851 | Literals_Block_Type | Value |
852 +---------------------------+-------+
853 | Raw_Literals_Block | 0 |
854 +---------------------------+-------+
855 | RLE_Literals_Block | 1 |
856 +---------------------------+-------+
857 | Compressed_Literals_Block | 2 |
858 +---------------------------+-------+
859 | Treeless_Literals_Block | 3 |
860 +---------------------------+-------+
861
862 Raw_Literals_Block: Literals are stored uncompressed.
863 Literals_Section_Content is Regenerated_Size.
864
865 RLE_Literals_Block: Literals consist of a single-byte value repeated
866 Regenerated_Size times. Literals_Section_Content is 1.
867
868 Compressed_Literals_Block: This is a standard Huffman-compressed
869 block, starting with a Huffman tree description. See details
870 below. Literals_Section_Content is Compressed_Size.
871
872 Treeless_Literals_Block: This is a Huffman-compressed block, using
873 the Huffman tree from the previous Compressed_Literals_Block, or a
874 dictionary if there is no previous Huffman-compressed literals
875 block. Huffman_Tree_Description will be skipped. Note that if
876 this mode is triggered without any previous Huffman-table in the
877 frame (or dictionary, per Section 5), it should be treated as data
878 corruption. Literals_Section_Content is Compressed_Size.
879
880 The Size_Format is divided into two families:
881
882 o For Raw_Literals_Block and RLE_Literals_Block, it's only necessary
883 to decode Regenerated_Size. There is no Compressed_Size field.
884
885 o For Compressed_Block and Treeless_Literals_Block, it's required to
886 decode both Compressed_Size and Regenerated_Size (the decompressed
887 size). It's also necessary to decode the number of streams (1 or
888 4).
889
890 For values spanning several bytes, the convention is little endian.
891
892 Size_Format for Raw_Literals_Block and RLE_Literals_Block uses 1 or 2
893 bits. Its value is (Literals_Section_Header[0]>>2) & 0x3.
894
895
896
897
898Collet & Kucherawy Informational [Page 16]
899
900RFC 8478 application/zstd October 2018
901
902
903 Size_Format == 00 or 10: Size_Format uses 1 bit. Regenerated_Size
904 uses 5 bits (value 0-31). Literals_Section_Header uses 1 byte.
905 Regenerated_Size = Literal_Section_Header[0]>>3.
906
907 Size_Format == 01: Size_Format uses 2 bits. Regenerated_Size uses
908 12 bits (values 0-4095). Literals_Section_Header uses 2 bytes.
909 Regenerated_Size = (Literals_Section_Header[0]>>4) +
910 (Literals_Section_Header[1]<<4).
911
912 Size_Format == 11: Size_Format uses 2 bits. Regenerated_Size uses
913 20 bits (values 0-1048575). Literals_Section_Header uses 3 bytes.
914 Regenerated_Size = (Literals_Section_Header[0]>>4) +
915 (Literals_Section_Header[1]<<4) + (Literals_Section_Header[2]<<12)
916
917 Only Stream_1 is present for these cases. Note that it is permitted
918 to represent a short value (for example, 13) using a long format,
919 even if it's less efficient.
920
921 Size_Format for Compressed_Literals_Block and Treeless_Literals_Block
922 always uses 2 bits.
923
924 Size_Format == 00: A single stream. Both Regenerated_Size and
925 Compressed_Size use 10 bits (values 0-1023).
926 Literals_Section_Header uses 3 bytes.
927
928 Size_Format == 01: 4 streams. Both Regenerated_Size and
929 Compressed_Size use 10 bits (values 0-1023).
930 Literals_Section_Header uses 3 bytes.
931
932 Size_Format == 10: 4 streams. Both Regenerated_Size and
933 Compressed_Size use 14 bits (values 0-16383).
934 Literals_Section_Header uses 4 bytes.
935
936 Size_Format == 11: 4 streams. Both Regenerated_Size and
937 Compressed_Size use 18 bits (values 0-262143).
938 Literals_Section_Header uses 5 bytes.
939
940 Both the Compressed_Size and Regenerated_Size fields follow little-
941 endian convention. Note that Compressed_Size includes the size of
942 the Huffman_Tree_Description when it is present.
943
9443.1.1.3.1.2. Raw_Literals_Block
945
946 The data in Stream_1 is Regenerated_Size bytes long. It contains the
947 raw literals data to be used during Sequence Execution
948 (Section 3.1.1.3.2).
949
950
951
952
953
954Collet & Kucherawy Informational [Page 17]
955
956RFC 8478 application/zstd October 2018
957
958
9593.1.1.3.1.3. RLE_Literals_Block
960
961 Stream_1 consists of a single byte that should be repeated
962 Regenerated_Size times to generate the decoded literals.
963
9643.1.1.3.1.4. Compressed_Literals_Block and Treeless_Literals_Block
965
966 Both of these modes contain Huffman-encoded data. For
967 Treeless_Literals_Block, the Huffman table comes from the previously
968 compressed literals block, or from a dictionary; see Section 5.
969
9703.1.1.3.1.5. Huffman_Tree_Description
971
972 This section is only present when the Literals_Block_Type type is
973 Compressed_Literals_Block (2). The format of
974 Huffman_Tree_Description can be found in Section 4.2.1. The size of
975 Huffman_Tree_Description is determined during the decoding process.
976 It must be used to determine where streams begin.
977
978 Total_Streams_Size = Compressed_Size
979 - Huffman_Tree_Description_Size
980
9813.1.1.3.1.6. Jump_Table
982
983 The Jump_Table is only present when there are 4 Huffman-coded
984 streams.
985
986 (Reminder: Huffman-compressed data consists of either 1 or 4 Huffman-
987 coded streams.)
988
989 If only 1 stream is present, it is a single bitstream occupying the
990 entire remaining portion of the literals block, encoded as described
991 within Section 4.2.2.
992
993 If there are 4 streams, Literals_Section_Header only provides enough
994 information to know the decompressed and compressed sizes of all 4
995 streams combined. The decompressed size of each stream is equal to
996 (Regenerated_Size+3)/4, except for the last stream, which may be up
997 to 3 bytes smaller, to reach a total decompressed size as specified
998 in Regenerated_Size.
999
1000 The compressed size of each stream is provided explicitly in the
1001 Jump_Table. The Jump_Table is 6 bytes long and consists of three
1002 2-byte little-endian fields, describing the compressed sizes of the
1003 first 3 streams. Stream4_Size is computed from Total_Streams_Size
1004 minus sizes of other streams.
1005
1006
1007
1008
1009
1010Collet & Kucherawy Informational [Page 18]
1011
1012RFC 8478 application/zstd October 2018
1013
1014
1015 Stream4_Size = Total_Streams_Size - 6
1016 - Stream1_Size - Stream2_Size
1017 - Stream3_Size
1018
1019 Note that if Stream1_Size + Stream2_Size + Stream3_Size exceeds
1020 Total_Streams_Size, the data are considered corrupted.
1021
1022 Each of these 4 bitstreams is then decoded independently as a
1023 Huffman-Coded stream, as described in Section 4.2.2.
1024
10253.1.1.3.2. Sequences_Section
1026
1027 A compressed block is a succession of sequences. A sequence is a
1028 literal copy command, followed by a match copy command. A literal
1029 copy command specifies a length. It is the number of bytes to be
1030 copied (or extracted) from the Literals Section. A match copy
1031 command specifies an offset and a length.
1032
1033 When all sequences are decoded, if there are literals left in the
1034 literals section, these bytes are added at the end of the block.
1035
1036 This is described in more detail in Section 3.1.1.4.
1037
1038 The Sequences_Section regroups all symbols required to decode
1039 commands. There are three symbol types: literals lengths, offsets,
1040 and match lengths. They are encoded together, interleaved, in a
1041 single "bitstream".
1042
1043 The Sequences_Section starts by a header, followed by optional
1044 probability tables for each symbol type, followed by the bitstream.
1045
1046 Sequences_Section_Header
1047 [Literals_Length_Table]
1048 [Offset_Table]
1049 [Match_Length_Table]
1050 bitStream
1051
1052 To decode the Sequences_Section, it's necessary to know its size.
1053 This size is deduced from the size of the Literals_Section:
1054 Sequences_Section_Size = Block_Size - Literals_Section_Header -
1055 Literals_Section_Content
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066Collet & Kucherawy Informational [Page 19]
1067
1068RFC 8478 application/zstd October 2018
1069
1070
10713.1.1.3.2.1. Sequences_Section_Header
1072
1073 This header consists of two items:
1074
1075 o Number_of_Sequences
1076
1077 o Symbol_Compression_Modes
1078
1079 Number_of_Sequences is a variable size field using between 1 and 3
1080 bytes. If the first byte is "byte0":
1081
1082 o if (byte0 == 0): there are no sequences. The sequence section
1083 stops here. Decompressed content is defined entirely as Literals
1084 Section content. The FSE tables used in Repeat_Mode are not
1085 updated.
1086
1087 o if (byte0 < 128): Number_of_Sequences = byte0. Uses 1 byte.
1088
1089 o if (byte0 < 255): Number_of_Sequences = ((byte0 - 128) << 8) +
1090 byte1. Uses 2 bytes.
1091
1092 o if (byte0 == 255): Number_of_Sequences = byte1 + (byte2 << 8) +
1093 0x7F00. Uses 3 bytes.
1094
1095 Symbol_Compression_Modes is a single byte, defining the compression
1096 mode of each symbol type.
1097
1098 +-------------+----------------------+
1099 | Bit Number | Field Name |
1100 +-------------+----------------------+
1101 | 7-6 | Literal_Lengths_Mode |
1102 +-------------+----------------------+
1103 | 5-4 | Offsets_Mode |
1104 +-------------+----------------------+
1105 | 3-2 | Match_Lengths_Mode |
1106 +-------------+----------------------+
1107 | 1-0 | Reserved |
1108 +-------------+----------------------+
1109
1110 The last field, Reserved, must be all zeroes.
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122Collet & Kucherawy Informational [Page 20]
1123
1124RFC 8478 application/zstd October 2018
1125
1126
1127 Literals_Lengths_Mode, Offsets_Mode, and Match_Lengths_Mode define
1128 the Compression_Mode of literals lengths, offsets, and match lengths
1129 symbols, respectively. They follow the same enumeration:
1130
1131 +-------+---------------------+
1132 | Value | Compression_Mode |
1133 +-------+---------------------+
1134 | 0 | Predefined_Mode |
1135 +-------+---------------------+
1136 | 1 | RLE_Mode |
1137 +-------+---------------------+
1138 | 2 | FSE_Compressed_Mode |
1139 +-------+---------------------+
1140 | 3 | Repeat_Mode |
1141 +-------+---------------------+
1142
1143 Predefined_Mode: A predefined FSE (see Section 4.1) distribution
1144 table is used, as defined in Section 3.1.1.3.2.2. No distribution
1145 table will be present.
1146
1147 RLE_Mode: The table description consists of a single byte, which
1148 contains the symbol's value. This symbol will be used for all
1149 sequences.
1150
1151 FSE_Compressed_Mode: Standard FSE compression. A distribution table
1152 will be present. The format of this distribution table is
1153 described in Section 4.1.1. Note that the maximum allowed
1154 accuracy log for literals length and match length tables is 9, and
1155 the maximum accuracy log for the offsets table is 8. This mode
1156 must not be used when only one symbol is present; RLE_Mode should
1157 be used instead (although any other mode will work).
1158
1159 Repeat_Mode: The table used in the previous Compressed_Block with
1160 Number_Of_Sequences > 0 will be used again, or if this is the
1161 first block, the table in the dictionary will be used. Note that
1162 this includes RLE_Mode, so if Repeat_Mode follows RLE_Mode, the
1163 same symbol will be repeated. It also includes Predefined_Mode,
1164 in which case Repeat_Mode will have the same outcome as
1165 Predefined_Mode. No distribution table will be present. If this
1166 mode is used without any previous sequence table in the frame (or
1167 dictionary; see Section 5) to repeat, this should be treated as
1168 corruption.
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178Collet & Kucherawy Informational [Page 21]
1179
1180RFC 8478 application/zstd October 2018
1181
1182
11833.1.1.3.2.1.1. Sequence Codes for Lengths and Offsets
1184
1185 Each symbol is a code in its own context, which specifies Baseline
1186 and Number_of_Bits to add. Codes are FSE compressed and interleaved
1187 with raw additional bits in the same bitstream.
1188
1189 Literals length codes are values ranging from 0 to 35 inclusive.
1190 They define lengths from 0 to 131071 bytes. The literals length is
1191 equal to the decoded Baseline plus the result of reading
1192 Number_of_Bits bits from the bitstream, as a little-endian value.
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234Collet & Kucherawy Informational [Page 22]
1235
1236RFC 8478 application/zstd October 2018
1237
1238
1239 +----------------------+----------+----------------+
1240 | Literals_Length_Code | Baseline | Number_of_Bits |
1241 +----------------------+----------+----------------+
1242 | 0-15 | length | 0 |
1243 +----------------------+----------+----------------+
1244 | 16 | 16 | 1 |
1245 +----------------------+----------+----------------+
1246 | 17 | 18 | 1 |
1247 +----------------------+----------+----------------+
1248 | 18 | 20 | 1 |
1249 +----------------------+----------+----------------+
1250 | 19 | 22 | 1 |
1251 +----------------------+----------+----------------+
1252 | 20 | 24 | 2 |
1253 +----------------------+----------+----------------+
1254 | 21 | 28 | 2 |
1255 +----------------------+----------+----------------+
1256 | 22 | 32 | 3 |
1257 +----------------------+----------+----------------+
1258 | 23 | 40 | 3 |
1259 +----------------------+----------+----------------+
1260 | 24 | 48 | 4 |
1261 +----------------------+----------+----------------+
1262 | 25 | 64 | 6 |
1263 +----------------------+----------+----------------+
1264 | 26 | 128 | 7 |
1265 +----------------------+----------+----------------+
1266 | 27 | 256 | 8 |
1267 +----------------------+----------+----------------+
1268 | 28 | 512 | 9 |
1269 +----------------------+----------+----------------+
1270 | 29 | 1024 | 10 |
1271 +----------------------+----------+----------------+
1272 | 30 | 2048 | 11 |
1273 +----------------------+----------+----------------+
1274 | 31 | 4096 | 12 |
1275 +----------------------+----------+----------------+
1276 | 32 | 8192 | 13 |
1277 +----------------------+----------+----------------+
1278 | 33 | 16384 | 14 |
1279 +----------------------+----------+----------------+
1280 | 34 | 32768 | 15 |
1281 +----------------------+----------+----------------+
1282 | 35 | 65536 | 16 |
1283 +----------------------+----------+----------------+
1284
1285
1286
1287
1288
1289
1290Collet & Kucherawy Informational [Page 23]
1291
1292RFC 8478 application/zstd October 2018
1293
1294
1295 Match length codes are values ranging from 0 to 52 inclusive. They
1296 define lengths from 3 to 131074 bytes. The match length is equal to
1297 the decoded Baseline plus the result of reading Number_of_Bits bits
1298 from the bitstream, as a little-endian value.
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346Collet & Kucherawy Informational [Page 24]
1347
1348RFC 8478 application/zstd October 2018
1349
1350
1351 +-------------------+-----------------------+----------------+
1352 | Match_Length_Code | Baseline | Number_of_Bits |
1353 +-------------------+-----------------------+----------------+
1354 | 0-31 | Match_Length_Code + 3 | 0 |
1355 +-------------------+-----------------------+----------------+
1356 | 32 | 35 | 1 |
1357 +-------------------+-----------------------+----------------+
1358 | 33 | 37 | 1 |
1359 +-------------------+-----------------------+----------------+
1360 | 34 | 39 | 1 |
1361 +-------------------+-----------------------+----------------+
1362 | 35 | 41 | 1 |
1363 +-------------------+-----------------------+----------------+
1364 | 36 | 43 | 2 |
1365 +-------------------+-----------------------+----------------+
1366 | 37 | 47 | 2 |
1367 +-------------------+-----------------------+----------------+
1368 | 38 | 51 | 3 |
1369 +-------------------+-----------------------+----------------+
1370 | 39 | 59 | 3 |
1371 +-------------------+-----------------------+----------------+
1372 | 40 | 67 | 4 |
1373 +-------------------+-----------------------+----------------+
1374 | 41 | 83 | 4 |
1375 +-------------------+-----------------------+----------------+
1376 | 42 | 99 | 5 |
1377 +-------------------+-----------------------+----------------+
1378 | 43 | 131 | 7 |
1379 +-------------------+-----------------------+----------------+
1380 | 44 | 259 | 8 |
1381 +-------------------+-----------------------+----------------+
1382 | 45 | 515 | 9 |
1383 +-------------------+-----------------------+----------------+
1384 | 46 | 1027 | 10 |
1385 +-------------------+-----------------------+----------------+
1386 | 47 | 2051 | 11 |
1387 +-------------------+-----------------------+----------------+
1388 | 48 | 4099 | 12 |
1389 +-------------------+-----------------------+----------------+
1390 | 49 | 8195 | 13 |
1391 +-------------------+-----------------------+----------------+
1392 | 50 | 16387 | 14 |
1393 +-------------------+-----------------------+----------------+
1394 | 51 | 32771 | 15 |
1395 +-------------------+-----------------------+----------------+
1396 | 52 | 65539 | 16 |
1397 +-------------------+-----------------------+----------------+
1398
1399
1400
1401
1402Collet & Kucherawy Informational [Page 25]
1403
1404RFC 8478 application/zstd October 2018
1405
1406
1407 Offset codes are values ranging from 0 to N.
1408
1409 A decoder is free to limit its maximum supported value for N.
1410 Support for values of at least 22 is recommended. At the time of
1411 this writing, the reference decoder supports a maximum N value of 31.
1412
1413 An offset code is also the number of additional bits to read in
1414 little-endian fashion and can be translated into an Offset_Value
1415 using the following formulas:
1416
1417 Offset_Value = (1 << offsetCode) + readNBits(offsetCode);
1418 if (Offset_Value > 3) Offset = Offset_Value - 3;
1419
1420 This means that maximum Offset_Value is (2^(N+1))-1, supporting back-
1421 reference distance up to (2^(N+1))-4, but it is limited by the
1422 maximum back-reference distance (see Section 3.1.1.1.2).
1423
1424 Offset_Value from 1 to 3 are special: they define "repeat codes".
1425 This is described in more detail in Section 3.1.1.5.
1426
14273.1.1.3.2.1.2. Decoding Sequences
1428
1429 FSE bitstreams are read in reverse of the direction they are written.
1430 In zstd, the compressor writes bits forward into a block, and the
1431 decompressor must read the bitstream backwards.
1432
1433 To find the start of the bitstream, it is therefore necessary to know
1434 the offset of the last byte of the block, which can be found by
1435 counting Block_Size bytes after the block header.
1436
1437 After writing the last bit containing information, the compressor
1438 writes a single 1 bit and then fills the byte with 0-7 zero bits of
1439 padding. The last byte of the compressed bitstream cannot be zero
1440 for that reason.
1441
1442 When decompressing, the last byte containing the padding is the first
1443 byte to read. The decompressor needs to skip 0-7 initial zero bits
1444 until the first 1 bit occurs. Afterwards, the useful part of the
1445 bitstream begins.
1446
1447 FSE decoding requires a 'state' to be carried from symbol to symbol.
1448 For more explanation on FSE decoding, see Section 4.1.
1449
1450 For sequence decoding, a separate state keeps track of each literal
1451 lengths, offsets, and match lengths symbols. Some FSE primitives are
1452 also used. For more details on the operation of these primitives,
1453 see Section 4.1.
1454
1455
1456
1457
1458Collet & Kucherawy Informational [Page 26]
1459
1460RFC 8478 application/zstd October 2018
1461
1462
1463 The bitstream starts with initial FSE state values, each using the
1464 required number of bits in their respective accuracy, decoded
1465 previously from their normalized distribution. It starts with
1466 Literals_Length_State, followed by Offset_State, and finally
1467 Match_Length_State.
1468
1469 Note that all values are read backward, so the 'start' of the
1470 bitstream is at the highest position in memory, immediately before
1471 the last 1 bit for padding.
1472
1473 After decoding the starting states, a single sequence is decoded
1474 Number_Of_Sequences times. These sequences are decoded in order from
1475 first to last. Since the compressor writes the bitstream in the
1476 forward direction, this means the compressor must encode the
1477 sequences starting with the last one and ending with the first.
1478
1479 For each of the symbol types, the FSE state can be used to determine
1480 the appropriate code. The code then defines the Baseline and
1481 Number_of_Bits to read for each type. The description of the codes
1482 for how to determine these values can be found in
1483 Section 3.1.1.3.2.1.
1484
1485 Decoding starts by reading the Number_of_Bits required to decode
1486 offset. It does the same for Match_Length and then for
1487 Literals_Length. This sequence is then used for Sequence Execution
1488 (see Section 3.1.1.4).
1489
1490 If it is not the last sequence in the block, the next operation is to
1491 update states. Using the rules pre-calculated in the decoding
1492 tables, Literals_Length_State is updated, followed by
1493 Match_Length_State, and then Offset_State. See Section 4.1 for
1494 details on how to update states from the bitstream.
1495
1496 This operation will be repeated Number_of_Sequences times. At the
1497 end, the bitstream shall be entirely consumed; otherwise, the
1498 bitstream is considered corrupted.
1499
15003.1.1.3.2.2. Default Distributions
1501
1502 If Predefined_Mode is selected for a symbol type, its FSE decoding
1503 table is generated from a predefined distribution table defined here.
1504 For details on how to convert this distribution into a decoding
1505 table, see Section 4.1.
1506
1507
1508
1509
1510
1511
1512
1513
1514Collet & Kucherawy Informational [Page 27]
1515
1516RFC 8478 application/zstd October 2018
1517
1518
15193.1.1.3.2.2.1. Literals Length
1520
1521 The decoding table uses an accuracy log of 6 bits (64 states).
1522
1523 short literalsLength_defaultDistribution[36] =
1524 { 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
1525 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1,
1526 -1,-1,-1,-1
1527 };
1528
15293.1.1.3.2.2.2. Match Length
1530
1531 The decoding table uses an accuracy log of 6 bits (64 states).
1532
1533 short matchLengths_defaultDistribution[53] =
1534 { 1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
1535 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1536 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1,-1,
1537 -1,-1,-1,-1,-1
1538 };
1539
15403.1.1.3.2.2.3. Offset Codes
1541
1542 The decoding table uses an accuracy log of 5 bits (32 states), and
1543 supports a maximum N value of 28, allowing offset values up to
1544 536,870,908.
1545
1546 If any sequence in the compressed block requires a larger offset than
1547 this, it's not possible to use the default distribution to represent
1548 it.
1549
1550 short offsetCodes_defaultDistribution[29] =
1551 { 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
1552 1, 1, 1, 1, 1, 1, 1, 1,-1,-1,-1,-1,-1
1553 };
1554
15553.1.1.4. Sequence Execution
1556
1557 Once literals and sequences have been decoded, they are combined to
1558 produce the decoded content of a block.
1559
1560 Each sequence consists of a tuple of (literals_length, offset_value,
1561 match_length), decoded as described in the
1562 Sequences_Section (Section 3.1.1.3.2). To execute a sequence, first
1563 copy literals_length bytes from the decoded literals to the output.
1564
1565
1566
1567
1568
1569
1570Collet & Kucherawy Informational [Page 28]
1571
1572RFC 8478 application/zstd October 2018
1573
1574
1575 Then, match_length bytes are copied from previous decoded data. The
1576 offset to copy from is determined by offset_value:
1577
1578 o if Offset_Value > 3, then the offset is Offset_Value - 3;
1579
1580 o if Offset_Value is from 1-3, the offset is a special repeat offset
1581 value. See Section 3.1.1.5 for how the offset is determined in
1582 this case.
1583
1584 The offset is defined as from the current position (after copying the
1585 literals), so an offset of 6 and a match length of 3 means that 3
1586 bytes should be copied from 6 bytes back. Note that all offsets
1587 leading to previously decoded data must be smaller than Window_Size
1588 defined in Frame_Header_Descriptor (Section 3.1.1.1.1).
1589
15903.1.1.5. Repeat Offsets
1591
1592 As seen above, the first three values define a repeated offset; we
1593 will call them Repeated_Offset1, Repeated_Offset2, and
1594 Repeated_Offset3. They are sorted in recency order, with
1595 Repeated_Offset1 meaning "most recent one".
1596
1597 If offset_value is 1, then the offset used is Repeated_Offset1, etc.
1598
1599 There is one exception: When the current sequence's literals_length
1600 is 0, repeated offsets are shifted by 1, so an offset_value of 1
1601 means Repeated_Offset2, an offset_value of 2 means Repeated_Offset3,
1602 and an offset_value of 3 means Repeated_Offset1 - 1_byte.
1603
1604 For the first block, the starting offset history is populated with
1605 the following values: Repeated_Offset1 (1), Repeated_Offset2 (4), and
1606 Repeated_Offset3 (8), unless a dictionary is used, in which case they
1607 come from the dictionary.
1608
1609 Then each block gets its starting offset history from the ending
1610 values of the most recent Compressed_Block. Note that blocks that
1611 are not Compressed_Block are skipped; they do not contribute to
1612 offset history.
1613
1614 The newest offset takes the lead in offset history, shifting others
1615 back (up to its previous place if it was already present). This
1616 means that when Repeated_Offset1 (most recent) is used, history is
1617 unmodified. When Repeated_Offset2 is used, it is swapped with
1618 Repeated_Offset1. If any other offset is used, it becomes
1619 Repeated_Offset1, and the rest are shifted back by 1.
1620
1621
1622
1623
1624
1625
1626Collet & Kucherawy Informational [Page 29]
1627
1628RFC 8478 application/zstd October 2018
1629
1630
16313.1.2. Skippable Frames
1632
1633 +--------------+------------+-----------+
1634 | Magic_Number | Frame_Size | User_Data |
1635 +--------------+------------+-----------+
1636 | 4 bytes | 4 bytes | n bytes |
1637 +--------------+------------+-----------+
1638
1639 Skippable frames allow the insertion of user-defined metadata into a
1640 flow of concatenated frames.
1641
1642 Skippable frames defined in this specification are compatible with
1643 skippable frames in [LZ4].
1644
1645 From a compliant decoder perspective, skippable frames simply need to
1646 be skipped, and their content ignored, resuming decoding after the
1647 skippable frame.
1648
1649 It should be noted that a skippable frame can be used to watermark a
1650 stream of concatenated frames embedding any kind of tracking
1651 information (even just a Universally Unique Identifier (UUID)).
1652 Users wary of such possibility should scan the stream of concatenated
1653 frames in an attempt to detect such frames for analysis or removal.
1654
1655 The fields are:
1656
1657 Magic_Number: 4 bytes, little-endian format. Value: 0x184D2A5?,
1658 which means any value from 0x184D2A50 to 0x184D2A5F. All 16
1659 values are valid to identify a skippable frame. This
1660 specification does not detail any specific tagging methods for
1661 skippable frames.
1662
1663 Frame_Size: This is the size, in bytes, of the following User_Data
1664 (without including the magic number nor the size field itself).
1665 This field is represented using 4 bytes, little-endian format,
1666 unsigned 32 bits. This means User_Data can't be bigger than
1667 (2^32-1) bytes.
1668
1669 User_Data: This field can be anything. Data will just be skipped by
1670 the decoder.
1671
16724. Entropy Encoding
1673
1674 Two types of entropy encoding are used by the Zstandard format: FSE
1675 and Huffman coding. Huffman is used to compress literals, while FSE
1676 is used for all other symbols (Literals_Length_Code,
1677 Match_Length_Code, and offset codes) and to compress Huffman headers.
1678
1679
1680
1681
1682Collet & Kucherawy Informational [Page 30]
1683
1684RFC 8478 application/zstd October 2018
1685
1686
16874.1. FSE
1688
1689 FSE, short for Finite State Entropy, is an entropy codec based on
1690 [ANS]. FSE encoding/decoding involves a state that is carried over
1691 between symbols, so decoding must be done in the opposite direction
1692 as encoding. Therefore, all FSE bitstreams are read from end to
1693 beginning. Note that the order of the bits in the stream is not
1694 reversed; they are simply read in the reverse order from which they
1695 were written.
1696
1697 For additional details on FSE, see Finite State Entropy [FSE].
1698
1699 FSE decoding involves a decoding table that has a power of 2 size and
1700 contains three elements: Symbol, Num_Bits, and Baseline. The base 2
1701 logarithm of the table size is its Accuracy_Log. An FSE state value
1702 represents an index in this table.
1703
1704 To obtain the initial state value, consume Accuracy_Log bits from the
1705 stream as a little-endian value. The next symbol in the stream is
1706 the Symbol indicated in the table for that state. To obtain the next
1707 state value, the decoder should consume Num_Bits bits from the stream
1708 as a little-endian value and add it to Baseline.
1709
17104.1.1. FSE Table Description
1711
1712 To decode FSE streams, it is necessary to construct the decoding
1713 table. The Zstandard format encodes FSE table descriptions as
1714 described here.
1715
1716 An FSE distribution table describes the probabilities of all symbols
1717 from 0 to the last present one (included) on a normalized scale of
1718 (1 << Accuracy_Log). Note that there must be two or more symbols
1719 with non-zero probability.
1720
1721 A bitstream is read forward, in little-endian fashion. It is not
1722 necessary to know its exact size, since the size will be discovered
1723 and reported by the decoding process. The bitstream starts by
1724 reporting on which scale it operates. If low4bits designates the
1725 lowest 4 bits of the first byte, then Accuracy_Log = low4bits + 5.
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738Collet & Kucherawy Informational [Page 31]
1739
1740RFC 8478 application/zstd October 2018
1741
1742
1743 This is followed by each symbol value, from 0 to the last present
1744 one. The number of bits used by each field is variable and depends
1745 on:
1746
1747 Remaining probabilities + 1: For example, presuming an Accuracy_Log
1748 of 8, and presuming 100 probabilities points have already been
1749 distributed, the decoder may read any value from 0 to
1750 (256 - 100 + 1) == 157, inclusive. Therefore, it must read
1751 log2sup(157) == 8 bits.
1752
1753 Value decoded: Small values use 1 fewer bit. For example, presuming
1754 values from 0 to 157 (inclusive) are possible, 255 - 157 = 98
1755 values are remaining in an 8-bit field. The first 98 values
1756 (hence from 0 to 97) use only 7 bits, and values from 98 to 157
1757 use 8 bits. This is achieved through this scheme:
1758
1759 +------------+---------------+-----------+
1760 | Value Read | Value Decoded | Bits Used |
1761 +------------+---------------+-----------+
1762 | 0 - 97 | 0 - 97 | 7 |
1763 +------------+---------------+-----------+
1764 | 98 - 127 | 98 - 127 | 8 |
1765 +------------+---------------+-----------+
1766 | 128 - 225 | 0 - 97 | 7 |
1767 +------------+---------------+-----------+
1768 | 226 - 255 | 128 - 157 | 8 |
1769 +------------+---------------+-----------+
1770
1771 Symbol probabilities are read one by one, in order. The probability
1772 is obtained from Value decoded using the formula P = Value - 1. This
1773 means the value 0 becomes the negative probability -1. This is a
1774 special probability that means "less than 1". Its effect on the
1775 distribution table is described below. For the purpose of
1776 calculating total allocated probability points, it counts as 1.
1777
1778 When a symbol has a probability of zero, it is followed by a 2-bit
1779 repeat flag. This repeat flag tells how many probabilities of zeroes
1780 follow the current one. It provides a number ranging from 0 to 3.
1781 If it is a 3, another 2-bit repeat flag follows, and so on.
1782
1783 When the last symbol reaches a cumulated total of
1784 (1 << Accuracy_Log), decoding is complete. If the last symbol makes
1785 the cumulated total go above (1 << Accuracy_Log), distribution is
1786 considered corrupted.
1787
1788
1789
1790
1791
1792
1793
1794Collet & Kucherawy Informational [Page 32]
1795
1796RFC 8478 application/zstd October 2018
1797
1798
1799 Finally, the decoder can tell how many bytes were used in this
1800 process and how many symbols are present. The bitstream consumes a
1801 round number of bytes. Any remaining bit within the last byte is
1802 simply unused.
1803
1804 The distribution of normalized probabilities is enough to create a
1805 unique decoding table. The table has a size of (1 << Accuracy_Log).
1806 Each cell describes the symbol decoded and instructions to get the
1807 next state.
1808
1809 Symbols are scanned in their natural order for "less than 1"
1810 probabilities as described above. Symbols with this probability are
1811 being attributed a single cell, starting from the end of the table
1812 and retreating. These symbols define a full state reset, reading
1813 Accuracy_Log bits.
1814
1815 All remaining symbols are allocated in their natural order. Starting
1816 from symbol 0 and table position 0, each symbol gets allocated as
1817 many cells as its probability. Cell allocation is spread, not
1818 linear; each successor position follows this rule:
1819
1820 position += (tableSize >> 1) + (tableSize >> 3) + 3;
1821 position &= tableSize - 1;
1822
1823 A position is skipped if it is already occupied by a "less than 1"
1824 probability symbol. Position does not reset between symbols; it
1825 simply iterates through each position in the table, switching to the
1826 next symbol when enough states have been allocated to the current
1827 one.
1828
1829 The result is a list of state values. Each state will decode the
1830 current symbol.
1831
1832 To get the Number_of_Bits and Baseline required for the next state,
1833 it is first necessary to sort all states in their natural order. The
1834 lower states will need 1 more bit than higher ones. The process is
1835 repeated for each symbol.
1836
1837 For example, presuming a symbol has a probability of 5, it receives
1838 five state values. States are sorted in natural order. The next
1839 power of 2 is 8. The space of probabilities is divided into 8 equal
1840 parts. Presuming the Accuracy_Log is 7, this defines 128 states, and
1841 each share (divided by 8) is 16 in size. In order to reach 8, 8 - 5
1842 = 3 lowest states will count "double", doubling the number of shares
1843 (32 in width), requiring 1 more bit in the process.
1844
1845
1846
1847
1848
1849
1850Collet & Kucherawy Informational [Page 33]
1851
1852RFC 8478 application/zstd October 2018
1853
1854
1855 Baseline is assigned starting from the higher states using fewer
1856 bits, and proceeding naturally, then resuming at the first state,
1857 each taking its allocated width from Baseline.
1858
1859 +----------------+-------+-------+--------+------+-------+
1860 | state order | 0 | 1 | 2 | 3 | 4 |
1861 +----------------+-------+-------+--------+------+-------+
1862 | width | 32 | 32 | 32 | 16 | 16 |
1863 +----------------+-------+-------+--------+------+-------+
1864 | Number_of_Bits | 5 | 5 | 5 | 4 | 4 |
1865 +----------------+-------+-------+--------+------+-------+
1866 | range number | 2 | 4 | 6 | 0 | 1 |
1867 +----------------+-------+-------+--------+------+-------+
1868 | Baseline | 32 | 64 | 96 | 0 | 16 |
1869 +----------------+-------+-------+--------+------+-------+
1870 | range | 32-63 | 64-95 | 96-127 | 0-15 | 16-31 |
1871 +----------------+-------+-------+--------+------+-------+
1872
1873 The next state is determined from the current state by reading the
1874 required Number_of_Bits and adding the specified Baseline.
1875
1876 See Appendix A for the results of this process that are applied to
1877 the default distributions.
1878
18794.2. Huffman Coding
1880
1881 Zstandard Huffman-coded streams are read backwards, similar to the
1882 FSE bitstreams. Therefore, to find the start of the bitstream, it is
1883 necessary to know the offset of the last byte of the Huffman-coded
1884 stream.
1885
1886 After writing the last bit containing information, the compressor
1887 writes a single 1 bit and then fills the byte with 0-7 0 bits of
1888 padding. The last byte of the compressed bitstream cannot be 0 for
1889 that reason.
1890
1891 When decompressing, the last byte containing the padding is the first
1892 byte to read. The decompressor needs to skip 0-7 initial 0 bits and
1893 the first 1 bit that occurs. Afterwards, the useful part of the
1894 bitstream begins.
1895
1896 The bitstream contains Huffman-coded symbols in little-endian order,
1897 with the codes defined by the method below.
1898
1899
1900
1901
1902
1903
1904
1905
1906Collet & Kucherawy Informational [Page 34]
1907
1908RFC 8478 application/zstd October 2018
1909
1910
19114.2.1. Huffman Tree Description
1912
1913 Prefix coding represents symbols from an a priori known alphabet by
1914 bit sequences (codewords), one codeword for each symbol, in a manner
1915 such that different symbols may be represented by bit sequences of
1916 different lengths, but a parser can always parse an encoded string
1917 unambiguously symbol by symbol.
1918
1919 Given an alphabet with known symbol frequencies, the Huffman
1920 algorithm allows the construction of an optimal prefix code using the
1921 fewest bits of any possible prefix codes for that alphabet.
1922
1923 The prefix code must not exceed a maximum code length. More bits
1924 improve accuracy but yield a larger header size and require more
1925 memory or more complex decoding operations. This specification
1926 limits the maximum code length to 11 bits.
1927
1928 All literal values from zero (included) to the last present one
1929 (excluded) are represented by Weight with values from 0 to
1930 Max_Number_of_Bits. Transformation from Weight to Number_of_Bits
1931 follows this pseudocode:
1932
1933 if Weight == 0
1934 Number_of_Bits = 0
1935 else
1936 Number_of_Bits = Max_Number_of_Bits + 1 - Weight
1937
1938 The last symbol's Weight is deduced from previously decoded ones, by
1939 completing to the nearest power of 2. This power of 2 gives
1940 Max_Number_of_Bits the depth of the current tree.
1941
1942 For example, presume the following Huffman tree must be described:
1943
1944 +---------------+----------------+
1945 | Literal Value | Number_of_Bits |
1946 +---------------+----------------+
1947 | 0 | 1 |
1948 +---------------+----------------+
1949 | 1 | 2 |
1950 +---------------+----------------+
1951 | 2 | 3 |
1952 +---------------+----------------+
1953 | 3 | 0 |
1954 +---------------+----------------+
1955 | 4 | 4 |
1956 +---------------+----------------+
1957 | 5 | 4 |
1958 +---------------+----------------+
1959
1960
1961
1962Collet & Kucherawy Informational [Page 35]
1963
1964RFC 8478 application/zstd October 2018
1965
1966
1967 The tree depth is 4, since its longest element uses 4 bits. (The
1968 longest elements are those with the smallest frequencies.) Value 5
1969 will not be listed as it can be determined from the values for 0-4,
1970 nor will values above 5 as they are all 0. Values from 0 to 4 will
1971 be listed using Weight instead of Number_of_Bits. The pseudocode to
1972 determine Weight is:
1973
1974 if Number_of_Bits == 0
1975 Weight = 0
1976 else
1977 Weight = Max_Number_of_Bits + 1 - Number_of_Bits
1978
1979 It gives the following series of weights:
1980
1981 +---------------+--------+
1982 | Literal Value | Weight |
1983 +---------------+--------+
1984 | 0 | 4 |
1985 +---------------+--------+
1986 | 1 | 3 |
1987 +---------------+--------+
1988 | 2 | 2 |
1989 +---------------+--------+
1990 | 3 | 0 |
1991 +---------------+--------+
1992 | 4 | 1 |
1993 +---------------+--------+
1994
1995 The decoder will do the inverse operation: having collected weights
1996 of literals from 0 to 4, it knows the last literal, 5, is present
1997 with a non-zero Weight. The Weight of 5 can be determined by
1998 advancing to the next power of 2. The sum of 2^(Weight-1) (excluding
1999 0's) is 15. The nearest power of 2 is 16. Therefore,
2000 Max_Number_of_Bits = 4 and Weight[5] = 16 - 15 = 1.
2001
20024.2.1.1. Huffman Tree Header
2003
2004 This is a single byte value (0-255), which describes how the series
2005 of weights is encoded.
2006
2007 headerByte < 128: The series of weights is compressed using FSE (see
2008 below). The length of the FSE-compressed series is equal to
2009 headerByte (0-127).
2010
2011
2012
2013
2014
2015
2016
2017
2018Collet & Kucherawy Informational [Page 36]
2019
2020RFC 8478 application/zstd October 2018
2021
2022
2023 headerByte >= 128: This is a direct representation, where each
2024 Weight is written directly as a 4-bit field (0-15). They are
2025 encoded forward, 2 weights to a byte with the first weight taking
2026 the top 4 bits and the second taking the bottom 4; for example,
2027 the following operations could be used to read the weights:
2028
2029 Weight[0] = (Byte[0] >> 4)
2030 Weight[1] = (Byte[0] & 0xf),
2031 etc.
2032
2033 The full representation occupies ceiling(Number_of_Symbols/2)
2034 bytes, meaning it uses only full bytes even if Number_of_Symbols
2035 is odd. Number_of_Symbols = headerByte - 127. Note that maximum
2036 Number_of_Symbols is 255 - 127 = 128. If any literal has a value
2037 over 128, raw header mode is not possible, and it is necessary to
2038 use FSE compression.
2039
20404.2.1.2. FSE Compression of Huffman Weights
2041
2042 In this case, the series of Huffman weights is compressed using FSE
2043 compression. It is a single bitstream with two interleaved states,
2044 sharing a single distribution table.
2045
2046 To decode an FSE bitstream, it is necessary to know its compressed
2047 size. Compressed size is provided by headerByte. It's also
2048 necessary to know its maximum possible decompressed size, which is
2049 255, since literal values span from 0 to 255, and the last symbol's
2050 Weight is not represented.
2051
2052 An FSE bitstream starts by a header, describing probabilities
2053 distribution. It will create a decoding table. For a list of
2054 Huffman weights, the maximum accuracy log is 6 bits. For more
2055 details, see Section 4.1.1.
2056
2057 The Huffman header compression uses two states, which share the same
2058 FSE distribution table. The first state (State1) encodes the even-
2059 numbered index symbols, and the second (State2) encodes the odd-
2060 numbered index symbols. State1 is initialized first, and then
2061 State2, and they take turns decoding a single symbol and updating
2062 their state. For more details on these FSE operations, see
2063 Section 4.1.
2064
2065 The number of symbols to be decoded is determined by tracking the
2066 bitStream overflow condition: If updating state after decoding a
2067 symbol would require more bits than remain in the stream, it is
2068 assumed that extra bits are zero. Then, symbols for each of the
2069 final states are decoded and the process is complete.
2070
2071
2072
2073
2074Collet & Kucherawy Informational [Page 37]
2075
2076RFC 8478 application/zstd October 2018
2077
2078
20794.2.1.3. Conversion from Weights to Huffman Prefix Codes
2080
2081 All present symbols will now have a Weight value. It is possible to
2082 transform weights into Number_of_Bits, using this formula:
2083
2084 if Weight > 0
2085 Number_of_Bits = Max_Number_of_Bits + 1 - Weight
2086 else
2087 Number_of_Bits = 0
2088
2089 Symbols are sorted by Weight. Within the same Weight, symbols keep
2090 natural sequential order. Symbols with a Weight of zero are removed.
2091 Then, starting from the lowest Weight, prefix codes are distributed
2092 in sequential order.
2093
2094 For example, assume the following list of weights has been decoded:
2095
2096 +---------+--------+
2097 | Literal | Weight |
2098 +---------+--------+
2099 | 0 | 4 |
2100 +---------+--------+
2101 | 1 | 3 |
2102 +---------+--------+
2103 | 2 | 2 |
2104 +---------+--------+
2105 | 3 | 0 |
2106 +---------+--------+
2107 | 4 | 1 |
2108 +---------+--------+
2109 | 5 | 1 |
2110 +---------+--------+
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130Collet & Kucherawy Informational [Page 38]
2131
2132RFC 8478 application/zstd October 2018
2133
2134
2135 Sorting by weight and then the natural sequential order yields the
2136 following distribution:
2137
2138 +---------+--------+----------------+--------------+
2139 | Literal | Weight | Number_Of_Bits | Prefix Codes |
2140 +---------+--------+----------------|--------------+
2141 | 3 | 0 | 0 | N/A |
2142 +---------+--------+----------------|--------------+
2143 | 4 | 1 | 4 | 0000 |
2144 +---------+--------+----------------|--------------+
2145 | 5 | 1 | 4 | 0001 |
2146 +---------+--------+----------------|--------------+
2147 | 2 | 2 | 3 | 001 |
2148 +---------+--------+----------------|--------------+
2149 | 1 | 3 | 2 | 01 |
2150 +---------+--------+----------------|--------------+
2151 | 0 | 4 | 1 | 1 |
2152 +---------+--------+----------------|--------------+
2153
21544.2.2. Huffman-Coded Streams
2155
2156 Given a Huffman decoding table, it is possible to decode a Huffman-
2157 coded stream.
2158
2159 Each bitstream must be read backward, which starts from the end and
2160 goes up to the beginning. Therefore, it is necessary to know the
2161 size of each bitstream.
2162
2163 It is also necessary to know exactly which bit is the last. This is
2164 detected by a final bit flag: the highest bit of the last byte is a
2165 final-bit-flag. Consequently, a last byte of 0 is not possible. And
2166 the final-bit-flag itself is not part of the useful bitstream.
2167 Hence, the last byte contains between 0 and 7 useful bits.
2168
2169 Starting from the end, it is possible to read the bitstream in a
2170 little-endian fashion, keeping track of already used bits. Since the
2171 bitstream is encoded in reverse order, starting from the end, read
2172 symbols in forward order.
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186Collet & Kucherawy Informational [Page 39]
2187
2188RFC 8478 application/zstd October 2018
2189
2190
2191 For example, if the literal sequence "0145" was encoded using the
2192 above prefix code, it would be encoded (in reverse order) as:
2193
2194 +---------+----------+
2195 | Symbol | Encoding |
2196 +---------+----------+
2197 | 5 | 0000 |
2198 +---------+----------+
2199 | 4 | 0001 |
2200 +---------+----------+
2201 | 1 | 01 |
2202 +---------+----------+
2203 | 0 | 1 |
2204 +---------+----------+
2205 | Padding | 00001 |
2206 +---------+----------+
2207
2208 This results in the following 2-byte bitstream:
2209
2210 00010000 00001101
2211
2212 Here is an alternative representation with the symbol codes separated
2213 by underscores:
2214
2215 0001_0000 00001_1_01
2216
2217 Reading the highest Max_Number_of_Bits bits, it's possible to compare
2218 the extracted value to the decoding table, determining the symbol to
2219 decode and number of bits to discard.
2220
2221 The process continues reading up to the required number of symbols
2222 per stream. If a bitstream is not entirely and exactly consumed,
2223 hence reaching exactly its beginning position with all bits consumed,
2224 the decoding process is considered faulty.
2225
22265. Dictionary Format
2227
2228 Zstandard is compatible with "raw content" dictionaries, free of any
2229 format restriction, except that they must be at least 8 bytes. These
2230 dictionaries function as if they were just the content part of a
2231 formatted dictionary.
2232
2233 However, dictionaries created by "zstd --train" in the reference
2234 implementation follow a specific format, described here.
2235
2236 Dictionaries are not included in the compressed content but rather
2237 are provided out of band. That is, the Dictionary_ID identifies
2238 which should be used, but this specification does not describe the
2239
2240
2241
2242Collet & Kucherawy Informational [Page 40]
2243
2244RFC 8478 application/zstd October 2018
2245
2246
2247 mechanism by which the dictionary is obtained prior to use during
2248 compression or decompression.
2249
2250 A dictionary has a size, defined either by a buffer limit or a file
2251 size. The general format is:
2252
2253 +--------------+---------------+----------------+---------+
2254 | Magic_Number | Dictionary_ID | Entropy_Tables | Content |
2255 +--------------+---------------+----------------+---------+
2256
2257 Magic_Number: 4 bytes ID, value 0xEC30A437, little-endian format.
2258
2259 Dictionary_ID: 4 bytes, stored in little-endian format.
2260 Dictionary_ID can be any value, except 0 (which means no
2261 Dictionary_ID). It is used by decoders to check if they use the
2262 correct dictionary. If the frame is going to be distributed in a
2263 private environment, any Dictionary_ID can be used. However, for
2264 public distribution of compressed frames, the following ranges are
2265 reserved and shall not be used:
2266
2267 low range: <= 32767
2268 high range: >= (2^31)
2269
2270 Entropy_Tables: Follow the same format as the tables in compressed
2271 blocks. See the relevant FSE and Huffman sections for how to
2272 decode these tables. They are stored in the following order:
2273 Huffman table for literals, FSE table for offsets, FSE table for
2274 match lengths, and FSE table for literals lengths. These tables
2275 populate the Repeat Stats literals mode and Repeat distribution
2276 mode for sequence decoding. It is finally followed by 3 offset
2277 values, populating repeat offsets (instead of using {1,4,8}),
2278 stored in order, 4-bytes little-endian each, for a total of 12
2279 bytes. Each repeat offset must have a value less than the
2280 dictionary size.
2281
2282 Content: The rest of the dictionary is its content. The content
2283 acts as a "past" in front of data to be compressed or
2284 decompressed, so it can be referenced in sequence commands. As
2285 long as the amount of data decoded from this frame is less than or
2286 equal to Window_Size, sequence commands may specify offsets longer
2287 than the total length of decoded output so far to reference back
2288 to the dictionary, even parts of the dictionary with offsets
2289 larger than Window_Size. After the total output has surpassed
2290 Window_Size, however, this is no longer allowed, and the
2291 dictionary is no longer accessible.
2292
2293
2294
2295
2296
2297
2298Collet & Kucherawy Informational [Page 41]
2299
2300RFC 8478 application/zstd October 2018
2301
2302
23036. IANA Considerations
2304
2305 IANA has made two registrations, as described below.
2306
23076.1. The 'application/zstd' Media Type
2308
2309 The 'application/zstd' media type identifies a block of data that is
2310 compressed using zstd compression. The data is a stream of bytes as
2311 described in this document. IANA has added the following to the
2312 "Media Types" registry:
2313
2314 Type name: application
2315
2316 Subtype name: zstd
2317
2318 Required parameters: N/A
2319
2320 Optional parameters: N/A
2321
2322 Encoding considerations: binary
2323
2324 Security considerations: See Section 7 of RFC 8478
2325
2326 Interoperability considerations: N/A
2327
2328 Published specification: RFC 8478
2329
2330 Applications that use this media type: anywhere data size is an
2331 issue
2332
2333 Additional information:
2334
2335 Magic number(s): 4 bytes, little-endian format.
2336 Value: 0xFD2FB528
2337
2338 File extension(s): zst
2339
2340 Macintosh file type code(s): N/A
2341
2342 For further information: See [ZSTD]
2343
2344 Intended usage: common
2345
2346 Restrictions on usage: N/A
2347
2348 Author: Murray S. Kucherawy
2349
2350 Change Controller: IETF
2351
2352
2353
2354Collet & Kucherawy Informational [Page 42]
2355
2356RFC 8478 application/zstd October 2018
2357
2358
2359 Provisional registration: no
2360
23616.2. Content Encoding
2362
2363 IANA has added the following entry to the "HTTP Content Coding
2364 Registry" within the "Hypertext Transfer Protocol (HTTP) Parameters"
2365 registry:
2366
2367 Name: zstd
2368
2369 Description: A stream of bytes compressed using the Zstandard
2370 protocol
2371
2372 Pointer to specification text: RFC 8478
2373
23746.3. Dictionaries
2375
2376 Work in progress includes development of dictionaries that will
2377 optimize compression and decompression of particular types of data.
2378 Specification of such dictionaries for public use will necessitate
2379 registration of a code point from the reserved range described in
2380 Section 3.1.1.1.3 and its association with a specific dictionary.
2381
2382 However, there are at present no such dictionaries published for
2383 public use, so this document makes no immediate request of IANA to
2384 create such a registry.
2385
23867. Security Considerations
2387
2388 Any data compression method involves the reduction of redundancy in
2389 the data. Zstandard is no exception, and the usual precautions
2390 apply.
2391
2392 One should never compress a message whose content must remain secret
2393 with a message generated by a third party. Such a compression can be
2394 used to guess the content of the secret message through analysis of
2395 entropy reduction. This was demonstrated in the Compression Ratio
2396 Info-leak Made Easy (CRIME) attack [CRIME], for example.
2397
2398 A decoder has to demonstrate capabilities to detect and prevent any
2399 kind of data tampering in the compressed frame from triggering system
2400 faults, such as reading or writing beyond allowed memory ranges.
2401 This can be guaranteed by either the implementation language or
2402 careful bound checkings. Of particular note is the encoding of
2403 Number_of_Sequences values that cause the decoder to read into the
2404 block header (and beyond), as well as the indication of a
2405 Frame_Content_Size that is smaller than the actual decompressed data,
2406 in an attempt to trigger a buffer overflow. It is highly recommended
2407
2408
2409
2410Collet & Kucherawy Informational [Page 43]
2411
2412RFC 8478 application/zstd October 2018
2413
2414
2415 to fuzz-test (i.e., provide invalid, unexpected, or random input and
2416 verify safe operation of) decoder implementations to test and harden
2417 their capability to detect bad frames and deal with them without any
2418 adverse system side effect.
2419
2420 An attacker may provide correctly formed compressed frames with
2421 unreasonable memory requirements. A decoder must always control
2422 memory requirements and enforce some (system-specific) limits in
2423 order to protect memory usage from such scenarios.
2424
2425 Compression can be optimized by training a dictionary on a variety of
2426 related content payloads. This dictionary must then be available at
2427 the decoder for decompression of the payload to be possible. While
2428 this document does not specify how to acquire a dictionary for a
2429 given compressed payload, it is worth noting that third-party
2430 dictionaries may interact unexpectedly with a decoder, leading to
2431 possible memory or other resource exhaustion attacks. We expect such
2432 topics to be discussed in further detail in the Security
2433 Considerations section of a forthcoming RFC for dictionary
2434 acquisition and transmission, but highlight this issue now out of an
2435 abundance of caution.
2436
2437 As discussed in Section 3.1.2, it is possible to store arbitrary user
2438 metadata in skippable frames. While such frames are ignored during
2439 decompression of the data, they can be used as a watermark to track
2440 the path of the compressed payload.
2441
24428. Implementation Status
2443
2444 Source code for a C language implementation of a Zstandard-compliant
2445 library is available at [ZSTD-GITHUB]. This implementation is
2446 considered to be the reference implementation and is production
2447 ready; it implements the full range of the specification. It is
2448 routinely tested against security hazards and widely deployed within
2449 Facebook infrastructure.
2450
2451 The reference version is optimized for speed and is highly portable.
2452 It has been proven to run safely on multiple architectures (e.g.,
2453 x86, x64, ARM, MIPS, PowerPC, IA64) featuring 32- or 64-bit
2454 addressing schemes, a little- or big-endian storage scheme, a number
2455 of different operating systems (e.g., UNIX (including Linux, BSD,
2456 OS-X, and Solaris) and Windows), and a number of compilers (e.g.,
2457 gcc, clang, visual, and icc).
2458
2459
2460
2461
2462
2463
2464
2465
2466Collet & Kucherawy Informational [Page 44]
2467
2468RFC 8478 application/zstd October 2018
2469
2470
24719. References
2472
24739.1. Normative References
2474
2475 [ZSTD] "Zstandard", <http://www.zstd.net>.
2476
24779.2. Informative References
2478
2479 [ANS] Duda, J., "Asymmetric numeral systems: entropy coding
2480 combining speed of Huffman coding with compression rate of
2481 arithmetic coding", January 2014,
2482 <https://arxiv.org/pdf/1311.2540>.
2483
2484 [CRIME] "CRIME", June 2018, <https://en.wikipedia.org/w/
2485 index.php?title=CRIME&oldid=844538656>.
2486
2487 [FSE] "FiniteStateEntropy", commit 6efa78a, June 2018,
2488 <https://github.com/Cyan4973/FiniteStateEntropy/>.
2489
2490 [LZ4] "LZ4 Frame Format Description", commit d03224b, January
2491 2018, <https://github.com/lz4/lz4/blob/master/doc/
2492 lz4_Frame_format.md>.
2493
2494 [RFC1952] Deutsch, P., "GZIP file format specification version 4.3",
2495 RFC 1952, DOI 10.17487/RFC1952, May 1996,
2496 <https://www.rfc-editor.org/info/rfc1952>.
2497
2498 [XXHASH] "XXHASH Algorithm", <http://www.xxhash.org>.
2499
2500 [ZSTD-GITHUB]
2501 "zstd", commit 8514bd8, August 2018,
2502 <https://github.com/facebook/zstd>.
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522Collet & Kucherawy Informational [Page 45]
2523
2524RFC 8478 application/zstd October 2018
2525
2526
2527Appendix A. Decoding Tables for Predefined Codes
2528
2529 This appendix contains FSE decoding tables for the predefined literal
2530 length, match length, and offset codes. The tables have been
2531 constructed using the algorithm as given above in Section 4.1.1. The
2532 tables here can be used as examples to crosscheck that an
2533 implementation has built its decoding tables correctly.
2534
2535A.1. Literal Length Code Table
2536
2537 +-------+--------+----------------+------+
2538 | State | Symbol | Number_Of_Bits | Base |
2539 +-------+--------+----------------+------+
2540 | 0 | 0 | 0 | 0 |
2541 +-------+--------+----------------+------+
2542 | 0 | 0 | 4 | 0 |
2543 +-------+--------+----------------+------+
2544 | 1 | 0 | 4 | 16 |
2545 +-------+--------+----------------+------+
2546 | 2 | 1 | 5 | 32 |
2547 +-------+--------+----------------+------+
2548 | 3 | 3 | 5 | 0 |
2549 +-------+--------+----------------+------+
2550 | 4 | 4 | 5 | 0 |
2551 +-------+--------+----------------+------+
2552 | 5 | 6 | 5 | 0 |
2553 +-------+--------+----------------+------+
2554 | 6 | 7 | 5 | 0 |
2555 +-------+--------+----------------+------+
2556 | 7 | 9 | 5 | 0 |
2557 +-------+--------+----------------+------+
2558 | 8 | 10 | 5 | 0 |
2559 +-------+--------+----------------+------+
2560 | 9 | 12 | 5 | 0 |
2561 +-------+--------+----------------+------+
2562 | 10 | 14 | 6 | 0 |
2563 +-------+--------+----------------+------+
2564 | 11 | 16 | 5 | 0 |
2565 +-------+--------+----------------+------+
2566 | 12 | 18 | 5 | 0 |
2567 +-------+--------+----------------+------+
2568 | 13 | 19 | 5 | 0 |
2569 +-------+--------+----------------+------+
2570 | 14 | 21 | 5 | 0 |
2571 +-------+--------+----------------+------+
2572 | 15 | 22 | 5 | 0 |
2573 +-------+--------+----------------+------+
2574 | 16 | 24 | 5 | 0 |
2575
2576
2577
2578Collet & Kucherawy Informational [Page 46]
2579
2580RFC 8478 application/zstd October 2018
2581
2582
2583 +-------+--------+----------------+------+
2584 | 17 | 25 | 5 | 32 |
2585 +-------+--------+----------------+------+
2586 | 18 | 26 | 5 | 0 |
2587 +-------+--------+----------------+------+
2588 | 19 | 27 | 6 | 0 |
2589 +-------+--------+----------------+------+
2590 | 20 | 29 | 6 | 0 |
2591 +-------+--------+----------------+------+
2592 | 21 | 31 | 6 | 0 |
2593 +-------+--------+----------------+------+
2594 | 22 | 0 | 4 | 32 |
2595 +-------+--------+----------------+------+
2596 | 23 | 1 | 4 | 0 |
2597 +-------+--------+----------------+------+
2598 | 24 | 2 | 5 | 0 |
2599 +-------+--------+----------------+------+
2600 | 25 | 4 | 5 | 32 |
2601 +-------+--------+----------------+------+
2602 | 26 | 5 | 5 | 0 |
2603 +-------+--------+----------------+------+
2604 | 27 | 7 | 5 | 32 |
2605 +-------+--------+----------------+------+
2606 | 28 | 8 | 5 | 0 |
2607 +-------+--------+----------------+------+
2608 | 29 | 10 | 5 | 32 |
2609 +-------+--------+----------------+------+
2610 | 30 | 11 | 5 | 0 |
2611 +-------+--------+----------------+------+
2612 | 31 | 13 | 6 | 0 |
2613 +-------+--------+----------------+------+
2614 | 32 | 16 | 5 | 32 |
2615 +-------+--------+----------------+------+
2616 | 33 | 17 | 5 | 0 |
2617 +-------+--------+----------------+------+
2618 | 34 | 19 | 5 | 32 |
2619 +-------+--------+----------------+------+
2620 | 35 | 20 | 5 | 0 |
2621 +-------+--------+----------------+------+
2622 | 36 | 22 | 5 | 32 |
2623 +-------+--------+----------------+------+
2624 | 37 | 23 | 5 | 0 |
2625 +-------+--------+----------------+------+
2626 | 38 | 25 | 4 | 0 |
2627 +-------+--------+----------------+------+
2628 | 39 | 25 | 4 | 16 |
2629 +-------+--------+----------------+------+
2630 | 40 | 26 | 5 | 32 |
2631
2632
2633
2634Collet & Kucherawy Informational [Page 47]
2635
2636RFC 8478 application/zstd October 2018
2637
2638
2639 +-------+--------+----------------+------+
2640 | 41 | 28 | 6 | 0 |
2641 +-------+--------+----------------+------+
2642 | 42 | 30 | 6 | 0 |
2643 +-------+--------+----------------+------+
2644 | 43 | 0 | 4 | 48 |
2645 +-------+--------+----------------+------+
2646 | 44 | 1 | 4 | 16 |
2647 +-------+--------+----------------+------+
2648 | 45 | 2 | 5 | 32 |
2649 +-------+--------+----------------+------+
2650 | 46 | 3 | 5 | 32 |
2651 +-------+--------+----------------+------+
2652 | 47 | 5 | 5 | 32 |
2653 +-------+--------+----------------+------+
2654 | 48 | 6 | 5 | 32 |
2655 +-------+--------+----------------+------+
2656 | 49 | 8 | 5 | 32 |
2657 +-------+--------+----------------+------+
2658 | 50 | 9 | 5 | 32 |
2659 +-------+--------+----------------+------+
2660 | 51 | 11 | 5 | 32 |
2661 +-------+--------+----------------+------+
2662 | 52 | 12 | 5 | 32 |
2663 +-------+--------+----------------+------+
2664 | 53 | 15 | 6 | 0 |
2665 +-------+--------+----------------+------+
2666 | 54 | 17 | 5 | 32 |
2667 +-------+--------+----------------+------+
2668 | 55 | 18 | 5 | 32 |
2669 +-------+--------+----------------+------+
2670 | 56 | 20 | 5 | 32 |
2671 +-------+--------+----------------+------+
2672 | 57 | 21 | 5 | 32 |
2673 +-------+--------+----------------+------+
2674 | 58 | 23 | 5 | 32 |
2675 +-------+--------+----------------+------+
2676 | 59 | 24 | 5 | 32 |
2677 +-------+--------+----------------+------+
2678 | 60 | 35 | 6 | 0 |
2679 +-------+--------+----------------+------+
2680 | 61 | 34 | 6 | 0 |
2681 +-------+--------+----------------+------+
2682 | 62 | 33 | 6 | 0 |
2683 +-------+--------+----------------+------+
2684 | 63 | 32 | 6 | 0 |
2685 +-------+--------+----------------+------+
2686
2687
2688
2689
2690Collet & Kucherawy Informational [Page 48]
2691
2692RFC 8478 application/zstd October 2018
2693
2694
2695A.2. Match Length Code Table
2696
2697 +-------+--------+----------------+------+
2698 | State | Symbol | Number_Of_Bits | Base |
2699 +-------+--------+----------------+------+
2700 | 0 | 0 | 0 | 0 |
2701 +-------+--------+----------------+------+
2702 | 0 | 0 | 6 | 0 |
2703 +-------+--------+----------------+------+
2704 | 1 | 1 | 4 | 0 |
2705 +-------+--------+----------------+------+
2706 | 2 | 2 | 5 | 32 |
2707 +-------+--------+----------------+------+
2708 | 3 | 3 | 5 | 0 |
2709 +-------+--------+----------------+------+
2710 | 4 | 5 | 5 | 0 |
2711 +-------+--------+----------------+------+
2712 | 5 | 6 | 5 | 0 |
2713 +-------+--------+----------------+------+
2714 | 6 | 8 | 5 | 0 |
2715 +-------+--------+----------------+------+
2716 | 7 | 10 | 6 | 0 |
2717 +-------+--------+----------------+------+
2718 | 8 | 13 | 6 | 0 |
2719 +-------+--------+----------------+------+
2720 | 9 | 16 | 6 | 0 |
2721 +-------+--------+----------------+------+
2722 | 10 | 19 | 6 | 0 |
2723 +-------+--------+----------------+------+
2724 | 11 | 22 | 6 | 0 |
2725 +-------+--------+----------------+------+
2726 | 12 | 25 | 6 | 0 |
2727 +-------+--------+----------------+------+
2728 | 13 | 28 | 6 | 0 |
2729 +-------+--------+----------------+------+
2730 | 14 | 31 | 6 | 0 |
2731 +-------+--------+----------------+------+
2732 | 15 | 33 | 6 | 0 |
2733 +-------+--------+----------------+------+
2734 | 16 | 35 | 6 | 0 |
2735 +-------+--------+----------------+------+
2736 | 17 | 37 | 6 | 0 |
2737 +-------+--------+----------------+------+
2738 | 18 | 39 | 6 | 0 |
2739 +-------+--------+----------------+------+
2740 | 19 | 41 | 6 | 0 |
2741 +-------+--------+----------------+------+
2742 | 20 | 43 | 6 | 0 |
2743
2744
2745
2746Collet & Kucherawy Informational [Page 49]
2747
2748RFC 8478 application/zstd October 2018
2749
2750
2751 +-------+--------+----------------+------+
2752 | 21 | 45 | 6 | 0 |
2753 +-------+--------+----------------+------+
2754 | 22 | 1 | 4 | 16 |
2755 +-------+--------+----------------+------+
2756 | 23 | 2 | 4 | 0 |
2757 +-------+--------+----------------+------+
2758 | 24 | 3 | 5 | 32 |
2759 +-------+--------+----------------+------+
2760 | 25 | 4 | 5 | 0 |
2761 +-------+--------+----------------+------+
2762 | 26 | 6 | 5 | 32 |
2763 +-------+--------+----------------+------+
2764 | 27 | 7 | 5 | 0 |
2765 +-------+--------+----------------+------+
2766 | 28 | 9 | 6 | 0 |
2767 +-------+--------+----------------+------+
2768 | 29 | 12 | 6 | 0 |
2769 +-------+--------+----------------+------+
2770 | 30 | 15 | 6 | 0 |
2771 +-------+--------+----------------+------+
2772 | 31 | 18 | 6 | 0 |
2773 +-------+--------+----------------+------+
2774 | 32 | 21 | 6 | 0 |
2775 +-------+--------+----------------+------+
2776 | 33 | 24 | 6 | 0 |
2777 +-------+--------+----------------+------+
2778 | 34 | 27 | 6 | 0 |
2779 +-------+--------+----------------+------+
2780 | 35 | 30 | 6 | 0 |
2781 +-------+--------+----------------+------+
2782 | 36 | 32 | 6 | 0 |
2783 +-------+--------+----------------+------+
2784 | 37 | 34 | 6 | 0 |
2785 +-------+--------+----------------+------+
2786 | 38 | 36 | 6 | 0 |
2787 +-------+--------+----------------+------+
2788 | 39 | 38 | 6 | 0 |
2789 +-------+--------+----------------+------+
2790 | 40 | 40 | 6 | 0 |
2791 +-------+--------+----------------+------+
2792 | 41 | 42 | 6 | 0 |
2793 +-------+--------+----------------+------+
2794 | 42 | 44 | 6 | 0 |
2795 +-------+--------+----------------+------+
2796 | 43 | 1 | 4 | 32 |
2797 +-------+--------+----------------+------+
2798 | 44 | 1 | 4 | 48 |
2799
2800
2801
2802Collet & Kucherawy Informational [Page 50]
2803
2804RFC 8478 application/zstd October 2018
2805
2806
2807 +-------+--------+----------------+------+
2808 | 45 | 2 | 4 | 16 |
2809 +-------+--------+----------------+------+
2810 | 46 | 4 | 5 | 32 |
2811 +-------+--------+----------------+------+
2812 | 47 | 5 | 5 | 32 |
2813 +-------+--------+----------------+------+
2814 | 48 | 7 | 5 | 32 |
2815 +-------+--------+----------------+------+
2816 | 49 | 8 | 5 | 32 |
2817 +-------+--------+----------------+------+
2818 | 50 | 11 | 6 | 0 |
2819 +-------+--------+----------------+------+
2820 | 51 | 14 | 6 | 0 |
2821 +-------+--------+----------------+------+
2822 | 52 | 17 | 6 | 0 |
2823 +-------+--------+----------------+------+
2824 | 53 | 20 | 6 | 0 |
2825 +-------+--------+----------------+------+
2826 | 54 | 23 | 6 | 0 |
2827 +-------+--------+----------------+------+
2828 | 55 | 26 | 6 | 0 |
2829 +-------+--------+----------------+------+
2830 | 56 | 29 | 6 | 0 |
2831 +-------+--------+----------------+------+
2832 | 57 | 52 | 6 | 0 |
2833 +-------+--------+----------------+------+
2834 | 58 | 51 | 6 | 0 |
2835 +-------+--------+----------------+------+
2836 | 59 | 50 | 6 | 0 |
2837 +-------+--------+----------------+------+
2838 | 60 | 49 | 6 | 0 |
2839 +-------+--------+----------------+------+
2840 | 61 | 48 | 6 | 0 |
2841 +-------+--------+----------------+------+
2842 | 62 | 47 | 6 | 0 |
2843 +-------+--------+----------------+------+
2844 | 63 | 46 | 6 | 0 |
2845 +-------+--------+----------------+------+
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858Collet & Kucherawy Informational [Page 51]
2859
2860RFC 8478 application/zstd October 2018
2861
2862
2863A.3. Offset Code Table
2864
2865 +-------+--------+----------------+------+
2866 | State | Symbol | Number_Of_Bits | Base |
2867 +-------+--------+----------------+------+
2868 | 0 | 0 | 0 | 0 |
2869 +-------+--------+----------------+------+
2870 | 0 | 0 | 5 | 0 |
2871 +-------+--------+----------------+------+
2872 | 1 | 6 | 4 | 0 |
2873 +-------+--------+----------------+------+
2874 | 2 | 9 | 5 | 0 |
2875 +-------+--------+----------------+------+
2876 | 3 | 15 | 5 | 0 |
2877 +-------+--------+----------------+------+
2878 | 4 | 21 | 5 | 0 |
2879 +-------+--------+----------------+------+
2880 | 5 | 3 | 5 | 0 |
2881 +-------+--------+----------------+------+
2882 | 6 | 7 | 4 | 0 |
2883 +-------+--------+----------------+------+
2884 | 7 | 12 | 5 | 0 |
2885 +-------+--------+----------------+------+
2886 | 8 | 18 | 5 | 0 |
2887 +-------+--------+----------------+------+
2888 | 9 | 23 | 5 | 0 |
2889 +-------+--------+----------------+------+
2890 | 10 | 5 | 5 | 0 |
2891 +-------+--------+----------------+------+
2892 | 11 | 8 | 4 | 0 |
2893 +-------+--------+----------------+------+
2894 | 12 | 14 | 5 | 0 |
2895 +-------+--------+----------------+------+
2896 | 13 | 20 | 5 | 0 |
2897 +-------+--------+----------------+------+
2898 | 14 | 2 | 5 | 0 |
2899 +-------+--------+----------------+------+
2900 | 15 | 7 | 4 | 16 |
2901 +-------+--------+----------------+------+
2902 | 16 | 11 | 5 | 0 |
2903 +-------+--------+----------------+------+
2904 | 17 | 17 | 5 | 0 |
2905 +-------+--------+----------------+------+
2906 | 18 | 22 | 5 | 0 |
2907 +-------+--------+----------------+------+
2908 | 19 | 4 | 5 | 0 |
2909 +-------+--------+----------------+------+
2910 | 20 | 8 | 4 | 16 |
2911
2912
2913
2914Collet & Kucherawy Informational [Page 52]
2915
2916RFC 8478 application/zstd October 2018
2917
2918
2919 +-------+--------+----------------+------+
2920 | 21 | 13 | 5 | 0 |
2921 +-------+--------+----------------+------+
2922 | 22 | 19 | 5 | 0 |
2923 +-------+--------+----------------+------+
2924 | 23 | 1 | 5 | 0 |
2925 +-------+--------+----------------+------+
2926 | 24 | 6 | 4 | 16 |
2927 +-------+--------+----------------+------+
2928 | 25 | 10 | 5 | 0 |
2929 +-------+--------+----------------+------+
2930 | 26 | 16 | 5 | 0 |
2931 +-------+--------+----------------+------+
2932 | 27 | 28 | 5 | 0 |
2933 +-------+--------+----------------+------+
2934 | 28 | 27 | 5 | 0 |
2935 +-------+--------+----------------+------+
2936 | 29 | 26 | 5 | 0 |
2937 +-------+--------+----------------+------+
2938 | 30 | 25 | 5 | 0 |
2939 +-------+--------+----------------+------+
2940 | 31 | 24 | 5 | 0 |
2941 +-------+--------+----------------+------+
2942
2943Acknowledgments
2944
2945 zstd was developed by Yann Collet.
2946
2947 Bobo Bose-Kolanu, Felix Handte, Kyle Nekritz, Nick Terrell, and David
2948 Schleimer provided helpful feedback during the development of this
2949 document.
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970Collet & Kucherawy Informational [Page 53]
2971
2972RFC 8478 application/zstd October 2018
2973
2974
2975Authors' Addresses
2976
2977 Yann Collet
2978 Facebook
2979 1 Hacker Way
2980 Menlo Park, CA 94025
2981 United States of America
2982
2983 Email: cyan@fb.com
2984
2985
2986 Murray S. Kucherawy (editor)
2987 Facebook
2988 1 Hacker Way
2989 Menlo Park, CA 94025
2990 United States of America
2991
2992 Email: msk@fb.com
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026Collet & Kucherawy Informational [Page 54]
3027
lib/std/compress/testdata/rfc8478.txt.zst.19 created
Binary files /dev/null and b/lib/std/compress/testdata/rfc8478.txt.zst.19 differ
lib/std/compress/testdata/rfc8478.txt.zst.3 created
Binary files /dev/null and b/lib/std/compress/testdata/rfc8478.txt.zst.3 differ
lib/std/compress/zstandard.zig created+286
...@@ -0,0 +1,286 @@
1const std = @import("std");
2const Allocator = std.mem.Allocator;
3const RingBuffer = std.RingBuffer;
4
5const types = @import("zstandard/types.zig");
6pub const frame = types.frame;
7pub const compressed_block = types.compressed_block;
8
9pub const decompress = @import("zstandard/decompress.zig");
10
11pub const DecompressStreamOptions = struct {
12 verify_checksum: bool = true,
13 window_size_max: usize = 1 << 23, // 8MiB default maximum window size,
14};
15
16pub fn DecompressStream(
17 comptime ReaderType: type,
18 comptime options: DecompressStreamOptions,
19) type {
20 return struct {
21 const Self = @This();
22
23 allocator: Allocator,
24 source: std.io.CountingReader(ReaderType),
25 state: enum { NewFrame, InFrame, LastBlock },
26 decode_state: decompress.block.DecodeState,
27 frame_context: decompress.FrameContext,
28 buffer: RingBuffer,
29 literal_fse_buffer: []types.compressed_block.Table.Fse,
30 match_fse_buffer: []types.compressed_block.Table.Fse,
31 offset_fse_buffer: []types.compressed_block.Table.Fse,
32 literals_buffer: []u8,
33 sequence_buffer: []u8,
34 checksum: if (options.verify_checksum) ?u32 else void,
35 current_frame_decompressed_size: usize,
36
37 pub const Error = ReaderType.Error || error{
38 ChecksumFailure,
39 DictionaryIdFlagUnsupported,
40 MalformedBlock,
41 MalformedFrame,
42 OutOfMemory,
43 };
44
45 pub const Reader = std.io.Reader(*Self, Error, read);
46
47 pub fn init(allocator: Allocator, source: ReaderType) Self {
48 return Self{
49 .allocator = allocator,
50 .source = std.io.countingReader(source),
51 .state = .NewFrame,
52 .decode_state = undefined,
53 .frame_context = undefined,
54 .buffer = undefined,
55 .literal_fse_buffer = undefined,
56 .match_fse_buffer = undefined,
57 .offset_fse_buffer = undefined,
58 .literals_buffer = undefined,
59 .sequence_buffer = undefined,
60 .checksum = undefined,
61 .current_frame_decompressed_size = undefined,
62 };
63 }
64
65 fn frameInit(self: *Self) !void {
66 const source_reader = self.source.reader();
67 switch (try decompress.decodeFrameHeader(source_reader)) {
68 .skippable => |header| {
69 try source_reader.skipBytes(header.frame_size, .{});
70 self.state = .NewFrame;
71 },
72 .zstandard => |header| {
73 const frame_context = context: {
74 break :context try decompress.FrameContext.init(
75 header,
76 options.window_size_max,
77 options.verify_checksum,
78 );
79 };
80
81 const literal_fse_buffer = try self.allocator.alloc(
82 types.compressed_block.Table.Fse,
83 types.compressed_block.table_size_max.literal,
84 );
85 errdefer self.allocator.free(literal_fse_buffer);
86
87 const match_fse_buffer = try self.allocator.alloc(
88 types.compressed_block.Table.Fse,
89 types.compressed_block.table_size_max.match,
90 );
91 errdefer self.allocator.free(match_fse_buffer);
92
93 const offset_fse_buffer = try self.allocator.alloc(
94 types.compressed_block.Table.Fse,
95 types.compressed_block.table_size_max.offset,
96 );
97 errdefer self.allocator.free(offset_fse_buffer);
98
99 const decode_state = decompress.block.DecodeState.init(
100 literal_fse_buffer,
101 match_fse_buffer,
102 offset_fse_buffer,
103 );
104 const buffer = try RingBuffer.init(self.allocator, frame_context.window_size);
105
106 const literals_data = try self.allocator.alloc(u8, options.window_size_max);
107 errdefer self.allocator.free(literals_data);
108
109 const sequence_data = try self.allocator.alloc(u8, options.window_size_max);
110 errdefer self.allocator.free(sequence_data);
111
112 self.literal_fse_buffer = literal_fse_buffer;
113 self.match_fse_buffer = match_fse_buffer;
114 self.offset_fse_buffer = offset_fse_buffer;
115 self.literals_buffer = literals_data;
116 self.sequence_buffer = sequence_data;
117
118 self.buffer = buffer;
119
120 self.decode_state = decode_state;
121 self.frame_context = frame_context;
122
123 self.checksum = if (options.verify_checksum) null else {};
124 self.current_frame_decompressed_size = 0;
125
126 self.state = .InFrame;
127 },
128 }
129 }
130
131 pub fn deinit(self: *Self) void {
132 if (self.state == .NewFrame) return;
133 self.allocator.free(self.decode_state.literal_fse_buffer);
134 self.allocator.free(self.decode_state.match_fse_buffer);
135 self.allocator.free(self.decode_state.offset_fse_buffer);
136 self.allocator.free(self.literals_buffer);
137 self.allocator.free(self.sequence_buffer);
138 self.buffer.deinit(self.allocator);
139 }
140
141 pub fn reader(self: *Self) Reader {
142 return .{ .context = self };
143 }
144
145 pub fn read(self: *Self, buffer: []u8) Error!usize {
146 if (buffer.len == 0) return 0;
147
148 var size: usize = 0;
149 while (size == 0) {
150 while (self.state == .NewFrame) {
151 const initial_count = self.source.bytes_read;
152 self.frameInit() catch |err| switch (err) {
153 error.DictionaryIdFlagUnsupported => return error.DictionaryIdFlagUnsupported,
154 error.EndOfStream => return if (self.source.bytes_read == initial_count)
155 0
156 else
157 error.MalformedFrame,
158 error.OutOfMemory => return error.OutOfMemory,
159 else => return error.MalformedFrame,
160 };
161 }
162 size = try self.readInner(buffer);
163 }
164 return size;
165 }
166
167 fn readInner(self: *Self, buffer: []u8) Error!usize {
168 std.debug.assert(self.state != .NewFrame);
169
170 const source_reader = self.source.reader();
171 while (self.buffer.isEmpty() and self.state != .LastBlock) {
172 const header_bytes = source_reader.readBytesNoEof(3) catch
173 return error.MalformedFrame;
174 const block_header = decompress.block.decodeBlockHeader(&header_bytes);
175
176 decompress.block.decodeBlockReader(
177 &self.buffer,
178 source_reader,
179 block_header,
180 &self.decode_state,
181 self.frame_context.block_size_max,
182 self.literals_buffer,
183 self.sequence_buffer,
184 ) catch
185 return error.MalformedBlock;
186
187 if (self.frame_context.content_size) |size| {
188 if (self.current_frame_decompressed_size > size) return error.MalformedFrame;
189 }
190
191 const size = self.buffer.len();
192 self.current_frame_decompressed_size += size;
193
194 if (self.frame_context.hasher_opt) |*hasher| {
195 if (size > 0) {
196 const written_slice = self.buffer.sliceLast(size);
197 hasher.update(written_slice.first);
198 hasher.update(written_slice.second);
199 }
200 }
201 if (block_header.last_block) {
202 self.state = .LastBlock;
203 if (self.frame_context.has_checksum) {
204 const checksum = source_reader.readIntLittle(u32) catch
205 return error.MalformedFrame;
206 if (comptime options.verify_checksum) {
207 if (self.frame_context.hasher_opt) |*hasher| {
208 if (checksum != decompress.computeChecksum(hasher))
209 return error.ChecksumFailure;
210 }
211 }
212 }
213 if (self.frame_context.content_size) |content_size| {
214 if (content_size != self.current_frame_decompressed_size) {
215 return error.MalformedFrame;
216 }
217 }
218 }
219 }
220
221 const size = @min(self.buffer.len(), buffer.len);
222 for (0..size) |i| {
223 buffer[i] = self.buffer.read().?;
224 }
225 if (self.state == .LastBlock and self.buffer.len() == 0) {
226 self.state = .NewFrame;
227 self.allocator.free(self.literal_fse_buffer);
228 self.allocator.free(self.match_fse_buffer);
229 self.allocator.free(self.offset_fse_buffer);
230 self.allocator.free(self.literals_buffer);
231 self.allocator.free(self.sequence_buffer);
232 self.buffer.deinit(self.allocator);
233 }
234 return size;
235 }
236 };
237}
238
239pub fn decompressStreamOptions(
240 allocator: Allocator,
241 reader: anytype,
242 comptime options: DecompressStreamOptions,
243) DecompressStream(@TypeOf(reader, options)) {
244 return DecompressStream(@TypeOf(reader), options).init(allocator, reader);
245}
246
247pub fn decompressStream(
248 allocator: Allocator,
249 reader: anytype,
250) DecompressStream(@TypeOf(reader), .{}) {
251 return DecompressStream(@TypeOf(reader), .{}).init(allocator, reader);
252}
253
254fn testDecompress(data: []const u8) ![]u8 {
255 var in_stream = std.io.fixedBufferStream(data);
256 var zstd_stream = decompressStream(std.testing.allocator, in_stream.reader());
257 defer zstd_stream.deinit();
258 const result = zstd_stream.reader().readAllAlloc(std.testing.allocator, std.math.maxInt(usize));
259 return result;
260}
261
262fn testReader(data: []const u8, comptime expected: []const u8) !void {
263 const buf = try testDecompress(data);
264 defer std.testing.allocator.free(buf);
265 try std.testing.expectEqualSlices(u8, expected, buf);
266}
267
268test "zstandard decompression" {
269 const uncompressed = @embedFile("testdata/rfc8478.txt");
270 const compressed3 = @embedFile("testdata/rfc8478.txt.zst.3");
271 const compressed19 = @embedFile("testdata/rfc8478.txt.zst.19");
272
273 var buffer = try std.testing.allocator.alloc(u8, uncompressed.len);
274 defer std.testing.allocator.free(buffer);
275
276 const res3 = try decompress.decode(buffer, compressed3, true);
277 try std.testing.expectEqual(uncompressed.len, res3);
278 try std.testing.expectEqualSlices(u8, uncompressed, buffer);
279
280 const res19 = try decompress.decode(buffer, compressed19, true);
281 try std.testing.expectEqual(uncompressed.len, res19);
282 try std.testing.expectEqualSlices(u8, uncompressed, buffer);
283
284 try testReader(compressed3, uncompressed);
285 try testReader(compressed19, uncompressed);
286}
lib/std/compress/zstandard/decode/block.zig created+1149
...@@ -0,0 +1,1149 @@
1const std = @import("std");
2const assert = std.debug.assert;
3const RingBuffer = std.RingBuffer;
4
5const types = @import("../types.zig");
6const frame = types.frame;
7const Table = types.compressed_block.Table;
8const LiteralsSection = types.compressed_block.LiteralsSection;
9const SequencesSection = types.compressed_block.SequencesSection;
10
11const huffman = @import("huffman.zig");
12const readers = @import("../readers.zig");
13
14const decodeFseTable = @import("fse.zig").decodeFseTable;
15
16const readInt = std.mem.readIntLittle;
17
18pub const Error = error{
19 BlockSizeOverMaximum,
20 MalformedBlockSize,
21 ReservedBlock,
22 MalformedRleBlock,
23 MalformedCompressedBlock,
24};
25
26pub const DecodeState = struct {
27 repeat_offsets: [3]u32,
28
29 offset: StateData(8),
30 match: StateData(9),
31 literal: StateData(9),
32
33 offset_fse_buffer: []Table.Fse,
34 match_fse_buffer: []Table.Fse,
35 literal_fse_buffer: []Table.Fse,
36
37 fse_tables_undefined: bool,
38
39 literal_stream_reader: readers.ReverseBitReader,
40 literal_stream_index: usize,
41 literal_streams: LiteralsSection.Streams,
42 literal_header: LiteralsSection.Header,
43 huffman_tree: ?LiteralsSection.HuffmanTree,
44
45 literal_written_count: usize,
46 written_count: usize = 0,
47
48 fn StateData(comptime max_accuracy_log: comptime_int) type {
49 return struct {
50 state: State,
51 table: Table,
52 accuracy_log: u8,
53
54 const State = std.meta.Int(.unsigned, max_accuracy_log);
55 };
56 }
57
58 pub fn init(
59 literal_fse_buffer: []Table.Fse,
60 match_fse_buffer: []Table.Fse,
61 offset_fse_buffer: []Table.Fse,
62 ) DecodeState {
63 return DecodeState{
64 .repeat_offsets = .{
65 types.compressed_block.start_repeated_offset_1,
66 types.compressed_block.start_repeated_offset_2,
67 types.compressed_block.start_repeated_offset_3,
68 },
69
70 .offset = undefined,
71 .match = undefined,
72 .literal = undefined,
73
74 .literal_fse_buffer = literal_fse_buffer,
75 .match_fse_buffer = match_fse_buffer,
76 .offset_fse_buffer = offset_fse_buffer,
77
78 .fse_tables_undefined = true,
79
80 .literal_written_count = 0,
81 .literal_header = undefined,
82 .literal_streams = undefined,
83 .literal_stream_reader = undefined,
84 .literal_stream_index = undefined,
85 .huffman_tree = null,
86
87 .written_count = 0,
88 };
89 }
90
91 /// Prepare the decoder to decode a compressed block. Loads the literals
92 /// stream and Huffman tree from `literals` and reads the FSE tables from
93 /// `source`.
94 ///
95 /// Errors returned:
96 /// - `error.BitStreamHasNoStartBit` if the (reversed) literal bitstream's
97 /// first byte does not have any bits set
98 /// - `error.TreelessLiteralsFirst` `literals` is a treeless literals
99 /// section and the decode state does not have a Huffman tree from a
100 /// previous block
101 /// - `error.RepeatModeFirst` on the first call if one of the sequence FSE
102 /// tables is set to repeat mode
103 /// - `error.MalformedAccuracyLog` if an FSE table has an invalid accuracy
104 /// - `error.MalformedFseTable` if there are errors decoding an FSE table
105 /// - `error.EndOfStream` if `source` ends before all FSE tables are read
106 pub fn prepare(
107 self: *DecodeState,
108 source: anytype,
109 literals: LiteralsSection,
110 sequences_header: SequencesSection.Header,
111 ) !void {
112 self.literal_written_count = 0;
113 self.literal_header = literals.header;
114 self.literal_streams = literals.streams;
115
116 if (literals.huffman_tree) |tree| {
117 self.huffman_tree = tree;
118 } else if (literals.header.block_type == .treeless and self.huffman_tree == null) {
119 return error.TreelessLiteralsFirst;
120 }
121
122 switch (literals.header.block_type) {
123 .raw, .rle => {},
124 .compressed, .treeless => {
125 self.literal_stream_index = 0;
126 switch (literals.streams) {
127 .one => |slice| try self.initLiteralStream(slice),
128 .four => |streams| try self.initLiteralStream(streams[0]),
129 }
130 },
131 }
132
133 if (sequences_header.sequence_count > 0) {
134 try self.updateFseTable(source, .literal, sequences_header.literal_lengths);
135 try self.updateFseTable(source, .offset, sequences_header.offsets);
136 try self.updateFseTable(source, .match, sequences_header.match_lengths);
137 self.fse_tables_undefined = false;
138 }
139 }
140
141 /// Read initial FSE states for sequence decoding.
142 ///
143 /// Errors returned:
144 /// - `error.EndOfStream` if `bit_reader` does not contain enough bits.
145 pub fn readInitialFseState(self: *DecodeState, bit_reader: *readers.ReverseBitReader) error{EndOfStream}!void {
146 self.literal.state = try bit_reader.readBitsNoEof(u9, self.literal.accuracy_log);
147 self.offset.state = try bit_reader.readBitsNoEof(u8, self.offset.accuracy_log);
148 self.match.state = try bit_reader.readBitsNoEof(u9, self.match.accuracy_log);
149 }
150
151 fn updateRepeatOffset(self: *DecodeState, offset: u32) void {
152 self.repeat_offsets[2] = self.repeat_offsets[1];
153 self.repeat_offsets[1] = self.repeat_offsets[0];
154 self.repeat_offsets[0] = offset;
155 }
156
157 fn useRepeatOffset(self: *DecodeState, index: usize) u32 {
158 if (index == 1)
159 std.mem.swap(u32, &self.repeat_offsets[0], &self.repeat_offsets[1])
160 else if (index == 2) {
161 std.mem.swap(u32, &self.repeat_offsets[0], &self.repeat_offsets[2]);
162 std.mem.swap(u32, &self.repeat_offsets[1], &self.repeat_offsets[2]);
163 }
164 return self.repeat_offsets[0];
165 }
166
167 const DataType = enum { offset, match, literal };
168
169 fn updateState(
170 self: *DecodeState,
171 comptime choice: DataType,
172 bit_reader: *readers.ReverseBitReader,
173 ) error{ MalformedFseBits, EndOfStream }!void {
174 switch (@field(self, @tagName(choice)).table) {
175 .rle => {},
176 .fse => |table| {
177 const data = table[@field(self, @tagName(choice)).state];
178 const T = @TypeOf(@field(self, @tagName(choice))).State;
179 const bits_summand = try bit_reader.readBitsNoEof(T, data.bits);
180 const next_state = std.math.cast(
181 @TypeOf(@field(self, @tagName(choice))).State,
182 data.baseline + bits_summand,
183 ) orelse return error.MalformedFseBits;
184 @field(self, @tagName(choice)).state = next_state;
185 },
186 }
187 }
188
189 const FseTableError = error{
190 MalformedFseTable,
191 MalformedAccuracyLog,
192 RepeatModeFirst,
193 EndOfStream,
194 };
195
196 fn updateFseTable(
197 self: *DecodeState,
198 source: anytype,
199 comptime choice: DataType,
200 mode: SequencesSection.Header.Mode,
201 ) !void {
202 const field_name = @tagName(choice);
203 switch (mode) {
204 .predefined => {
205 @field(self, field_name).accuracy_log =
206 @field(types.compressed_block.default_accuracy_log, field_name);
207
208 @field(self, field_name).table =
209 @field(types.compressed_block, "predefined_" ++ field_name ++ "_fse_table");
210 },
211 .rle => {
212 @field(self, field_name).accuracy_log = 0;
213 @field(self, field_name).table = .{ .rle = try source.readByte() };
214 },
215 .fse => {
216 var bit_reader = readers.bitReader(source);
217
218 const table_size = try decodeFseTable(
219 &bit_reader,
220 @field(types.compressed_block.table_symbol_count_max, field_name),
221 @field(types.compressed_block.table_accuracy_log_max, field_name),
222 @field(self, field_name ++ "_fse_buffer"),
223 );
224 @field(self, field_name).table = .{
225 .fse = @field(self, field_name ++ "_fse_buffer")[0..table_size],
226 };
227 @field(self, field_name).accuracy_log = std.math.log2_int_ceil(usize, table_size);
228 },
229 .repeat => if (self.fse_tables_undefined) return error.RepeatModeFirst,
230 }
231 }
232
233 const Sequence = struct {
234 literal_length: u32,
235 match_length: u32,
236 offset: u32,
237 };
238
239 fn nextSequence(
240 self: *DecodeState,
241 bit_reader: *readers.ReverseBitReader,
242 ) error{ InvalidBitStream, EndOfStream }!Sequence {
243 const raw_code = self.getCode(.offset);
244 const offset_code = std.math.cast(u5, raw_code) orelse {
245 return error.InvalidBitStream;
246 };
247 const offset_value = (@as(u32, 1) << offset_code) + try bit_reader.readBitsNoEof(u32, offset_code);
248
249 const match_code = self.getCode(.match);
250 if (match_code >= types.compressed_block.match_length_code_table.len)
251 return error.InvalidBitStream;
252 const match = types.compressed_block.match_length_code_table[match_code];
253 const match_length = match[0] + try bit_reader.readBitsNoEof(u32, match[1]);
254
255 const literal_code = self.getCode(.literal);
256 if (literal_code >= types.compressed_block.literals_length_code_table.len)
257 return error.InvalidBitStream;
258 const literal = types.compressed_block.literals_length_code_table[literal_code];
259 const literal_length = literal[0] + try bit_reader.readBitsNoEof(u32, literal[1]);
260
261 const offset = if (offset_value > 3) offset: {
262 const offset = offset_value - 3;
263 self.updateRepeatOffset(offset);
264 break :offset offset;
265 } else offset: {
266 if (literal_length == 0) {
267 if (offset_value == 3) {
268 const offset = self.repeat_offsets[0] - 1;
269 self.updateRepeatOffset(offset);
270 break :offset offset;
271 }
272 break :offset self.useRepeatOffset(offset_value);
273 }
274 break :offset self.useRepeatOffset(offset_value - 1);
275 };
276
277 if (offset == 0) return error.InvalidBitStream;
278
279 return .{
280 .literal_length = literal_length,
281 .match_length = match_length,
282 .offset = offset,
283 };
284 }
285
286 fn executeSequenceSlice(
287 self: *DecodeState,
288 dest: []u8,
289 write_pos: usize,
290 sequence: Sequence,
291 ) (error{MalformedSequence} || DecodeLiteralsError)!void {
292 if (sequence.offset > write_pos + sequence.literal_length) return error.MalformedSequence;
293
294 try self.decodeLiteralsSlice(dest[write_pos..], sequence.literal_length);
295 const copy_start = write_pos + sequence.literal_length - sequence.offset;
296 const copy_end = copy_start + sequence.match_length;
297 // NOTE: we ignore the usage message for std.mem.copy and copy with dest.ptr >= src.ptr
298 // to allow repeats
299 std.mem.copy(u8, dest[write_pos + sequence.literal_length ..], dest[copy_start..copy_end]);
300 self.written_count += sequence.match_length;
301 }
302
303 fn executeSequenceRingBuffer(
304 self: *DecodeState,
305 dest: *RingBuffer,
306 sequence: Sequence,
307 ) (error{MalformedSequence} || DecodeLiteralsError)!void {
308 if (sequence.offset > @min(dest.data.len, self.written_count + sequence.literal_length))
309 return error.MalformedSequence;
310
311 try self.decodeLiteralsRingBuffer(dest, sequence.literal_length);
312 const copy_start = dest.write_index + dest.data.len - sequence.offset;
313 const copy_slice = dest.sliceAt(copy_start, sequence.match_length);
314 // TODO: would std.mem.copy and figuring out dest slice be better/faster?
315 for (copy_slice.first) |b| dest.writeAssumeCapacity(b);
316 for (copy_slice.second) |b| dest.writeAssumeCapacity(b);
317 self.written_count += sequence.match_length;
318 }
319
320 const DecodeSequenceError = error{
321 InvalidBitStream,
322 EndOfStream,
323 MalformedSequence,
324 MalformedFseBits,
325 } || DecodeLiteralsError;
326
327 /// Decode one sequence from `bit_reader` into `dest`, written starting at
328 /// `write_pos` and update FSE states if `last_sequence` is `false`.
329 /// `prepare()` must be called for the block before attempting to decode
330 /// sequences.
331 ///
332 /// Errors returned:
333 /// - `error.MalformedSequence` if the decompressed sequence would be
334 /// longer than `sequence_size_limit` or the sequence's offset is too
335 /// large
336 /// - `error.UnexpectedEndOfLiteralStream` if the decoder state's literal
337 /// streams do not contain enough literals for the sequence (this may
338 /// mean the literal stream or the sequence is malformed).
339 /// - `error.InvalidBitStream` if the FSE sequence bitstream is malformed
340 /// - `error.EndOfStream` if `bit_reader` does not contain enough bits
341 /// - `error.DestTooSmall` if `dest` is not large enough to holde the
342 /// decompressed sequence
343 pub fn decodeSequenceSlice(
344 self: *DecodeState,
345 dest: []u8,
346 write_pos: usize,
347 bit_reader: *readers.ReverseBitReader,
348 sequence_size_limit: usize,
349 last_sequence: bool,
350 ) (error{DestTooSmall} || DecodeSequenceError)!usize {
351 const sequence = try self.nextSequence(bit_reader);
352 const sequence_length = @as(usize, sequence.literal_length) + sequence.match_length;
353 if (sequence_length > sequence_size_limit) return error.MalformedSequence;
354 if (sequence_length > dest[write_pos..].len) return error.DestTooSmall;
355
356 try self.executeSequenceSlice(dest, write_pos, sequence);
357 if (!last_sequence) {
358 try self.updateState(.literal, bit_reader);
359 try self.updateState(.match, bit_reader);
360 try self.updateState(.offset, bit_reader);
361 }
362 return sequence_length;
363 }
364
365 /// Decode one sequence from `bit_reader` into `dest`; see
366 /// `decodeSequenceSlice`.
367 pub fn decodeSequenceRingBuffer(
368 self: *DecodeState,
369 dest: *RingBuffer,
370 bit_reader: anytype,
371 sequence_size_limit: usize,
372 last_sequence: bool,
373 ) DecodeSequenceError!usize {
374 const sequence = try self.nextSequence(bit_reader);
375 const sequence_length = @as(usize, sequence.literal_length) + sequence.match_length;
376 if (sequence_length > sequence_size_limit) return error.MalformedSequence;
377
378 try self.executeSequenceRingBuffer(dest, sequence);
379 if (!last_sequence) {
380 try self.updateState(.literal, bit_reader);
381 try self.updateState(.match, bit_reader);
382 try self.updateState(.offset, bit_reader);
383 }
384 return sequence_length;
385 }
386
387 fn nextLiteralMultiStream(
388 self: *DecodeState,
389 ) error{BitStreamHasNoStartBit}!void {
390 self.literal_stream_index += 1;
391 try self.initLiteralStream(self.literal_streams.four[self.literal_stream_index]);
392 }
393
394 fn initLiteralStream(self: *DecodeState, bytes: []const u8) error{BitStreamHasNoStartBit}!void {
395 try self.literal_stream_reader.init(bytes);
396 }
397
398 fn isLiteralStreamEmpty(self: *DecodeState) bool {
399 switch (self.literal_streams) {
400 .one => return self.literal_stream_reader.isEmpty(),
401 .four => return self.literal_stream_index == 3 and self.literal_stream_reader.isEmpty(),
402 }
403 }
404
405 const LiteralBitsError = error{
406 BitStreamHasNoStartBit,
407 UnexpectedEndOfLiteralStream,
408 };
409 fn readLiteralsBits(
410 self: *DecodeState,
411 bit_count_to_read: usize,
412 ) LiteralBitsError!u16 {
413 return self.literal_stream_reader.readBitsNoEof(u16, bit_count_to_read) catch bits: {
414 if (self.literal_streams == .four and self.literal_stream_index < 3) {
415 try self.nextLiteralMultiStream();
416 break :bits self.literal_stream_reader.readBitsNoEof(u16, bit_count_to_read) catch
417 return error.UnexpectedEndOfLiteralStream;
418 } else {
419 return error.UnexpectedEndOfLiteralStream;
420 }
421 };
422 }
423
424 const DecodeLiteralsError = error{
425 MalformedLiteralsLength,
426 NotFound,
427 } || LiteralBitsError;
428
429 /// Decode `len` bytes of literals into `dest`.
430 ///
431 /// Errors returned:
432 /// - `error.MalformedLiteralsLength` if the number of literal bytes
433 /// decoded by `self` plus `len` is greater than the regenerated size of
434 /// `literals`
435 /// - `error.UnexpectedEndOfLiteralStream` and `error.NotFound` if there
436 /// are problems decoding Huffman compressed literals
437 pub fn decodeLiteralsSlice(
438 self: *DecodeState,
439 dest: []u8,
440 len: usize,
441 ) DecodeLiteralsError!void {
442 if (self.literal_written_count + len > self.literal_header.regenerated_size)
443 return error.MalformedLiteralsLength;
444
445 switch (self.literal_header.block_type) {
446 .raw => {
447 const literals_end = self.literal_written_count + len;
448 const literal_data = self.literal_streams.one[self.literal_written_count..literals_end];
449 std.mem.copy(u8, dest, literal_data);
450 self.literal_written_count += len;
451 self.written_count += len;
452 },
453 .rle => {
454 for (0..len) |i| {
455 dest[i] = self.literal_streams.one[0];
456 }
457 self.literal_written_count += len;
458 self.written_count += len;
459 },
460 .compressed, .treeless => {
461 // const written_bytes_per_stream = (literals.header.regenerated_size + 3) / 4;
462 const huffman_tree = self.huffman_tree orelse unreachable;
463 const max_bit_count = huffman_tree.max_bit_count;
464 const starting_bit_count = LiteralsSection.HuffmanTree.weightToBitCount(
465 huffman_tree.nodes[huffman_tree.symbol_count_minus_one].weight,
466 max_bit_count,
467 );
468 var bits_read: u4 = 0;
469 var huffman_tree_index: usize = huffman_tree.symbol_count_minus_one;
470 var bit_count_to_read: u4 = starting_bit_count;
471 for (0..len) |i| {
472 var prefix: u16 = 0;
473 while (true) {
474 const new_bits = self.readLiteralsBits(bit_count_to_read) catch |err| {
475 return err;
476 };
477 prefix <<= bit_count_to_read;
478 prefix |= new_bits;
479 bits_read += bit_count_to_read;
480 const result = huffman_tree.query(huffman_tree_index, prefix) catch |err| {
481 return err;
482 };
483
484 switch (result) {
485 .symbol => |sym| {
486 dest[i] = sym;
487 bit_count_to_read = starting_bit_count;
488 bits_read = 0;
489 huffman_tree_index = huffman_tree.symbol_count_minus_one;
490 break;
491 },
492 .index => |index| {
493 huffman_tree_index = index;
494 const bit_count = LiteralsSection.HuffmanTree.weightToBitCount(
495 huffman_tree.nodes[index].weight,
496 max_bit_count,
497 );
498 bit_count_to_read = bit_count - bits_read;
499 },
500 }
501 }
502 }
503 self.literal_written_count += len;
504 self.written_count += len;
505 },
506 }
507 }
508
509 /// Decode literals into `dest`; see `decodeLiteralsSlice()`.
510 pub fn decodeLiteralsRingBuffer(
511 self: *DecodeState,
512 dest: *RingBuffer,
513 len: usize,
514 ) DecodeLiteralsError!void {
515 if (self.literal_written_count + len > self.literal_header.regenerated_size)
516 return error.MalformedLiteralsLength;
517
518 switch (self.literal_header.block_type) {
519 .raw => {
520 const literals_end = self.literal_written_count + len;
521 const literal_data = self.literal_streams.one[self.literal_written_count..literals_end];
522 dest.writeSliceAssumeCapacity(literal_data);
523 self.literal_written_count += len;
524 self.written_count += len;
525 },
526 .rle => {
527 for (0..len) |_| {
528 dest.writeAssumeCapacity(self.literal_streams.one[0]);
529 }
530 self.literal_written_count += len;
531 self.written_count += len;
532 },
533 .compressed, .treeless => {
534 // const written_bytes_per_stream = (literals.header.regenerated_size + 3) / 4;
535 const huffman_tree = self.huffman_tree orelse unreachable;
536 const max_bit_count = huffman_tree.max_bit_count;
537 const starting_bit_count = LiteralsSection.HuffmanTree.weightToBitCount(
538 huffman_tree.nodes[huffman_tree.symbol_count_minus_one].weight,
539 max_bit_count,
540 );
541 var bits_read: u4 = 0;
542 var huffman_tree_index: usize = huffman_tree.symbol_count_minus_one;
543 var bit_count_to_read: u4 = starting_bit_count;
544 for (0..len) |_| {
545 var prefix: u16 = 0;
546 while (true) {
547 const new_bits = try self.readLiteralsBits(bit_count_to_read);
548 prefix <<= bit_count_to_read;
549 prefix |= new_bits;
550 bits_read += bit_count_to_read;
551 const result = try huffman_tree.query(huffman_tree_index, prefix);
552
553 switch (result) {
554 .symbol => |sym| {
555 dest.writeAssumeCapacity(sym);
556 bit_count_to_read = starting_bit_count;
557 bits_read = 0;
558 huffman_tree_index = huffman_tree.symbol_count_minus_one;
559 break;
560 },
561 .index => |index| {
562 huffman_tree_index = index;
563 const bit_count = LiteralsSection.HuffmanTree.weightToBitCount(
564 huffman_tree.nodes[index].weight,
565 max_bit_count,
566 );
567 bit_count_to_read = bit_count - bits_read;
568 },
569 }
570 }
571 }
572 self.literal_written_count += len;
573 self.written_count += len;
574 },
575 }
576 }
577
578 fn getCode(self: *DecodeState, comptime choice: DataType) u32 {
579 return switch (@field(self, @tagName(choice)).table) {
580 .rle => |value| value,
581 .fse => |table| table[@field(self, @tagName(choice)).state].symbol,
582 };
583 }
584};
585
586/// Decode a single block from `src` into `dest`. The beginning of `src` must be
587/// the start of the block content (i.e. directly after the block header).
588/// Increments `consumed_count` by the number of bytes read from `src` to decode
589/// the block and returns the decompressed size of the block.
590///
591/// Errors returned:
592///
593/// - `error.BlockSizeOverMaximum` if block's size is larger than 1 << 17 or
594/// `dest[written_count..].len`
595/// - `error.MalformedBlockSize` if `src.len` is smaller than the block size
596/// and the block is a raw or compressed block
597/// - `error.ReservedBlock` if the block is a reserved block
598/// - `error.MalformedRleBlock` if the block is an RLE block and `src.len < 1`
599/// - `error.MalformedCompressedBlock` if there are errors decoding a
600/// compressed block
601/// - `error.DestTooSmall` is `dest` is not large enough to hold the
602/// decompressed block
603pub fn decodeBlock(
604 dest: []u8,
605 src: []const u8,
606 block_header: frame.Zstandard.Block.Header,
607 decode_state: *DecodeState,
608 consumed_count: *usize,
609 block_size_max: usize,
610 written_count: usize,
611) (error{DestTooSmall} || Error)!usize {
612 const block_size = block_header.block_size;
613 if (block_size_max < block_size) return error.BlockSizeOverMaximum;
614 switch (block_header.block_type) {
615 .raw => {
616 if (src.len < block_size) return error.MalformedBlockSize;
617 if (dest[written_count..].len < block_size) return error.DestTooSmall;
618 const data = src[0..block_size];
619 std.mem.copy(u8, dest[written_count..], data);
620 consumed_count.* += block_size;
621 decode_state.written_count += block_size;
622 return block_size;
623 },
624 .rle => {
625 if (src.len < 1) return error.MalformedRleBlock;
626 if (dest[written_count..].len < block_size) return error.DestTooSmall;
627 for (written_count..block_size + written_count) |write_pos| {
628 dest[write_pos] = src[0];
629 }
630 consumed_count.* += 1;
631 decode_state.written_count += block_size;
632 return block_size;
633 },
634 .compressed => {
635 if (src.len < block_size) return error.MalformedBlockSize;
636 var bytes_read: usize = 0;
637 const literals = decodeLiteralsSectionSlice(src[0..block_size], &bytes_read) catch
638 return error.MalformedCompressedBlock;
639 var fbs = std.io.fixedBufferStream(src[bytes_read..block_size]);
640 const fbs_reader = fbs.reader();
641 const sequences_header = decodeSequencesHeader(fbs_reader) catch
642 return error.MalformedCompressedBlock;
643
644 decode_state.prepare(fbs_reader, literals, sequences_header) catch
645 return error.MalformedCompressedBlock;
646
647 bytes_read += fbs.pos;
648
649 var bytes_written: usize = 0;
650 {
651 const bit_stream_bytes = src[bytes_read..block_size];
652 var bit_stream: readers.ReverseBitReader = undefined;
653 bit_stream.init(bit_stream_bytes) catch return error.MalformedCompressedBlock;
654
655 if (sequences_header.sequence_count > 0) {
656 decode_state.readInitialFseState(&bit_stream) catch
657 return error.MalformedCompressedBlock;
658
659 var sequence_size_limit = block_size_max;
660 for (0..sequences_header.sequence_count) |i| {
661 const write_pos = written_count + bytes_written;
662 const decompressed_size = decode_state.decodeSequenceSlice(
663 dest,
664 write_pos,
665 &bit_stream,
666 sequence_size_limit,
667 i == sequences_header.sequence_count - 1,
668 ) catch |err| switch (err) {
669 error.DestTooSmall => return error.DestTooSmall,
670 else => return error.MalformedCompressedBlock,
671 };
672 bytes_written += decompressed_size;
673 sequence_size_limit -= decompressed_size;
674 }
675 }
676
677 if (!bit_stream.isEmpty()) {
678 return error.MalformedCompressedBlock;
679 }
680 }
681
682 if (decode_state.literal_written_count < literals.header.regenerated_size) {
683 const len = literals.header.regenerated_size - decode_state.literal_written_count;
684 if (len > dest[written_count + bytes_written ..].len) return error.DestTooSmall;
685 decode_state.decodeLiteralsSlice(dest[written_count + bytes_written ..], len) catch
686 return error.MalformedCompressedBlock;
687 bytes_written += len;
688 }
689
690 switch (decode_state.literal_header.block_type) {
691 .treeless, .compressed => {
692 if (!decode_state.isLiteralStreamEmpty()) return error.MalformedCompressedBlock;
693 },
694 .raw, .rle => {},
695 }
696
697 consumed_count.* += block_size;
698 return bytes_written;
699 },
700 .reserved => return error.ReservedBlock,
701 }
702}
703
704/// Decode a single block from `src` into `dest`; see `decodeBlock()`. Returns
705/// the size of the decompressed block, which can be used with `dest.sliceLast()`
706/// to get the decompressed bytes. `error.BlockSizeOverMaximum` is returned if
707/// the block's compressed or decompressed size is larger than `block_size_max`.
708pub fn decodeBlockRingBuffer(
709 dest: *RingBuffer,
710 src: []const u8,
711 block_header: frame.Zstandard.Block.Header,
712 decode_state: *DecodeState,
713 consumed_count: *usize,
714 block_size_max: usize,
715) Error!usize {
716 const block_size = block_header.block_size;
717 if (block_size_max < block_size) return error.BlockSizeOverMaximum;
718 switch (block_header.block_type) {
719 .raw => {
720 if (src.len < block_size) return error.MalformedBlockSize;
721 const data = src[0..block_size];
722 dest.writeSliceAssumeCapacity(data);
723 consumed_count.* += block_size;
724 decode_state.written_count += block_size;
725 return block_size;
726 },
727 .rle => {
728 if (src.len < 1) return error.MalformedRleBlock;
729 for (0..block_size) |_| {
730 dest.writeAssumeCapacity(src[0]);
731 }
732 consumed_count.* += 1;
733 decode_state.written_count += block_size;
734 return block_size;
735 },
736 .compressed => {
737 if (src.len < block_size) return error.MalformedBlockSize;
738 var bytes_read: usize = 0;
739 const literals = decodeLiteralsSectionSlice(src[0..block_size], &bytes_read) catch
740 return error.MalformedCompressedBlock;
741 var fbs = std.io.fixedBufferStream(src[bytes_read..block_size]);
742 const fbs_reader = fbs.reader();
743 const sequences_header = decodeSequencesHeader(fbs_reader) catch
744 return error.MalformedCompressedBlock;
745
746 decode_state.prepare(fbs_reader, literals, sequences_header) catch
747 return error.MalformedCompressedBlock;
748
749 bytes_read += fbs.pos;
750
751 var bytes_written: usize = 0;
752 {
753 const bit_stream_bytes = src[bytes_read..block_size];
754 var bit_stream: readers.ReverseBitReader = undefined;
755 bit_stream.init(bit_stream_bytes) catch return error.MalformedCompressedBlock;
756
757 if (sequences_header.sequence_count > 0) {
758 decode_state.readInitialFseState(&bit_stream) catch
759 return error.MalformedCompressedBlock;
760
761 var sequence_size_limit = block_size_max;
762 for (0..sequences_header.sequence_count) |i| {
763 const decompressed_size = decode_state.decodeSequenceRingBuffer(
764 dest,
765 &bit_stream,
766 sequence_size_limit,
767 i == sequences_header.sequence_count - 1,
768 ) catch return error.MalformedCompressedBlock;
769 bytes_written += decompressed_size;
770 sequence_size_limit -= decompressed_size;
771 }
772 }
773
774 if (!bit_stream.isEmpty()) {
775 return error.MalformedCompressedBlock;
776 }
777 }
778
779 if (decode_state.literal_written_count < literals.header.regenerated_size) {
780 const len = literals.header.regenerated_size - decode_state.literal_written_count;
781 decode_state.decodeLiteralsRingBuffer(dest, len) catch
782 return error.MalformedCompressedBlock;
783 bytes_written += len;
784 }
785
786 switch (decode_state.literal_header.block_type) {
787 .treeless, .compressed => {
788 if (!decode_state.isLiteralStreamEmpty()) return error.MalformedCompressedBlock;
789 },
790 .raw, .rle => {},
791 }
792
793 consumed_count.* += block_size;
794 if (bytes_written > block_size_max) return error.BlockSizeOverMaximum;
795 return bytes_written;
796 },
797 .reserved => return error.ReservedBlock,
798 }
799}
800
801/// Decode a single block from `source` into `dest`. Literal and sequence data
802/// from the block is copied into `literals_buffer` and `sequence_buffer`, which
803/// must be large enough or `error.LiteralsBufferTooSmall` and
804/// `error.SequenceBufferTooSmall` are returned (the maximum block size is an
805/// upper bound for the size of both buffers). See `decodeBlock`
806/// and `decodeBlockRingBuffer` for function that can decode a block without
807/// these extra copies. `error.EndOfStream` is returned if `source` does not
808/// contain enough bytes.
809pub fn decodeBlockReader(
810 dest: *RingBuffer,
811 source: anytype,
812 block_header: frame.Zstandard.Block.Header,
813 decode_state: *DecodeState,
814 block_size_max: usize,
815 literals_buffer: []u8,
816 sequence_buffer: []u8,
817) !void {
818 const block_size = block_header.block_size;
819 var block_reader_limited = std.io.limitedReader(source, block_size);
820 const block_reader = block_reader_limited.reader();
821 if (block_size_max < block_size) return error.BlockSizeOverMaximum;
822 switch (block_header.block_type) {
823 .raw => {
824 if (block_size == 0) return;
825 const slice = dest.sliceAt(dest.write_index, block_size);
826 try source.readNoEof(slice.first);
827 try source.readNoEof(slice.second);
828 dest.write_index = dest.mask2(dest.write_index + block_size);
829 decode_state.written_count += block_size;
830 },
831 .rle => {
832 const byte = try source.readByte();
833 for (0..block_size) |_| {
834 dest.writeAssumeCapacity(byte);
835 }
836 decode_state.written_count += block_size;
837 },
838 .compressed => {
839 const literals = try decodeLiteralsSection(block_reader, literals_buffer);
840 const sequences_header = try decodeSequencesHeader(block_reader);
841
842 try decode_state.prepare(block_reader, literals, sequences_header);
843
844 var bytes_written: usize = 0;
845 {
846 const size = try block_reader.readAll(sequence_buffer);
847 var bit_stream: readers.ReverseBitReader = undefined;
848 try bit_stream.init(sequence_buffer[0..size]);
849
850 if (sequences_header.sequence_count > 0) {
851 if (sequence_buffer.len < block_reader_limited.bytes_left)
852 return error.SequenceBufferTooSmall;
853
854 decode_state.readInitialFseState(&bit_stream) catch
855 return error.MalformedCompressedBlock;
856
857 var sequence_size_limit = block_size_max;
858 for (0..sequences_header.sequence_count) |i| {
859 const decompressed_size = decode_state.decodeSequenceRingBuffer(
860 dest,
861 &bit_stream,
862 sequence_size_limit,
863 i == sequences_header.sequence_count - 1,
864 ) catch return error.MalformedCompressedBlock;
865 sequence_size_limit -= decompressed_size;
866 bytes_written += decompressed_size;
867 }
868 }
869
870 if (!bit_stream.isEmpty()) {
871 return error.MalformedCompressedBlock;
872 }
873 }
874
875 if (decode_state.literal_written_count < literals.header.regenerated_size) {
876 const len = literals.header.regenerated_size - decode_state.literal_written_count;
877 decode_state.decodeLiteralsRingBuffer(dest, len) catch
878 return error.MalformedCompressedBlock;
879 bytes_written += len;
880 }
881
882 switch (decode_state.literal_header.block_type) {
883 .treeless, .compressed => {
884 if (!decode_state.isLiteralStreamEmpty()) return error.MalformedCompressedBlock;
885 },
886 .raw, .rle => {},
887 }
888
889 if (bytes_written > block_size_max) return error.BlockSizeOverMaximum;
890 if (block_reader_limited.bytes_left != 0) return error.MalformedCompressedBlock;
891 decode_state.literal_written_count = 0;
892 },
893 .reserved => return error.ReservedBlock,
894 }
895}
896
897/// Decode the header of a block.
898pub fn decodeBlockHeader(src: *const [3]u8) frame.Zstandard.Block.Header {
899 const last_block = src[0] & 1 == 1;
900 const block_type = @intToEnum(frame.Zstandard.Block.Type, (src[0] & 0b110) >> 1);
901 const block_size = ((src[0] & 0b11111000) >> 3) + (@as(u21, src[1]) << 5) + (@as(u21, src[2]) << 13);
902 return .{
903 .last_block = last_block,
904 .block_type = block_type,
905 .block_size = block_size,
906 };
907}
908
909/// Decode the header of a block.
910///
911/// Errors returned:
912/// - `error.EndOfStream` if `src.len < 3`
913pub fn decodeBlockHeaderSlice(src: []const u8) error{EndOfStream}!frame.Zstandard.Block.Header {
914 if (src.len < 3) return error.EndOfStream;
915 return decodeBlockHeader(src[0..3]);
916}
917
918/// Decode a `LiteralsSection` from `src`, incrementing `consumed_count` by the
919/// number of bytes the section uses.
920///
921/// Errors returned:
922/// - `error.MalformedLiteralsHeader` if the header is invalid
923/// - `error.MalformedLiteralsSection` if there are decoding errors
924/// - `error.MalformedAccuracyLog` if compressed literals have invalid
925/// accuracy
926/// - `error.MalformedFseTable` if compressed literals have invalid FSE table
927/// - `error.MalformedHuffmanTree` if there are errors decoding a Huffamn tree
928/// - `error.EndOfStream` if there are not enough bytes in `src`
929pub fn decodeLiteralsSectionSlice(
930 src: []const u8,
931 consumed_count: *usize,
932) (error{ MalformedLiteralsHeader, MalformedLiteralsSection, EndOfStream } || huffman.Error)!LiteralsSection {
933 var bytes_read: usize = 0;
934 const header = header: {
935 var fbs = std.io.fixedBufferStream(src);
936 defer bytes_read = fbs.pos;
937 break :header decodeLiteralsHeader(fbs.reader()) catch return error.MalformedLiteralsHeader;
938 };
939 switch (header.block_type) {
940 .raw => {
941 if (src.len < bytes_read + header.regenerated_size) return error.MalformedLiteralsSection;
942 const stream = src[bytes_read .. bytes_read + header.regenerated_size];
943 consumed_count.* += header.regenerated_size + bytes_read;
944 return LiteralsSection{
945 .header = header,
946 .huffman_tree = null,
947 .streams = .{ .one = stream },
948 };
949 },
950 .rle => {
951 if (src.len < bytes_read + 1) return error.MalformedLiteralsSection;
952 const stream = src[bytes_read .. bytes_read + 1];
953 consumed_count.* += 1 + bytes_read;
954 return LiteralsSection{
955 .header = header,
956 .huffman_tree = null,
957 .streams = .{ .one = stream },
958 };
959 },
960 .compressed, .treeless => {
961 const huffman_tree_start = bytes_read;
962 const huffman_tree = if (header.block_type == .compressed)
963 try huffman.decodeHuffmanTreeSlice(src[bytes_read..], &bytes_read)
964 else
965 null;
966 const huffman_tree_size = bytes_read - huffman_tree_start;
967 const total_streams_size = std.math.sub(usize, header.compressed_size.?, huffman_tree_size) catch
968 return error.MalformedLiteralsSection;
969
970 if (src.len < bytes_read + total_streams_size) return error.MalformedLiteralsSection;
971 const stream_data = src[bytes_read .. bytes_read + total_streams_size];
972
973 const streams = try decodeStreams(header.size_format, stream_data);
974 consumed_count.* += bytes_read + total_streams_size;
975 return LiteralsSection{
976 .header = header,
977 .huffman_tree = huffman_tree,
978 .streams = streams,
979 };
980 },
981 }
982}
983
984/// Decode a `LiteralsSection` from `src`, incrementing `consumed_count` by the
985/// number of bytes the section uses. See `decodeLiterasSectionSlice()`.
986pub fn decodeLiteralsSection(
987 source: anytype,
988 buffer: []u8,
989) !LiteralsSection {
990 const header = try decodeLiteralsHeader(source);
991 switch (header.block_type) {
992 .raw => {
993 try source.readNoEof(buffer[0..header.regenerated_size]);
994 return LiteralsSection{
995 .header = header,
996 .huffman_tree = null,
997 .streams = .{ .one = buffer },
998 };
999 },
1000 .rle => {
1001 buffer[0] = try source.readByte();
1002 return LiteralsSection{
1003 .header = header,
1004 .huffman_tree = null,
1005 .streams = .{ .one = buffer[0..1] },
1006 };
1007 },
1008 .compressed, .treeless => {
1009 var counting_reader = std.io.countingReader(source);
1010 const huffman_tree = if (header.block_type == .compressed)
1011 try huffman.decodeHuffmanTree(counting_reader.reader(), buffer)
1012 else
1013 null;
1014 const huffman_tree_size = @intCast(usize, counting_reader.bytes_read);
1015 const total_streams_size = std.math.sub(usize, header.compressed_size.?, huffman_tree_size) catch
1016 return error.MalformedLiteralsSection;
1017
1018 if (total_streams_size > buffer.len) return error.LiteralsBufferTooSmall;
1019 try source.readNoEof(buffer[0..total_streams_size]);
1020 const stream_data = buffer[0..total_streams_size];
1021
1022 const streams = try decodeStreams(header.size_format, stream_data);
1023 return LiteralsSection{
1024 .header = header,
1025 .huffman_tree = huffman_tree,
1026 .streams = streams,
1027 };
1028 },
1029 }
1030}
1031
1032fn decodeStreams(size_format: u2, stream_data: []const u8) !LiteralsSection.Streams {
1033 if (size_format == 0) {
1034 return .{ .one = stream_data };
1035 }
1036
1037 if (stream_data.len < 6) return error.MalformedLiteralsSection;
1038
1039 const stream_1_length = @as(usize, readInt(u16, stream_data[0..2]));
1040 const stream_2_length = @as(usize, readInt(u16, stream_data[2..4]));
1041 const stream_3_length = @as(usize, readInt(u16, stream_data[4..6]));
1042
1043 const stream_1_start = 6;
1044 const stream_2_start = stream_1_start + stream_1_length;
1045 const stream_3_start = stream_2_start + stream_2_length;
1046 const stream_4_start = stream_3_start + stream_3_length;
1047
1048 if (stream_data.len < stream_4_start) return error.MalformedLiteralsSection;
1049
1050 return .{ .four = .{
1051 stream_data[stream_1_start .. stream_1_start + stream_1_length],
1052 stream_data[stream_2_start .. stream_2_start + stream_2_length],
1053 stream_data[stream_3_start .. stream_3_start + stream_3_length],
1054 stream_data[stream_4_start..],
1055 } };
1056}
1057
1058/// Decode a literals section header.
1059///
1060/// Errors returned:
1061/// - `error.EndOfStream` if there are not enough bytes in `source`
1062pub fn decodeLiteralsHeader(source: anytype) !LiteralsSection.Header {
1063 const byte0 = try source.readByte();
1064 const block_type = @intToEnum(LiteralsSection.BlockType, byte0 & 0b11);
1065 const size_format = @intCast(u2, (byte0 & 0b1100) >> 2);
1066 var regenerated_size: u20 = undefined;
1067 var compressed_size: ?u18 = null;
1068 switch (block_type) {
1069 .raw, .rle => {
1070 switch (size_format) {
1071 0, 2 => {
1072 regenerated_size = byte0 >> 3;
1073 },
1074 1 => regenerated_size = (byte0 >> 4) + (@as(u20, try source.readByte()) << 4),
1075 3 => regenerated_size = (byte0 >> 4) +
1076 (@as(u20, try source.readByte()) << 4) +
1077 (@as(u20, try source.readByte()) << 12),
1078 }
1079 },
1080 .compressed, .treeless => {
1081 const byte1 = try source.readByte();
1082 const byte2 = try source.readByte();
1083 switch (size_format) {
1084 0, 1 => {
1085 regenerated_size = (byte0 >> 4) + ((@as(u20, byte1) & 0b00111111) << 4);
1086 compressed_size = ((byte1 & 0b11000000) >> 6) + (@as(u18, byte2) << 2);
1087 },
1088 2 => {
1089 const byte3 = try source.readByte();
1090 regenerated_size = (byte0 >> 4) + (@as(u20, byte1) << 4) + ((@as(u20, byte2) & 0b00000011) << 12);
1091 compressed_size = ((byte2 & 0b11111100) >> 2) + (@as(u18, byte3) << 6);
1092 },
1093 3 => {
1094 const byte3 = try source.readByte();
1095 const byte4 = try source.readByte();
1096 regenerated_size = (byte0 >> 4) + (@as(u20, byte1) << 4) + ((@as(u20, byte2) & 0b00111111) << 12);
1097 compressed_size = ((byte2 & 0b11000000) >> 6) + (@as(u18, byte3) << 2) + (@as(u18, byte4) << 10);
1098 },
1099 }
1100 },
1101 }
1102 return LiteralsSection.Header{
1103 .block_type = block_type,
1104 .size_format = size_format,
1105 .regenerated_size = regenerated_size,
1106 .compressed_size = compressed_size,
1107 };
1108}
1109
1110/// Decode a sequences section header.
1111///
1112/// Errors returned:
1113/// - `error.ReservedBitSet` if the reserved bit is set
1114/// - `error.EndOfStream` if there are not enough bytes in `source`
1115pub fn decodeSequencesHeader(
1116 source: anytype,
1117) !SequencesSection.Header {
1118 var sequence_count: u24 = undefined;
1119
1120 const byte0 = try source.readByte();
1121 if (byte0 == 0) {
1122 return SequencesSection.Header{
1123 .sequence_count = 0,
1124 .offsets = undefined,
1125 .match_lengths = undefined,
1126 .literal_lengths = undefined,
1127 };
1128 } else if (byte0 < 128) {
1129 sequence_count = byte0;
1130 } else if (byte0 < 255) {
1131 sequence_count = (@as(u24, (byte0 - 128)) << 8) + try source.readByte();
1132 } else {
1133 sequence_count = (try source.readByte()) + (@as(u24, try source.readByte()) << 8) + 0x7F00;
1134 }
1135
1136 const compression_modes = try source.readByte();
1137
1138 const matches_mode = @intToEnum(SequencesSection.Header.Mode, (compression_modes & 0b00001100) >> 2);
1139 const offsets_mode = @intToEnum(SequencesSection.Header.Mode, (compression_modes & 0b00110000) >> 4);
1140 const literal_mode = @intToEnum(SequencesSection.Header.Mode, (compression_modes & 0b11000000) >> 6);
1141 if (compression_modes & 0b11 != 0) return error.ReservedBitSet;
1142
1143 return SequencesSection.Header{
1144 .sequence_count = sequence_count,
1145 .offsets = offsets_mode,
1146 .match_lengths = matches_mode,
1147 .literal_lengths = literal_mode,
1148 };
1149}
lib/std/compress/zstandard/decode/fse.zig created+153
...@@ -0,0 +1,153 @@
1const std = @import("std");
2const assert = std.debug.assert;
3
4const types = @import("../types.zig");
5const Table = types.compressed_block.Table;
6
7pub fn decodeFseTable(
8 bit_reader: anytype,
9 expected_symbol_count: usize,
10 max_accuracy_log: u4,
11 entries: []Table.Fse,
12) !usize {
13 const accuracy_log_biased = try bit_reader.readBitsNoEof(u4, 4);
14 if (accuracy_log_biased > max_accuracy_log -| 5) return error.MalformedAccuracyLog;
15 const accuracy_log = accuracy_log_biased + 5;
16
17 var values: [256]u16 = undefined;
18 var value_count: usize = 0;
19
20 const total_probability = @as(u16, 1) << accuracy_log;
21 var accumulated_probability: u16 = 0;
22
23 while (accumulated_probability < total_probability) {
24 // WARNING: The RFC in poorly worded, and would suggest std.math.log2_int_ceil is correct here,
25 // but power of two (remaining probabilities + 1) need max bits set to 1 more.
26 const max_bits = std.math.log2_int(u16, total_probability - accumulated_probability + 1) + 1;
27 const small = try bit_reader.readBitsNoEof(u16, max_bits - 1);
28
29 const cutoff = (@as(u16, 1) << max_bits) - 1 - (total_probability - accumulated_probability + 1);
30
31 const value = if (small < cutoff)
32 small
33 else value: {
34 const value_read = small + (try bit_reader.readBitsNoEof(u16, 1) << (max_bits - 1));
35 break :value if (value_read < @as(u16, 1) << (max_bits - 1))
36 value_read
37 else
38 value_read - cutoff;
39 };
40
41 accumulated_probability += if (value != 0) value - 1 else 1;
42
43 values[value_count] = value;
44 value_count += 1;
45
46 if (value == 1) {
47 while (true) {
48 const repeat_flag = try bit_reader.readBitsNoEof(u2, 2);
49 if (repeat_flag + value_count > 256) return error.MalformedFseTable;
50 for (0..repeat_flag) |_| {
51 values[value_count] = 1;
52 value_count += 1;
53 }
54 if (repeat_flag < 3) break;
55 }
56 }
57 if (value_count == 256) break;
58 }
59 bit_reader.alignToByte();
60
61 if (value_count < 2) return error.MalformedFseTable;
62 if (accumulated_probability != total_probability) return error.MalformedFseTable;
63 if (value_count > expected_symbol_count) return error.MalformedFseTable;
64
65 const table_size = total_probability;
66
67 try buildFseTable(values[0..value_count], entries[0..table_size]);
68 return table_size;
69}
70
71fn buildFseTable(values: []const u16, entries: []Table.Fse) !void {
72 const total_probability = @intCast(u16, entries.len);
73 const accuracy_log = std.math.log2_int(u16, total_probability);
74 assert(total_probability <= 1 << 9);
75
76 var less_than_one_count: usize = 0;
77 for (values, 0..) |value, i| {
78 if (value == 0) {
79 entries[entries.len - 1 - less_than_one_count] = Table.Fse{
80 .symbol = @intCast(u8, i),
81 .baseline = 0,
82 .bits = accuracy_log,
83 };
84 less_than_one_count += 1;
85 }
86 }
87
88 var position: usize = 0;
89 var temp_states: [1 << 9]u16 = undefined;
90 for (values, 0..) |value, symbol| {
91 if (value == 0 or value == 1) continue;
92 const probability = value - 1;
93
94 const state_share_dividend = std.math.ceilPowerOfTwo(u16, probability) catch
95 return error.MalformedFseTable;
96 const share_size = @divExact(total_probability, state_share_dividend);
97 const double_state_count = state_share_dividend - probability;
98 const single_state_count = probability - double_state_count;
99 const share_size_log = std.math.log2_int(u16, share_size);
100
101 for (0..probability) |i| {
102 temp_states[i] = @intCast(u16, position);
103 position += (entries.len >> 1) + (entries.len >> 3) + 3;
104 position &= entries.len - 1;
105 while (position >= entries.len - less_than_one_count) {
106 position += (entries.len >> 1) + (entries.len >> 3) + 3;
107 position &= entries.len - 1;
108 }
109 }
110 std.sort.sort(u16, temp_states[0..probability], {}, std.sort.asc(u16));
111 for (0..probability) |i| {
112 entries[temp_states[i]] = if (i < double_state_count) Table.Fse{
113 .symbol = @intCast(u8, symbol),
114 .bits = share_size_log + 1,
115 .baseline = single_state_count * share_size + @intCast(u16, i) * 2 * share_size,
116 } else Table.Fse{
117 .symbol = @intCast(u8, symbol),
118 .bits = share_size_log,
119 .baseline = (@intCast(u16, i) - double_state_count) * share_size,
120 };
121 }
122 }
123}
124
125test buildFseTable {
126 const literals_length_default_values = [36]u16{
127 5, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2,
128 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 2, 2, 2, 2, 2,
129 0, 0, 0, 0,
130 };
131
132 const match_lengths_default_values = [53]u16{
133 2, 5, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2,
134 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
135 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0,
136 0, 0, 0, 0, 0,
137 };
138
139 const offset_codes_default_values = [29]u16{
140 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2,
141 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0,
142 };
143
144 var entries: [64]Table.Fse = undefined;
145 try buildFseTable(&literals_length_default_values, &entries);
146 try std.testing.expectEqualSlices(Table.Fse, types.compressed_block.predefined_literal_fse_table.fse, &entries);
147
148 try buildFseTable(&match_lengths_default_values, &entries);
149 try std.testing.expectEqualSlices(Table.Fse, types.compressed_block.predefined_match_fse_table.fse, &entries);
150
151 try buildFseTable(&offset_codes_default_values, entries[0..32]);
152 try std.testing.expectEqualSlices(Table.Fse, types.compressed_block.predefined_offset_fse_table.fse, entries[0..32]);
153}
lib/std/compress/zstandard/decode/huffman.zig created+234
...@@ -0,0 +1,234 @@
1const std = @import("std");
2
3const types = @import("../types.zig");
4const LiteralsSection = types.compressed_block.LiteralsSection;
5const Table = types.compressed_block.Table;
6
7const readers = @import("../readers.zig");
8
9const decodeFseTable = @import("fse.zig").decodeFseTable;
10
11pub const Error = error{
12 MalformedHuffmanTree,
13 MalformedFseTable,
14 MalformedAccuracyLog,
15 EndOfStream,
16};
17
18fn decodeFseHuffmanTree(
19 source: anytype,
20 compressed_size: usize,
21 buffer: []u8,
22 weights: *[256]u4,
23) !usize {
24 var stream = std.io.limitedReader(source, compressed_size);
25 var bit_reader = readers.bitReader(stream.reader());
26
27 var entries: [1 << 6]Table.Fse = undefined;
28 const table_size = decodeFseTable(&bit_reader, 256, 6, &entries) catch |err| switch (err) {
29 error.MalformedAccuracyLog, error.MalformedFseTable => |e| return e,
30 error.EndOfStream => return error.MalformedFseTable,
31 else => |e| return e,
32 };
33 const accuracy_log = std.math.log2_int_ceil(usize, table_size);
34
35 const amount = try stream.reader().readAll(buffer);
36 var huff_bits: readers.ReverseBitReader = undefined;
37 huff_bits.init(buffer[0..amount]) catch return error.MalformedHuffmanTree;
38
39 return assignWeights(&huff_bits, accuracy_log, &entries, weights);
40}
41
42fn decodeFseHuffmanTreeSlice(src: []const u8, compressed_size: usize, weights: *[256]u4) !usize {
43 if (src.len < compressed_size) return error.MalformedHuffmanTree;
44 var stream = std.io.fixedBufferStream(src[0..compressed_size]);
45 var counting_reader = std.io.countingReader(stream.reader());
46 var bit_reader = readers.bitReader(counting_reader.reader());
47
48 var entries: [1 << 6]Table.Fse = undefined;
49 const table_size = decodeFseTable(&bit_reader, 256, 6, &entries) catch |err| switch (err) {
50 error.MalformedAccuracyLog, error.MalformedFseTable => |e| return e,
51 error.EndOfStream => return error.MalformedFseTable,
52 };
53 const accuracy_log = std.math.log2_int_ceil(usize, table_size);
54
55 const start_index = std.math.cast(usize, counting_reader.bytes_read) orelse
56 return error.MalformedHuffmanTree;
57 var huff_data = src[start_index..compressed_size];
58 var huff_bits: readers.ReverseBitReader = undefined;
59 huff_bits.init(huff_data) catch return error.MalformedHuffmanTree;
60
61 return assignWeights(&huff_bits, accuracy_log, &entries, weights);
62}
63
64fn assignWeights(
65 huff_bits: *readers.ReverseBitReader,
66 accuracy_log: usize,
67 entries: *[1 << 6]Table.Fse,
68 weights: *[256]u4,
69) !usize {
70 var i: usize = 0;
71 var even_state: u32 = huff_bits.readBitsNoEof(u32, accuracy_log) catch return error.MalformedHuffmanTree;
72 var odd_state: u32 = huff_bits.readBitsNoEof(u32, accuracy_log) catch return error.MalformedHuffmanTree;
73
74 while (i < 254) {
75 const even_data = entries[even_state];
76 var read_bits: usize = 0;
77 const even_bits = huff_bits.readBits(u32, even_data.bits, &read_bits) catch unreachable;
78 weights[i] = std.math.cast(u4, even_data.symbol) orelse return error.MalformedHuffmanTree;
79 i += 1;
80 if (read_bits < even_data.bits) {
81 weights[i] = std.math.cast(u4, entries[odd_state].symbol) orelse return error.MalformedHuffmanTree;
82 i += 1;
83 break;
84 }
85 even_state = even_data.baseline + even_bits;
86
87 read_bits = 0;
88 const odd_data = entries[odd_state];
89 const odd_bits = huff_bits.readBits(u32, odd_data.bits, &read_bits) catch unreachable;
90 weights[i] = std.math.cast(u4, odd_data.symbol) orelse return error.MalformedHuffmanTree;
91 i += 1;
92 if (read_bits < odd_data.bits) {
93 if (i == 255) return error.MalformedHuffmanTree;
94 weights[i] = std.math.cast(u4, entries[even_state].symbol) orelse return error.MalformedHuffmanTree;
95 i += 1;
96 break;
97 }
98 odd_state = odd_data.baseline + odd_bits;
99 } else return error.MalformedHuffmanTree;
100
101 if (!huff_bits.isEmpty()) {
102 return error.MalformedHuffmanTree;
103 }
104
105 return i + 1; // stream contains all but the last symbol
106}
107
108fn decodeDirectHuffmanTree(source: anytype, encoded_symbol_count: usize, weights: *[256]u4) !usize {
109 const weights_byte_count = (encoded_symbol_count + 1) / 2;
110 for (0..weights_byte_count) |i| {
111 const byte = try source.readByte();
112 weights[2 * i] = @intCast(u4, byte >> 4);
113 weights[2 * i + 1] = @intCast(u4, byte & 0xF);
114 }
115 return encoded_symbol_count + 1;
116}
117
118fn assignSymbols(weight_sorted_prefixed_symbols: []LiteralsSection.HuffmanTree.PrefixedSymbol, weights: [256]u4) usize {
119 for (0..weight_sorted_prefixed_symbols.len) |i| {
120 weight_sorted_prefixed_symbols[i] = .{
121 .symbol = @intCast(u8, i),
122 .weight = undefined,
123 .prefix = undefined,
124 };
125 }
126
127 std.sort.sort(
128 LiteralsSection.HuffmanTree.PrefixedSymbol,
129 weight_sorted_prefixed_symbols,
130 weights,
131 lessThanByWeight,
132 );
133
134 var prefix: u16 = 0;
135 var prefixed_symbol_count: usize = 0;
136 var sorted_index: usize = 0;
137 const symbol_count = weight_sorted_prefixed_symbols.len;
138 while (sorted_index < symbol_count) {
139 var symbol = weight_sorted_prefixed_symbols[sorted_index].symbol;
140 const weight = weights[symbol];
141 if (weight == 0) {
142 sorted_index += 1;
143 continue;
144 }
145
146 while (sorted_index < symbol_count) : ({
147 sorted_index += 1;
148 prefixed_symbol_count += 1;
149 prefix += 1;
150 }) {
151 symbol = weight_sorted_prefixed_symbols[sorted_index].symbol;
152 if (weights[symbol] != weight) {
153 prefix = ((prefix - 1) >> (weights[symbol] - weight)) + 1;
154 break;
155 }
156 weight_sorted_prefixed_symbols[prefixed_symbol_count].symbol = symbol;
157 weight_sorted_prefixed_symbols[prefixed_symbol_count].prefix = prefix;
158 weight_sorted_prefixed_symbols[prefixed_symbol_count].weight = weight;
159 }
160 }
161 return prefixed_symbol_count;
162}
163
164fn buildHuffmanTree(weights: *[256]u4, symbol_count: usize) error{MalformedHuffmanTree}!LiteralsSection.HuffmanTree {
165 var weight_power_sum_big: u32 = 0;
166 for (weights[0 .. symbol_count - 1]) |value| {
167 weight_power_sum_big += (@as(u16, 1) << value) >> 1;
168 }
169 if (weight_power_sum_big >= 1 << 11) return error.MalformedHuffmanTree;
170 const weight_power_sum = @intCast(u16, weight_power_sum_big);
171
172 // advance to next power of two (even if weight_power_sum is a power of 2)
173 // TODO: is it valid to have weight_power_sum == 0?
174 const max_number_of_bits = if (weight_power_sum == 0) 1 else std.math.log2_int(u16, weight_power_sum) + 1;
175 const next_power_of_two = @as(u16, 1) << max_number_of_bits;
176 weights[symbol_count - 1] = std.math.log2_int(u16, next_power_of_two - weight_power_sum) + 1;
177
178 var weight_sorted_prefixed_symbols: [256]LiteralsSection.HuffmanTree.PrefixedSymbol = undefined;
179 const prefixed_symbol_count = assignSymbols(weight_sorted_prefixed_symbols[0..symbol_count], weights.*);
180 const tree = LiteralsSection.HuffmanTree{
181 .max_bit_count = max_number_of_bits,
182 .symbol_count_minus_one = @intCast(u8, prefixed_symbol_count - 1),
183 .nodes = weight_sorted_prefixed_symbols,
184 };
185 return tree;
186}
187
188pub fn decodeHuffmanTree(
189 source: anytype,
190 buffer: []u8,
191) (@TypeOf(source).Error || Error)!LiteralsSection.HuffmanTree {
192 const header = try source.readByte();
193 var weights: [256]u4 = undefined;
194 const symbol_count = if (header < 128)
195 // FSE compressed weights
196 try decodeFseHuffmanTree(source, header, buffer, &weights)
197 else
198 try decodeDirectHuffmanTree(source, header - 127, &weights);
199
200 return buildHuffmanTree(&weights, symbol_count);
201}
202
203pub fn decodeHuffmanTreeSlice(
204 src: []const u8,
205 consumed_count: *usize,
206) Error!LiteralsSection.HuffmanTree {
207 if (src.len == 0) return error.MalformedHuffmanTree;
208 const header = src[0];
209 var bytes_read: usize = 1;
210 var weights: [256]u4 = undefined;
211 const symbol_count = if (header < 128) count: {
212 // FSE compressed weights
213 bytes_read += header;
214 break :count try decodeFseHuffmanTreeSlice(src[1..], header, &weights);
215 } else count: {
216 var fbs = std.io.fixedBufferStream(src[1..]);
217 defer bytes_read += fbs.pos;
218 break :count try decodeDirectHuffmanTree(fbs.reader(), header - 127, &weights);
219 };
220
221 consumed_count.* += bytes_read;
222 return buildHuffmanTree(&weights, symbol_count);
223}
224
225fn lessThanByWeight(
226 weights: [256]u4,
227 lhs: LiteralsSection.HuffmanTree.PrefixedSymbol,
228 rhs: LiteralsSection.HuffmanTree.PrefixedSymbol,
229) bool {
230 // NOTE: this function relies on the use of a stable sorting algorithm,
231 // otherwise a special case of if (weights[lhs] == weights[rhs]) return lhs < rhs;
232 // should be added
233 return weights[lhs.symbol] < weights[rhs.symbol];
234}
lib/std/compress/zstandard/decompress.zig created+636
...@@ -0,0 +1,636 @@
1const std = @import("std");
2const assert = std.debug.assert;
3const Allocator = std.mem.Allocator;
4const RingBuffer = std.RingBuffer;
5
6const types = @import("types.zig");
7const frame = types.frame;
8const LiteralsSection = types.compressed_block.LiteralsSection;
9const SequencesSection = types.compressed_block.SequencesSection;
10const SkippableHeader = types.frame.Skippable.Header;
11const ZstandardHeader = types.frame.Zstandard.Header;
12const Table = types.compressed_block.Table;
13
14pub const block = @import("decode/block.zig");
15
16const readers = @import("readers.zig");
17
18const readInt = std.mem.readIntLittle;
19const readIntSlice = std.mem.readIntSliceLittle;
20
21/// Returns `true` is `magic` is a valid magic number for a skippable frame
22pub fn isSkippableMagic(magic: u32) bool {
23 return frame.Skippable.magic_number_min <= magic and magic <= frame.Skippable.magic_number_max;
24}
25
26/// Returns the kind of frame at the beginning of `source`.
27///
28/// Errors returned:
29/// - `error.BadMagic` if `source` begins with bytes not equal to the
30/// Zstandard frame magic number, or outside the range of magic numbers for
31/// skippable frames.
32/// - `error.EndOfStream` if `source` contains fewer than 4 bytes
33pub fn decodeFrameType(source: anytype) error{ BadMagic, EndOfStream }!frame.Kind {
34 const magic = try source.readIntLittle(u32);
35 return frameType(magic);
36}
37
38/// Returns the kind of frame associated to `magic`.
39///
40/// Errors returned:
41/// - `error.BadMagic` if `magic` is not a valid magic number.
42pub fn frameType(magic: u32) error{BadMagic}!frame.Kind {
43 return if (magic == frame.Zstandard.magic_number)
44 .zstandard
45 else if (isSkippableMagic(magic))
46 .skippable
47 else
48 error.BadMagic;
49}
50
51pub const FrameHeader = union(enum) {
52 zstandard: ZstandardHeader,
53 skippable: SkippableHeader,
54};
55
56pub const HeaderError = error{ BadMagic, EndOfStream, ReservedBitSet };
57
58/// Returns the header of the frame at the beginning of `source`.
59///
60/// Errors returned:
61/// - `error.BadMagic` if `source` begins with bytes not equal to the
62/// Zstandard frame magic number, or outside the range of magic numbers for
63/// skippable frames.
64/// - `error.EndOfStream` if `source` contains fewer than 4 bytes
65/// - `error.ReservedBitSet` if the frame is a Zstandard frame and any of the
66/// reserved bits are set
67pub fn decodeFrameHeader(source: anytype) (@TypeOf(source).Error || HeaderError)!FrameHeader {
68 const magic = try source.readIntLittle(u32);
69 const frame_type = try frameType(magic);
70 switch (frame_type) {
71 .zstandard => return FrameHeader{ .zstandard = try decodeZstandardHeader(source) },
72 .skippable => return FrameHeader{
73 .skippable = .{
74 .magic_number = magic,
75 .frame_size = try source.readIntLittle(u32),
76 },
77 },
78 }
79}
80
81pub const ReadWriteCount = struct {
82 read_count: usize,
83 write_count: usize,
84};
85
86/// Decodes frames from `src` into `dest`; returns the length of the result.
87/// The stream should not have extra trailing bytes - either all bytes in `src`
88/// will be decoded, or an error will be returned. An error will be returned if
89/// a Zstandard frame in `src` does not declare its content size.
90///
91/// Errors returned:
92/// - `error.DictionaryIdFlagUnsupported` if a `src` contains a frame that
93/// uses a dictionary
94/// - `error.MalformedFrame` if a frame in `src` is invalid
95/// - `error.UnknownContentSizeUnsupported` if a frame in `src` does not
96/// declare its content size
97pub fn decode(dest: []u8, src: []const u8, verify_checksum: bool) error{
98 MalformedFrame,
99 UnknownContentSizeUnsupported,
100 DictionaryIdFlagUnsupported,
101}!usize {
102 var write_count: usize = 0;
103 var read_count: usize = 0;
104 while (read_count < src.len) {
105 const counts = decodeFrame(dest, src[read_count..], verify_checksum) catch |err| {
106 switch (err) {
107 error.UnknownContentSizeUnsupported => return error.UnknownContentSizeUnsupported,
108 error.DictionaryIdFlagUnsupported => return error.DictionaryIdFlagUnsupported,
109 else => return error.MalformedFrame,
110 }
111 };
112 read_count += counts.read_count;
113 write_count += counts.write_count;
114 }
115 return write_count;
116}
117
118/// Decodes a stream of frames from `src`; returns the decoded bytes. The stream
119/// should not have extra trailing bytes - either all bytes in `src` will be
120/// decoded, or an error will be returned.
121///
122/// Errors returned:
123/// - `error.DictionaryIdFlagUnsupported` if a `src` contains a frame that
124/// uses a dictionary
125/// - `error.MalformedFrame` if a frame in `src` is invalid
126/// - `error.OutOfMemory` if `allocator` cannot allocate enough memory
127pub fn decodeAlloc(
128 allocator: Allocator,
129 src: []const u8,
130 verify_checksum: bool,
131 window_size_max: usize,
132) error{ DictionaryIdFlagUnsupported, MalformedFrame, OutOfMemory }![]u8 {
133 var result = std.ArrayList(u8).init(allocator);
134 errdefer result.deinit();
135
136 var read_count: usize = 0;
137 while (read_count < src.len) {
138 read_count += decodeFrameArrayList(
139 allocator,
140 &result,
141 src[read_count..],
142 verify_checksum,
143 window_size_max,
144 ) catch |err| switch (err) {
145 error.OutOfMemory => return error.OutOfMemory,
146 error.DictionaryIdFlagUnsupported => return error.DictionaryIdFlagUnsupported,
147 else => return error.MalformedFrame,
148 };
149 }
150 return result.toOwnedSlice();
151}
152
153/// Decodes the frame at the start of `src` into `dest`. Returns the number of
154/// bytes read from `src` and written to `dest`. This function can only decode
155/// frames that declare the decompressed content size.
156///
157/// Errors returned:
158/// - `error.BadMagic` if the first 4 bytes of `src` is not a valid magic
159/// number for a Zstandard or skippable frame
160/// - `error.UnknownContentSizeUnsupported` if the frame does not declare the
161/// uncompressed content size
162/// - `error.WindowSizeUnknown` if the frame does not have a valid window size
163/// - `error.ContentTooLarge` if `dest` is smaller than the uncompressed data
164/// size declared by the frame header
165/// - `error.ContentSizeTooLarge` if the frame header indicates a content size
166/// that is larger than `std.math.maxInt(usize)`
167/// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary
168/// - `error.ChecksumFailure` if `verify_checksum` is true and the frame
169/// contains a checksum that does not match the checksum of the decompressed
170/// data
171/// - `error.ReservedBitSet` if any of the reserved bits of the frame header
172/// are set
173/// - `error.EndOfStream` if `src` does not contain a complete frame
174/// - `error.BadContentSize` if the content size declared by the frame does
175/// not equal the actual size of decompressed data
176/// - an error in `block.Error` if there are errors decoding a block
177/// - `error.SkippableSizeTooLarge` if the frame is skippable and reports a
178/// size greater than `src.len`
179pub fn decodeFrame(
180 dest: []u8,
181 src: []const u8,
182 verify_checksum: bool,
183) (error{
184 BadMagic,
185 UnknownContentSizeUnsupported,
186 ContentTooLarge,
187 ContentSizeTooLarge,
188 WindowSizeUnknown,
189 DictionaryIdFlagUnsupported,
190 SkippableSizeTooLarge,
191} || FrameError)!ReadWriteCount {
192 var fbs = std.io.fixedBufferStream(src);
193 switch (try decodeFrameType(fbs.reader())) {
194 .zstandard => return decodeZstandardFrame(dest, src, verify_checksum),
195 .skippable => {
196 const content_size = try fbs.reader().readIntLittle(u32);
197 if (content_size > std.math.maxInt(usize) - 8) return error.SkippableSizeTooLarge;
198 const read_count = @as(usize, content_size) + 8;
199 if (read_count > src.len) return error.SkippableSizeTooLarge;
200 return ReadWriteCount{
201 .read_count = read_count,
202 .write_count = 0,
203 };
204 },
205 }
206}
207
208/// Decodes the frame at the start of `src` into `dest`. Returns the number of
209/// bytes read from `src`.
210///
211/// Errors returned:
212/// - `error.BadMagic` if the first 4 bytes of `src` is not a valid magic
213/// number for a Zstandard or skippable frame
214/// - `error.WindowSizeUnknown` if the frame does not have a valid window size
215/// - `error.WindowTooLarge` if the window size is larger than
216/// `window_size_max`
217/// - `error.ContentSizeTooLarge` if the frame header indicates a content size
218/// that is larger than `std.math.maxInt(usize)`
219/// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary
220/// - `error.ChecksumFailure` if `verify_checksum` is true and the frame
221/// contains a checksum that does not match the checksum of the decompressed
222/// data
223/// - `error.ReservedBitSet` if any of the reserved bits of the frame header
224/// are set
225/// - `error.EndOfStream` if `src` does not contain a complete frame
226/// - `error.BadContentSize` if the content size declared by the frame does
227/// not equal the actual size of decompressed data
228/// - `error.OutOfMemory` if `allocator` cannot allocate enough memory
229/// - an error in `block.Error` if there are errors decoding a block
230/// - `error.SkippableSizeTooLarge` if the frame is skippable and reports a
231/// size greater than `src.len`
232pub fn decodeFrameArrayList(
233 allocator: Allocator,
234 dest: *std.ArrayList(u8),
235 src: []const u8,
236 verify_checksum: bool,
237 window_size_max: usize,
238) (error{ BadMagic, OutOfMemory, SkippableSizeTooLarge } || FrameContext.Error || FrameError)!usize {
239 var fbs = std.io.fixedBufferStream(src);
240 const reader = fbs.reader();
241 const magic = try reader.readIntLittle(u32);
242 switch (try frameType(magic)) {
243 .zstandard => return decodeZstandardFrameArrayList(
244 allocator,
245 dest,
246 src,
247 verify_checksum,
248 window_size_max,
249 ),
250 .skippable => {
251 const content_size = try fbs.reader().readIntLittle(u32);
252 if (content_size > std.math.maxInt(usize) - 8) return error.SkippableSizeTooLarge;
253 const read_count = @as(usize, content_size) + 8;
254 if (read_count > src.len) return error.SkippableSizeTooLarge;
255 return read_count;
256 },
257 }
258}
259
260/// Returns the frame checksum corresponding to the data fed into `hasher`
261pub fn computeChecksum(hasher: *std.hash.XxHash64) u32 {
262 const hash = hasher.final();
263 return @intCast(u32, hash & 0xFFFFFFFF);
264}
265
266const FrameError = error{
267 ChecksumFailure,
268 BadContentSize,
269 EndOfStream,
270 ReservedBitSet,
271} || block.Error;
272
273/// Decode a Zstandard frame from `src` into `dest`, returning the number of
274/// bytes read from `src` and written to `dest`. The first four bytes of `src`
275/// must be the magic number for a Zstandard frame.
276///
277/// Error returned:
278/// - `error.UnknownContentSizeUnsupported` if the frame does not declare the
279/// uncompressed content size
280/// - `error.ContentTooLarge` if `dest` is smaller than the uncompressed data
281/// size declared by the frame header
282/// - `error.WindowSizeUnknown` if the frame does not have a valid window size
283/// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary
284/// - `error.ContentSizeTooLarge` if the frame header indicates a content size
285/// that is larger than `std.math.maxInt(usize)`
286/// - `error.ChecksumFailure` if `verify_checksum` is true and the frame
287/// contains a checksum that does not match the checksum of the decompressed
288/// data
289/// - `error.ReservedBitSet` if the reserved bit of the frame header is set
290/// - `error.EndOfStream` if `src` does not contain a complete frame
291/// - an error in `block.Error` if there are errors decoding a block
292/// - `error.BadContentSize` if the content size declared by the frame does
293/// not equal the actual size of decompressed data
294pub fn decodeZstandardFrame(
295 dest: []u8,
296 src: []const u8,
297 verify_checksum: bool,
298) (error{
299 UnknownContentSizeUnsupported,
300 ContentTooLarge,
301 ContentSizeTooLarge,
302 WindowSizeUnknown,
303 DictionaryIdFlagUnsupported,
304} || FrameError)!ReadWriteCount {
305 assert(readInt(u32, src[0..4]) == frame.Zstandard.magic_number);
306 var consumed_count: usize = 4;
307
308 var frame_context = context: {
309 var fbs = std.io.fixedBufferStream(src[consumed_count..]);
310 var source = fbs.reader();
311 const frame_header = try decodeZstandardHeader(source);
312 consumed_count += fbs.pos;
313 break :context FrameContext.init(
314 frame_header,
315 std.math.maxInt(usize),
316 verify_checksum,
317 ) catch |err| switch (err) {
318 error.WindowTooLarge => unreachable,
319 inline else => |e| return e,
320 };
321 };
322 const counts = try decodeZStandardFrameBlocks(
323 dest,
324 src[consumed_count..],
325 &frame_context,
326 );
327 return ReadWriteCount{
328 .read_count = counts.read_count + consumed_count,
329 .write_count = counts.write_count,
330 };
331}
332
333pub fn decodeZStandardFrameBlocks(
334 dest: []u8,
335 src: []const u8,
336 frame_context: *FrameContext,
337) (error{ ContentTooLarge, UnknownContentSizeUnsupported } || FrameError)!ReadWriteCount {
338 const content_size = frame_context.content_size orelse
339 return error.UnknownContentSizeUnsupported;
340 if (dest.len < content_size) return error.ContentTooLarge;
341
342 var consumed_count: usize = 0;
343 const written_count = decodeFrameBlocksInner(
344 dest[0..content_size],
345 src[consumed_count..],
346 &consumed_count,
347 if (frame_context.hasher_opt) |*hasher| hasher else null,
348 frame_context.block_size_max,
349 ) catch |err| switch (err) {
350 error.DestTooSmall => return error.BadContentSize,
351 inline else => |e| return e,
352 };
353
354 if (written_count != content_size) return error.BadContentSize;
355 if (frame_context.has_checksum) {
356 if (src.len < consumed_count + 4) return error.EndOfStream;
357 const checksum = readIntSlice(u32, src[consumed_count .. consumed_count + 4]);
358 consumed_count += 4;
359 if (frame_context.hasher_opt) |*hasher| {
360 if (checksum != computeChecksum(hasher)) return error.ChecksumFailure;
361 }
362 }
363 return ReadWriteCount{ .read_count = consumed_count, .write_count = written_count };
364}
365
366pub const FrameContext = struct {
367 hasher_opt: ?std.hash.XxHash64,
368 window_size: usize,
369 has_checksum: bool,
370 block_size_max: usize,
371 content_size: ?usize,
372
373 const Error = error{
374 DictionaryIdFlagUnsupported,
375 WindowSizeUnknown,
376 WindowTooLarge,
377 ContentSizeTooLarge,
378 };
379 /// Validates `frame_header` and returns the associated `FrameContext`.
380 ///
381 /// Errors returned:
382 /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary
383 /// - `error.WindowSizeUnknown` if the frame does not have a valid window
384 /// size
385 /// - `error.WindowTooLarge` if the window size is larger than
386 /// `window_size_max`
387 /// - `error.ContentSizeTooLarge` if the frame header indicates a content
388 /// size larger than `std.math.maxInt(usize)`
389 pub fn init(
390 frame_header: ZstandardHeader,
391 window_size_max: usize,
392 verify_checksum: bool,
393 ) Error!FrameContext {
394 if (frame_header.descriptor.dictionary_id_flag != 0)
395 return error.DictionaryIdFlagUnsupported;
396
397 const window_size_raw = frameWindowSize(frame_header) orelse return error.WindowSizeUnknown;
398 const window_size = if (window_size_raw > window_size_max)
399 return error.WindowTooLarge
400 else
401 @intCast(usize, window_size_raw);
402
403 const should_compute_checksum =
404 frame_header.descriptor.content_checksum_flag and verify_checksum;
405
406 const content_size = if (frame_header.content_size) |size|
407 std.math.cast(usize, size) orelse return error.ContentSizeTooLarge
408 else
409 null;
410
411 return .{
412 .hasher_opt = if (should_compute_checksum) std.hash.XxHash64.init(0) else null,
413 .window_size = window_size,
414 .has_checksum = frame_header.descriptor.content_checksum_flag,
415 .block_size_max = @min(1 << 17, window_size),
416 .content_size = content_size,
417 };
418 }
419};
420
421/// Decode a Zstandard from from `src` and return number of bytes read; see
422/// `decodeZstandardFrame()`. The first four bytes of `src` must be the magic
423/// number for a Zstandard frame.
424///
425/// Errors returned:
426/// - `error.WindowSizeUnknown` if the frame does not have a valid window size
427/// - `error.WindowTooLarge` if the window size is larger than
428/// `window_size_max`
429/// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary
430/// - `error.ContentSizeTooLarge` if the frame header indicates a content size
431/// that is larger than `std.math.maxInt(usize)`
432/// - `error.ChecksumFailure` if `verify_checksum` is true and the frame
433/// contains a checksum that does not match the checksum of the decompressed
434/// data
435/// - `error.ReservedBitSet` if the reserved bit of the frame header is set
436/// - `error.EndOfStream` if `src` does not contain a complete frame
437/// - `error.OutOfMemory` if `allocator` cannot allocate enough memory
438/// - an error in `block.Error` if there are errors decoding a block
439/// - `error.BadContentSize` if the content size declared by the frame does
440/// not equal the size of decompressed data
441pub fn decodeZstandardFrameArrayList(
442 allocator: Allocator,
443 dest: *std.ArrayList(u8),
444 src: []const u8,
445 verify_checksum: bool,
446 window_size_max: usize,
447) (error{OutOfMemory} || FrameContext.Error || FrameError)!usize {
448 assert(readInt(u32, src[0..4]) == frame.Zstandard.magic_number);
449 var consumed_count: usize = 4;
450
451 var frame_context = context: {
452 var fbs = std.io.fixedBufferStream(src[consumed_count..]);
453 var source = fbs.reader();
454 const frame_header = try decodeZstandardHeader(source);
455 consumed_count += fbs.pos;
456 break :context try FrameContext.init(frame_header, window_size_max, verify_checksum);
457 };
458
459 consumed_count += try decodeZstandardFrameBlocksArrayList(
460 allocator,
461 dest,
462 src[consumed_count..],
463 &frame_context,
464 );
465 return consumed_count;
466}
467
468pub fn decodeZstandardFrameBlocksArrayList(
469 allocator: Allocator,
470 dest: *std.ArrayList(u8),
471 src: []const u8,
472 frame_context: *FrameContext,
473) (error{OutOfMemory} || FrameError)!usize {
474 const initial_len = dest.items.len;
475
476 var ring_buffer = try RingBuffer.init(allocator, frame_context.window_size);
477 defer ring_buffer.deinit(allocator);
478
479 // These tables take 7680 bytes
480 var literal_fse_data: [types.compressed_block.table_size_max.literal]Table.Fse = undefined;
481 var match_fse_data: [types.compressed_block.table_size_max.match]Table.Fse = undefined;
482 var offset_fse_data: [types.compressed_block.table_size_max.offset]Table.Fse = undefined;
483
484 var block_header = try block.decodeBlockHeaderSlice(src);
485 var consumed_count: usize = 3;
486 var decode_state = block.DecodeState.init(&literal_fse_data, &match_fse_data, &offset_fse_data);
487 while (true) : ({
488 block_header = try block.decodeBlockHeaderSlice(src[consumed_count..]);
489 consumed_count += 3;
490 }) {
491 const written_size = try block.decodeBlockRingBuffer(
492 &ring_buffer,
493 src[consumed_count..],
494 block_header,
495 &decode_state,
496 &consumed_count,
497 frame_context.block_size_max,
498 );
499 if (frame_context.content_size) |size| {
500 if (dest.items.len - initial_len > size) {
501 return error.BadContentSize;
502 }
503 }
504 if (written_size > 0) {
505 const written_slice = ring_buffer.sliceLast(written_size);
506 try dest.appendSlice(written_slice.first);
507 try dest.appendSlice(written_slice.second);
508 if (frame_context.hasher_opt) |*hasher| {
509 hasher.update(written_slice.first);
510 hasher.update(written_slice.second);
511 }
512 }
513 if (block_header.last_block) break;
514 }
515 if (frame_context.content_size) |size| {
516 if (dest.items.len - initial_len != size) {
517 return error.BadContentSize;
518 }
519 }
520
521 if (frame_context.has_checksum) {
522 if (src.len < consumed_count + 4) return error.EndOfStream;
523 const checksum = readIntSlice(u32, src[consumed_count .. consumed_count + 4]);
524 consumed_count += 4;
525 if (frame_context.hasher_opt) |*hasher| {
526 if (checksum != computeChecksum(hasher)) return error.ChecksumFailure;
527 }
528 }
529 return consumed_count;
530}
531
532fn decodeFrameBlocksInner(
533 dest: []u8,
534 src: []const u8,
535 consumed_count: *usize,
536 hash: ?*std.hash.XxHash64,
537 block_size_max: usize,
538) (error{ EndOfStream, DestTooSmall } || block.Error)!usize {
539 // These tables take 7680 bytes
540 var literal_fse_data: [types.compressed_block.table_size_max.literal]Table.Fse = undefined;
541 var match_fse_data: [types.compressed_block.table_size_max.match]Table.Fse = undefined;
542 var offset_fse_data: [types.compressed_block.table_size_max.offset]Table.Fse = undefined;
543
544 var block_header = try block.decodeBlockHeaderSlice(src);
545 var bytes_read: usize = 3;
546 defer consumed_count.* += bytes_read;
547 var decode_state = block.DecodeState.init(&literal_fse_data, &match_fse_data, &offset_fse_data);
548 var count: usize = 0;
549 while (true) : ({
550 block_header = try block.decodeBlockHeaderSlice(src[bytes_read..]);
551 bytes_read += 3;
552 }) {
553 const written_size = try block.decodeBlock(
554 dest,
555 src[bytes_read..],
556 block_header,
557 &decode_state,
558 &bytes_read,
559 block_size_max,
560 count,
561 );
562 if (hash) |hash_state| hash_state.update(dest[count .. count + written_size]);
563 count += written_size;
564 if (block_header.last_block) break;
565 }
566 return count;
567}
568
569/// Decode the header of a skippable frame. The first four bytes of `src` must
570/// be a valid magic number for a skippable frame.
571pub fn decodeSkippableHeader(src: *const [8]u8) SkippableHeader {
572 const magic = readInt(u32, src[0..4]);
573 assert(isSkippableMagic(magic));
574 const frame_size = readInt(u32, src[4..8]);
575 return .{
576 .magic_number = magic,
577 .frame_size = frame_size,
578 };
579}
580
581/// Returns the window size required to decompress a frame, or `null` if it
582/// cannot be determined (which indicates a malformed frame header).
583pub fn frameWindowSize(header: ZstandardHeader) ?u64 {
584 if (header.window_descriptor) |descriptor| {
585 const exponent = (descriptor & 0b11111000) >> 3;
586 const mantissa = descriptor & 0b00000111;
587 const window_log = 10 + exponent;
588 const window_base = @as(u64, 1) << @intCast(u6, window_log);
589 const window_add = (window_base / 8) * mantissa;
590 return window_base + window_add;
591 } else return header.content_size;
592}
593
594/// Decode the header of a Zstandard frame.
595///
596/// Errors returned:
597/// - `error.ReservedBitSet` if any of the reserved bits of the header are set
598/// - `error.EndOfStream` if `source` does not contain a complete header
599pub fn decodeZstandardHeader(
600 source: anytype,
601) (@TypeOf(source).Error || error{ EndOfStream, ReservedBitSet })!ZstandardHeader {
602 const descriptor = @bitCast(ZstandardHeader.Descriptor, try source.readByte());
603
604 if (descriptor.reserved) return error.ReservedBitSet;
605
606 var window_descriptor: ?u8 = null;
607 if (!descriptor.single_segment_flag) {
608 window_descriptor = try source.readByte();
609 }
610
611 var dictionary_id: ?u32 = null;
612 if (descriptor.dictionary_id_flag > 0) {
613 // if flag is 3 then field_size = 4, else field_size = flag
614 const field_size = (@as(u4, 1) << descriptor.dictionary_id_flag) >> 1;
615 dictionary_id = try source.readVarInt(u32, .Little, field_size);
616 }
617
618 var content_size: ?u64 = null;
619 if (descriptor.single_segment_flag or descriptor.content_size_flag > 0) {
620 const field_size = @as(u4, 1) << descriptor.content_size_flag;
621 content_size = try source.readVarInt(u64, .Little, field_size);
622 if (field_size == 2) content_size.? += 256;
623 }
624
625 const header = ZstandardHeader{
626 .descriptor = descriptor,
627 .window_descriptor = window_descriptor,
628 .dictionary_id = dictionary_id,
629 .content_size = content_size,
630 };
631 return header;
632}
633
634test {
635 std.testing.refAllDecls(@This());
636}
lib/std/compress/zstandard/readers.zig created+82
...@@ -0,0 +1,82 @@
1const std = @import("std");
2
3pub const ReversedByteReader = struct {
4 remaining_bytes: usize,
5 bytes: []const u8,
6
7 const Reader = std.io.Reader(*ReversedByteReader, error{}, readFn);
8
9 pub fn init(bytes: []const u8) ReversedByteReader {
10 return .{
11 .bytes = bytes,
12 .remaining_bytes = bytes.len,
13 };
14 }
15
16 pub fn reader(self: *ReversedByteReader) Reader {
17 return .{ .context = self };
18 }
19
20 fn readFn(ctx: *ReversedByteReader, buffer: []u8) !usize {
21 if (ctx.remaining_bytes == 0) return 0;
22 const byte_index = ctx.remaining_bytes - 1;
23 buffer[0] = ctx.bytes[byte_index];
24 // buffer[0] = @bitReverse(ctx.bytes[byte_index]);
25 ctx.remaining_bytes = byte_index;
26 return 1;
27 }
28};
29
30/// A bit reader for reading the reversed bit streams used to encode
31/// FSE compressed data.
32pub const ReverseBitReader = struct {
33 byte_reader: ReversedByteReader,
34 bit_reader: std.io.BitReader(.Big, ReversedByteReader.Reader),
35
36 pub fn init(self: *ReverseBitReader, bytes: []const u8) error{BitStreamHasNoStartBit}!void {
37 self.byte_reader = ReversedByteReader.init(bytes);
38 self.bit_reader = std.io.bitReader(.Big, self.byte_reader.reader());
39 if (bytes.len == 0) return;
40 var i: usize = 0;
41 while (i < 8 and 0 == self.readBitsNoEof(u1, 1) catch unreachable) : (i += 1) {}
42 if (i == 8) return error.BitStreamHasNoStartBit;
43 }
44
45 pub fn readBitsNoEof(self: *@This(), comptime U: type, num_bits: usize) error{EndOfStream}!U {
46 return self.bit_reader.readBitsNoEof(U, num_bits);
47 }
48
49 pub fn readBits(self: *@This(), comptime U: type, num_bits: usize, out_bits: *usize) error{}!U {
50 return try self.bit_reader.readBits(U, num_bits, out_bits);
51 }
52
53 pub fn alignToByte(self: *@This()) void {
54 self.bit_reader.alignToByte();
55 }
56
57 pub fn isEmpty(self: ReverseBitReader) bool {
58 return self.byte_reader.remaining_bytes == 0 and self.bit_reader.bit_count == 0;
59 }
60};
61
62pub fn BitReader(comptime Reader: type) type {
63 return struct {
64 underlying: std.io.BitReader(.Little, Reader),
65
66 pub fn readBitsNoEof(self: *@This(), comptime U: type, num_bits: usize) !U {
67 return self.underlying.readBitsNoEof(U, num_bits);
68 }
69
70 pub fn readBits(self: *@This(), comptime U: type, num_bits: usize, out_bits: *usize) !U {
71 return self.underlying.readBits(U, num_bits, out_bits);
72 }
73
74 pub fn alignToByte(self: *@This()) void {
75 self.underlying.alignToByte();
76 }
77 };
78}
79
80pub fn bitReader(reader: anytype) BitReader(@TypeOf(reader)) {
81 return .{ .underlying = std.io.bitReader(.Little, reader) };
82}
lib/std/compress/zstandard/types.zig created+401
...@@ -0,0 +1,401 @@
1pub const frame = struct {
2 pub const Kind = enum { zstandard, skippable };
3
4 pub const Zstandard = struct {
5 pub const magic_number = 0xFD2FB528;
6
7 header: Header,
8 data_blocks: []Block,
9 checksum: ?u32,
10
11 pub const Header = struct {
12 descriptor: Descriptor,
13 window_descriptor: ?u8,
14 dictionary_id: ?u32,
15 content_size: ?u64,
16
17 pub const Descriptor = packed struct {
18 dictionary_id_flag: u2,
19 content_checksum_flag: bool,
20 reserved: bool,
21 unused: bool,
22 single_segment_flag: bool,
23 content_size_flag: u2,
24 };
25 };
26
27 pub const Block = struct {
28 pub const Header = struct {
29 last_block: bool,
30 block_type: Block.Type,
31 block_size: u21,
32 };
33
34 pub const Type = enum(u2) {
35 raw,
36 rle,
37 compressed,
38 reserved,
39 };
40 };
41 };
42
43 pub const Skippable = struct {
44 pub const magic_number_min = 0x184D2A50;
45 pub const magic_number_max = 0x184D2A5F;
46
47 pub const Header = struct {
48 magic_number: u32,
49 frame_size: u32,
50 };
51 };
52};
53
54pub const compressed_block = struct {
55 pub const LiteralsSection = struct {
56 header: Header,
57 huffman_tree: ?HuffmanTree,
58 streams: Streams,
59
60 pub const Streams = union(enum) {
61 one: []const u8,
62 four: [4][]const u8,
63 };
64
65 pub const Header = struct {
66 block_type: BlockType,
67 size_format: u2,
68 regenerated_size: u20,
69 compressed_size: ?u18,
70 };
71
72 pub const BlockType = enum(u2) {
73 raw,
74 rle,
75 compressed,
76 treeless,
77 };
78
79 pub const HuffmanTree = struct {
80 max_bit_count: u4,
81 symbol_count_minus_one: u8,
82 nodes: [256]PrefixedSymbol,
83
84 pub const PrefixedSymbol = struct {
85 symbol: u8,
86 prefix: u16,
87 weight: u4,
88 };
89
90 pub const Result = union(enum) {
91 symbol: u8,
92 index: usize,
93 };
94
95 pub fn query(self: HuffmanTree, index: usize, prefix: u16) error{NotFound}!Result {
96 var node = self.nodes[index];
97 const weight = node.weight;
98 var i: usize = index;
99 while (node.weight == weight) {
100 if (node.prefix == prefix) return Result{ .symbol = node.symbol };
101 if (i == 0) return error.NotFound;
102 i -= 1;
103 node = self.nodes[i];
104 }
105 return Result{ .index = i };
106 }
107
108 pub fn weightToBitCount(weight: u4, max_bit_count: u4) u4 {
109 return if (weight == 0) 0 else ((max_bit_count + 1) - weight);
110 }
111 };
112
113 pub const StreamCount = enum { one, four };
114 pub fn streamCount(size_format: u2, block_type: BlockType) StreamCount {
115 return switch (block_type) {
116 .raw, .rle => .one,
117 .compressed, .treeless => if (size_format == 0) .one else .four,
118 };
119 }
120 };
121
122 pub const SequencesSection = struct {
123 header: SequencesSection.Header,
124 literals_length_table: Table,
125 offset_table: Table,
126 match_length_table: Table,
127
128 pub const Header = struct {
129 sequence_count: u24,
130 match_lengths: Mode,
131 offsets: Mode,
132 literal_lengths: Mode,
133
134 pub const Mode = enum(u2) {
135 predefined,
136 rle,
137 fse,
138 repeat,
139 };
140 };
141 };
142
143 pub const Table = union(enum) {
144 fse: []const Fse,
145 rle: u8,
146
147 pub const Fse = struct {
148 symbol: u8,
149 baseline: u16,
150 bits: u8,
151 };
152 };
153
154 pub const literals_length_code_table = [36]struct { u32, u5 }{
155 .{ 0, 0 }, .{ 1, 0 }, .{ 2, 0 }, .{ 3, 0 },
156 .{ 4, 0 }, .{ 5, 0 }, .{ 6, 0 }, .{ 7, 0 },
157 .{ 8, 0 }, .{ 9, 0 }, .{ 10, 0 }, .{ 11, 0 },
158 .{ 12, 0 }, .{ 13, 0 }, .{ 14, 0 }, .{ 15, 0 },
159 .{ 16, 1 }, .{ 18, 1 }, .{ 20, 1 }, .{ 22, 1 },
160 .{ 24, 2 }, .{ 28, 2 }, .{ 32, 3 }, .{ 40, 3 },
161 .{ 48, 4 }, .{ 64, 6 }, .{ 128, 7 }, .{ 256, 8 },
162 .{ 512, 9 }, .{ 1024, 10 }, .{ 2048, 11 }, .{ 4096, 12 },
163 .{ 8192, 13 }, .{ 16384, 14 }, .{ 32768, 15 }, .{ 65536, 16 },
164 };
165
166 pub const match_length_code_table = [53]struct { u32, u5 }{
167 .{ 3, 0 }, .{ 4, 0 }, .{ 5, 0 }, .{ 6, 0 }, .{ 7, 0 }, .{ 8, 0 },
168 .{ 9, 0 }, .{ 10, 0 }, .{ 11, 0 }, .{ 12, 0 }, .{ 13, 0 }, .{ 14, 0 },
169 .{ 15, 0 }, .{ 16, 0 }, .{ 17, 0 }, .{ 18, 0 }, .{ 19, 0 }, .{ 20, 0 },
170 .{ 21, 0 }, .{ 22, 0 }, .{ 23, 0 }, .{ 24, 0 }, .{ 25, 0 }, .{ 26, 0 },
171 .{ 27, 0 }, .{ 28, 0 }, .{ 29, 0 }, .{ 30, 0 }, .{ 31, 0 }, .{ 32, 0 },
172 .{ 33, 0 }, .{ 34, 0 }, .{ 35, 1 }, .{ 37, 1 }, .{ 39, 1 }, .{ 41, 1 },
173 .{ 43, 2 }, .{ 47, 2 }, .{ 51, 3 }, .{ 59, 3 }, .{ 67, 4 }, .{ 83, 4 },
174 .{ 99, 5 }, .{ 131, 7 }, .{ 259, 8 }, .{ 515, 9 }, .{ 1027, 10 }, .{ 2051, 11 },
175 .{ 4099, 12 }, .{ 8195, 13 }, .{ 16387, 14 }, .{ 32771, 15 }, .{ 65539, 16 },
176 };
177
178 pub const literals_length_default_distribution = [36]i16{
179 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
180 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1,
181 -1, -1, -1, -1,
182 };
183
184 pub const match_lengths_default_distribution = [53]i16{
185 1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
186 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
187 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1,
188 -1, -1, -1, -1, -1,
189 };
190
191 pub const offset_codes_default_distribution = [29]i16{
192 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
193 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
194 };
195
196 pub const predefined_literal_fse_table = Table{
197 .fse = &[64]Table.Fse{
198 .{ .symbol = 0, .bits = 4, .baseline = 0 },
199 .{ .symbol = 0, .bits = 4, .baseline = 16 },
200 .{ .symbol = 1, .bits = 5, .baseline = 32 },
201 .{ .symbol = 3, .bits = 5, .baseline = 0 },
202 .{ .symbol = 4, .bits = 5, .baseline = 0 },
203 .{ .symbol = 6, .bits = 5, .baseline = 0 },
204 .{ .symbol = 7, .bits = 5, .baseline = 0 },
205 .{ .symbol = 9, .bits = 5, .baseline = 0 },
206 .{ .symbol = 10, .bits = 5, .baseline = 0 },
207 .{ .symbol = 12, .bits = 5, .baseline = 0 },
208 .{ .symbol = 14, .bits = 6, .baseline = 0 },
209 .{ .symbol = 16, .bits = 5, .baseline = 0 },
210 .{ .symbol = 18, .bits = 5, .baseline = 0 },
211 .{ .symbol = 19, .bits = 5, .baseline = 0 },
212 .{ .symbol = 21, .bits = 5, .baseline = 0 },
213 .{ .symbol = 22, .bits = 5, .baseline = 0 },
214 .{ .symbol = 24, .bits = 5, .baseline = 0 },
215 .{ .symbol = 25, .bits = 5, .baseline = 32 },
216 .{ .symbol = 26, .bits = 5, .baseline = 0 },
217 .{ .symbol = 27, .bits = 6, .baseline = 0 },
218 .{ .symbol = 29, .bits = 6, .baseline = 0 },
219 .{ .symbol = 31, .bits = 6, .baseline = 0 },
220 .{ .symbol = 0, .bits = 4, .baseline = 32 },
221 .{ .symbol = 1, .bits = 4, .baseline = 0 },
222 .{ .symbol = 2, .bits = 5, .baseline = 0 },
223 .{ .symbol = 4, .bits = 5, .baseline = 32 },
224 .{ .symbol = 5, .bits = 5, .baseline = 0 },
225 .{ .symbol = 7, .bits = 5, .baseline = 32 },
226 .{ .symbol = 8, .bits = 5, .baseline = 0 },
227 .{ .symbol = 10, .bits = 5, .baseline = 32 },
228 .{ .symbol = 11, .bits = 5, .baseline = 0 },
229 .{ .symbol = 13, .bits = 6, .baseline = 0 },
230 .{ .symbol = 16, .bits = 5, .baseline = 32 },
231 .{ .symbol = 17, .bits = 5, .baseline = 0 },
232 .{ .symbol = 19, .bits = 5, .baseline = 32 },
233 .{ .symbol = 20, .bits = 5, .baseline = 0 },
234 .{ .symbol = 22, .bits = 5, .baseline = 32 },
235 .{ .symbol = 23, .bits = 5, .baseline = 0 },
236 .{ .symbol = 25, .bits = 4, .baseline = 0 },
237 .{ .symbol = 25, .bits = 4, .baseline = 16 },
238 .{ .symbol = 26, .bits = 5, .baseline = 32 },
239 .{ .symbol = 28, .bits = 6, .baseline = 0 },
240 .{ .symbol = 30, .bits = 6, .baseline = 0 },
241 .{ .symbol = 0, .bits = 4, .baseline = 48 },
242 .{ .symbol = 1, .bits = 4, .baseline = 16 },
243 .{ .symbol = 2, .bits = 5, .baseline = 32 },
244 .{ .symbol = 3, .bits = 5, .baseline = 32 },
245 .{ .symbol = 5, .bits = 5, .baseline = 32 },
246 .{ .symbol = 6, .bits = 5, .baseline = 32 },
247 .{ .symbol = 8, .bits = 5, .baseline = 32 },
248 .{ .symbol = 9, .bits = 5, .baseline = 32 },
249 .{ .symbol = 11, .bits = 5, .baseline = 32 },
250 .{ .symbol = 12, .bits = 5, .baseline = 32 },
251 .{ .symbol = 15, .bits = 6, .baseline = 0 },
252 .{ .symbol = 17, .bits = 5, .baseline = 32 },
253 .{ .symbol = 18, .bits = 5, .baseline = 32 },
254 .{ .symbol = 20, .bits = 5, .baseline = 32 },
255 .{ .symbol = 21, .bits = 5, .baseline = 32 },
256 .{ .symbol = 23, .bits = 5, .baseline = 32 },
257 .{ .symbol = 24, .bits = 5, .baseline = 32 },
258 .{ .symbol = 35, .bits = 6, .baseline = 0 },
259 .{ .symbol = 34, .bits = 6, .baseline = 0 },
260 .{ .symbol = 33, .bits = 6, .baseline = 0 },
261 .{ .symbol = 32, .bits = 6, .baseline = 0 },
262 },
263 };
264
265 pub const predefined_match_fse_table = Table{
266 .fse = &[64]Table.Fse{
267 .{ .symbol = 0, .bits = 6, .baseline = 0 },
268 .{ .symbol = 1, .bits = 4, .baseline = 0 },
269 .{ .symbol = 2, .bits = 5, .baseline = 32 },
270 .{ .symbol = 3, .bits = 5, .baseline = 0 },
271 .{ .symbol = 5, .bits = 5, .baseline = 0 },
272 .{ .symbol = 6, .bits = 5, .baseline = 0 },
273 .{ .symbol = 8, .bits = 5, .baseline = 0 },
274 .{ .symbol = 10, .bits = 6, .baseline = 0 },
275 .{ .symbol = 13, .bits = 6, .baseline = 0 },
276 .{ .symbol = 16, .bits = 6, .baseline = 0 },
277 .{ .symbol = 19, .bits = 6, .baseline = 0 },
278 .{ .symbol = 22, .bits = 6, .baseline = 0 },
279 .{ .symbol = 25, .bits = 6, .baseline = 0 },
280 .{ .symbol = 28, .bits = 6, .baseline = 0 },
281 .{ .symbol = 31, .bits = 6, .baseline = 0 },
282 .{ .symbol = 33, .bits = 6, .baseline = 0 },
283 .{ .symbol = 35, .bits = 6, .baseline = 0 },
284 .{ .symbol = 37, .bits = 6, .baseline = 0 },
285 .{ .symbol = 39, .bits = 6, .baseline = 0 },
286 .{ .symbol = 41, .bits = 6, .baseline = 0 },
287 .{ .symbol = 43, .bits = 6, .baseline = 0 },
288 .{ .symbol = 45, .bits = 6, .baseline = 0 },
289 .{ .symbol = 1, .bits = 4, .baseline = 16 },
290 .{ .symbol = 2, .bits = 4, .baseline = 0 },
291 .{ .symbol = 3, .bits = 5, .baseline = 32 },
292 .{ .symbol = 4, .bits = 5, .baseline = 0 },
293 .{ .symbol = 6, .bits = 5, .baseline = 32 },
294 .{ .symbol = 7, .bits = 5, .baseline = 0 },
295 .{ .symbol = 9, .bits = 6, .baseline = 0 },
296 .{ .symbol = 12, .bits = 6, .baseline = 0 },
297 .{ .symbol = 15, .bits = 6, .baseline = 0 },
298 .{ .symbol = 18, .bits = 6, .baseline = 0 },
299 .{ .symbol = 21, .bits = 6, .baseline = 0 },
300 .{ .symbol = 24, .bits = 6, .baseline = 0 },
301 .{ .symbol = 27, .bits = 6, .baseline = 0 },
302 .{ .symbol = 30, .bits = 6, .baseline = 0 },
303 .{ .symbol = 32, .bits = 6, .baseline = 0 },
304 .{ .symbol = 34, .bits = 6, .baseline = 0 },
305 .{ .symbol = 36, .bits = 6, .baseline = 0 },
306 .{ .symbol = 38, .bits = 6, .baseline = 0 },
307 .{ .symbol = 40, .bits = 6, .baseline = 0 },
308 .{ .symbol = 42, .bits = 6, .baseline = 0 },
309 .{ .symbol = 44, .bits = 6, .baseline = 0 },
310 .{ .symbol = 1, .bits = 4, .baseline = 32 },
311 .{ .symbol = 1, .bits = 4, .baseline = 48 },
312 .{ .symbol = 2, .bits = 4, .baseline = 16 },
313 .{ .symbol = 4, .bits = 5, .baseline = 32 },
314 .{ .symbol = 5, .bits = 5, .baseline = 32 },
315 .{ .symbol = 7, .bits = 5, .baseline = 32 },
316 .{ .symbol = 8, .bits = 5, .baseline = 32 },
317 .{ .symbol = 11, .bits = 6, .baseline = 0 },
318 .{ .symbol = 14, .bits = 6, .baseline = 0 },
319 .{ .symbol = 17, .bits = 6, .baseline = 0 },
320 .{ .symbol = 20, .bits = 6, .baseline = 0 },
321 .{ .symbol = 23, .bits = 6, .baseline = 0 },
322 .{ .symbol = 26, .bits = 6, .baseline = 0 },
323 .{ .symbol = 29, .bits = 6, .baseline = 0 },
324 .{ .symbol = 52, .bits = 6, .baseline = 0 },
325 .{ .symbol = 51, .bits = 6, .baseline = 0 },
326 .{ .symbol = 50, .bits = 6, .baseline = 0 },
327 .{ .symbol = 49, .bits = 6, .baseline = 0 },
328 .{ .symbol = 48, .bits = 6, .baseline = 0 },
329 .{ .symbol = 47, .bits = 6, .baseline = 0 },
330 .{ .symbol = 46, .bits = 6, .baseline = 0 },
331 },
332 };
333
334 pub const predefined_offset_fse_table = Table{
335 .fse = &[32]Table.Fse{
336 .{ .symbol = 0, .bits = 5, .baseline = 0 },
337 .{ .symbol = 6, .bits = 4, .baseline = 0 },
338 .{ .symbol = 9, .bits = 5, .baseline = 0 },
339 .{ .symbol = 15, .bits = 5, .baseline = 0 },
340 .{ .symbol = 21, .bits = 5, .baseline = 0 },
341 .{ .symbol = 3, .bits = 5, .baseline = 0 },
342 .{ .symbol = 7, .bits = 4, .baseline = 0 },
343 .{ .symbol = 12, .bits = 5, .baseline = 0 },
344 .{ .symbol = 18, .bits = 5, .baseline = 0 },
345 .{ .symbol = 23, .bits = 5, .baseline = 0 },
346 .{ .symbol = 5, .bits = 5, .baseline = 0 },
347 .{ .symbol = 8, .bits = 4, .baseline = 0 },
348 .{ .symbol = 14, .bits = 5, .baseline = 0 },
349 .{ .symbol = 20, .bits = 5, .baseline = 0 },
350 .{ .symbol = 2, .bits = 5, .baseline = 0 },
351 .{ .symbol = 7, .bits = 4, .baseline = 16 },
352 .{ .symbol = 11, .bits = 5, .baseline = 0 },
353 .{ .symbol = 17, .bits = 5, .baseline = 0 },
354 .{ .symbol = 22, .bits = 5, .baseline = 0 },
355 .{ .symbol = 4, .bits = 5, .baseline = 0 },
356 .{ .symbol = 8, .bits = 4, .baseline = 16 },
357 .{ .symbol = 13, .bits = 5, .baseline = 0 },
358 .{ .symbol = 19, .bits = 5, .baseline = 0 },
359 .{ .symbol = 1, .bits = 5, .baseline = 0 },
360 .{ .symbol = 6, .bits = 4, .baseline = 16 },
361 .{ .symbol = 10, .bits = 5, .baseline = 0 },
362 .{ .symbol = 16, .bits = 5, .baseline = 0 },
363 .{ .symbol = 28, .bits = 5, .baseline = 0 },
364 .{ .symbol = 27, .bits = 5, .baseline = 0 },
365 .{ .symbol = 26, .bits = 5, .baseline = 0 },
366 .{ .symbol = 25, .bits = 5, .baseline = 0 },
367 .{ .symbol = 24, .bits = 5, .baseline = 0 },
368 },
369 };
370 pub const start_repeated_offset_1 = 1;
371 pub const start_repeated_offset_2 = 4;
372 pub const start_repeated_offset_3 = 8;
373
374 pub const table_accuracy_log_max = struct {
375 pub const literal = 9;
376 pub const match = 9;
377 pub const offset = 8;
378 };
379
380 pub const table_symbol_count_max = struct {
381 pub const literal = 36;
382 pub const match = 53;
383 pub const offset = 32;
384 };
385
386 pub const default_accuracy_log = struct {
387 pub const literal = 6;
388 pub const match = 6;
389 pub const offset = 5;
390 };
391 pub const table_size_max = struct {
392 pub const literal = 1 << table_accuracy_log_max.literal;
393 pub const match = 1 << table_accuracy_log_max.match;
394 pub const offset = 1 << table_accuracy_log_max.match;
395 };
396};
397
398test {
399 const testing = @import("std").testing;
400 testing.refAllDeclsRecursive(@This());
401}
lib/std/crypto/benchmark.zig+1-1
...@@ -178,7 +178,7 @@ pub fn benchmarkBatchSignatureVerification(comptime Signature: anytype, comptime...@@ -178,7 +178,7 @@ pub fn benchmarkBatchSignatureVerification(comptime Signature: anytype, comptime
178 const sig = try key_pair.sign(&msg, null);178 const sig = try key_pair.sign(&msg, null);
179179
180 var batch: [64]Signature.BatchElement = undefined;180 var batch: [64]Signature.BatchElement = undefined;
181 for (batch) |*element| {181 for (&batch) |*element| {
182 element.* = Signature.BatchElement{ .sig = sig, .msg = &msg, .public_key = key_pair.public_key };182 element.* = Signature.BatchElement{ .sig = sig, .msg = &msg, .public_key = key_pair.public_key };
183 }183 }
184184
lib/std/hash.zig+5
...@@ -32,6 +32,10 @@ pub const CityHash64 = cityhash.CityHash64;...@@ -32,6 +32,10 @@ pub const CityHash64 = cityhash.CityHash64;
32const wyhash = @import("hash/wyhash.zig");32const wyhash = @import("hash/wyhash.zig");
33pub const Wyhash = wyhash.Wyhash;33pub const Wyhash = wyhash.Wyhash;
3434
35const xxhash = @import("hash/xxhash.zig");
36pub const XxHash64 = xxhash.XxHash64;
37pub const XxHash32 = xxhash.XxHash32;
38
35test "hash" {39test "hash" {
36 _ = adler;40 _ = adler;
37 _ = auto_hash;41 _ = auto_hash;
...@@ -40,4 +44,5 @@ test "hash" {...@@ -40,4 +44,5 @@ test "hash" {
40 _ = murmur;44 _ = murmur;
41 _ = cityhash;45 _ = cityhash;
42 _ = wyhash;46 _ = wyhash;
47 _ = xxhash;
43}48}
lib/std/hash/xxhash.zig created+268
...@@ -0,0 +1,268 @@
1const std = @import("std");
2const mem = std.mem;
3const expectEqual = std.testing.expectEqual;
4
5const rotl = std.math.rotl;
6
7pub const XxHash64 = struct {
8 acc1: u64,
9 acc2: u64,
10 acc3: u64,
11 acc4: u64,
12
13 seed: u64,
14 buf: [32]u8,
15 buf_len: usize,
16 byte_count: usize,
17
18 const prime_1 = 0x9E3779B185EBCA87; // 0b1001111000110111011110011011000110000101111010111100101010000111
19 const prime_2 = 0xC2B2AE3D27D4EB4F; // 0b1100001010110010101011100011110100100111110101001110101101001111
20 const prime_3 = 0x165667B19E3779F9; // 0b0001011001010110011001111011000110011110001101110111100111111001
21 const prime_4 = 0x85EBCA77C2B2AE63; // 0b1000010111101011110010100111011111000010101100101010111001100011
22 const prime_5 = 0x27D4EB2F165667C5; // 0b0010011111010100111010110010111100010110010101100110011111000101
23
24 pub fn init(seed: u64) XxHash64 {
25 return XxHash64{
26 .seed = seed,
27 .acc1 = seed +% prime_1 +% prime_2,
28 .acc2 = seed +% prime_2,
29 .acc3 = seed,
30 .acc4 = seed -% prime_1,
31 .buf = undefined,
32 .buf_len = 0,
33 .byte_count = 0,
34 };
35 }
36
37 pub fn update(self: *XxHash64, input: []const u8) void {
38 if (input.len < 32 - self.buf_len) {
39 mem.copy(u8, self.buf[self.buf_len..], input);
40 self.buf_len += input.len;
41 return;
42 }
43
44 var i: usize = 0;
45
46 if (self.buf_len > 0) {
47 i = 32 - self.buf_len;
48 mem.copy(u8, self.buf[self.buf_len..], input[0..i]);
49 self.processStripe(&self.buf);
50 self.buf_len = 0;
51 }
52
53 while (i + 32 <= input.len) : (i += 32) {
54 self.processStripe(input[i..][0..32]);
55 }
56
57 const remaining_bytes = input[i..];
58 mem.copy(u8, &self.buf, remaining_bytes);
59 self.buf_len = remaining_bytes.len;
60 }
61
62 inline fn processStripe(self: *XxHash64, buf: *const [32]u8) void {
63 self.acc1 = round(self.acc1, mem.readIntLittle(u64, buf[0..8]));
64 self.acc2 = round(self.acc2, mem.readIntLittle(u64, buf[8..16]));
65 self.acc3 = round(self.acc3, mem.readIntLittle(u64, buf[16..24]));
66 self.acc4 = round(self.acc4, mem.readIntLittle(u64, buf[24..32]));
67 self.byte_count += 32;
68 }
69
70 inline fn round(acc: u64, lane: u64) u64 {
71 const a = acc +% (lane *% prime_2);
72 const b = rotl(u64, a, 31);
73 return b *% prime_1;
74 }
75
76 pub fn final(self: *XxHash64) u64 {
77 var acc: u64 = undefined;
78
79 if (self.byte_count < 32) {
80 acc = self.seed +% prime_5;
81 } else {
82 acc = rotl(u64, self.acc1, 1) +% rotl(u64, self.acc2, 7) +%
83 rotl(u64, self.acc3, 12) +% rotl(u64, self.acc4, 18);
84 acc = mergeAccumulator(acc, self.acc1);
85 acc = mergeAccumulator(acc, self.acc2);
86 acc = mergeAccumulator(acc, self.acc3);
87 acc = mergeAccumulator(acc, self.acc4);
88 }
89
90 acc = acc +% @as(u64, self.byte_count) +% @as(u64, self.buf_len);
91
92 var pos: usize = 0;
93 while (pos + 8 <= self.buf_len) : (pos += 8) {
94 const lane = mem.readIntLittle(u64, self.buf[pos..][0..8]);
95 acc ^= round(0, lane);
96 acc = rotl(u64, acc, 27) *% prime_1;
97 acc +%= prime_4;
98 }
99
100 if (pos + 4 <= self.buf_len) {
101 const lane = @as(u64, mem.readIntLittle(u32, self.buf[pos..][0..4]));
102 acc ^= lane *% prime_1;
103 acc = rotl(u64, acc, 23) *% prime_2;
104 acc +%= prime_3;
105 pos += 4;
106 }
107
108 while (pos < self.buf_len) : (pos += 1) {
109 const lane = @as(u64, self.buf[pos]);
110 acc ^= lane *% prime_5;
111 acc = rotl(u64, acc, 11) *% prime_1;
112 }
113
114 acc ^= acc >> 33;
115 acc *%= prime_2;
116 acc ^= acc >> 29;
117 acc *%= prime_3;
118 acc ^= acc >> 32;
119
120 return acc;
121 }
122
123 inline fn mergeAccumulator(acc: u64, other: u64) u64 {
124 const a = acc ^ round(0, other);
125 const b = a *% prime_1;
126 return b +% prime_4;
127 }
128
129 pub fn hash(input: []const u8) u64 {
130 var hasher = XxHash64.init(0);
131 hasher.update(input);
132 return hasher.final();
133 }
134};
135
136pub const XxHash32 = struct {
137 acc1: u32,
138 acc2: u32,
139 acc3: u32,
140 acc4: u32,
141
142 seed: u32,
143 buf: [16]u8,
144 buf_len: usize,
145 byte_count: usize,
146
147 const prime_1 = 0x9E3779B1; // 0b10011110001101110111100110110001
148 const prime_2 = 0x85EBCA77; // 0b10000101111010111100101001110111
149 const prime_3 = 0xC2B2AE3D; // 0b11000010101100101010111000111101
150 const prime_4 = 0x27D4EB2F; // 0b00100111110101001110101100101111
151 const prime_5 = 0x165667B1; // 0b00010110010101100110011110110001
152
153 pub fn init(seed: u32) XxHash32 {
154 return XxHash32{
155 .seed = seed,
156 .acc1 = seed +% prime_1 +% prime_2,
157 .acc2 = seed +% prime_2,
158 .acc3 = seed,
159 .acc4 = seed -% prime_1,
160 .buf = undefined,
161 .buf_len = 0,
162 .byte_count = 0,
163 };
164 }
165
166 pub fn update(self: *XxHash32, input: []const u8) void {
167 if (input.len < 16 - self.buf_len) {
168 mem.copy(u8, self.buf[self.buf_len..], input);
169 self.buf_len += input.len;
170 return;
171 }
172
173 var i: usize = 0;
174
175 if (self.buf_len > 0) {
176 i = 16 - self.buf_len;
177 mem.copy(u8, self.buf[self.buf_len..], input[0..i]);
178 self.processStripe(&self.buf);
179 self.buf_len = 0;
180 }
181
182 while (i + 16 <= input.len) : (i += 16) {
183 self.processStripe(input[i..][0..16]);
184 }
185
186 const remaining_bytes = input[i..];
187 mem.copy(u8, &self.buf, remaining_bytes);
188 self.buf_len = remaining_bytes.len;
189 }
190
191 inline fn processStripe(self: *XxHash32, buf: *const [16]u8) void {
192 self.acc1 = round(self.acc1, mem.readIntLittle(u32, buf[0..4]));
193 self.acc2 = round(self.acc2, mem.readIntLittle(u32, buf[4..8]));
194 self.acc3 = round(self.acc3, mem.readIntLittle(u32, buf[8..12]));
195 self.acc4 = round(self.acc4, mem.readIntLittle(u32, buf[12..16]));
196 self.byte_count += 16;
197 }
198
199 inline fn round(acc: u32, lane: u32) u32 {
200 const a = acc +% (lane *% prime_2);
201 const b = rotl(u32, a, 13);
202 return b *% prime_1;
203 }
204
205 pub fn final(self: *XxHash32) u32 {
206 var acc: u32 = undefined;
207
208 if (self.byte_count < 16) {
209 acc = self.seed +% prime_5;
210 } else {
211 acc = rotl(u32, self.acc1, 1) +% rotl(u32, self.acc2, 7) +%
212 rotl(u32, self.acc3, 12) +% rotl(u32, self.acc4, 18);
213 }
214
215 acc = acc +% @intCast(u32, self.byte_count) +% @intCast(u32, self.buf_len);
216
217 var pos: usize = 0;
218 while (pos + 4 <= self.buf_len) : (pos += 4) {
219 const lane = mem.readIntLittle(u32, self.buf[pos..][0..4]);
220 acc +%= lane *% prime_3;
221 acc = rotl(u32, acc, 17) *% prime_4;
222 }
223
224 while (pos < self.buf_len) : (pos += 1) {
225 const lane = @as(u32, self.buf[pos]);
226 acc +%= lane *% prime_5;
227 acc = rotl(u32, acc, 11) *% prime_1;
228 }
229
230 acc ^= acc >> 15;
231 acc *%= prime_2;
232 acc ^= acc >> 13;
233 acc *%= prime_3;
234 acc ^= acc >> 16;
235
236 return acc;
237 }
238
239 pub fn hash(input: []const u8) u32 {
240 var hasher = XxHash32.init(0);
241 hasher.update(input);
242 return hasher.final();
243 }
244};
245
246test "xxhash64" {
247 const hash = XxHash64.hash;
248
249 try expectEqual(hash(""), 0xef46db3751d8e999);
250 try expectEqual(hash("a"), 0xd24ec4f1a98c6e5b);
251 try expectEqual(hash("abc"), 0x44bc2cf5ad770999);
252 try expectEqual(hash("message digest"), 0x066ed728fceeb3be);
253 try expectEqual(hash("abcdefghijklmnopqrstuvwxyz"), 0xcfe1f278fa89835c);
254 try expectEqual(hash("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"), 0xaaa46907d3047814);
255 try expectEqual(hash("12345678901234567890123456789012345678901234567890123456789012345678901234567890"), 0xe04a477f19ee145d);
256}
257
258test "xxhash32" {
259 const hash = XxHash32.hash;
260
261 try expectEqual(hash(""), 0x02cc5d05);
262 try expectEqual(hash("a"), 0x550d7456);
263 try expectEqual(hash("abc"), 0x32d153ff);
264 try expectEqual(hash("message digest"), 0x7c948494);
265 try expectEqual(hash("abcdefghijklmnopqrstuvwxyz"), 0x63a14d5f);
266 try expectEqual(hash("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"), 0x9c285e64);
267 try expectEqual(hash("12345678901234567890123456789012345678901234567890123456789012345678901234567890"), 0x9c05f475);
268}
lib/std/hash_map.zig+2-2
...@@ -508,7 +508,7 @@ pub fn HashMap(...@@ -508,7 +508,7 @@ pub fn HashMap(
508 /// If a new entry needs to be stored, this function asserts there508 /// If a new entry needs to be stored, this function asserts there
509 /// is enough capacity to store it.509 /// is enough capacity to store it.
510 pub fn getOrPutAssumeCapacityAdapted(self: *Self, key: anytype, ctx: anytype) GetOrPutResult {510 pub fn getOrPutAssumeCapacityAdapted(self: *Self, key: anytype, ctx: anytype) GetOrPutResult {
511 return self.unmanaged.getOrPutAssumeCapacityAdapted(self.allocator, key, ctx);511 return self.unmanaged.getOrPutAssumeCapacityAdapted(key, ctx);
512 }512 }
513513
514 pub fn getOrPutValue(self: *Self, key: K, value: V) Allocator.Error!Entry {514 pub fn getOrPutValue(self: *Self, key: K, value: V) Allocator.Error!Entry {
...@@ -2130,7 +2130,7 @@ test "std.hash_map getOrPutAdapted" {...@@ -2130,7 +2130,7 @@ test "std.hash_map getOrPutAdapted" {
2130 try testing.expectEqual(map.count(), keys.len);2130 try testing.expectEqual(map.count(), keys.len);
21312131
2132 inline for (keys, 0..) |key_str, i| {2132 inline for (keys, 0..) |key_str, i| {
2133 const result = try map.getOrPutAdapted(key_str, AdaptedContext{});2133 const result = map.getOrPutAssumeCapacityAdapted(key_str, AdaptedContext{});
2134 try testing.expect(result.found_existing);2134 try testing.expect(result.found_existing);
2135 try testing.expectEqual(real_keys[i], result.key_ptr.*);2135 try testing.expectEqual(real_keys[i], result.key_ptr.*);
2136 try testing.expectEqual(@as(u64, i) * 2, result.value_ptr.*);2136 try testing.expectEqual(@as(u64, i) * 2, result.value_ptr.*);
lib/std/mem.zig+3-3
...@@ -941,21 +941,21 @@ pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool {...@@ -941,21 +941,21 @@ pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool {
941 return true;941 return true;
942}942}
943943
944/// Remove values from the beginning of a slice.944/// Remove a set of values from the beginning of a slice.
945pub fn trimLeft(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {945pub fn trimLeft(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
946 var begin: usize = 0;946 var begin: usize = 0;
947 while (begin < slice.len and indexOfScalar(T, values_to_strip, slice[begin]) != null) : (begin += 1) {}947 while (begin < slice.len and indexOfScalar(T, values_to_strip, slice[begin]) != null) : (begin += 1) {}
948 return slice[begin..];948 return slice[begin..];
949}949}
950950
951/// Remove values from the end of a slice.951/// Remove a set of values from the end of a slice.
952pub fn trimRight(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {952pub fn trimRight(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
953 var end: usize = slice.len;953 var end: usize = slice.len;
954 while (end > 0 and indexOfScalar(T, values_to_strip, slice[end - 1]) != null) : (end -= 1) {}954 while (end > 0 and indexOfScalar(T, values_to_strip, slice[end - 1]) != null) : (end -= 1) {}
955 return slice[0..end];955 return slice[0..end];
956}956}
957957
958/// Remove values from the beginning and end of a slice.958/// Remove a set of values from the beginning and end of a slice.
959pub fn trim(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {959pub fn trim(comptime T: type, slice: []const T, values_to_strip: []const T) []const T {
960 var begin: usize = 0;960 var begin: usize = 0;
961 var end: usize = slice.len;961 var end: usize = slice.len;
lib/std/multi_array_list.zig+3-9
...@@ -433,15 +433,9 @@ pub fn MultiArrayList(comptime S: type) type {...@@ -433,15 +433,9 @@ pub fn MultiArrayList(comptime S: type) type {
433 }433 }
434434
435 fn capacityInBytes(capacity: usize) usize {435 fn capacityInBytes(capacity: usize) usize {
436 if (builtin.zig_backend == .stage2_c) {436 comptime var elem_bytes: usize = 0;
437 var bytes: usize = 0;437 inline for (sizes.bytes) |size| elem_bytes += size;
438 for (sizes.bytes) |size| bytes += size * capacity;438 return elem_bytes * capacity;
439 return bytes;
440 } else {
441 const sizes_vector: @Vector(sizes.bytes.len, usize) = sizes.bytes;
442 const capacity_vector = @splat(sizes.bytes.len, capacity);
443 return @reduce(.Add, capacity_vector * sizes_vector);
444 }
445 }439 }
446440
447 fn allocatedBytes(self: Self) []align(@alignOf(S)) u8 {441 fn allocatedBytes(self: Self) []align(@alignOf(S)) u8 {
lib/std/os.zig+18
...@@ -7056,3 +7056,21 @@ pub fn timerfd_gettime(fd: i32) TimerFdGetError!linux.itimerspec {...@@ -7056,3 +7056,21 @@ pub fn timerfd_gettime(fd: i32) TimerFdGetError!linux.itimerspec {
7056 else => |err| return unexpectedErrno(err),7056 else => |err| return unexpectedErrno(err),
7057 };7057 };
7058}7058}
7059
7060pub const have_sigpipe_support = @hasDecl(@This(), "SIG") and @hasDecl(SIG, "PIPE");
7061
7062fn noopSigHandler(_: c_int) callconv(.C) void {}
7063
7064pub fn maybeIgnoreSigpipe() void {
7065 if (have_sigpipe_support and !std.options.keep_sigpipe) {
7066 const act = Sigaction{
7067 // We set handler to a noop function instead of SIG.IGN so we don't leak our
7068 // signal disposition to a child process
7069 .handler = .{ .handler = noopSigHandler },
7070 .mask = empty_sigset,
7071 .flags = 0,
7072 };
7073 sigaction(SIG.PIPE, &act, null) catch |err|
7074 std.debug.panic("failed to install noop SIGPIPE handler with '{s}'", .{@errorName(err)});
7075 }
7076}
lib/std/os/windows/advapi32.zig+4-4
...@@ -21,10 +21,10 @@ pub extern "advapi32" fn RegOpenKeyExW(...@@ -21,10 +21,10 @@ pub extern "advapi32" fn RegOpenKeyExW(
21pub extern "advapi32" fn RegQueryValueExW(21pub extern "advapi32" fn RegQueryValueExW(
22 hKey: HKEY,22 hKey: HKEY,
23 lpValueName: LPCWSTR,23 lpValueName: LPCWSTR,
24 lpReserved: *DWORD,24 lpReserved: ?*DWORD,
25 lpType: *DWORD,25 lpType: ?*DWORD,
26 lpData: *BYTE,26 lpData: ?*BYTE,
27 lpcbData: *DWORD,27 lpcbData: ?*DWORD,
28) callconv(WINAPI) LSTATUS;28) callconv(WINAPI) LSTATUS;
2929
30// RtlGenRandom is known as SystemFunction036 under advapi3230// RtlGenRandom is known as SystemFunction036 under advapi32
lib/std/sort.zig+44-10
...@@ -6,10 +6,10 @@ const math = std.math;...@@ -6,10 +6,10 @@ const math = std.math;
66
7pub fn binarySearch(7pub fn binarySearch(
8 comptime T: type,8 comptime T: type,
9 key: T,9 key: anytype,
10 items: []const T,10 items: []const T,
11 context: anytype,11 context: anytype,
12 comptime compareFn: fn (context: @TypeOf(context), lhs: T, rhs: T) math.Order,12 comptime compareFn: fn (context: @TypeOf(context), key: @TypeOf(key), mid: T) math.Order,
13) ?usize {13) ?usize {
14 var left: usize = 0;14 var left: usize = 0;
15 var right: usize = items.len;15 var right: usize = items.len;
...@@ -41,35 +41,69 @@ test "binarySearch" {...@@ -41,35 +41,69 @@ test "binarySearch" {
41 };41 };
42 try testing.expectEqual(42 try testing.expectEqual(
43 @as(?usize, null),43 @as(?usize, null),
44 binarySearch(u32, 1, &[_]u32{}, {}, S.order_u32),44 binarySearch(u32, @as(u32, 1), &[_]u32{}, {}, S.order_u32),
45 );45 );
46 try testing.expectEqual(46 try testing.expectEqual(
47 @as(?usize, 0),47 @as(?usize, 0),
48 binarySearch(u32, 1, &[_]u32{1}, {}, S.order_u32),48 binarySearch(u32, @as(u32, 1), &[_]u32{1}, {}, S.order_u32),
49 );49 );
50 try testing.expectEqual(50 try testing.expectEqual(
51 @as(?usize, null),51 @as(?usize, null),
52 binarySearch(u32, 1, &[_]u32{0}, {}, S.order_u32),52 binarySearch(u32, @as(u32, 1), &[_]u32{0}, {}, S.order_u32),
53 );53 );
54 try testing.expectEqual(54 try testing.expectEqual(
55 @as(?usize, null),55 @as(?usize, null),
56 binarySearch(u32, 0, &[_]u32{1}, {}, S.order_u32),56 binarySearch(u32, @as(u32, 0), &[_]u32{1}, {}, S.order_u32),
57 );57 );
58 try testing.expectEqual(58 try testing.expectEqual(
59 @as(?usize, 4),59 @as(?usize, 4),
60 binarySearch(u32, 5, &[_]u32{ 1, 2, 3, 4, 5 }, {}, S.order_u32),60 binarySearch(u32, @as(u32, 5), &[_]u32{ 1, 2, 3, 4, 5 }, {}, S.order_u32),
61 );61 );
62 try testing.expectEqual(62 try testing.expectEqual(
63 @as(?usize, 0),63 @as(?usize, 0),
64 binarySearch(u32, 2, &[_]u32{ 2, 4, 8, 16, 32, 64 }, {}, S.order_u32),64 binarySearch(u32, @as(u32, 2), &[_]u32{ 2, 4, 8, 16, 32, 64 }, {}, S.order_u32),
65 );65 );
66 try testing.expectEqual(66 try testing.expectEqual(
67 @as(?usize, 1),67 @as(?usize, 1),
68 binarySearch(i32, -4, &[_]i32{ -7, -4, 0, 9, 10 }, {}, S.order_i32),68 binarySearch(i32, @as(i32, -4), &[_]i32{ -7, -4, 0, 9, 10 }, {}, S.order_i32),
69 );69 );
70 try testing.expectEqual(70 try testing.expectEqual(
71 @as(?usize, 3),71 @as(?usize, 3),
72 binarySearch(i32, 98, &[_]i32{ -100, -25, 2, 98, 99, 100 }, {}, S.order_i32),72 binarySearch(i32, @as(i32, 98), &[_]i32{ -100, -25, 2, 98, 99, 100 }, {}, S.order_i32),
73 );
74 const R = struct {
75 b: i32,
76 e: i32,
77
78 fn r(b: i32, e: i32) @This() {
79 return @This(){ .b = b, .e = e };
80 }
81
82 fn order(context: void, key: i32, mid: @This()) math.Order {
83 _ = context;
84
85 if (key < mid.b) {
86 return .lt;
87 }
88
89 if (key > mid.e) {
90 return .gt;
91 }
92
93 return .eq;
94 }
95 };
96 try testing.expectEqual(
97 @as(?usize, null),
98 binarySearch(R, @as(i32, -45), &[_]R{ R.r(-100, -50), R.r(-40, -20), R.r(-10, 20), R.r(30, 40) }, {}, R.order),
99 );
100 try testing.expectEqual(
101 @as(?usize, 2),
102 binarySearch(R, @as(i32, 10), &[_]R{ R.r(-100, -50), R.r(-40, -20), R.r(-10, 20), R.r(30, 40) }, {}, R.order),
103 );
104 try testing.expectEqual(
105 @as(?usize, 1),
106 binarySearch(R, @as(i32, -20), &[_]R{ R.r(-100, -50), R.r(-40, -20), R.r(-10, 20), R.r(30, 40) }, {}, R.order),
73 );107 );
74}108}
75109
lib/std/start.zig+1
...@@ -496,6 +496,7 @@ fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 {...@@ -496,6 +496,7 @@ fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 {
496 std.os.environ = envp;496 std.os.environ = envp;
497497
498 std.debug.maybeEnableSegfaultHandler();498 std.debug.maybeEnableSegfaultHandler();
499 std.os.maybeIgnoreSigpipe();
499500
500 return initEventLoopAndCallMain();501 return initEventLoopAndCallMain();
501}502}
lib/std/std.zig+17
...@@ -31,6 +31,7 @@ pub const PackedIntSliceEndian = @import("packed_int_array.zig").PackedIntSliceE...@@ -31,6 +31,7 @@ pub const PackedIntSliceEndian = @import("packed_int_array.zig").PackedIntSliceE
31pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;31pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
32pub const PriorityDequeue = @import("priority_dequeue.zig").PriorityDequeue;32pub const PriorityDequeue = @import("priority_dequeue.zig").PriorityDequeue;
33pub const Progress = @import("Progress.zig");33pub const Progress = @import("Progress.zig");
34pub const RingBuffer = @import("RingBuffer.zig");
34pub const SegmentedList = @import("segmented_list.zig").SegmentedList;35pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
35pub const SemanticVersion = @import("SemanticVersion.zig");36pub const SemanticVersion = @import("SemanticVersion.zig");
36pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList;37pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList;
...@@ -167,6 +168,22 @@ pub const options = struct {...@@ -167,6 +168,22 @@ pub const options = struct {
167 options_override.crypto_always_getrandom168 options_override.crypto_always_getrandom
168 else169 else
169 false;170 false;
171
172 /// By default Zig disables SIGPIPE by setting a "no-op" handler for it. Set this option
173 /// to `true` to prevent that.
174 ///
175 /// Note that we use a "no-op" handler instead of SIG_IGN because it will not be inherited by
176 /// any child process.
177 ///
178 /// SIGPIPE is triggered when a process attempts to write to a broken pipe. By default, SIGPIPE
179 /// will terminate the process instead of exiting. It doesn't trigger the panic handler so in many
180 /// cases it's unclear why the process was terminated. By capturing SIGPIPE instead, functions that
181 /// write to broken pipes will return the EPIPE error (error.BrokenPipe) and the program can handle
182 /// it like any other error.
183 pub const keep_sigpipe: bool = if (@hasDecl(options_override, "keep_sigpipe"))
184 options_override.keep_sigpipe
185 else
186 false;
170};187};
171188
172// This forces the start.zig file to be imported, and the comptime logic inside that189// This forces the start.zig file to be imported, and the comptime logic inside that
lib/std/target/loongarch.zig+1-1
...@@ -89,7 +89,7 @@ pub const all_features = blk: {...@@ -89,7 +89,7 @@ pub const all_features = blk: {
89 .dependencies = featureSet(&[_]Feature{}),89 .dependencies = featureSet(&[_]Feature{}),
90 };90 };
91 const ti = @typeInfo(Feature);91 const ti = @typeInfo(Feature);
92 for (result) |*elem, i| {92 for (&result, 0..) |*elem, i| {
93 elem.index = i;93 elem.index = i;
94 elem.name = ti.Enum.fields[i].name;94 elem.name = ti.Enum.fields[i].name;
95 }95 }
lib/std/target/xtensa.zig+1-1
...@@ -23,7 +23,7 @@ pub const all_features = blk: {...@@ -23,7 +23,7 @@ pub const all_features = blk: {
23 .dependencies = featureSet(&[_]Feature{}),23 .dependencies = featureSet(&[_]Feature{}),
24 };24 };
25 const ti = @typeInfo(Feature);25 const ti = @typeInfo(Feature);
26 for (result) |*elem, i| {26 for (&result, 0..) |*elem, i| {
27 elem.index = i;27 elem.index = i;
28 elem.name = ti.Enum.fields[i].name;28 elem.name = ti.Enum.fields[i].name;
29 }29 }
lib/zig.h+915-787
...@@ -1,8 +1,11 @@...@@ -1,8 +1,11 @@
1#undef linux1#undef linux
22
3#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
3#define __STDC_WANT_IEC_60559_TYPES_EXT__4#define __STDC_WANT_IEC_60559_TYPES_EXT__
5#endif
4#include <float.h>6#include <float.h>
5#include <limits.h>7#include <limits.h>
8#include <stdarg.h>
6#include <stddef.h>9#include <stddef.h>
7#include <stdint.h>10#include <stdint.h>
811
...@@ -75,6 +78,32 @@ typedef char bool;...@@ -75,6 +78,32 @@ typedef char bool;
75#define zig_cold78#define zig_cold
76#endif79#endif
7780
81#if zig_has_attribute(flatten)
82#define zig_maybe_flatten __attribute__((flatten))
83#else
84#define zig_maybe_flatten
85#endif
86
87#if zig_has_attribute(noinline)
88#define zig_never_inline __attribute__((noinline)) zig_maybe_flatten
89#elif defined(_MSC_VER)
90#define zig_never_inline __declspec(noinline) zig_maybe_flatten
91#else
92#define zig_never_inline zig_never_inline_unavailable
93#endif
94
95#if zig_has_attribute(not_tail_called)
96#define zig_never_tail __attribute__((not_tail_called)) zig_never_inline
97#else
98#define zig_never_tail zig_never_tail_unavailable
99#endif
100
101#if zig_has_attribute(always_inline)
102#define zig_always_tail __attribute__((musttail))
103#else
104#define zig_always_tail zig_always_tail_unavailable
105#endif
106
78#if __STDC_VERSION__ >= 199901L107#if __STDC_VERSION__ >= 199901L
79#define zig_restrict restrict108#define zig_restrict restrict
80#elif defined(__GNUC__)109#elif defined(__GNUC__)
...@@ -286,701 +315,802 @@ typedef char bool;...@@ -286,701 +315,802 @@ typedef char bool;
286#endif315#endif
287316
288#if __STDC_VERSION__ >= 201112L317#if __STDC_VERSION__ >= 201112L
289#define zig_noreturn _Noreturn void318#define zig_noreturn _Noreturn
290#elif zig_has_attribute(noreturn) || defined(zig_gnuc)319#elif zig_has_attribute(noreturn) || defined(zig_gnuc)
291#define zig_noreturn __attribute__((noreturn)) void320#define zig_noreturn __attribute__((noreturn))
292#elif _MSC_VER321#elif _MSC_VER
293#define zig_noreturn __declspec(noreturn) void322#define zig_noreturn __declspec(noreturn)
294#else323#else
295#define zig_noreturn void324#define zig_noreturn
296#endif325#endif
297326
298#define zig_bitSizeOf(T) (CHAR_BIT * sizeof(T))327#define zig_bitSizeOf(T) (CHAR_BIT * sizeof(T))
299328
300typedef uintptr_t zig_usize;329#define zig_compiler_rt_abbrev_uint32_t si
301typedef intptr_t zig_isize;330#define zig_compiler_rt_abbrev_int32_t si
302typedef signed short int zig_c_short;331#define zig_compiler_rt_abbrev_uint64_t di
303typedef unsigned short int zig_c_ushort;332#define zig_compiler_rt_abbrev_int64_t di
304typedef signed int zig_c_int;333#define zig_compiler_rt_abbrev_zig_u128 ti
305typedef unsigned int zig_c_uint;334#define zig_compiler_rt_abbrev_zig_i128 ti
306typedef signed long int zig_c_long;335#define zig_compiler_rt_abbrev_zig_f16 hf
307typedef unsigned long int zig_c_ulong;336#define zig_compiler_rt_abbrev_zig_f32 sf
308typedef signed long long int zig_c_longlong;337#define zig_compiler_rt_abbrev_zig_f64 df
309typedef unsigned long long int zig_c_ulonglong;338#define zig_compiler_rt_abbrev_zig_f80 xf
310339#define zig_compiler_rt_abbrev_zig_f128 tf
311typedef uint8_t zig_u8;340
312typedef int8_t zig_i8;341zig_extern void *memcpy (void *zig_restrict, void const *zig_restrict, size_t);
313typedef uint16_t zig_u16;342zig_extern void *memset (void *, int, size_t);
314typedef int16_t zig_i16;343
315typedef uint32_t zig_u32;344/* ===================== 8/16/32/64-bit Integer Support ===================== */
316typedef int32_t zig_i32;345
317typedef uint64_t zig_u64;346#if __STDC_VERSION__ >= 199901L || _MSC_VER
318typedef int64_t zig_i64;347#include <stdint.h>
319348#else
320#define zig_as_u8(val) UINT8_C(val)349
321#define zig_as_i8(val) INT8_C(val)350#if SCHAR_MIN == ~0x7F && SCHAR_MAX == 0x7F && UCHAR_MAX == 0xFF
322#define zig_as_u16(val) UINT16_C(val)351typedef unsigned char uint8_t;
323#define zig_as_i16(val) INT16_C(val)352typedef signed char int8_t;
324#define zig_as_u32(val) UINT32_C(val)353#define INT8_C(c) c
325#define zig_as_i32(val) INT32_C(val)354#define UINT8_C(c) c##U
326#define zig_as_u64(val) UINT64_C(val)355#elif SHRT_MIN == ~0x7F && SHRT_MAX == 0x7F && USHRT_MAX == 0xFF
327#define zig_as_i64(val) INT64_C(val)356typedef unsigned short uint8_t;
328357typedef signed short int8_t;
329#define zig_minInt_u8 zig_as_u8(0)358#define INT8_C(c) c
330#define zig_maxInt_u8 UINT8_MAX359#define UINT8_C(c) c##U
360#elif INT_MIN == ~0x7F && INT_MAX == 0x7F && UINT_MAX == 0xFF
361typedef unsigned int uint8_t;
362typedef signed int int8_t;
363#define INT8_C(c) c
364#define UINT8_C(c) c##U
365#elif LONG_MIN == ~0x7F && LONG_MAX == 0x7F && ULONG_MAX == 0xFF
366typedef unsigned long uint8_t;
367typedef signed long int8_t;
368#define INT8_C(c) c##L
369#define UINT8_C(c) c##LU
370#elif LLONG_MIN == ~0x7F && LLONG_MAX == 0x7F && ULLONG_MAX == 0xFF
371typedef unsigned long long uint8_t;
372typedef signed long long int8_t;
373#define INT8_C(c) c##LL
374#define UINT8_C(c) c##LLU
375#endif
376#define INT8_MIN (~INT8_C(0x7F))
377#define INT8_MAX ( INT8_C(0x7F))
378#define UINT8_MAX ( INT8_C(0xFF))
379
380#if SCHAR_MIN == ~0x7FFF && SCHAR_MAX == 0x7FFF && UCHAR_MAX == 0xFFFF
381typedef unsigned char uint16_t;
382typedef signed char int16_t;
383#define INT16_C(c) c
384#define UINT16_C(c) c##U
385#elif SHRT_MIN == ~0x7FFF && SHRT_MAX == 0x7FFF && USHRT_MAX == 0xFFFF
386typedef unsigned short uint16_t;
387typedef signed short int16_t;
388#define INT16_C(c) c
389#define UINT16_C(c) c##U
390#elif INT_MIN == ~0x7FFF && INT_MAX == 0x7FFF && UINT_MAX == 0xFFFF
391typedef unsigned int uint16_t;
392typedef signed int int16_t;
393#define INT16_C(c) c
394#define UINT16_C(c) c##U
395#elif LONG_MIN == ~0x7FFF && LONG_MAX == 0x7FFF && ULONG_MAX == 0xFFFF
396typedef unsigned long uint16_t;
397typedef signed long int16_t;
398#define INT16_C(c) c##L
399#define UINT16_C(c) c##LU
400#elif LLONG_MIN == ~0x7FFF && LLONG_MAX == 0x7FFF && ULLONG_MAX == 0xFFFF
401typedef unsigned long long uint16_t;
402typedef signed long long int16_t;
403#define INT16_C(c) c##LL
404#define UINT16_C(c) c##LLU
405#endif
406#define INT16_MIN (~INT16_C(0x7FFF))
407#define INT16_MAX ( INT16_C(0x7FFF))
408#define UINT16_MAX ( INT16_C(0xFFFF))
409
410#if SCHAR_MIN == ~0x7FFFFFFF && SCHAR_MAX == 0x7FFFFFFF && UCHAR_MAX == 0xFFFFFFFF
411typedef unsigned char uint32_t;
412typedef signed char int32_t;
413#define INT32_C(c) c
414#define UINT32_C(c) c##U
415#elif SHRT_MIN == ~0x7FFFFFFF && SHRT_MAX == 0x7FFFFFFF && USHRT_MAX == 0xFFFFFFFF
416typedef unsigned short uint32_t;
417typedef signed short int32_t;
418#define INT32_C(c) c
419#define UINT32_C(c) c##U
420#elif INT_MIN == ~0x7FFFFFFF && INT_MAX == 0x7FFFFFFF && UINT_MAX == 0xFFFFFFFF
421typedef unsigned int uint32_t;
422typedef signed int int32_t;
423#define INT32_C(c) c
424#define UINT32_C(c) c##U
425#elif LONG_MIN == ~0x7FFFFFFF && LONG_MAX == 0x7FFFFFFF && ULONG_MAX == 0xFFFFFFFF
426typedef unsigned long uint32_t;
427typedef signed long int32_t;
428#define INT32_C(c) c##L
429#define UINT32_C(c) c##LU
430#elif LLONG_MIN == ~0x7FFFFFFF && LLONG_MAX == 0x7FFFFFFF && ULLONG_MAX == 0xFFFFFFFF
431typedef unsigned long long uint32_t;
432typedef signed long long int32_t;
433#define INT32_C(c) c##LL
434#define UINT32_C(c) c##LLU
435#endif
436#define INT32_MIN (~INT32_C(0x7FFFFFFF))
437#define INT32_MAX ( INT32_C(0x7FFFFFFF))
438#define UINT32_MAX ( INT32_C(0xFFFFFFFF))
439
440#if SCHAR_MIN == ~0x7FFFFFFFFFFFFFFF && SCHAR_MAX == 0x7FFFFFFFFFFFFFFF && UCHAR_MAX == 0xFFFFFFFFFFFFFFFF
441typedef unsigned char uint64_t;
442typedef signed char int64_t;
443#define INT64_C(c) c
444#define UINT64_C(c) c##U
445#elif SHRT_MIN == ~0x7FFFFFFFFFFFFFFF && SHRT_MAX == 0x7FFFFFFFFFFFFFFF && USHRT_MAX == 0xFFFFFFFFFFFFFFFF
446typedef unsigned short uint64_t;
447typedef signed short int64_t;
448#define INT64_C(c) c
449#define UINT64_C(c) c##U
450#elif INT_MIN == ~0x7FFFFFFFFFFFFFFF && INT_MAX == 0x7FFFFFFFFFFFFFFF && UINT_MAX == 0xFFFFFFFFFFFFFFFF
451typedef unsigned int uint64_t;
452typedef signed int int64_t;
453#define INT64_C(c) c
454#define UINT64_C(c) c##U
455#elif LONG_MIN == ~0x7FFFFFFFFFFFFFFF && LONG_MAX == 0x7FFFFFFFFFFFFFFF && ULONG_MAX == 0xFFFFFFFFFFFFFFFF
456typedef unsigned long uint64_t;
457typedef signed long int64_t;
458#define INT64_C(c) c##L
459#define UINT64_C(c) c##LU
460#elif LLONG_MIN == ~0x7FFFFFFFFFFFFFFF && LLONG_MAX == 0x7FFFFFFFFFFFFFFF && ULLONG_MAX == 0xFFFFFFFFFFFFFFFF
461typedef unsigned long long uint64_t;
462typedef signed long long int64_t;
463#define INT64_C(c) c##LL
464#define UINT64_C(c) c##LLU
465#endif
466#define INT64_MIN (~INT64_C(0x7FFFFFFFFFFFFFFF))
467#define INT64_MAX ( INT64_C(0x7FFFFFFFFFFFFFFF))
468#define UINT64_MAX ( INT64_C(0xFFFFFFFFFFFFFFFF))
469
470typedef size_t uintptr_t;
471typedef ptrdiff_t intptr_t;
472
473#endif
474
331#define zig_minInt_i8 INT8_MIN475#define zig_minInt_i8 INT8_MIN
332#define zig_maxInt_i8 INT8_MAX476#define zig_maxInt_i8 INT8_MAX
333#define zig_minInt_u16 zig_as_u16(0)477#define zig_minInt_u8 UINT8_C(0)
334#define zig_maxInt_u16 UINT16_MAX478#define zig_maxInt_u8 UINT8_MAX
335#define zig_minInt_i16 INT16_MIN479#define zig_minInt_i16 INT16_MIN
336#define zig_maxInt_i16 INT16_MAX480#define zig_maxInt_i16 INT16_MAX
337#define zig_minInt_u32 zig_as_u32(0)481#define zig_minInt_u16 UINT16_C(0)
338#define zig_maxInt_u32 UINT32_MAX482#define zig_maxInt_u16 UINT16_MAX
339#define zig_minInt_i32 INT32_MIN483#define zig_minInt_i32 INT32_MIN
340#define zig_maxInt_i32 INT32_MAX484#define zig_maxInt_i32 INT32_MAX
341#define zig_minInt_u64 zig_as_u64(0)485#define zig_minInt_u32 UINT32_C(0)
342#define zig_maxInt_u64 UINT64_MAX486#define zig_maxInt_u32 UINT32_MAX
343#define zig_minInt_i64 INT64_MIN487#define zig_minInt_i64 INT64_MIN
344#define zig_maxInt_i64 INT64_MAX488#define zig_maxInt_i64 INT64_MAX
489#define zig_minInt_u64 UINT64_C(0)
490#define zig_maxInt_u64 UINT64_MAX
345491
346#define zig_compiler_rt_abbrev_u32 si492#define zig_intLimit(s, w, limit, bits) zig_shr_##s##w(zig_##limit##Int_##s##w, w - (bits))
347#define zig_compiler_rt_abbrev_i32 si493#define zig_minInt_i(w, bits) zig_intLimit(i, w, min, bits)
348#define zig_compiler_rt_abbrev_u64 di494#define zig_maxInt_i(w, bits) zig_intLimit(i, w, max, bits)
349#define zig_compiler_rt_abbrev_i64 di495#define zig_minInt_u(w, bits) zig_intLimit(u, w, min, bits)
350#define zig_compiler_rt_abbrev_u128 ti496#define zig_maxInt_u(w, bits) zig_intLimit(u, w, max, bits)
351#define zig_compiler_rt_abbrev_i128 ti
352#define zig_compiler_rt_abbrev_f16 hf
353#define zig_compiler_rt_abbrev_f32 sf
354#define zig_compiler_rt_abbrev_f64 df
355#define zig_compiler_rt_abbrev_f80 xf
356#define zig_compiler_rt_abbrev_f128 tf
357
358zig_extern void *memcpy (void *zig_restrict, void const *zig_restrict, zig_usize);
359zig_extern void *memset (void *, int, zig_usize);
360
361/* ==================== 8/16/32/64-bit Integer Routines ===================== */
362
363#define zig_maxInt(Type, bits) zig_shr_##Type(zig_maxInt_##Type, (zig_bitSizeOf(zig_##Type) - bits))
364#define zig_expand_maxInt(Type, bits) zig_maxInt(Type, bits)
365#define zig_minInt(Type, bits) zig_not_##Type(zig_maxInt(Type, bits), bits)
366#define zig_expand_minInt(Type, bits) zig_minInt(Type, bits)
367497
368#define zig_int_operator(Type, RhsType, operation, operator) \498#define zig_int_operator(Type, RhsType, operation, operator) \
369 static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##RhsType rhs) { \499 static inline Type zig_##operation(Type lhs, RhsType rhs) { \
370 return lhs operator rhs; \500 return lhs operator rhs; \
371 }501 }
372#define zig_int_basic_operator(Type, operation, operator) \502#define zig_int_basic_operator(Type, operation, operator) \
373 zig_int_operator(Type, Type, operation, operator)503 zig_int_operator(Type, Type, operation, operator)
374#define zig_int_shift_operator(Type, operation, operator) \504#define zig_int_shift_operator(Type, operation, operator) \
375 zig_int_operator(Type, u8, operation, operator)505 zig_int_operator(Type, uint8_t, operation, operator)
376#define zig_int_helpers(w) \506#define zig_int_helpers(w) \
377 zig_int_basic_operator(u##w, and, &) \507 zig_int_basic_operator(uint##w##_t, and_u##w, &) \
378 zig_int_basic_operator(i##w, and, &) \508 zig_int_basic_operator( int##w##_t, and_i##w, &) \
379 zig_int_basic_operator(u##w, or, |) \509 zig_int_basic_operator(uint##w##_t, or_u##w, |) \
380 zig_int_basic_operator(i##w, or, |) \510 zig_int_basic_operator( int##w##_t, or_i##w, |) \
381 zig_int_basic_operator(u##w, xor, ^) \511 zig_int_basic_operator(uint##w##_t, xor_u##w, ^) \
382 zig_int_basic_operator(i##w, xor, ^) \512 zig_int_basic_operator( int##w##_t, xor_i##w, ^) \
383 zig_int_shift_operator(u##w, shl, <<) \513 zig_int_shift_operator(uint##w##_t, shl_u##w, <<) \
384 zig_int_shift_operator(i##w, shl, <<) \514 zig_int_shift_operator( int##w##_t, shl_i##w, <<) \
385 zig_int_shift_operator(u##w, shr, >>) \515 zig_int_shift_operator(uint##w##_t, shr_u##w, >>) \
386\516\
387 static inline zig_i##w zig_shr_i##w(zig_i##w lhs, zig_u8 rhs) { \517 static inline int##w##_t zig_shr_i##w(int##w##_t lhs, uint8_t rhs) { \
388 zig_i##w sign_mask = lhs < zig_as_i##w(0) ? -zig_as_i##w(1) : zig_as_i##w(0); \518 int##w##_t sign_mask = lhs < INT##w##_C(0) ? -INT##w##_C(1) : INT##w##_C(0); \
389 return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; \519 return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; \
390 } \520 } \
391\521\
392 static inline zig_u##w zig_not_u##w(zig_u##w val, zig_u8 bits) { \522 static inline uint##w##_t zig_not_u##w(uint##w##_t val, uint8_t bits) { \
393 return val ^ zig_maxInt(u##w, bits); \523 return val ^ zig_maxInt_u(w, bits); \
394 } \524 } \
395\525\
396 static inline zig_i##w zig_not_i##w(zig_i##w val, zig_u8 bits) { \526 static inline int##w##_t zig_not_i##w(int##w##_t val, uint8_t bits) { \
397 (void)bits; \527 (void)bits; \
398 return ~val; \528 return ~val; \
399 } \529 } \
400\530\
401 static inline zig_u##w zig_wrap_u##w(zig_u##w val, zig_u8 bits) { \531 static inline uint##w##_t zig_wrap_u##w(uint##w##_t val, uint8_t bits) { \
402 return val & zig_maxInt(u##w, bits); \532 return val & zig_maxInt_u(w, bits); \
403 } \533 } \
404\534\
405 static inline zig_i##w zig_wrap_i##w(zig_i##w val, zig_u8 bits) { \535 static inline int##w##_t zig_wrap_i##w(int##w##_t val, uint8_t bits) { \
406 return (val & zig_as_u##w(1) << (bits - zig_as_u8(1))) != 0 \536 return (val & UINT##w##_C(1) << (bits - UINT8_C(1))) != 0 \
407 ? val | zig_minInt(i##w, bits) : val & zig_maxInt(i##w, bits); \537 ? val | zig_minInt_i(w, bits) : val & zig_maxInt_i(w, bits); \
408 } \538 } \
409\539\
410 zig_int_basic_operator(u##w, div_floor, /) \540 zig_int_basic_operator(uint##w##_t, div_floor_u##w, /) \
411\541\
412 static inline zig_i##w zig_div_floor_i##w(zig_i##w lhs, zig_i##w rhs) { \542 static inline int##w##_t zig_div_floor_i##w(int##w##_t lhs, int##w##_t rhs) { \
413 return lhs / rhs - (((lhs ^ rhs) & (lhs % rhs)) < zig_as_i##w(0)); \543 return lhs / rhs - (((lhs ^ rhs) & (lhs % rhs)) < INT##w##_C(0)); \
414 } \544 } \
415\545\
416 zig_int_basic_operator(u##w, mod, %) \546 zig_int_basic_operator(uint##w##_t, mod_u##w, %) \
417\547\
418 static inline zig_i##w zig_mod_i##w(zig_i##w lhs, zig_i##w rhs) { \548 static inline int##w##_t zig_mod_i##w(int##w##_t lhs, int##w##_t rhs) { \
419 zig_i##w rem = lhs % rhs; \549 int##w##_t rem = lhs % rhs; \
420 return rem + (((lhs ^ rhs) & rem) < zig_as_i##w(0) ? rhs : zig_as_i##w(0)); \550 return rem + (((lhs ^ rhs) & rem) < INT##w##_C(0) ? rhs : INT##w##_C(0)); \
421 } \551 } \
422\552\
423 static inline zig_u##w zig_shlw_u##w(zig_u##w lhs, zig_u8 rhs, zig_u8 bits) { \553 static inline uint##w##_t zig_shlw_u##w(uint##w##_t lhs, uint8_t rhs, uint8_t bits) { \
424 return zig_wrap_u##w(zig_shl_u##w(lhs, rhs), bits); \554 return zig_wrap_u##w(zig_shl_u##w(lhs, rhs), bits); \
425 } \555 } \
426\556\
427 static inline zig_i##w zig_shlw_i##w(zig_i##w lhs, zig_u8 rhs, zig_u8 bits) { \557 static inline int##w##_t zig_shlw_i##w(int##w##_t lhs, uint8_t rhs, uint8_t bits) { \
428 return zig_wrap_i##w((zig_i##w)zig_shl_u##w((zig_u##w)lhs, (zig_u##w)rhs), bits); \558 return zig_wrap_i##w((int##w##_t)zig_shl_u##w((uint##w##_t)lhs, (uint##w##_t)rhs), bits); \
429 } \559 } \
430\560\
431 static inline zig_u##w zig_addw_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \561 static inline uint##w##_t zig_addw_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \
432 return zig_wrap_u##w(lhs + rhs, bits); \562 return zig_wrap_u##w(lhs + rhs, bits); \
433 } \563 } \
434\564\
435 static inline zig_i##w zig_addw_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \565 static inline int##w##_t zig_addw_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \
436 return zig_wrap_i##w((zig_i##w)((zig_u##w)lhs + (zig_u##w)rhs), bits); \566 return zig_wrap_i##w((int##w##_t)((uint##w##_t)lhs + (uint##w##_t)rhs), bits); \
437 } \567 } \
438\568\
439 static inline zig_u##w zig_subw_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \569 static inline uint##w##_t zig_subw_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \
440 return zig_wrap_u##w(lhs - rhs, bits); \570 return zig_wrap_u##w(lhs - rhs, bits); \
441 } \571 } \
442\572\
443 static inline zig_i##w zig_subw_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \573 static inline int##w##_t zig_subw_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \
444 return zig_wrap_i##w((zig_i##w)((zig_u##w)lhs - (zig_u##w)rhs), bits); \574 return zig_wrap_i##w((int##w##_t)((uint##w##_t)lhs - (uint##w##_t)rhs), bits); \
445 } \575 } \
446\576\
447 static inline zig_u##w zig_mulw_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \577 static inline uint##w##_t zig_mulw_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \
448 return zig_wrap_u##w(lhs * rhs, bits); \578 return zig_wrap_u##w(lhs * rhs, bits); \
449 } \579 } \
450\580\
451 static inline zig_i##w zig_mulw_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \581 static inline int##w##_t zig_mulw_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \
452 return zig_wrap_i##w((zig_i##w)((zig_u##w)lhs * (zig_u##w)rhs), bits); \582 return zig_wrap_i##w((int##w##_t)((uint##w##_t)lhs * (uint##w##_t)rhs), bits); \
453 }583 }
454zig_int_helpers(8)584zig_int_helpers(8)
455zig_int_helpers(16)585zig_int_helpers(16)
456zig_int_helpers(32)586zig_int_helpers(32)
457zig_int_helpers(64)587zig_int_helpers(64)
458588
459static inline bool zig_addo_u32(zig_u32 *res, zig_u32 lhs, zig_u32 rhs, zig_u8 bits) {589static inline bool zig_addo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8_t bits) {
460#if zig_has_builtin(add_overflow) || defined(zig_gnuc)590#if zig_has_builtin(add_overflow) || defined(zig_gnuc)
461 zig_u32 full_res;591 uint32_t full_res;
462 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);592 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);
463 *res = zig_wrap_u32(full_res, bits);593 *res = zig_wrap_u32(full_res, bits);
464 return overflow || full_res < zig_minInt(u32, bits) || full_res > zig_maxInt(u32, bits);594 return overflow || full_res < zig_minInt_u(32, bits) || full_res > zig_maxInt_u(32, bits);
465#else595#else
466 *res = zig_addw_u32(lhs, rhs, bits);596 *res = zig_addw_u32(lhs, rhs, bits);
467 return *res < lhs;597 return *res < lhs;
468#endif598#endif
469}599}
470600
471static inline void zig_vaddo_u32(zig_u8 *ov, zig_u32 *res, int n,601static inline void zig_vaddo_u32(uint8_t *ov, uint32_t *res, int n,
472 const zig_u32 *lhs, const zig_u32 *rhs, zig_u8 bits)602 const uint32_t *lhs, const uint32_t *rhs, uint8_t bits)
473{603{
474 for (int i = 0; i < n; ++i) ov[i] = zig_addo_u32(&res[i], lhs[i], rhs[i], bits);604 for (int i = 0; i < n; ++i) ov[i] = zig_addo_u32(&res[i], lhs[i], rhs[i], bits);
475}605}
476606
477zig_extern zig_i32 __addosi4(zig_i32 lhs, zig_i32 rhs, zig_c_int *overflow);607zig_extern int32_t __addosi4(int32_t lhs, int32_t rhs, int *overflow);
478static inline bool zig_addo_i32(zig_i32 *res, zig_i32 lhs, zig_i32 rhs, zig_u8 bits) {608static inline bool zig_addo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t bits) {
479#if zig_has_builtin(add_overflow) || defined(zig_gnuc)609#if zig_has_builtin(add_overflow) || defined(zig_gnuc)
480 zig_i32 full_res;610 int32_t full_res;
481 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);611 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);
482#else612#else
483 zig_c_int overflow_int;613 int overflow_int;
484 zig_i32 full_res = __addosi4(lhs, rhs, &overflow_int);614 int32_t full_res = __addosi4(lhs, rhs, &overflow_int);
485 bool overflow = overflow_int != 0;615 bool overflow = overflow_int != 0;
486#endif616#endif
487 *res = zig_wrap_i32(full_res, bits);617 *res = zig_wrap_i32(full_res, bits);
488 return overflow || full_res < zig_minInt(i32, bits) || full_res > zig_maxInt(i32, bits);618 return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits);
489}619}
490620
491static inline void zig_vaddo_i32(zig_u8 *ov, zig_i32 *res, int n,621static inline void zig_vaddo_i32(uint8_t *ov, int32_t *res, int n,
492 const zig_i32 *lhs, const zig_i32 *rhs, zig_u8 bits)622 const int32_t *lhs, const int32_t *rhs, uint8_t bits)
493{623{
494 for (int i = 0; i < n; ++i) ov[i] = zig_addo_i32(&res[i], lhs[i], rhs[i], bits);624 for (int i = 0; i < n; ++i) ov[i] = zig_addo_i32(&res[i], lhs[i], rhs[i], bits);
495}625}
496626
497static inline bool zig_addo_u64(zig_u64 *res, zig_u64 lhs, zig_u64 rhs, zig_u8 bits) {627static inline bool zig_addo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8_t bits) {
498#if zig_has_builtin(add_overflow) || defined(zig_gnuc)628#if zig_has_builtin(add_overflow) || defined(zig_gnuc)
499 zig_u64 full_res;629 uint64_t full_res;
500 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);630 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);
501 *res = zig_wrap_u64(full_res, bits);631 *res = zig_wrap_u64(full_res, bits);
502 return overflow || full_res < zig_minInt(u64, bits) || full_res > zig_maxInt(u64, bits);632 return overflow || full_res < zig_minInt_u(64, bits) || full_res > zig_maxInt_u(64, bits);
503#else633#else
504 *res = zig_addw_u64(lhs, rhs, bits);634 *res = zig_addw_u64(lhs, rhs, bits);
505 return *res < lhs;635 return *res < lhs;
506#endif636#endif
507}637}
508638
509static inline void zig_vaddo_u64(zig_u8 *ov, zig_u64 *res, int n,639static inline void zig_vaddo_u64(uint8_t *ov, uint64_t *res, int n,
510 const zig_u64 *lhs, const zig_u64 *rhs, zig_u8 bits)640 const uint64_t *lhs, const uint64_t *rhs, uint8_t bits)
511{641{
512 for (int i = 0; i < n; ++i) ov[i] = zig_addo_u64(&res[i], lhs[i], rhs[i], bits);642 for (int i = 0; i < n; ++i) ov[i] = zig_addo_u64(&res[i], lhs[i], rhs[i], bits);
513}643}
514644
515zig_extern zig_i64 __addodi4(zig_i64 lhs, zig_i64 rhs, zig_c_int *overflow);645zig_extern int64_t __addodi4(int64_t lhs, int64_t rhs, int *overflow);
516static inline bool zig_addo_i64(zig_i64 *res, zig_i64 lhs, zig_i64 rhs, zig_u8 bits) {646static inline bool zig_addo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t bits) {
517#if zig_has_builtin(add_overflow) || defined(zig_gnuc)647#if zig_has_builtin(add_overflow) || defined(zig_gnuc)
518 zig_i64 full_res;648 int64_t full_res;
519 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);649 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);
520#else650#else
521 zig_c_int overflow_int;651 int overflow_int;
522 zig_i64 full_res = __addodi4(lhs, rhs, &overflow_int);652 int64_t full_res = __addodi4(lhs, rhs, &overflow_int);
523 bool overflow = overflow_int != 0;653 bool overflow = overflow_int != 0;
524#endif654#endif
525 *res = zig_wrap_i64(full_res, bits);655 *res = zig_wrap_i64(full_res, bits);
526 return overflow || full_res < zig_minInt(i64, bits) || full_res > zig_maxInt(i64, bits);656 return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits);
527}657}
528658
529static inline void zig_vaddo_i64(zig_u8 *ov, zig_i64 *res, int n,659static inline void zig_vaddo_i64(uint8_t *ov, int64_t *res, int n,
530 const zig_i64 *lhs, const zig_i64 *rhs, zig_u8 bits)660 const int64_t *lhs, const int64_t *rhs, uint8_t bits)
531{661{
532 for (int i = 0; i < n; ++i) ov[i] = zig_addo_i64(&res[i], lhs[i], rhs[i], bits);662 for (int i = 0; i < n; ++i) ov[i] = zig_addo_i64(&res[i], lhs[i], rhs[i], bits);
533}663}
534664
535static inline bool zig_addo_u8(zig_u8 *res, zig_u8 lhs, zig_u8 rhs, zig_u8 bits) {665static inline bool zig_addo_u8(uint8_t *res, uint8_t lhs, uint8_t rhs, uint8_t bits) {
536#if zig_has_builtin(add_overflow) || defined(zig_gnuc)666#if zig_has_builtin(add_overflow) || defined(zig_gnuc)
537 zig_u8 full_res;667 uint8_t full_res;
538 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);668 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);
539 *res = zig_wrap_u8(full_res, bits);669 *res = zig_wrap_u8(full_res, bits);
540 return overflow || full_res < zig_minInt(u8, bits) || full_res > zig_maxInt(u8, bits);670 return overflow || full_res < zig_minInt_u(8, bits) || full_res > zig_maxInt_u(8, bits);
541#else671#else
542 zig_u32 full_res;672 uint32_t full_res;
543 bool overflow = zig_addo_u32(&full_res, lhs, rhs, bits);673 bool overflow = zig_addo_u32(&full_res, lhs, rhs, bits);
544 *res = (zig_u8)full_res;674 *res = (uint8_t)full_res;
545 return overflow;675 return overflow;
546#endif676#endif
547}677}
548678
549static inline void zig_vaddo_u8(zig_u8 *ov, zig_u8 *res, int n,679static inline void zig_vaddo_u8(uint8_t *ov, uint8_t *res, int n,
550 const zig_u8 *lhs, const zig_u8 *rhs, zig_u8 bits)680 const uint8_t *lhs, const uint8_t *rhs, uint8_t bits)
551{681{
552 for (int i = 0; i < n; ++i) ov[i] = zig_addo_u8(&res[i], lhs[i], rhs[i], bits);682 for (int i = 0; i < n; ++i) ov[i] = zig_addo_u8(&res[i], lhs[i], rhs[i], bits);
553}683}
554684
555static inline bool zig_addo_i8(zig_i8 *res, zig_i8 lhs, zig_i8 rhs, zig_u8 bits) {685static inline bool zig_addo_i8(int8_t *res, int8_t lhs, int8_t rhs, uint8_t bits) {
556#if zig_has_builtin(add_overflow) || defined(zig_gnuc)686#if zig_has_builtin(add_overflow) || defined(zig_gnuc)
557 zig_i8 full_res;687 int8_t full_res;
558 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);688 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);
559 *res = zig_wrap_i8(full_res, bits);689 *res = zig_wrap_i8(full_res, bits);
560 return overflow || full_res < zig_minInt(i8, bits) || full_res > zig_maxInt(i8, bits);690 return overflow || full_res < zig_minInt_i(8, bits) || full_res > zig_maxInt_i(8, bits);
561#else691#else
562 zig_i32 full_res;692 int32_t full_res;
563 bool overflow = zig_addo_i32(&full_res, lhs, rhs, bits);693 bool overflow = zig_addo_i32(&full_res, lhs, rhs, bits);
564 *res = (zig_i8)full_res;694 *res = (int8_t)full_res;
565 return overflow;695 return overflow;
566#endif696#endif
567}697}
568698
569static inline void zig_vaddo_i8(zig_u8 *ov, zig_i8 *res, int n,699static inline void zig_vaddo_i8(uint8_t *ov, int8_t *res, int n,
570 const zig_i8 *lhs, const zig_i8 *rhs, zig_u8 bits)700 const int8_t *lhs, const int8_t *rhs, uint8_t bits)
571{701{
572 for (int i = 0; i < n; ++i) ov[i] = zig_addo_i8(&res[i], lhs[i], rhs[i], bits);702 for (int i = 0; i < n; ++i) ov[i] = zig_addo_i8(&res[i], lhs[i], rhs[i], bits);
573}703}
574704
575static inline bool zig_addo_u16(zig_u16 *res, zig_u16 lhs, zig_u16 rhs, zig_u8 bits) {705static inline bool zig_addo_u16(uint16_t *res, uint16_t lhs, uint16_t rhs, uint8_t bits) {
576#if zig_has_builtin(add_overflow) || defined(zig_gnuc)706#if zig_has_builtin(add_overflow) || defined(zig_gnuc)
577 zig_u16 full_res;707 uint16_t full_res;
578 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);708 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);
579 *res = zig_wrap_u16(full_res, bits);709 *res = zig_wrap_u16(full_res, bits);
580 return overflow || full_res < zig_minInt(u16, bits) || full_res > zig_maxInt(u16, bits);710 return overflow || full_res < zig_minInt_u(16, bits) || full_res > zig_maxInt_u(16, bits);
581#else711#else
582 zig_u32 full_res;712 uint32_t full_res;
583 bool overflow = zig_addo_u32(&full_res, lhs, rhs, bits);713 bool overflow = zig_addo_u32(&full_res, lhs, rhs, bits);
584 *res = (zig_u16)full_res;714 *res = (uint16_t)full_res;
585 return overflow;715 return overflow;
586#endif716#endif
587}717}
588718
589static inline void zig_vaddo_u16(zig_u8 *ov, zig_u16 *res, int n,719static inline void zig_vaddo_u16(uint8_t *ov, uint16_t *res, int n,
590 const zig_u16 *lhs, const zig_u16 *rhs, zig_u8 bits)720 const uint16_t *lhs, const uint16_t *rhs, uint8_t bits)
591{721{
592 for (int i = 0; i < n; ++i) ov[i] = zig_addo_u16(&res[i], lhs[i], rhs[i], bits);722 for (int i = 0; i < n; ++i) ov[i] = zig_addo_u16(&res[i], lhs[i], rhs[i], bits);
593}723}
594724
595static inline bool zig_addo_i16(zig_i16 *res, zig_i16 lhs, zig_i16 rhs, zig_u8 bits) {725static inline bool zig_addo_i16(int16_t *res, int16_t lhs, int16_t rhs, uint8_t bits) {
596#if zig_has_builtin(add_overflow) || defined(zig_gnuc)726#if zig_has_builtin(add_overflow) || defined(zig_gnuc)
597 zig_i16 full_res;727 int16_t full_res;
598 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);728 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);
599 *res = zig_wrap_i16(full_res, bits);729 *res = zig_wrap_i16(full_res, bits);
600 return overflow || full_res < zig_minInt(i16, bits) || full_res > zig_maxInt(i16, bits);730 return overflow || full_res < zig_minInt_i(16, bits) || full_res > zig_maxInt_i(16, bits);
601#else731#else
602 zig_i32 full_res;732 int32_t full_res;
603 bool overflow = zig_addo_i32(&full_res, lhs, rhs, bits);733 bool overflow = zig_addo_i32(&full_res, lhs, rhs, bits);
604 *res = (zig_i16)full_res;734 *res = (int16_t)full_res;
605 return overflow;735 return overflow;
606#endif736#endif
607}737}
608738
609static inline void zig_vaddo_i16(zig_u8 *ov, zig_i16 *res, int n,739static inline void zig_vaddo_i16(uint8_t *ov, int16_t *res, int n,
610 const zig_i16 *lhs, const zig_i16 *rhs, zig_u8 bits)740 const int16_t *lhs, const int16_t *rhs, uint8_t bits)
611{741{
612 for (int i = 0; i < n; ++i) ov[i] = zig_addo_i16(&res[i], lhs[i], rhs[i], bits);742 for (int i = 0; i < n; ++i) ov[i] = zig_addo_i16(&res[i], lhs[i], rhs[i], bits);
613}743}
614744
615static inline bool zig_subo_u32(zig_u32 *res, zig_u32 lhs, zig_u32 rhs, zig_u8 bits) {745static inline bool zig_subo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8_t bits) {
616#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)746#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)
617 zig_u32 full_res;747 uint32_t full_res;
618 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);748 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);
619 *res = zig_wrap_u32(full_res, bits);749 *res = zig_wrap_u32(full_res, bits);
620 return overflow || full_res < zig_minInt(u32, bits) || full_res > zig_maxInt(u32, bits);750 return overflow || full_res < zig_minInt_u(32, bits) || full_res > zig_maxInt_u(32, bits);
621#else751#else
622 *res = zig_subw_u32(lhs, rhs, bits);752 *res = zig_subw_u32(lhs, rhs, bits);
623 return *res > lhs;753 return *res > lhs;
624#endif754#endif
625}755}
626756
627static inline void zig_vsubo_u32(zig_u8 *ov, zig_u32 *res, int n,757static inline void zig_vsubo_u32(uint8_t *ov, uint32_t *res, int n,
628 const zig_u32 *lhs, const zig_u32 *rhs, zig_u8 bits)758 const uint32_t *lhs, const uint32_t *rhs, uint8_t bits)
629{759{
630 for (int i = 0; i < n; ++i) ov[i] = zig_subo_u32(&res[i], lhs[i], rhs[i], bits);760 for (int i = 0; i < n; ++i) ov[i] = zig_subo_u32(&res[i], lhs[i], rhs[i], bits);
631}761}
632762
633zig_extern zig_i32 __subosi4(zig_i32 lhs, zig_i32 rhs, zig_c_int *overflow);763zig_extern int32_t __subosi4(int32_t lhs, int32_t rhs, int *overflow);
634static inline bool zig_subo_i32(zig_i32 *res, zig_i32 lhs, zig_i32 rhs, zig_u8 bits) {764static inline bool zig_subo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t bits) {
635#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)765#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)
636 zig_i32 full_res;766 int32_t full_res;
637 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);767 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);
638#else768#else
639 zig_c_int overflow_int;769 int overflow_int;
640 zig_i32 full_res = __subosi4(lhs, rhs, &overflow_int);770 int32_t full_res = __subosi4(lhs, rhs, &overflow_int);
641 bool overflow = overflow_int != 0;771 bool overflow = overflow_int != 0;
642#endif772#endif
643 *res = zig_wrap_i32(full_res, bits);773 *res = zig_wrap_i32(full_res, bits);
644 return overflow || full_res < zig_minInt(i32, bits) || full_res > zig_maxInt(i32, bits);774 return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits);
645}775}
646776
647static inline void zig_vsubo_i32(zig_u8 *ov, zig_i32 *res, int n,777static inline void zig_vsubo_i32(uint8_t *ov, int32_t *res, int n,
648 const zig_i32 *lhs, const zig_i32 *rhs, zig_u8 bits)778 const int32_t *lhs, const int32_t *rhs, uint8_t bits)
649{779{
650 for (int i = 0; i < n; ++i) ov[i] = zig_subo_i32(&res[i], lhs[i], rhs[i], bits);780 for (int i = 0; i < n; ++i) ov[i] = zig_subo_i32(&res[i], lhs[i], rhs[i], bits);
651}781}
652782
653static inline bool zig_subo_u64(zig_u64 *res, zig_u64 lhs, zig_u64 rhs, zig_u8 bits) {783static inline bool zig_subo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8_t bits) {
654#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)784#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)
655 zig_u64 full_res;785 uint64_t full_res;
656 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);786 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);
657 *res = zig_wrap_u64(full_res, bits);787 *res = zig_wrap_u64(full_res, bits);
658 return overflow || full_res < zig_minInt(u64, bits) || full_res > zig_maxInt(u64, bits);788 return overflow || full_res < zig_minInt_u(64, bits) || full_res > zig_maxInt_u(64, bits);
659#else789#else
660 *res = zig_subw_u64(lhs, rhs, bits);790 *res = zig_subw_u64(lhs, rhs, bits);
661 return *res > lhs;791 return *res > lhs;
662#endif792#endif
663}793}
664794
665static inline void zig_vsubo_u64(zig_u8 *ov, zig_u64 *res, int n,795static inline void zig_vsubo_u64(uint8_t *ov, uint64_t *res, int n,
666 const zig_u64 *lhs, const zig_u64 *rhs, zig_u8 bits)796 const uint64_t *lhs, const uint64_t *rhs, uint8_t bits)
667{797{
668 for (int i = 0; i < n; ++i) ov[i] = zig_subo_u64(&res[i], lhs[i], rhs[i], bits);798 for (int i = 0; i < n; ++i) ov[i] = zig_subo_u64(&res[i], lhs[i], rhs[i], bits);
669}799}
670800
671zig_extern zig_i64 __subodi4(zig_i64 lhs, zig_i64 rhs, zig_c_int *overflow);801zig_extern int64_t __subodi4(int64_t lhs, int64_t rhs, int *overflow);
672static inline bool zig_subo_i64(zig_i64 *res, zig_i64 lhs, zig_i64 rhs, zig_u8 bits) {802static inline bool zig_subo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t bits) {
673#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)803#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)
674 zig_i64 full_res;804 int64_t full_res;
675 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);805 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);
676#else806#else
677 zig_c_int overflow_int;807 int overflow_int;
678 zig_i64 full_res = __subodi4(lhs, rhs, &overflow_int);808 int64_t full_res = __subodi4(lhs, rhs, &overflow_int);
679 bool overflow = overflow_int != 0;809 bool overflow = overflow_int != 0;
680#endif810#endif
681 *res = zig_wrap_i64(full_res, bits);811 *res = zig_wrap_i64(full_res, bits);
682 return overflow || full_res < zig_minInt(i64, bits) || full_res > zig_maxInt(i64, bits);812 return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits);
683}813}
684814
685static inline void zig_vsubo_i64(zig_u8 *ov, zig_i64 *res, int n,815static inline void zig_vsubo_i64(uint8_t *ov, int64_t *res, int n,
686 const zig_i64 *lhs, const zig_i64 *rhs, zig_u8 bits)816 const int64_t *lhs, const int64_t *rhs, uint8_t bits)
687{817{
688 for (int i = 0; i < n; ++i) ov[i] = zig_subo_i64(&res[i], lhs[i], rhs[i], bits);818 for (int i = 0; i < n; ++i) ov[i] = zig_subo_i64(&res[i], lhs[i], rhs[i], bits);
689}819}
690820
691static inline bool zig_subo_u8(zig_u8 *res, zig_u8 lhs, zig_u8 rhs, zig_u8 bits) {821static inline bool zig_subo_u8(uint8_t *res, uint8_t lhs, uint8_t rhs, uint8_t bits) {
692#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)822#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)
693 zig_u8 full_res;823 uint8_t full_res;
694 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);824 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);
695 *res = zig_wrap_u8(full_res, bits);825 *res = zig_wrap_u8(full_res, bits);
696 return overflow || full_res < zig_minInt(u8, bits) || full_res > zig_maxInt(u8, bits);826 return overflow || full_res < zig_minInt_u(8, bits) || full_res > zig_maxInt_u(8, bits);
697#else827#else
698 zig_u32 full_res;828 uint32_t full_res;
699 bool overflow = zig_subo_u32(&full_res, lhs, rhs, bits);829 bool overflow = zig_subo_u32(&full_res, lhs, rhs, bits);
700 *res = (zig_u8)full_res;830 *res = (uint8_t)full_res;
701 return overflow;831 return overflow;
702#endif832#endif
703}833}
704834
705static inline void zig_vsubo_u8(zig_u8 *ov, zig_u8 *res, int n,835static inline void zig_vsubo_u8(uint8_t *ov, uint8_t *res, int n,
706 const zig_u8 *lhs, const zig_u8 *rhs, zig_u8 bits)836 const uint8_t *lhs, const uint8_t *rhs, uint8_t bits)
707{837{
708 for (int i = 0; i < n; ++i) ov[i] = zig_subo_u8(&res[i], lhs[i], rhs[i], bits);838 for (int i = 0; i < n; ++i) ov[i] = zig_subo_u8(&res[i], lhs[i], rhs[i], bits);
709}839}
710840
711static inline bool zig_subo_i8(zig_i8 *res, zig_i8 lhs, zig_i8 rhs, zig_u8 bits) {841static inline bool zig_subo_i8(int8_t *res, int8_t lhs, int8_t rhs, uint8_t bits) {
712#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)842#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)
713 zig_i8 full_res;843 int8_t full_res;
714 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);844 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);
715 *res = zig_wrap_i8(full_res, bits);845 *res = zig_wrap_i8(full_res, bits);
716 return overflow || full_res < zig_minInt(i8, bits) || full_res > zig_maxInt(i8, bits);846 return overflow || full_res < zig_minInt_i(8, bits) || full_res > zig_maxInt_i(8, bits);
717#else847#else
718 zig_i32 full_res;848 int32_t full_res;
719 bool overflow = zig_subo_i32(&full_res, lhs, rhs, bits);849 bool overflow = zig_subo_i32(&full_res, lhs, rhs, bits);
720 *res = (zig_i8)full_res;850 *res = (int8_t)full_res;
721 return overflow;851 return overflow;
722#endif852#endif
723}853}
724854
725static inline void zig_vsubo_i8(zig_u8 *ov, zig_i8 *res, int n,855static inline void zig_vsubo_i8(uint8_t *ov, int8_t *res, int n,
726 const zig_i8 *lhs, const zig_i8 *rhs, zig_u8 bits)856 const int8_t *lhs, const int8_t *rhs, uint8_t bits)
727{857{
728 for (int i = 0; i < n; ++i) ov[i] = zig_subo_i8(&res[i], lhs[i], rhs[i], bits);858 for (int i = 0; i < n; ++i) ov[i] = zig_subo_i8(&res[i], lhs[i], rhs[i], bits);
729}859}
730860
731861
732static inline bool zig_subo_u16(zig_u16 *res, zig_u16 lhs, zig_u16 rhs, zig_u8 bits) {862static inline bool zig_subo_u16(uint16_t *res, uint16_t lhs, uint16_t rhs, uint8_t bits) {
733#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)863#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)
734 zig_u16 full_res;864 uint16_t full_res;
735 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);865 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);
736 *res = zig_wrap_u16(full_res, bits);866 *res = zig_wrap_u16(full_res, bits);
737 return overflow || full_res < zig_minInt(u16, bits) || full_res > zig_maxInt(u16, bits);867 return overflow || full_res < zig_minInt_u(16, bits) || full_res > zig_maxInt_u(16, bits);
738#else868#else
739 zig_u32 full_res;869 uint32_t full_res;
740 bool overflow = zig_subo_u32(&full_res, lhs, rhs, bits);870 bool overflow = zig_subo_u32(&full_res, lhs, rhs, bits);
741 *res = (zig_u16)full_res;871 *res = (uint16_t)full_res;
742 return overflow;872 return overflow;
743#endif873#endif
744}874}
745875
746static inline void zig_vsubo_u16(zig_u8 *ov, zig_u16 *res, int n,876static inline void zig_vsubo_u16(uint8_t *ov, uint16_t *res, int n,
747 const zig_u16 *lhs, const zig_u16 *rhs, zig_u8 bits)877 const uint16_t *lhs, const uint16_t *rhs, uint8_t bits)
748{878{
749 for (int i = 0; i < n; ++i) ov[i] = zig_subo_u16(&res[i], lhs[i], rhs[i], bits);879 for (int i = 0; i < n; ++i) ov[i] = zig_subo_u16(&res[i], lhs[i], rhs[i], bits);
750}880}
751881
752882
753static inline bool zig_subo_i16(zig_i16 *res, zig_i16 lhs, zig_i16 rhs, zig_u8 bits) {883static inline bool zig_subo_i16(int16_t *res, int16_t lhs, int16_t rhs, uint8_t bits) {
754#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)884#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)
755 zig_i16 full_res;885 int16_t full_res;
756 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);886 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);
757 *res = zig_wrap_i16(full_res, bits);887 *res = zig_wrap_i16(full_res, bits);
758 return overflow || full_res < zig_minInt(i16, bits) || full_res > zig_maxInt(i16, bits);888 return overflow || full_res < zig_minInt_i(16, bits) || full_res > zig_maxInt_i(16, bits);
759#else889#else
760 zig_i32 full_res;890 int32_t full_res;
761 bool overflow = zig_subo_i32(&full_res, lhs, rhs, bits);891 bool overflow = zig_subo_i32(&full_res, lhs, rhs, bits);
762 *res = (zig_i16)full_res;892 *res = (int16_t)full_res;
763 return overflow;893 return overflow;
764#endif894#endif
765}895}
766896
767static inline void zig_vsubo_i16(zig_u8 *ov, zig_i16 *res, int n,897static inline void zig_vsubo_i16(uint8_t *ov, int16_t *res, int n,
768 const zig_i16 *lhs, const zig_i16 *rhs, zig_u8 bits)898 const int16_t *lhs, const int16_t *rhs, uint8_t bits)
769{899{
770 for (int i = 0; i < n; ++i) ov[i] = zig_subo_i16(&res[i], lhs[i], rhs[i], bits);900 for (int i = 0; i < n; ++i) ov[i] = zig_subo_i16(&res[i], lhs[i], rhs[i], bits);
771}901}
772902
773static inline bool zig_mulo_u32(zig_u32 *res, zig_u32 lhs, zig_u32 rhs, zig_u8 bits) {903static inline bool zig_mulo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8_t bits) {
774#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)904#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)
775 zig_u32 full_res;905 uint32_t full_res;
776 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);906 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);
777 *res = zig_wrap_u32(full_res, bits);907 *res = zig_wrap_u32(full_res, bits);
778 return overflow || full_res < zig_minInt(u32, bits) || full_res > zig_maxInt(u32, bits);908 return overflow || full_res < zig_minInt_u(32, bits) || full_res > zig_maxInt_u(32, bits);
779#else909#else
780 *res = zig_mulw_u32(lhs, rhs, bits);910 *res = zig_mulw_u32(lhs, rhs, bits);
781 return rhs != zig_as_u32(0) && lhs > zig_maxInt(u32, bits) / rhs;911 return rhs != UINT32_C(0) && lhs > zig_maxInt_u(32, bits) / rhs;
782#endif912#endif
783}913}
784914
785static inline void zig_vmulo_u32(zig_u8 *ov, zig_u32 *res, int n,915static inline void zig_vmulo_u32(uint8_t *ov, uint32_t *res, int n,
786 const zig_u32 *lhs, const zig_u32 *rhs, zig_u8 bits)916 const uint32_t *lhs, const uint32_t *rhs, uint8_t bits)
787{917{
788 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_u32(&res[i], lhs[i], rhs[i], bits);918 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_u32(&res[i], lhs[i], rhs[i], bits);
789}919}
790920
791zig_extern zig_i32 __mulosi4(zig_i32 lhs, zig_i32 rhs, zig_c_int *overflow);921zig_extern int32_t __mulosi4(int32_t lhs, int32_t rhs, int *overflow);
792static inline bool zig_mulo_i32(zig_i32 *res, zig_i32 lhs, zig_i32 rhs, zig_u8 bits) {922static inline bool zig_mulo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t bits) {
793#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)923#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)
794 zig_i32 full_res;924 int32_t full_res;
795 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);925 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);
796#else926#else
797 zig_c_int overflow_int;927 int overflow_int;
798 zig_i32 full_res = __mulosi4(lhs, rhs, &overflow_int);928 int32_t full_res = __mulosi4(lhs, rhs, &overflow_int);
799 bool overflow = overflow_int != 0;929 bool overflow = overflow_int != 0;
800#endif930#endif
801 *res = zig_wrap_i32(full_res, bits);931 *res = zig_wrap_i32(full_res, bits);
802 return overflow || full_res < zig_minInt(i32, bits) || full_res > zig_maxInt(i32, bits);932 return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits);
803}933}
804934
805static inline void zig_vmulo_i32(zig_u8 *ov, zig_i32 *res, int n,935static inline void zig_vmulo_i32(uint8_t *ov, int32_t *res, int n,
806 const zig_i32 *lhs, const zig_i32 *rhs, zig_u8 bits)936 const int32_t *lhs, const int32_t *rhs, uint8_t bits)
807{937{
808 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_i32(&res[i], lhs[i], rhs[i], bits);938 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_i32(&res[i], lhs[i], rhs[i], bits);
809}939}
810940
811static inline bool zig_mulo_u64(zig_u64 *res, zig_u64 lhs, zig_u64 rhs, zig_u8 bits) {941static inline bool zig_mulo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8_t bits) {
812#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)942#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)
813 zig_u64 full_res;943 uint64_t full_res;
814 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);944 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);
815 *res = zig_wrap_u64(full_res, bits);945 *res = zig_wrap_u64(full_res, bits);
816 return overflow || full_res < zig_minInt(u64, bits) || full_res > zig_maxInt(u64, bits);946 return overflow || full_res < zig_minInt_u(64, bits) || full_res > zig_maxInt_u(64, bits);
817#else947#else
818 *res = zig_mulw_u64(lhs, rhs, bits);948 *res = zig_mulw_u64(lhs, rhs, bits);
819 return rhs != zig_as_u64(0) && lhs > zig_maxInt(u64, bits) / rhs;949 return rhs != UINT64_C(0) && lhs > zig_maxInt_u(64, bits) / rhs;
820#endif950#endif
821}951}
822952
823static inline void zig_vmulo_u64(zig_u8 *ov, zig_u64 *res, int n,953static inline void zig_vmulo_u64(uint8_t *ov, uint64_t *res, int n,
824 const zig_u64 *lhs, const zig_u64 *rhs, zig_u8 bits)954 const uint64_t *lhs, const uint64_t *rhs, uint8_t bits)
825{955{
826 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_u64(&res[i], lhs[i], rhs[i], bits);956 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_u64(&res[i], lhs[i], rhs[i], bits);
827}957}
828958
829zig_extern zig_i64 __mulodi4(zig_i64 lhs, zig_i64 rhs, zig_c_int *overflow);959zig_extern int64_t __mulodi4(int64_t lhs, int64_t rhs, int *overflow);
830static inline bool zig_mulo_i64(zig_i64 *res, zig_i64 lhs, zig_i64 rhs, zig_u8 bits) {960static inline bool zig_mulo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t bits) {
831#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)961#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)
832 zig_i64 full_res;962 int64_t full_res;
833 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);963 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);
834#else964#else
835 zig_c_int overflow_int;965 int overflow_int;
836 zig_i64 full_res = __mulodi4(lhs, rhs, &overflow_int);966 int64_t full_res = __mulodi4(lhs, rhs, &overflow_int);
837 bool overflow = overflow_int != 0;967 bool overflow = overflow_int != 0;
838#endif968#endif
839 *res = zig_wrap_i64(full_res, bits);969 *res = zig_wrap_i64(full_res, bits);
840 return overflow || full_res < zig_minInt(i64, bits) || full_res > zig_maxInt(i64, bits);970 return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits);
841}971}
842972
843static inline void zig_vmulo_i64(zig_u8 *ov, zig_i64 *res, int n,973static inline void zig_vmulo_i64(uint8_t *ov, int64_t *res, int n,
844 const zig_i64 *lhs, const zig_i64 *rhs, zig_u8 bits)974 const int64_t *lhs, const int64_t *rhs, uint8_t bits)
845{975{
846 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_i64(&res[i], lhs[i], rhs[i], bits);976 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_i64(&res[i], lhs[i], rhs[i], bits);
847}977}
848978
849static inline bool zig_mulo_u8(zig_u8 *res, zig_u8 lhs, zig_u8 rhs, zig_u8 bits) {979static inline bool zig_mulo_u8(uint8_t *res, uint8_t lhs, uint8_t rhs, uint8_t bits) {
850#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)980#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)
851 zig_u8 full_res;981 uint8_t full_res;
852 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);982 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);
853 *res = zig_wrap_u8(full_res, bits);983 *res = zig_wrap_u8(full_res, bits);
854 return overflow || full_res < zig_minInt(u8, bits) || full_res > zig_maxInt(u8, bits);984 return overflow || full_res < zig_minInt_u(8, bits) || full_res > zig_maxInt_u(8, bits);
855#else985#else
856 zig_u32 full_res;986 uint32_t full_res;
857 bool overflow = zig_mulo_u32(&full_res, lhs, rhs, bits);987 bool overflow = zig_mulo_u32(&full_res, lhs, rhs, bits);
858 *res = (zig_u8)full_res;988 *res = (uint8_t)full_res;
859 return overflow;989 return overflow;
860#endif990#endif
861}991}
862992
863static inline void zig_vmulo_u8(zig_u8 *ov, zig_u8 *res, int n,993static inline void zig_vmulo_u8(uint8_t *ov, uint8_t *res, int n,
864 const zig_u8 *lhs, const zig_u8 *rhs, zig_u8 bits)994 const uint8_t *lhs, const uint8_t *rhs, uint8_t bits)
865{995{
866 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_u8(&res[i], lhs[i], rhs[i], bits);996 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_u8(&res[i], lhs[i], rhs[i], bits);
867}997}
868998
869static inline bool zig_mulo_i8(zig_i8 *res, zig_i8 lhs, zig_i8 rhs, zig_u8 bits) {999static inline bool zig_mulo_i8(int8_t *res, int8_t lhs, int8_t rhs, uint8_t bits) {
870#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)1000#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)
871 zig_i8 full_res;1001 int8_t full_res;
872 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);1002 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);
873 *res = zig_wrap_i8(full_res, bits);1003 *res = zig_wrap_i8(full_res, bits);
874 return overflow || full_res < zig_minInt(i8, bits) || full_res > zig_maxInt(i8, bits);1004 return overflow || full_res < zig_minInt_i(8, bits) || full_res > zig_maxInt_i(8, bits);
875#else1005#else
876 zig_i32 full_res;1006 int32_t full_res;
877 bool overflow = zig_mulo_i32(&full_res, lhs, rhs, bits);1007 bool overflow = zig_mulo_i32(&full_res, lhs, rhs, bits);
878 *res = (zig_i8)full_res;1008 *res = (int8_t)full_res;
879 return overflow;1009 return overflow;
880#endif1010#endif
881}1011}
8821012
883static inline void zig_vmulo_i8(zig_u8 *ov, zig_i8 *res, int n,1013static inline void zig_vmulo_i8(uint8_t *ov, int8_t *res, int n,
884 const zig_i8 *lhs, const zig_i8 *rhs, zig_u8 bits)1014 const int8_t *lhs, const int8_t *rhs, uint8_t bits)
885{1015{
886 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_i8(&res[i], lhs[i], rhs[i], bits);1016 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_i8(&res[i], lhs[i], rhs[i], bits);
887}1017}
8881018
889static inline bool zig_mulo_u16(zig_u16 *res, zig_u16 lhs, zig_u16 rhs, zig_u8 bits) {1019static inline bool zig_mulo_u16(uint16_t *res, uint16_t lhs, uint16_t rhs, uint8_t bits) {
890#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)1020#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)
891 zig_u16 full_res;1021 uint16_t full_res;
892 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);1022 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);
893 *res = zig_wrap_u16(full_res, bits);1023 *res = zig_wrap_u16(full_res, bits);
894 return overflow || full_res < zig_minInt(u16, bits) || full_res > zig_maxInt(u16, bits);1024 return overflow || full_res < zig_minInt_u(16, bits) || full_res > zig_maxInt_u(16, bits);
895#else1025#else
896 zig_u32 full_res;1026 uint32_t full_res;
897 bool overflow = zig_mulo_u32(&full_res, lhs, rhs, bits);1027 bool overflow = zig_mulo_u32(&full_res, lhs, rhs, bits);
898 *res = (zig_u16)full_res;1028 *res = (uint16_t)full_res;
899 return overflow;1029 return overflow;
900#endif1030#endif
901}1031}
9021032
903static inline void zig_vmulo_u16(zig_u8 *ov, zig_u16 *res, int n,1033static inline void zig_vmulo_u16(uint8_t *ov, uint16_t *res, int n,
904 const zig_u16 *lhs, const zig_u16 *rhs, zig_u8 bits)1034 const uint16_t *lhs, const uint16_t *rhs, uint8_t bits)
905{1035{
906 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_u16(&res[i], lhs[i], rhs[i], bits);1036 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_u16(&res[i], lhs[i], rhs[i], bits);
907}1037}
9081038
909static inline bool zig_mulo_i16(zig_i16 *res, zig_i16 lhs, zig_i16 rhs, zig_u8 bits) {1039static inline bool zig_mulo_i16(int16_t *res, int16_t lhs, int16_t rhs, uint8_t bits) {
910#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)1040#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)
911 zig_i16 full_res;1041 int16_t full_res;
912 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);1042 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);
913 *res = zig_wrap_i16(full_res, bits);1043 *res = zig_wrap_i16(full_res, bits);
914 return overflow || full_res < zig_minInt(i16, bits) || full_res > zig_maxInt(i16, bits);1044 return overflow || full_res < zig_minInt_i(16, bits) || full_res > zig_maxInt_i(16, bits);
915#else1045#else
916 zig_i32 full_res;1046 int32_t full_res;
917 bool overflow = zig_mulo_i32(&full_res, lhs, rhs, bits);1047 bool overflow = zig_mulo_i32(&full_res, lhs, rhs, bits);
918 *res = (zig_i16)full_res;1048 *res = (int16_t)full_res;
919 return overflow;1049 return overflow;
920#endif1050#endif
921}1051}
9221052
923static inline void zig_vmulo_i16(zig_u8 *ov, zig_i16 *res, int n,1053static inline void zig_vmulo_i16(uint8_t *ov, int16_t *res, int n,
924 const zig_i16 *lhs, const zig_i16 *rhs, zig_u8 bits)1054 const int16_t *lhs, const int16_t *rhs, uint8_t bits)
925{1055{
926 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_i16(&res[i], lhs[i], rhs[i], bits);1056 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_i16(&res[i], lhs[i], rhs[i], bits);
927}1057}
9281058
929#define zig_int_builtins(w) \1059#define zig_int_builtins(w) \
930 static inline bool zig_shlo_u##w(zig_u##w *res, zig_u##w lhs, zig_u8 rhs, zig_u8 bits) { \1060 static inline bool zig_shlo_u##w(uint##w##_t *res, uint##w##_t lhs, uint8_t rhs, uint8_t bits) { \
931 *res = zig_shlw_u##w(lhs, rhs, bits); \1061 *res = zig_shlw_u##w(lhs, rhs, bits); \
932 return lhs > zig_maxInt(u##w, bits) >> rhs; \1062 return lhs > zig_maxInt_u(w, bits) >> rhs; \
933 } \1063 } \
934\1064\
935 static inline bool zig_shlo_i##w(zig_i##w *res, zig_i##w lhs, zig_u8 rhs, zig_u8 bits) { \1065 static inline bool zig_shlo_i##w(int##w##_t *res, int##w##_t lhs, uint8_t rhs, uint8_t bits) { \
936 *res = zig_shlw_i##w(lhs, rhs, bits); \1066 *res = zig_shlw_i##w(lhs, rhs, bits); \
937 zig_i##w mask = (zig_i##w)(zig_maxInt_u##w << (bits - rhs - 1)); \1067 int##w##_t mask = (int##w##_t)(UINT##w##_MAX << (bits - rhs - 1)); \
938 return (lhs & mask) != zig_as_i##w(0) && (lhs & mask) != mask; \1068 return (lhs & mask) != INT##w##_C(0) && (lhs & mask) != mask; \
939 } \1069 } \
940\1070\
941 static inline zig_u##w zig_shls_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \1071 static inline uint##w##_t zig_shls_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \
942 zig_u##w res; \1072 uint##w##_t res; \
943 if (rhs >= bits) return lhs != zig_as_u##w(0) ? zig_maxInt(u##w, bits) : lhs; \1073 if (rhs >= bits) return lhs != UINT##w##_C(0) ? zig_maxInt_u(w, bits) : lhs; \
944 return zig_shlo_u##w(&res, lhs, (zig_u8)rhs, bits) ? zig_maxInt(u##w, bits) : res; \1074 return zig_shlo_u##w(&res, lhs, (uint8_t)rhs, bits) ? zig_maxInt_u(w, bits) : res; \
945 } \1075 } \
946\1076\
947 static inline zig_i##w zig_shls_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \1077 static inline int##w##_t zig_shls_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \
948 zig_i##w res; \1078 int##w##_t res; \
949 if ((zig_u##w)rhs < (zig_u##w)bits && !zig_shlo_i##w(&res, lhs, rhs, bits)) return res; \1079 if ((uint##w##_t)rhs < (uint##w##_t)bits && !zig_shlo_i##w(&res, lhs, (uint8_t)rhs, bits)) return res; \
950 return lhs < zig_as_i##w(0) ? zig_minInt(i##w, bits) : zig_maxInt(i##w, bits); \1080 return lhs < INT##w##_C(0) ? zig_minInt_i(w, bits) : zig_maxInt_i(w, bits); \
951 } \1081 } \
952\1082\
953 static inline zig_u##w zig_adds_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \1083 static inline uint##w##_t zig_adds_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \
954 zig_u##w res; \1084 uint##w##_t res; \
955 return zig_addo_u##w(&res, lhs, rhs, bits) ? zig_maxInt(u##w, bits) : res; \1085 return zig_addo_u##w(&res, lhs, rhs, bits) ? zig_maxInt_u(w, bits) : res; \
956 } \1086 } \
957\1087\
958 static inline zig_i##w zig_adds_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \1088 static inline int##w##_t zig_adds_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \
959 zig_i##w res; \1089 int##w##_t res; \
960 if (!zig_addo_i##w(&res, lhs, rhs, bits)) return res; \1090 if (!zig_addo_i##w(&res, lhs, rhs, bits)) return res; \
961 return res >= zig_as_i##w(0) ? zig_minInt(i##w, bits) : zig_maxInt(i##w, bits); \1091 return res >= INT##w##_C(0) ? zig_minInt_i(w, bits) : zig_maxInt_i(w, bits); \
962 } \1092 } \
963\1093\
964 static inline zig_u##w zig_subs_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \1094 static inline uint##w##_t zig_subs_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \
965 zig_u##w res; \1095 uint##w##_t res; \
966 return zig_subo_u##w(&res, lhs, rhs, bits) ? zig_minInt(u##w, bits) : res; \1096 return zig_subo_u##w(&res, lhs, rhs, bits) ? zig_minInt_u(w, bits) : res; \
967 } \1097 } \
968\1098\
969 static inline zig_i##w zig_subs_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \1099 static inline int##w##_t zig_subs_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \
970 zig_i##w res; \1100 int##w##_t res; \
971 if (!zig_subo_i##w(&res, lhs, rhs, bits)) return res; \1101 if (!zig_subo_i##w(&res, lhs, rhs, bits)) return res; \
972 return res >= zig_as_i##w(0) ? zig_minInt(i##w, bits) : zig_maxInt(i##w, bits); \1102 return res >= INT##w##_C(0) ? zig_minInt_i(w, bits) : zig_maxInt_i(w, bits); \
973 } \1103 } \
974\1104\
975 static inline zig_u##w zig_muls_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \1105 static inline uint##w##_t zig_muls_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \
976 zig_u##w res; \1106 uint##w##_t res; \
977 return zig_mulo_u##w(&res, lhs, rhs, bits) ? zig_maxInt(u##w, bits) : res; \1107 return zig_mulo_u##w(&res, lhs, rhs, bits) ? zig_maxInt_u(w, bits) : res; \
978 } \1108 } \
979\1109\
980 static inline zig_i##w zig_muls_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \1110 static inline int##w##_t zig_muls_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \
981 zig_i##w res; \1111 int##w##_t res; \
982 if (!zig_mulo_i##w(&res, lhs, rhs, bits)) return res; \1112 if (!zig_mulo_i##w(&res, lhs, rhs, bits)) return res; \
983 return (lhs ^ rhs) < zig_as_i##w(0) ? zig_minInt(i##w, bits) : zig_maxInt(i##w, bits); \1113 return (lhs ^ rhs) < INT##w##_C(0) ? zig_minInt_i(w, bits) : zig_maxInt_i(w, bits); \
984 }1114 }
985zig_int_builtins(8)1115zig_int_builtins(8)
986zig_int_builtins(16)1116zig_int_builtins(16)
...@@ -988,89 +1118,89 @@ zig_int_builtins(32)...@@ -988,89 +1118,89 @@ zig_int_builtins(32)
988zig_int_builtins(64)1118zig_int_builtins(64)
9891119
990#define zig_builtin8(name, val) __builtin_##name(val)1120#define zig_builtin8(name, val) __builtin_##name(val)
991typedef zig_c_uint zig_Builtin8;1121typedef unsigned int zig_Builtin8;
9921122
993#define zig_builtin16(name, val) __builtin_##name(val)1123#define zig_builtin16(name, val) __builtin_##name(val)
994typedef zig_c_uint zig_Builtin16;1124typedef unsigned int zig_Builtin16;
9951125
996#if INT_MIN <= INT32_MIN1126#if INT_MIN <= INT32_MIN
997#define zig_builtin32(name, val) __builtin_##name(val)1127#define zig_builtin32(name, val) __builtin_##name(val)
998typedef zig_c_uint zig_Builtin32;1128typedef unsigned int zig_Builtin32;
999#elif LONG_MIN <= INT32_MIN1129#elif LONG_MIN <= INT32_MIN
1000#define zig_builtin32(name, val) __builtin_##name##l(val)1130#define zig_builtin32(name, val) __builtin_##name##l(val)
1001typedef zig_c_ulong zig_Builtin32;1131typedef unsigned long zig_Builtin32;
1002#endif1132#endif
10031133
1004#if INT_MIN <= INT64_MIN1134#if INT_MIN <= INT64_MIN
1005#define zig_builtin64(name, val) __builtin_##name(val)1135#define zig_builtin64(name, val) __builtin_##name(val)
1006typedef zig_c_uint zig_Builtin64;1136typedef unsigned int zig_Builtin64;
1007#elif LONG_MIN <= INT64_MIN1137#elif LONG_MIN <= INT64_MIN
1008#define zig_builtin64(name, val) __builtin_##name##l(val)1138#define zig_builtin64(name, val) __builtin_##name##l(val)
1009typedef zig_c_ulong zig_Builtin64;1139typedef unsigned long zig_Builtin64;
1010#elif LLONG_MIN <= INT64_MIN1140#elif LLONG_MIN <= INT64_MIN
1011#define zig_builtin64(name, val) __builtin_##name##ll(val)1141#define zig_builtin64(name, val) __builtin_##name##ll(val)
1012typedef zig_c_ulonglong zig_Builtin64;1142typedef unsigned long long zig_Builtin64;
1013#endif1143#endif
10141144
1015static inline zig_u8 zig_byte_swap_u8(zig_u8 val, zig_u8 bits) {1145static inline uint8_t zig_byte_swap_u8(uint8_t val, uint8_t bits) {
1016 return zig_wrap_u8(val >> (8 - bits), bits);1146 return zig_wrap_u8(val >> (8 - bits), bits);
1017}1147}
10181148
1019static inline zig_i8 zig_byte_swap_i8(zig_i8 val, zig_u8 bits) {1149static inline int8_t zig_byte_swap_i8(int8_t val, uint8_t bits) {
1020 return zig_wrap_i8((zig_i8)zig_byte_swap_u8((zig_u8)val, bits), bits);1150 return zig_wrap_i8((int8_t)zig_byte_swap_u8((uint8_t)val, bits), bits);
1021}1151}
10221152
1023static inline zig_u16 zig_byte_swap_u16(zig_u16 val, zig_u8 bits) {1153static inline uint16_t zig_byte_swap_u16(uint16_t val, uint8_t bits) {
1024 zig_u16 full_res;1154 uint16_t full_res;
1025#if zig_has_builtin(bswap16) || defined(zig_gnuc)1155#if zig_has_builtin(bswap16) || defined(zig_gnuc)
1026 full_res = __builtin_bswap16(val);1156 full_res = __builtin_bswap16(val);
1027#else1157#else
1028 full_res = (zig_u16)zig_byte_swap_u8((zig_u8)(val >> 0), 8) << 8 |1158 full_res = (uint16_t)zig_byte_swap_u8((uint8_t)(val >> 0), 8) << 8 |
1029 (zig_u16)zig_byte_swap_u8((zig_u8)(val >> 8), 8) >> 0;1159 (uint16_t)zig_byte_swap_u8((uint8_t)(val >> 8), 8) >> 0;
1030#endif1160#endif
1031 return zig_wrap_u16(full_res >> (16 - bits), bits);1161 return zig_wrap_u16(full_res >> (16 - bits), bits);
1032}1162}
10331163
1034static inline zig_i16 zig_byte_swap_i16(zig_i16 val, zig_u8 bits) {1164static inline int16_t zig_byte_swap_i16(int16_t val, uint8_t bits) {
1035 return zig_wrap_i16((zig_i16)zig_byte_swap_u16((zig_u16)val, bits), bits);1165 return zig_wrap_i16((int16_t)zig_byte_swap_u16((uint16_t)val, bits), bits);
1036}1166}
10371167
1038static inline zig_u32 zig_byte_swap_u32(zig_u32 val, zig_u8 bits) {1168static inline uint32_t zig_byte_swap_u32(uint32_t val, uint8_t bits) {
1039 zig_u32 full_res;1169 uint32_t full_res;
1040#if zig_has_builtin(bswap32) || defined(zig_gnuc)1170#if zig_has_builtin(bswap32) || defined(zig_gnuc)
1041 full_res = __builtin_bswap32(val);1171 full_res = __builtin_bswap32(val);
1042#else1172#else
1043 full_res = (zig_u32)zig_byte_swap_u16((zig_u16)(val >> 0), 16) << 16 |1173 full_res = (uint32_t)zig_byte_swap_u16((uint16_t)(val >> 0), 16) << 16 |
1044 (zig_u32)zig_byte_swap_u16((zig_u16)(val >> 16), 16) >> 0;1174 (uint32_t)zig_byte_swap_u16((uint16_t)(val >> 16), 16) >> 0;
1045#endif1175#endif
1046 return zig_wrap_u32(full_res >> (32 - bits), bits);1176 return zig_wrap_u32(full_res >> (32 - bits), bits);
1047}1177}
10481178
1049static inline zig_i32 zig_byte_swap_i32(zig_i32 val, zig_u8 bits) {1179static inline int32_t zig_byte_swap_i32(int32_t val, uint8_t bits) {
1050 return zig_wrap_i32((zig_i32)zig_byte_swap_u32((zig_u32)val, bits), bits);1180 return zig_wrap_i32((int32_t)zig_byte_swap_u32((uint32_t)val, bits), bits);
1051}1181}
10521182
1053static inline zig_u64 zig_byte_swap_u64(zig_u64 val, zig_u8 bits) {1183static inline uint64_t zig_byte_swap_u64(uint64_t val, uint8_t bits) {
1054 zig_u64 full_res;1184 uint64_t full_res;
1055#if zig_has_builtin(bswap64) || defined(zig_gnuc)1185#if zig_has_builtin(bswap64) || defined(zig_gnuc)
1056 full_res = __builtin_bswap64(val);1186 full_res = __builtin_bswap64(val);
1057#else1187#else
1058 full_res = (zig_u64)zig_byte_swap_u32((zig_u32)(val >> 0), 32) << 32 |1188 full_res = (uint64_t)zig_byte_swap_u32((uint32_t)(val >> 0), 32) << 32 |
1059 (zig_u64)zig_byte_swap_u32((zig_u32)(val >> 32), 32) >> 0;1189 (uint64_t)zig_byte_swap_u32((uint32_t)(val >> 32), 32) >> 0;
1060#endif1190#endif
1061 return zig_wrap_u64(full_res >> (64 - bits), bits);1191 return zig_wrap_u64(full_res >> (64 - bits), bits);
1062}1192}
10631193
1064static inline zig_i64 zig_byte_swap_i64(zig_i64 val, zig_u8 bits) {1194static inline int64_t zig_byte_swap_i64(int64_t val, uint8_t bits) {
1065 return zig_wrap_i64((zig_i64)zig_byte_swap_u64((zig_u64)val, bits), bits);1195 return zig_wrap_i64((int64_t)zig_byte_swap_u64((uint64_t)val, bits), bits);
1066}1196}
10671197
1068static inline zig_u8 zig_bit_reverse_u8(zig_u8 val, zig_u8 bits) {1198static inline uint8_t zig_bit_reverse_u8(uint8_t val, uint8_t bits) {
1069 zig_u8 full_res;1199 uint8_t full_res;
1070#if zig_has_builtin(bitreverse8)1200#if zig_has_builtin(bitreverse8)
1071 full_res = __builtin_bitreverse8(val);1201 full_res = __builtin_bitreverse8(val);
1072#else1202#else
1073 static zig_u8 const lut[0x10] = {1203 static uint8_t const lut[0x10] = {
1074 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,1204 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
1075 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf1205 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf
1076 };1206 };
...@@ -1079,62 +1209,62 @@ static inline zig_u8 zig_bit_reverse_u8(zig_u8 val, zig_u8 bits) {...@@ -1079,62 +1209,62 @@ static inline zig_u8 zig_bit_reverse_u8(zig_u8 val, zig_u8 bits) {
1079 return zig_wrap_u8(full_res >> (8 - bits), bits);1209 return zig_wrap_u8(full_res >> (8 - bits), bits);
1080}1210}
10811211
1082static inline zig_i8 zig_bit_reverse_i8(zig_i8 val, zig_u8 bits) {1212static inline int8_t zig_bit_reverse_i8(int8_t val, uint8_t bits) {
1083 return zig_wrap_i8((zig_i8)zig_bit_reverse_u8((zig_u8)val, bits), bits);1213 return zig_wrap_i8((int8_t)zig_bit_reverse_u8((uint8_t)val, bits), bits);
1084}1214}
10851215
1086static inline zig_u16 zig_bit_reverse_u16(zig_u16 val, zig_u8 bits) {1216static inline uint16_t zig_bit_reverse_u16(uint16_t val, uint8_t bits) {
1087 zig_u16 full_res;1217 uint16_t full_res;
1088#if zig_has_builtin(bitreverse16)1218#if zig_has_builtin(bitreverse16)
1089 full_res = __builtin_bitreverse16(val);1219 full_res = __builtin_bitreverse16(val);
1090#else1220#else
1091 full_res = (zig_u16)zig_bit_reverse_u8((zig_u8)(val >> 0), 8) << 8 |1221 full_res = (uint16_t)zig_bit_reverse_u8((uint8_t)(val >> 0), 8) << 8 |
1092 (zig_u16)zig_bit_reverse_u8((zig_u8)(val >> 8), 8) >> 0;1222 (uint16_t)zig_bit_reverse_u8((uint8_t)(val >> 8), 8) >> 0;
1093#endif1223#endif
1094 return zig_wrap_u16(full_res >> (16 - bits), bits);1224 return zig_wrap_u16(full_res >> (16 - bits), bits);
1095}1225}
10961226
1097static inline zig_i16 zig_bit_reverse_i16(zig_i16 val, zig_u8 bits) {1227static inline int16_t zig_bit_reverse_i16(int16_t val, uint8_t bits) {
1098 return zig_wrap_i16((zig_i16)zig_bit_reverse_u16((zig_u16)val, bits), bits);1228 return zig_wrap_i16((int16_t)zig_bit_reverse_u16((uint16_t)val, bits), bits);
1099}1229}
11001230
1101static inline zig_u32 zig_bit_reverse_u32(zig_u32 val, zig_u8 bits) {1231static inline uint32_t zig_bit_reverse_u32(uint32_t val, uint8_t bits) {
1102 zig_u32 full_res;1232 uint32_t full_res;
1103#if zig_has_builtin(bitreverse32)1233#if zig_has_builtin(bitreverse32)
1104 full_res = __builtin_bitreverse32(val);1234 full_res = __builtin_bitreverse32(val);
1105#else1235#else
1106 full_res = (zig_u32)zig_bit_reverse_u16((zig_u16)(val >> 0), 16) << 16 |1236 full_res = (uint32_t)zig_bit_reverse_u16((uint16_t)(val >> 0), 16) << 16 |
1107 (zig_u32)zig_bit_reverse_u16((zig_u16)(val >> 16), 16) >> 0;1237 (uint32_t)zig_bit_reverse_u16((uint16_t)(val >> 16), 16) >> 0;
1108#endif1238#endif
1109 return zig_wrap_u32(full_res >> (32 - bits), bits);1239 return zig_wrap_u32(full_res >> (32 - bits), bits);
1110}1240}
11111241
1112static inline zig_i32 zig_bit_reverse_i32(zig_i32 val, zig_u8 bits) {1242static inline int32_t zig_bit_reverse_i32(int32_t val, uint8_t bits) {
1113 return zig_wrap_i32((zig_i32)zig_bit_reverse_u32((zig_u32)val, bits), bits);1243 return zig_wrap_i32((int32_t)zig_bit_reverse_u32((uint32_t)val, bits), bits);
1114}1244}
11151245
1116static inline zig_u64 zig_bit_reverse_u64(zig_u64 val, zig_u8 bits) {1246static inline uint64_t zig_bit_reverse_u64(uint64_t val, uint8_t bits) {
1117 zig_u64 full_res;1247 uint64_t full_res;
1118#if zig_has_builtin(bitreverse64)1248#if zig_has_builtin(bitreverse64)
1119 full_res = __builtin_bitreverse64(val);1249 full_res = __builtin_bitreverse64(val);
1120#else1250#else
1121 full_res = (zig_u64)zig_bit_reverse_u32((zig_u32)(val >> 0), 32) << 32 |1251 full_res = (uint64_t)zig_bit_reverse_u32((uint32_t)(val >> 0), 32) << 32 |
1122 (zig_u64)zig_bit_reverse_u32((zig_u32)(val >> 32), 32) >> 0;1252 (uint64_t)zig_bit_reverse_u32((uint32_t)(val >> 32), 32) >> 0;
1123#endif1253#endif
1124 return zig_wrap_u64(full_res >> (64 - bits), bits);1254 return zig_wrap_u64(full_res >> (64 - bits), bits);
1125}1255}
11261256
1127static inline zig_i64 zig_bit_reverse_i64(zig_i64 val, zig_u8 bits) {1257static inline int64_t zig_bit_reverse_i64(int64_t val, uint8_t bits) {
1128 return zig_wrap_i64((zig_i64)zig_bit_reverse_u64((zig_u64)val, bits), bits);1258 return zig_wrap_i64((int64_t)zig_bit_reverse_u64((uint64_t)val, bits), bits);
1129}1259}
11301260
1131#define zig_builtin_popcount_common(w) \1261#define zig_builtin_popcount_common(w) \
1132 static inline zig_u8 zig_popcount_i##w(zig_i##w val, zig_u8 bits) { \1262 static inline uint8_t zig_popcount_i##w(int##w##_t val, uint8_t bits) { \
1133 return zig_popcount_u##w((zig_u##w)val, bits); \1263 return zig_popcount_u##w((uint##w##_t)val, bits); \
1134 }1264 }
1135#if zig_has_builtin(popcount) || defined(zig_gnuc)1265#if zig_has_builtin(popcount) || defined(zig_gnuc)
1136#define zig_builtin_popcount(w) \1266#define zig_builtin_popcount(w) \
1137 static inline zig_u8 zig_popcount_u##w(zig_u##w val, zig_u8 bits) { \1267 static inline uint8_t zig_popcount_u##w(uint##w##_t val, uint8_t bits) { \
1138 (void)bits; \1268 (void)bits; \
1139 return zig_builtin##w(popcount, val); \1269 return zig_builtin##w(popcount, val); \
1140 } \1270 } \
...@@ -1142,12 +1272,12 @@ static inline zig_i64 zig_bit_reverse_i64(zig_i64 val, zig_u8 bits) {...@@ -1142,12 +1272,12 @@ static inline zig_i64 zig_bit_reverse_i64(zig_i64 val, zig_u8 bits) {
1142 zig_builtin_popcount_common(w)1272 zig_builtin_popcount_common(w)
1143#else1273#else
1144#define zig_builtin_popcount(w) \1274#define zig_builtin_popcount(w) \
1145 static inline zig_u8 zig_popcount_u##w(zig_u##w val, zig_u8 bits) { \1275 static inline uint8_t zig_popcount_u##w(uint##w##_t val, uint8_t bits) { \
1146 (void)bits; \1276 (void)bits; \
1147 zig_u##w temp = val - ((val >> 1) & (zig_maxInt_u##w / 3)); \1277 uint##w##_t temp = val - ((val >> 1) & (UINT##w##_MAX / 3)); \
1148 temp = (temp & (zig_maxInt_u##w / 5)) + ((temp >> 2) & (zig_maxInt_u##w / 5)); \1278 temp = (temp & (UINT##w##_MAX / 5)) + ((temp >> 2) & (UINT##w##_MAX / 5)); \
1149 temp = (temp + (temp >> 4)) & (zig_maxInt_u##w / 17); \1279 temp = (temp + (temp >> 4)) & (UINT##w##_MAX / 17); \
1150 return temp * (zig_maxInt_u##w / 255) >> (w - 8); \1280 return temp * (UINT##w##_MAX / 255) >> (w - 8); \
1151 } \1281 } \
1152\1282\
1153 zig_builtin_popcount_common(w)1283 zig_builtin_popcount_common(w)
...@@ -1158,12 +1288,12 @@ zig_builtin_popcount(32)...@@ -1158,12 +1288,12 @@ zig_builtin_popcount(32)
1158zig_builtin_popcount(64)1288zig_builtin_popcount(64)
11591289
1160#define zig_builtin_ctz_common(w) \1290#define zig_builtin_ctz_common(w) \
1161 static inline zig_u8 zig_ctz_i##w(zig_i##w val, zig_u8 bits) { \1291 static inline uint8_t zig_ctz_i##w(int##w##_t val, uint8_t bits) { \
1162 return zig_ctz_u##w((zig_u##w)val, bits); \1292 return zig_ctz_u##w((uint##w##_t)val, bits); \
1163 }1293 }
1164#if zig_has_builtin(ctz) || defined(zig_gnuc)1294#if zig_has_builtin(ctz) || defined(zig_gnuc)
1165#define zig_builtin_ctz(w) \1295#define zig_builtin_ctz(w) \
1166 static inline zig_u8 zig_ctz_u##w(zig_u##w val, zig_u8 bits) { \1296 static inline uint8_t zig_ctz_u##w(uint##w##_t val, uint8_t bits) { \
1167 if (val == 0) return bits; \1297 if (val == 0) return bits; \
1168 return zig_builtin##w(ctz, val); \1298 return zig_builtin##w(ctz, val); \
1169 } \1299 } \
...@@ -1171,7 +1301,7 @@ zig_builtin_popcount(64)...@@ -1171,7 +1301,7 @@ zig_builtin_popcount(64)
1171 zig_builtin_ctz_common(w)1301 zig_builtin_ctz_common(w)
1172#else1302#else
1173#define zig_builtin_ctz(w) \1303#define zig_builtin_ctz(w) \
1174 static inline zig_u8 zig_ctz_u##w(zig_u##w val, zig_u8 bits) { \1304 static inline uint8_t zig_ctz_u##w(uint##w##_t val, uint8_t bits) { \
1175 return zig_popcount_u##w(zig_not_u##w(val, bits) & zig_subw_u##w(val, 1, bits), bits); \1305 return zig_popcount_u##w(zig_not_u##w(val, bits) & zig_subw_u##w(val, 1, bits), bits); \
1176 } \1306 } \
1177\1307\
...@@ -1183,12 +1313,12 @@ zig_builtin_ctz(32)...@@ -1183,12 +1313,12 @@ zig_builtin_ctz(32)
1183zig_builtin_ctz(64)1313zig_builtin_ctz(64)
11841314
1185#define zig_builtin_clz_common(w) \1315#define zig_builtin_clz_common(w) \
1186 static inline zig_u8 zig_clz_i##w(zig_i##w val, zig_u8 bits) { \1316 static inline uint8_t zig_clz_i##w(int##w##_t val, uint8_t bits) { \
1187 return zig_clz_u##w((zig_u##w)val, bits); \1317 return zig_clz_u##w((uint##w##_t)val, bits); \
1188 }1318 }
1189#if zig_has_builtin(clz) || defined(zig_gnuc)1319#if zig_has_builtin(clz) || defined(zig_gnuc)
1190#define zig_builtin_clz(w) \1320#define zig_builtin_clz(w) \
1191 static inline zig_u8 zig_clz_u##w(zig_u##w val, zig_u8 bits) { \1321 static inline uint8_t zig_clz_u##w(uint##w##_t val, uint8_t bits) { \
1192 if (val == 0) return bits; \1322 if (val == 0) return bits; \
1193 return zig_builtin##w(clz, val) - (zig_bitSizeOf(zig_Builtin##w) - bits); \1323 return zig_builtin##w(clz, val) - (zig_bitSizeOf(zig_Builtin##w) - bits); \
1194 } \1324 } \
...@@ -1196,7 +1326,7 @@ zig_builtin_ctz(64)...@@ -1196,7 +1326,7 @@ zig_builtin_ctz(64)
1196 zig_builtin_clz_common(w)1326 zig_builtin_clz_common(w)
1197#else1327#else
1198#define zig_builtin_clz(w) \1328#define zig_builtin_clz(w) \
1199 static inline zig_u8 zig_clz_u##w(zig_u##w val, zig_u8 bits) { \1329 static inline uint8_t zig_clz_u##w(uint##w##_t val, uint8_t bits) { \
1200 return zig_ctz_u##w(zig_bit_reverse_u##w(val, bits), bits); \1330 return zig_ctz_u##w(zig_bit_reverse_u##w(val, bits), bits); \
1201 } \1331 } \
1202\1332\
...@@ -1207,7 +1337,7 @@ zig_builtin_clz(16)...@@ -1207,7 +1337,7 @@ zig_builtin_clz(16)
1207zig_builtin_clz(32)1337zig_builtin_clz(32)
1208zig_builtin_clz(64)1338zig_builtin_clz(64)
12091339
1210/* ======================== 128-bit Integer Routines ======================== */1340/* ======================== 128-bit Integer Support ========================= */
12111341
1212#if !defined(zig_has_int128)1342#if !defined(zig_has_int128)
1213# if defined(__SIZEOF_INT128__)1343# if defined(__SIZEOF_INT128__)
...@@ -1222,18 +1352,18 @@ zig_builtin_clz(64)...@@ -1222,18 +1352,18 @@ zig_builtin_clz(64)
1222typedef unsigned __int128 zig_u128;1352typedef unsigned __int128 zig_u128;
1223typedef signed __int128 zig_i128;1353typedef signed __int128 zig_i128;
12241354
1225#define zig_as_u128(hi, lo) ((zig_u128)(hi)<<64|(lo))1355#define zig_make_u128(hi, lo) ((zig_u128)(hi)<<64|(lo))
1226#define zig_as_i128(hi, lo) ((zig_i128)zig_as_u128(hi, lo))1356#define zig_make_i128(hi, lo) ((zig_i128)zig_make_u128(hi, lo))
1227#define zig_as_constant_u128(hi, lo) zig_as_u128(hi, lo)1357#define zig_make_constant_u128(hi, lo) zig_make_u128(hi, lo)
1228#define zig_as_constant_i128(hi, lo) zig_as_i128(hi, lo)1358#define zig_make_constant_i128(hi, lo) zig_make_i128(hi, lo)
1229#define zig_hi_u128(val) ((zig_u64)((val) >> 64))1359#define zig_hi_u128(val) ((uint64_t)((val) >> 64))
1230#define zig_lo_u128(val) ((zig_u64)((val) >> 0))1360#define zig_lo_u128(val) ((uint64_t)((val) >> 0))
1231#define zig_hi_i128(val) ((zig_i64)((val) >> 64))1361#define zig_hi_i128(val) (( int64_t)((val) >> 64))
1232#define zig_lo_i128(val) ((zig_u64)((val) >> 0))1362#define zig_lo_i128(val) ((uint64_t)((val) >> 0))
1233#define zig_bitcast_u128(val) ((zig_u128)(val))1363#define zig_bitcast_u128(val) ((zig_u128)(val))
1234#define zig_bitcast_i128(val) ((zig_i128)(val))1364#define zig_bitcast_i128(val) ((zig_i128)(val))
1235#define zig_cmp_int128(Type) \1365#define zig_cmp_int128(Type) \
1236 static inline zig_i32 zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \1366 static inline int32_t zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \
1237 return (lhs > rhs) - (lhs < rhs); \1367 return (lhs > rhs) - (lhs < rhs); \
1238 }1368 }
1239#define zig_bit_int128(Type, operation, operator) \1369#define zig_bit_int128(Type, operation, operator) \
...@@ -1244,31 +1374,31 @@ typedef signed __int128 zig_i128;...@@ -1244,31 +1374,31 @@ typedef signed __int128 zig_i128;
1244#else /* zig_has_int128 */1374#else /* zig_has_int128 */
12451375
1246#if __LITTLE_ENDIAN__ || _MSC_VER1376#if __LITTLE_ENDIAN__ || _MSC_VER
1247typedef struct { zig_align(16) zig_u64 lo; zig_u64 hi; } zig_u128;1377typedef struct { zig_align(16) uint64_t lo; uint64_t hi; } zig_u128;
1248typedef struct { zig_align(16) zig_u64 lo; zig_i64 hi; } zig_i128;1378typedef struct { zig_align(16) uint64_t lo; int64_t hi; } zig_i128;
1249#else1379#else
1250typedef struct { zig_align(16) zig_u64 hi; zig_u64 lo; } zig_u128;1380typedef struct { zig_align(16) uint64_t hi; uint64_t lo; } zig_u128;
1251typedef struct { zig_align(16) zig_i64 hi; zig_u64 lo; } zig_i128;1381typedef struct { zig_align(16) int64_t hi; uint64_t lo; } zig_i128;
1252#endif1382#endif
12531383
1254#define zig_as_u128(hi, lo) ((zig_u128){ .h##i = (hi), .l##o = (lo) })1384#define zig_make_u128(hi, lo) ((zig_u128){ .h##i = (hi), .l##o = (lo) })
1255#define zig_as_i128(hi, lo) ((zig_i128){ .h##i = (hi), .l##o = (lo) })1385#define zig_make_i128(hi, lo) ((zig_i128){ .h##i = (hi), .l##o = (lo) })
12561386
1257#if _MSC_VER1387#if _MSC_VER /* MSVC doesn't allow struct literals in constant expressions */
1258#define zig_as_constant_u128(hi, lo) { .h##i = (hi), .l##o = (lo) }1388#define zig_make_constant_u128(hi, lo) { .h##i = (hi), .l##o = (lo) }
1259#define zig_as_constant_i128(hi, lo) { .h##i = (hi), .l##o = (lo) }1389#define zig_make_constant_i128(hi, lo) { .h##i = (hi), .l##o = (lo) }
1260#else1390#else /* But non-MSVC doesn't like the unprotected commas */
1261#define zig_as_constant_u128(hi, lo) zig_as_u128(hi, lo)1391#define zig_make_constant_u128(hi, lo) zig_make_u128(hi, lo)
1262#define zig_as_constant_i128(hi, lo) zig_as_i128(hi, lo)1392#define zig_make_constant_i128(hi, lo) zig_make_i128(hi, lo)
1263#endif1393#endif
1264#define zig_hi_u128(val) ((val).hi)1394#define zig_hi_u128(val) ((val).hi)
1265#define zig_lo_u128(val) ((val).lo)1395#define zig_lo_u128(val) ((val).lo)
1266#define zig_hi_i128(val) ((val).hi)1396#define zig_hi_i128(val) ((val).hi)
1267#define zig_lo_i128(val) ((val).lo)1397#define zig_lo_i128(val) ((val).lo)
1268#define zig_bitcast_u128(val) zig_as_u128((zig_u64)(val).hi, (val).lo)1398#define zig_bitcast_u128(val) zig_make_u128((uint64_t)(val).hi, (val).lo)
1269#define zig_bitcast_i128(val) zig_as_i128((zig_i64)(val).hi, (val).lo)1399#define zig_bitcast_i128(val) zig_make_i128(( int64_t)(val).hi, (val).lo)
1270#define zig_cmp_int128(Type) \1400#define zig_cmp_int128(Type) \
1271 static inline zig_i32 zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \1401 static inline int32_t zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \
1272 return (lhs.hi == rhs.hi) \1402 return (lhs.hi == rhs.hi) \
1273 ? (lhs.lo > rhs.lo) - (lhs.lo < rhs.lo) \1403 ? (lhs.lo > rhs.lo) - (lhs.lo < rhs.lo) \
1274 : (lhs.hi > rhs.hi) - (lhs.hi < rhs.hi); \1404 : (lhs.hi > rhs.hi) - (lhs.hi < rhs.hi); \
...@@ -1280,10 +1410,10 @@ typedef struct { zig_align(16) zig_i64 hi; zig_u64 lo; } zig_i128;...@@ -1280,10 +1410,10 @@ typedef struct { zig_align(16) zig_i64 hi; zig_u64 lo; } zig_i128;
12801410
1281#endif /* zig_has_int128 */1411#endif /* zig_has_int128 */
12821412
1283#define zig_minInt_u128 zig_as_u128(zig_minInt_u64, zig_minInt_u64)1413#define zig_minInt_u128 zig_make_u128(zig_minInt_u64, zig_minInt_u64)
1284#define zig_maxInt_u128 zig_as_u128(zig_maxInt_u64, zig_maxInt_u64)1414#define zig_maxInt_u128 zig_make_u128(zig_maxInt_u64, zig_maxInt_u64)
1285#define zig_minInt_i128 zig_as_i128(zig_minInt_i64, zig_minInt_u64)1415#define zig_minInt_i128 zig_make_i128(zig_minInt_i64, zig_minInt_u64)
1286#define zig_maxInt_i128 zig_as_i128(zig_maxInt_i64, zig_maxInt_u64)1416#define zig_maxInt_i128 zig_make_i128(zig_maxInt_i64, zig_maxInt_u64)
12871417
1288zig_cmp_int128(u128)1418zig_cmp_int128(u128)
1289zig_cmp_int128(i128)1419zig_cmp_int128(i128)
...@@ -1297,28 +1427,33 @@ zig_bit_int128(i128, or, |)...@@ -1297,28 +1427,33 @@ zig_bit_int128(i128, or, |)
1297zig_bit_int128(u128, xor, ^)1427zig_bit_int128(u128, xor, ^)
1298zig_bit_int128(i128, xor, ^)1428zig_bit_int128(i128, xor, ^)
12991429
1300static inline zig_u128 zig_shr_u128(zig_u128 lhs, zig_u8 rhs);1430static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs);
13011431
1302#if zig_has_int1281432#if zig_has_int128
13031433
1304static inline zig_u128 zig_not_u128(zig_u128 val, zig_u8 bits) {1434static inline zig_u128 zig_not_u128(zig_u128 val, uint8_t bits) {
1305 return val ^ zig_maxInt(u128, bits);1435 return val ^ zig_maxInt_u(128, bits);
1306}1436}
13071437
1308static inline zig_i128 zig_not_i128(zig_i128 val, zig_u8 bits) {1438static inline zig_i128 zig_not_i128(zig_i128 val, uint8_t bits) {
1309 (void)bits;1439 (void)bits;
1310 return ~val;1440 return ~val;
1311}1441}
13121442
1313static inline zig_u128 zig_shr_u128(zig_u128 lhs, zig_u8 rhs) {1443static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs) {
1314 return lhs >> rhs;1444 return lhs >> rhs;
1315}1445}
13161446
1317static inline zig_u128 zig_shl_u128(zig_u128 lhs, zig_u8 rhs) {1447static inline zig_u128 zig_shl_u128(zig_u128 lhs, uint8_t rhs) {
1318 return lhs << rhs;1448 return lhs << rhs;
1319}1449}
13201450
1321static inline zig_i128 zig_shl_i128(zig_i128 lhs, zig_u8 rhs) {1451static inline zig_i128 zig_shr_i128(zig_i128 lhs, uint8_t rhs) {
1452 zig_i128 sign_mask = lhs < zig_make_i128(0, 0) ? -zig_make_i128(0, 1) : zig_make_i128(0, 0);
1453 return ((lhs ^ sign_mask) >> rhs) ^ sign_mask;
1454}
1455
1456static inline zig_i128 zig_shl_i128(zig_i128 lhs, uint8_t rhs) {
1322 return lhs << rhs;1457 return lhs << rhs;
1323}1458}
13241459
...@@ -1363,40 +1498,46 @@ static inline zig_i128 zig_rem_i128(zig_i128 lhs, zig_i128 rhs) {...@@ -1363,40 +1498,46 @@ static inline zig_i128 zig_rem_i128(zig_i128 lhs, zig_i128 rhs) {
1363}1498}
13641499
1365static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) {1500static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) {
1366 return zig_div_trunc_i128(lhs, rhs) - (((lhs ^ rhs) & zig_rem_i128(lhs, rhs)) < zig_as_i128(0, 0));1501 return zig_div_trunc_i128(lhs, rhs) - (((lhs ^ rhs) & zig_rem_i128(lhs, rhs)) < zig_make_i128(0, 0));
1367}1502}
13681503
1369static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) {1504static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) {
1370 zig_i128 rem = zig_rem_i128(lhs, rhs);1505 zig_i128 rem = zig_rem_i128(lhs, rhs);
1371 return rem + (((lhs ^ rhs) & rem) < zig_as_i128(0, 0) ? rhs : zig_as_i128(0, 0));1506 return rem + (((lhs ^ rhs) & rem) < zig_make_i128(0, 0) ? rhs : zig_make_i128(0, 0));
1372}1507}
13731508
1374#else /* zig_has_int128 */1509#else /* zig_has_int128 */
13751510
1376static inline zig_u128 zig_not_u128(zig_u128 val, zig_u8 bits) {1511static inline zig_u128 zig_not_u128(zig_u128 val, uint8_t bits) {
1377 return (zig_u128){ .hi = zig_not_u64(val.hi, bits - zig_as_u8(64)), .lo = zig_not_u64(val.lo, zig_as_u8(64)) };1512 return (zig_u128){ .hi = zig_not_u64(val.hi, bits - UINT8_C(64)), .lo = zig_not_u64(val.lo, UINT8_C(64)) };
1378}1513}
13791514
1380static inline zig_i128 zig_not_i128(zig_i128 val, zig_u8 bits) {1515static inline zig_i128 zig_not_i128(zig_i128 val, uint8_t bits) {
1381 return (zig_i128){ .hi = zig_not_i64(val.hi, bits - zig_as_u8(64)), .lo = zig_not_u64(val.lo, zig_as_u8(64)) };1516 return (zig_i128){ .hi = zig_not_i64(val.hi, bits - UINT8_C(64)), .lo = zig_not_u64(val.lo, UINT8_C(64)) };
1382}1517}
13831518
1384static inline zig_u128 zig_shr_u128(zig_u128 lhs, zig_u8 rhs) {1519static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs) {
1385 if (rhs == zig_as_u8(0)) return lhs;1520 if (rhs == UINT8_C(0)) return lhs;
1386 if (rhs >= zig_as_u8(64)) return (zig_u128){ .hi = zig_minInt_u64, .lo = lhs.hi >> (rhs - zig_as_u8(64)) };1521 if (rhs >= UINT8_C(64)) return (zig_u128){ .hi = zig_minInt_u64, .lo = lhs.hi >> (rhs - UINT8_C(64)) };
1387 return (zig_u128){ .hi = lhs.hi >> rhs, .lo = lhs.hi << (zig_as_u8(64) - rhs) | lhs.lo >> rhs };1522 return (zig_u128){ .hi = lhs.hi >> rhs, .lo = lhs.hi << (UINT8_C(64) - rhs) | lhs.lo >> rhs };
1388}1523}
13891524
1390static inline zig_u128 zig_shl_u128(zig_u128 lhs, zig_u8 rhs) {1525static inline zig_u128 zig_shl_u128(zig_u128 lhs, uint8_t rhs) {
1391 if (rhs == zig_as_u8(0)) return lhs;1526 if (rhs == UINT8_C(0)) return lhs;
1392 if (rhs >= zig_as_u8(64)) return (zig_u128){ .hi = lhs.lo << (rhs - zig_as_u8(64)), .lo = zig_minInt_u64 };1527 if (rhs >= UINT8_C(64)) return (zig_u128){ .hi = lhs.lo << (rhs - UINT8_C(64)), .lo = zig_minInt_u64 };
1393 return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs };1528 return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (UINT8_C(64) - rhs), .lo = lhs.lo << rhs };
1394}1529}
13951530
1396static inline zig_i128 zig_shl_i128(zig_i128 lhs, zig_u8 rhs) {1531static inline zig_i128 zig_shr_i128(zig_i128 lhs, uint8_t rhs) {
1397 if (rhs == zig_as_u8(0)) return lhs;1532 if (rhs == UINT8_C(0)) return lhs;
1398 if (rhs >= zig_as_u8(64)) return (zig_i128){ .hi = lhs.lo << (rhs - zig_as_u8(64)), .lo = zig_minInt_u64 };1533 if (rhs >= UINT8_C(64)) return (zig_i128){ .hi = zig_shr_i64(lhs.hi, 63), .lo = zig_shr_i64(lhs.hi, (rhs - UINT8_C(64))) };
1399 return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs };1534 return (zig_i128){ .hi = zig_shr_i64(lhs.hi, rhs), .lo = lhs.lo >> rhs | (uint64_t)lhs.hi << (UINT8_C(64) - rhs) };
1535}
1536
1537static inline zig_i128 zig_shl_i128(zig_i128 lhs, uint8_t rhs) {
1538 if (rhs == UINT8_C(0)) return lhs;
1539 if (rhs >= UINT8_C(64)) return (zig_i128){ .hi = lhs.lo << (rhs - UINT8_C(64)), .lo = zig_minInt_u64 };
1540 return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (UINT8_C(64) - rhs), .lo = lhs.lo << rhs };
1400}1541}
14011542
1402static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) {1543static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) {
...@@ -1424,14 +1565,14 @@ static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) {...@@ -1424,14 +1565,14 @@ static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) {
1424}1565}
14251566
1426zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs);1567zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs);
1427static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs) {
1428 return zig_bitcast_u128(__multi3(zig_bitcast_i128(lhs), zig_bitcast_i128(rhs)));
1429}
1430
1431static zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) {1568static zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) {
1432 return __multi3(lhs, rhs);1569 return __multi3(lhs, rhs);
1433}1570}
14341571
1572static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs) {
1573 return zig_bitcast_u128(zig_mul_i128(zig_bitcast_i128(lhs), zig_bitcast_i128(rhs)));
1574}
1575
1435zig_extern zig_u128 __udivti3(zig_u128 lhs, zig_u128 rhs);1576zig_extern zig_u128 __udivti3(zig_u128 lhs, zig_u128 rhs);
1436static zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) {1577static zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) {
1437 return __udivti3(lhs, rhs);1578 return __udivti3(lhs, rhs);
...@@ -1454,11 +1595,11 @@ static zig_i128 zig_rem_i128(zig_i128 lhs, zig_i128 rhs) {...@@ -1454,11 +1595,11 @@ static zig_i128 zig_rem_i128(zig_i128 lhs, zig_i128 rhs) {
14541595
1455static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) {1596static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) {
1456 zig_i128 rem = zig_rem_i128(lhs, rhs);1597 zig_i128 rem = zig_rem_i128(lhs, rhs);
1457 return zig_add_i128(rem, (((lhs.hi ^ rhs.hi) & rem.hi) < zig_as_i64(0) ? rhs : zig_as_i128(0, 0)));1598 return zig_add_i128(rem, ((lhs.hi ^ rhs.hi) & rem.hi) < INT64_C(0) ? rhs : zig_make_i128(0, 0));
1458}1599}
14591600
1460static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) {1601static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) {
1461 return zig_sub_i128(zig_div_trunc_i128(lhs, rhs), zig_as_i128(0, zig_cmp_i128(zig_and_i128(zig_xor_i128(lhs, rhs), zig_rem_i128(lhs, rhs)), zig_as_i128(0, 0)) < zig_as_i32(0)));1602 return zig_sub_i128(zig_div_trunc_i128(lhs, rhs), zig_make_i128(0, zig_cmp_i128(zig_and_i128(zig_xor_i128(lhs, rhs), zig_rem_i128(lhs, rhs)), zig_make_i128(0, 0)) < INT32_C(0)));
1462}1603}
14631604
1464#endif /* zig_has_int128 */1605#endif /* zig_has_int128 */
...@@ -1471,323 +1612,294 @@ static inline zig_u128 zig_nand_u128(zig_u128 lhs, zig_u128 rhs) {...@@ -1471,323 +1612,294 @@ static inline zig_u128 zig_nand_u128(zig_u128 lhs, zig_u128 rhs) {
1471}1612}
14721613
1473static inline zig_u128 zig_min_u128(zig_u128 lhs, zig_u128 rhs) {1614static inline zig_u128 zig_min_u128(zig_u128 lhs, zig_u128 rhs) {
1474 return zig_cmp_u128(lhs, rhs) < zig_as_i32(0) ? lhs : rhs;1615 return zig_cmp_u128(lhs, rhs) < INT32_C(0) ? lhs : rhs;
1475}1616}
14761617
1477static inline zig_i128 zig_min_i128(zig_i128 lhs, zig_i128 rhs) {1618static inline zig_i128 zig_min_i128(zig_i128 lhs, zig_i128 rhs) {
1478 return zig_cmp_i128(lhs, rhs) < zig_as_i32(0) ? lhs : rhs;1619 return zig_cmp_i128(lhs, rhs) < INT32_C(0) ? lhs : rhs;
1479}1620}
14801621
1481static inline zig_u128 zig_max_u128(zig_u128 lhs, zig_u128 rhs) {1622static inline zig_u128 zig_max_u128(zig_u128 lhs, zig_u128 rhs) {
1482 return zig_cmp_u128(lhs, rhs) > zig_as_i32(0) ? lhs : rhs;1623 return zig_cmp_u128(lhs, rhs) > INT32_C(0) ? lhs : rhs;
1483}1624}
14841625
1485static inline zig_i128 zig_max_i128(zig_i128 lhs, zig_i128 rhs) {1626static inline zig_i128 zig_max_i128(zig_i128 lhs, zig_i128 rhs) {
1486 return zig_cmp_i128(lhs, rhs) > zig_as_i32(0) ? lhs : rhs;1627 return zig_cmp_i128(lhs, rhs) > INT32_C(0) ? lhs : rhs;
1487}
1488
1489static inline zig_i128 zig_shr_i128(zig_i128 lhs, zig_u8 rhs) {
1490 zig_i128 sign_mask = zig_cmp_i128(lhs, zig_as_i128(0, 0)) < zig_as_i32(0) ? zig_sub_i128(zig_as_i128(0, 0), zig_as_i128(0, 1)) : zig_as_i128(0, 0);
1491 return zig_xor_i128(zig_bitcast_i128(zig_shr_u128(zig_bitcast_u128(zig_xor_i128(lhs, sign_mask)), rhs)), sign_mask);
1492}1628}
14931629
1494static inline zig_u128 zig_wrap_u128(zig_u128 val, zig_u8 bits) {1630static inline zig_u128 zig_wrap_u128(zig_u128 val, uint8_t bits) {
1495 return zig_and_u128(val, zig_maxInt(u128, bits));1631 return zig_and_u128(val, zig_maxInt_u(128, bits));
1496}1632}
14971633
1498static inline zig_i128 zig_wrap_i128(zig_i128 val, zig_u8 bits) {1634static inline zig_i128 zig_wrap_i128(zig_i128 val, uint8_t bits) {
1499 return zig_as_i128(zig_wrap_i64(zig_hi_i128(val), bits - zig_as_u8(64)), zig_lo_i128(val));1635 return zig_make_i128(zig_wrap_i64(zig_hi_i128(val), bits - UINT8_C(64)), zig_lo_i128(val));
1500}1636}
15011637
1502static inline zig_u128 zig_shlw_u128(zig_u128 lhs, zig_u8 rhs, zig_u8 bits) {1638static inline zig_u128 zig_shlw_u128(zig_u128 lhs, uint8_t rhs, uint8_t bits) {
1503 return zig_wrap_u128(zig_shl_u128(lhs, rhs), bits);1639 return zig_wrap_u128(zig_shl_u128(lhs, rhs), bits);
1504}1640}
15051641
1506static inline zig_i128 zig_shlw_i128(zig_i128 lhs, zig_u8 rhs, zig_u8 bits) {1642static inline zig_i128 zig_shlw_i128(zig_i128 lhs, uint8_t rhs, uint8_t bits) {
1507 return zig_wrap_i128(zig_bitcast_i128(zig_shl_u128(zig_bitcast_u128(lhs), rhs)), bits);1643 return zig_wrap_i128(zig_bitcast_i128(zig_shl_u128(zig_bitcast_u128(lhs), rhs)), bits);
1508}1644}
15091645
1510static inline zig_u128 zig_addw_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1646static inline zig_u128 zig_addw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
1511 return zig_wrap_u128(zig_add_u128(lhs, rhs), bits);1647 return zig_wrap_u128(zig_add_u128(lhs, rhs), bits);
1512}1648}
15131649
1514static inline zig_i128 zig_addw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {1650static inline zig_i128 zig_addw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
1515 return zig_wrap_i128(zig_bitcast_i128(zig_add_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits);1651 return zig_wrap_i128(zig_bitcast_i128(zig_add_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits);
1516}1652}
15171653
1518static inline zig_u128 zig_subw_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1654static inline zig_u128 zig_subw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
1519 return zig_wrap_u128(zig_sub_u128(lhs, rhs), bits);1655 return zig_wrap_u128(zig_sub_u128(lhs, rhs), bits);
1520}1656}
15211657
1522static inline zig_i128 zig_subw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {1658static inline zig_i128 zig_subw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
1523 return zig_wrap_i128(zig_bitcast_i128(zig_sub_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits);1659 return zig_wrap_i128(zig_bitcast_i128(zig_sub_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits);
1524}1660}
15251661
1526static inline zig_u128 zig_mulw_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1662static inline zig_u128 zig_mulw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
1527 return zig_wrap_u128(zig_mul_u128(lhs, rhs), bits);1663 return zig_wrap_u128(zig_mul_u128(lhs, rhs), bits);
1528}1664}
15291665
1530static inline zig_i128 zig_mulw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {1666static inline zig_i128 zig_mulw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
1531 return zig_wrap_i128(zig_bitcast_i128(zig_mul_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits);1667 return zig_wrap_i128(zig_bitcast_i128(zig_mul_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits);
1532}1668}
15331669
1534#if zig_has_int1281670#if zig_has_int128
15351671
1536static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1672static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
1537#if zig_has_builtin(add_overflow)1673#if zig_has_builtin(add_overflow)
1538 zig_u128 full_res;1674 zig_u128 full_res;
1539 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);1675 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);
1540 *res = zig_wrap_u128(full_res, bits);1676 *res = zig_wrap_u128(full_res, bits);
1541 return overflow || full_res < zig_minInt(u128, bits) || full_res > zig_maxInt(u128, bits);1677 return overflow || full_res < zig_minInt_u(128, bits) || full_res > zig_maxInt_u(128, bits);
1542#else1678#else
1543 *res = zig_addw_u128(lhs, rhs, bits);1679 *res = zig_addw_u128(lhs, rhs, bits);
1544 return *res < lhs;1680 return *res < lhs;
1545#endif1681#endif
1546}1682}
15471683
1548zig_extern zig_i128 __addoti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow);1684zig_extern zig_i128 __addoti4(zig_i128 lhs, zig_i128 rhs, int *overflow);
1549static inline bool zig_addo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {1685static inline bool zig_addo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
1550#if zig_has_builtin(add_overflow)1686#if zig_has_builtin(add_overflow)
1551 zig_i128 full_res;1687 zig_i128 full_res;
1552 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);1688 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);
1553#else1689#else
1554 zig_c_int overflow_int;1690 int overflow_int;
1555 zig_i128 full_res = __addoti4(lhs, rhs, &overflow_int);1691 zig_i128 full_res = __addoti4(lhs, rhs, &overflow_int);
1556 bool overflow = overflow_int != 0;1692 bool overflow = overflow_int != 0;
1557#endif1693#endif
1558 *res = zig_wrap_i128(full_res, bits);1694 *res = zig_wrap_i128(full_res, bits);
1559 return overflow || full_res < zig_minInt(i128, bits) || full_res > zig_maxInt(i128, bits);1695 return overflow || full_res < zig_minInt_i(128, bits) || full_res > zig_maxInt_i(128, bits);
1560}1696}
15611697
1562static inline bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1698static inline bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
1563#if zig_has_builtin(sub_overflow)1699#if zig_has_builtin(sub_overflow)
1564 zig_u128 full_res;1700 zig_u128 full_res;
1565 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);1701 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);
1566 *res = zig_wrap_u128(full_res, bits);1702 *res = zig_wrap_u128(full_res, bits);
1567 return overflow || full_res < zig_minInt(u128, bits) || full_res > zig_maxInt(u128, bits);1703 return overflow || full_res < zig_minInt_u(128, bits) || full_res > zig_maxInt_u(128, bits);
1568#else1704#else
1569 *res = zig_subw_u128(lhs, rhs, bits);1705 *res = zig_subw_u128(lhs, rhs, bits);
1570 return *res > lhs;1706 return *res > lhs;
1571#endif1707#endif
1572}1708}
15731709
1574zig_extern zig_i128 __suboti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow);1710zig_extern zig_i128 __suboti4(zig_i128 lhs, zig_i128 rhs, int *overflow);
1575static inline bool zig_subo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {1711static inline bool zig_subo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
1576#if zig_has_builtin(sub_overflow)1712#if zig_has_builtin(sub_overflow)
1577 zig_i128 full_res;1713 zig_i128 full_res;
1578 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);1714 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);
1579#else1715#else
1580 zig_c_int overflow_int;1716 int overflow_int;
1581 zig_i128 full_res = __suboti4(lhs, rhs, &overflow_int);1717 zig_i128 full_res = __suboti4(lhs, rhs, &overflow_int);
1582 bool overflow = overflow_int != 0;1718 bool overflow = overflow_int != 0;
1583#endif1719#endif
1584 *res = zig_wrap_i128(full_res, bits);1720 *res = zig_wrap_i128(full_res, bits);
1585 return overflow || full_res < zig_minInt(i128, bits) || full_res > zig_maxInt(i128, bits);1721 return overflow || full_res < zig_minInt_i(128, bits) || full_res > zig_maxInt_i(128, bits);
1586}1722}
15871723
1588static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1724static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
1589#if zig_has_builtin(mul_overflow)1725#if zig_has_builtin(mul_overflow)
1590 zig_u128 full_res;1726 zig_u128 full_res;
1591 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);1727 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);
1592 *res = zig_wrap_u128(full_res, bits);1728 *res = zig_wrap_u128(full_res, bits);
1593 return overflow || full_res < zig_minInt(u128, bits) || full_res > zig_maxInt(u128, bits);1729 return overflow || full_res < zig_minInt_u(128, bits) || full_res > zig_maxInt_u(128, bits);
1594#else1730#else
1595 *res = zig_mulw_u128(lhs, rhs, bits);1731 *res = zig_mulw_u128(lhs, rhs, bits);
1596 return rhs != zig_as_u128(0, 0) && lhs > zig_maxInt(u128, bits) / rhs;1732 return rhs != zig_make_u128(0, 0) && lhs > zig_maxInt_u(128, bits) / rhs;
1597#endif1733#endif
1598}1734}
15991735
1600zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow);1736zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, int *overflow);
1601static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {1737static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
1602#if zig_has_builtin(mul_overflow)1738#if zig_has_builtin(mul_overflow)
1603 zig_i128 full_res;1739 zig_i128 full_res;
1604 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);1740 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);
1605#else1741#else
1606 zig_c_int overflow_int;1742 int overflow_int;
1607 zig_i128 full_res = __muloti4(lhs, rhs, &overflow_int);1743 zig_i128 full_res = __muloti4(lhs, rhs, &overflow_int);
1608 bool overflow = overflow_int != 0;1744 bool overflow = overflow_int != 0;
1609#endif1745#endif
1610 *res = zig_wrap_i128(full_res, bits);1746 *res = zig_wrap_i128(full_res, bits);
1611 return overflow || full_res < zig_minInt(i128, bits) || full_res > zig_maxInt(i128, bits);1747 return overflow || full_res < zig_minInt_i(128, bits) || full_res > zig_maxInt_i(128, bits);
1612}1748}
16131749
1614#else /* zig_has_int128 */1750#else /* zig_has_int128 */
16151751
1616static inline bool zig_overflow_u128(bool overflow, zig_u128 full_res, zig_u8 bits) {1752static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
1617 return overflow ||1753 uint64_t hi;
1618 zig_cmp_u128(full_res, zig_minInt(u128, bits)) < zig_as_i32(0) ||1754 bool overflow = zig_addo_u64(&hi, lhs.hi, rhs.hi, bits - 64);
1619 zig_cmp_u128(full_res, zig_maxInt(u128, bits)) > zig_as_i32(0);1755 return overflow ^ zig_addo_u64(&res->hi, hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64);
1620}1756}
16211757
1622static inline bool zig_overflow_i128(bool overflow, zig_i128 full_res, zig_u8 bits) {1758static inline bool zig_addo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
1623 return overflow ||1759 int64_t hi;
1624 zig_cmp_i128(full_res, zig_minInt(i128, bits)) < zig_as_i32(0) ||1760 bool overflow = zig_addo_i64(&hi, lhs.hi, rhs.hi, bits - 64);
1625 zig_cmp_i128(full_res, zig_maxInt(i128, bits)) > zig_as_i32(0);1761 return overflow ^ zig_addo_i64(&res->hi, hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64);
1626}1762}
16271763
1628static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1764static inline bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
1629 zig_u128 full_res;1765 uint64_t hi;
1630 bool overflow =1766 bool overflow = zig_subo_u64(&hi, lhs.hi, rhs.hi, bits - 64);
1631 zig_addo_u64(&full_res.hi, lhs.hi, rhs.hi, 64) |1767 return overflow ^ zig_subo_u64(&res->hi, hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64);
1632 zig_addo_u64(&full_res.hi, full_res.hi, zig_addo_u64(&full_res.lo, lhs.lo, rhs.lo, 64), 64);
1633 *res = zig_wrap_u128(full_res, bits);
1634 return zig_overflow_u128(overflow, full_res, bits);
1635}1768}
16361769
1637zig_extern zig_i128 __addoti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow);1770static inline bool zig_subo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
1638static inline bool zig_addo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {1771 int64_t hi;
1639 zig_c_int overflow_int;1772 bool overflow = zig_subo_i64(&hi, lhs.hi, rhs.hi, bits - 64);
1640 zig_i128 full_res = __addoti4(lhs, rhs, &overflow_int);1773 return overflow ^ zig_subo_i64(&res->hi, hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64);
1641 *res = zig_wrap_i128(full_res, bits);
1642 return zig_overflow_i128(overflow_int, full_res, bits);
1643}1774}
16441775
1645static inline bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1776static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
1646 zig_u128 full_res;
1647 bool overflow =
1648 zig_subo_u64(&full_res.hi, lhs.hi, rhs.hi, 64) |
1649 zig_subo_u64(&full_res.hi, full_res.hi, zig_subo_u64(&full_res.lo, lhs.lo, rhs.lo, 64), 64);
1650 *res = zig_wrap_u128(full_res, bits);
1651 return zig_overflow_u128(overflow, full_res, bits);
1652}
1653
1654zig_extern zig_i128 __suboti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow);
1655static inline bool zig_subo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1656 zig_c_int overflow_int;
1657 zig_i128 full_res = __suboti4(lhs, rhs, &overflow_int);
1658 *res = zig_wrap_i128(full_res, bits);
1659 return zig_overflow_i128(overflow_int, full_res, bits);
1660}
1661
1662static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1663 *res = zig_mulw_u128(lhs, rhs, bits);1777 *res = zig_mulw_u128(lhs, rhs, bits);
1664 return zig_cmp_u128(*res, zig_as_u128(0, 0)) != zig_as_i32(0) &&1778 return zig_cmp_u128(*res, zig_make_u128(0, 0)) != INT32_C(0) &&
1665 zig_cmp_u128(lhs, zig_div_trunc_u128(zig_maxInt(u128, bits), rhs)) > zig_as_i32(0);1779 zig_cmp_u128(lhs, zig_div_trunc_u128(zig_maxInt_u(128, bits), rhs)) > INT32_C(0);
1666}1780}
16671781
1668zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow);1782zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, int *overflow);
1669static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {1783static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
1670 zig_c_int overflow_int;1784 int overflow_int;
1671 zig_i128 full_res = __muloti4(lhs, rhs, &overflow_int);1785 zig_i128 full_res = __muloti4(lhs, rhs, &overflow_int);
1786 bool overflow = overflow_int != 0 ||
1787 zig_cmp_i128(full_res, zig_minInt_i(128, bits)) < INT32_C(0) ||
1788 zig_cmp_i128(full_res, zig_maxInt_i(128, bits)) > INT32_C(0);
1672 *res = zig_wrap_i128(full_res, bits);1789 *res = zig_wrap_i128(full_res, bits);
1673 return zig_overflow_i128(overflow_int, full_res, bits);1790 return overflow;
1674}1791}
16751792
1676#endif /* zig_has_int128 */1793#endif /* zig_has_int128 */
16771794
1678static inline bool zig_shlo_u128(zig_u128 *res, zig_u128 lhs, zig_u8 rhs, zig_u8 bits) {1795static inline bool zig_shlo_u128(zig_u128 *res, zig_u128 lhs, uint8_t rhs, uint8_t bits) {
1679 *res = zig_shlw_u128(lhs, rhs, bits);1796 *res = zig_shlw_u128(lhs, rhs, bits);
1680 return zig_cmp_u128(lhs, zig_shr_u128(zig_maxInt(u128, bits), rhs)) > zig_as_i32(0);1797 return zig_cmp_u128(lhs, zig_shr_u128(zig_maxInt_u(128, bits), rhs)) > INT32_C(0);
1681}1798}
16821799
1683static inline bool zig_shlo_i128(zig_i128 *res, zig_i128 lhs, zig_u8 rhs, zig_u8 bits) {1800static inline bool zig_shlo_i128(zig_i128 *res, zig_i128 lhs, uint8_t rhs, uint8_t bits) {
1684 *res = zig_shlw_i128(lhs, rhs, bits);1801 *res = zig_shlw_i128(lhs, rhs, bits);
1685 zig_i128 mask = zig_bitcast_i128(zig_shl_u128(zig_maxInt_u128, bits - rhs - zig_as_u8(1)));1802 zig_i128 mask = zig_bitcast_i128(zig_shl_u128(zig_maxInt_u128, bits - rhs - UINT8_C(1)));
1686 return zig_cmp_i128(zig_and_i128(lhs, mask), zig_as_i128(0, 0)) != zig_as_i32(0) &&1803 return zig_cmp_i128(zig_and_i128(lhs, mask), zig_make_i128(0, 0)) != INT32_C(0) &&
1687 zig_cmp_i128(zig_and_i128(lhs, mask), mask) != zig_as_i32(0);1804 zig_cmp_i128(zig_and_i128(lhs, mask), mask) != INT32_C(0);
1688}1805}
16891806
1690static inline zig_u128 zig_shls_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1807static inline zig_u128 zig_shls_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
1691 zig_u128 res;1808 zig_u128 res;
1692 if (zig_cmp_u128(rhs, zig_as_u128(0, bits)) >= zig_as_i32(0))1809 if (zig_cmp_u128(rhs, zig_make_u128(0, bits)) >= INT32_C(0))
1693 return zig_cmp_u128(lhs, zig_as_u128(0, 0)) != zig_as_i32(0) ? zig_maxInt(u128, bits) : lhs;1810 return zig_cmp_u128(lhs, zig_make_u128(0, 0)) != INT32_C(0) ? zig_maxInt_u(128, bits) : lhs;
16941811 return zig_shlo_u128(&res, lhs, (uint8_t)zig_lo_u128(rhs), bits) ? zig_maxInt_u(128, bits) : res;
1695#if zig_has_int128
1696 return zig_shlo_u128(&res, lhs, (zig_u8)rhs, bits) ? zig_maxInt(u128, bits) : res;
1697#else
1698 return zig_shlo_u128(&res, lhs, (zig_u8)rhs.lo, bits) ? zig_maxInt(u128, bits) : res;
1699#endif
1700}1812}
17011813
1702static inline zig_i128 zig_shls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {1814static inline zig_i128 zig_shls_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
1703 zig_i128 res;1815 zig_i128 res;
1704 if (zig_cmp_u128(zig_bitcast_u128(rhs), zig_as_u128(0, bits)) < zig_as_i32(0) && !zig_shlo_i128(&res, lhs, zig_lo_i128(rhs), bits)) return res;1816 if (zig_cmp_u128(zig_bitcast_u128(rhs), zig_make_u128(0, bits)) < INT32_C(0) && !zig_shlo_i128(&res, lhs, (uint8_t)zig_lo_i128(rhs), bits)) return res;
1705 return zig_cmp_i128(lhs, zig_as_i128(0, 0)) < zig_as_i32(0) ? zig_minInt(i128, bits) : zig_maxInt(i128, bits);1817 return zig_cmp_i128(lhs, zig_make_i128(0, 0)) < INT32_C(0) ? zig_minInt_i(128, bits) : zig_maxInt_i(128, bits);
1706}1818}
17071819
1708static inline zig_u128 zig_adds_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1820static inline zig_u128 zig_adds_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
1709 zig_u128 res;1821 zig_u128 res;
1710 return zig_addo_u128(&res, lhs, rhs, bits) ? zig_maxInt(u128, bits) : res;1822 return zig_addo_u128(&res, lhs, rhs, bits) ? zig_maxInt_u(128, bits) : res;
1711}1823}
17121824
1713static inline zig_i128 zig_adds_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {1825static inline zig_i128 zig_adds_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
1714 zig_i128 res;1826 zig_i128 res;
1715 if (!zig_addo_i128(&res, lhs, rhs, bits)) return res;1827 if (!zig_addo_i128(&res, lhs, rhs, bits)) return res;
1716 return zig_cmp_i128(res, zig_as_i128(0, 0)) >= zig_as_i32(0) ? zig_minInt(i128, bits) : zig_maxInt(i128, bits);1828 return zig_cmp_i128(res, zig_make_i128(0, 0)) >= INT32_C(0) ? zig_minInt_i(128, bits) : zig_maxInt_i(128, bits);
1717}1829}
17181830
1719static inline zig_u128 zig_subs_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1831static inline zig_u128 zig_subs_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
1720 zig_u128 res;1832 zig_u128 res;
1721 return zig_subo_u128(&res, lhs, rhs, bits) ? zig_minInt(u128, bits) : res;1833 return zig_subo_u128(&res, lhs, rhs, bits) ? zig_minInt_u(128, bits) : res;
1722}1834}
17231835
1724static inline zig_i128 zig_subs_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {1836static inline zig_i128 zig_subs_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
1725 zig_i128 res;1837 zig_i128 res;
1726 if (!zig_subo_i128(&res, lhs, rhs, bits)) return res;1838 if (!zig_subo_i128(&res, lhs, rhs, bits)) return res;
1727 return zig_cmp_i128(res, zig_as_i128(0, 0)) >= zig_as_i32(0) ? zig_minInt(i128, bits) : zig_maxInt(i128, bits);1839 return zig_cmp_i128(res, zig_make_i128(0, 0)) >= INT32_C(0) ? zig_minInt_i(128, bits) : zig_maxInt_i(128, bits);
1728}1840}
17291841
1730static inline zig_u128 zig_muls_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {1842static inline zig_u128 zig_muls_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
1731 zig_u128 res;1843 zig_u128 res;
1732 return zig_mulo_u128(&res, lhs, rhs, bits) ? zig_maxInt(u128, bits) : res;1844 return zig_mulo_u128(&res, lhs, rhs, bits) ? zig_maxInt_u(128, bits) : res;
1733}1845}
17341846
1735static inline zig_i128 zig_muls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {1847static inline zig_i128 zig_muls_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
1736 zig_i128 res;1848 zig_i128 res;
1737 if (!zig_mulo_i128(&res, lhs, rhs, bits)) return res;1849 if (!zig_mulo_i128(&res, lhs, rhs, bits)) return res;
1738 return zig_cmp_i128(zig_xor_i128(lhs, rhs), zig_as_i128(0, 0)) < zig_as_i32(0) ? zig_minInt(i128, bits) : zig_maxInt(i128, bits);1850 return zig_cmp_i128(zig_xor_i128(lhs, rhs), zig_make_i128(0, 0)) < INT32_C(0) ? zig_minInt_i(128, bits) : zig_maxInt_i(128, bits);
1739}1851}
17401852
1741static inline zig_u8 zig_clz_u128(zig_u128 val, zig_u8 bits) {1853static inline uint8_t zig_clz_u128(zig_u128 val, uint8_t bits) {
1742 if (bits <= zig_as_u8(64)) return zig_clz_u64(zig_lo_u128(val), bits);1854 if (bits <= UINT8_C(64)) return zig_clz_u64(zig_lo_u128(val), bits);
1743 if (zig_hi_u128(val) != 0) return zig_clz_u64(zig_hi_u128(val), bits - zig_as_u8(64));1855 if (zig_hi_u128(val) != 0) return zig_clz_u64(zig_hi_u128(val), bits - UINT8_C(64));
1744 return zig_clz_u64(zig_lo_u128(val), zig_as_u8(64)) + (bits - zig_as_u8(64));1856 return zig_clz_u64(zig_lo_u128(val), UINT8_C(64)) + (bits - UINT8_C(64));
1745}1857}
17461858
1747static inline zig_u8 zig_clz_i128(zig_i128 val, zig_u8 bits) {1859static inline uint8_t zig_clz_i128(zig_i128 val, uint8_t bits) {
1748 return zig_clz_u128(zig_bitcast_u128(val), bits);1860 return zig_clz_u128(zig_bitcast_u128(val), bits);
1749}1861}
17501862
1751static inline zig_u8 zig_ctz_u128(zig_u128 val, zig_u8 bits) {1863static inline uint8_t zig_ctz_u128(zig_u128 val, uint8_t bits) {
1752 if (zig_lo_u128(val) != 0) return zig_ctz_u64(zig_lo_u128(val), zig_as_u8(64));1864 if (zig_lo_u128(val) != 0) return zig_ctz_u64(zig_lo_u128(val), UINT8_C(64));
1753 return zig_ctz_u64(zig_hi_u128(val), bits - zig_as_u8(64)) + zig_as_u8(64);1865 return zig_ctz_u64(zig_hi_u128(val), bits - UINT8_C(64)) + UINT8_C(64);
1754}1866}
17551867
1756static inline zig_u8 zig_ctz_i128(zig_i128 val, zig_u8 bits) {1868static inline uint8_t zig_ctz_i128(zig_i128 val, uint8_t bits) {
1757 return zig_ctz_u128(zig_bitcast_u128(val), bits);1869 return zig_ctz_u128(zig_bitcast_u128(val), bits);
1758}1870}
17591871
1760static inline zig_u8 zig_popcount_u128(zig_u128 val, zig_u8 bits) {1872static inline uint8_t zig_popcount_u128(zig_u128 val, uint8_t bits) {
1761 return zig_popcount_u64(zig_hi_u128(val), bits - zig_as_u8(64)) +1873 return zig_popcount_u64(zig_hi_u128(val), bits - UINT8_C(64)) +
1762 zig_popcount_u64(zig_lo_u128(val), zig_as_u8(64));1874 zig_popcount_u64(zig_lo_u128(val), UINT8_C(64));
1763}1875}
17641876
1765static inline zig_u8 zig_popcount_i128(zig_i128 val, zig_u8 bits) {1877static inline uint8_t zig_popcount_i128(zig_i128 val, uint8_t bits) {
1766 return zig_popcount_u128(zig_bitcast_u128(val), bits);1878 return zig_popcount_u128(zig_bitcast_u128(val), bits);
1767}1879}
17681880
1769static inline zig_u128 zig_byte_swap_u128(zig_u128 val, zig_u8 bits) {1881static inline zig_u128 zig_byte_swap_u128(zig_u128 val, uint8_t bits) {
1770 zig_u128 full_res;1882 zig_u128 full_res;
1771#if zig_has_builtin(bswap128)1883#if zig_has_builtin(bswap128)
1772 full_res = __builtin_bswap128(val);1884 full_res = __builtin_bswap128(val);
1773#else1885#else
1774 full_res = zig_as_u128(zig_byte_swap_u64(zig_lo_u128(val), zig_as_u8(64)),1886 full_res = zig_make_u128(zig_byte_swap_u64(zig_lo_u128(val), UINT8_C(64)),
1775 zig_byte_swap_u64(zig_hi_u128(val), zig_as_u8(64)));1887 zig_byte_swap_u64(zig_hi_u128(val), UINT8_C(64)));
1776#endif1888#endif
1777 return zig_shr_u128(full_res, zig_as_u8(128) - bits);1889 return zig_shr_u128(full_res, UINT8_C(128) - bits);
1778}1890}
17791891
1780static inline zig_i128 zig_byte_swap_i128(zig_i128 val, zig_u8 bits) {1892static inline zig_i128 zig_byte_swap_i128(zig_i128 val, uint8_t bits) {
1781 return zig_bitcast_i128(zig_byte_swap_u128(zig_bitcast_u128(val), bits));1893 return zig_bitcast_i128(zig_byte_swap_u128(zig_bitcast_u128(val), bits));
1782}1894}
17831895
1784static inline zig_u128 zig_bit_reverse_u128(zig_u128 val, zig_u8 bits) {1896static inline zig_u128 zig_bit_reverse_u128(zig_u128 val, uint8_t bits) {
1785 return zig_shr_u128(zig_as_u128(zig_bit_reverse_u64(zig_lo_u128(val), zig_as_u8(64)),1897 return zig_shr_u128(zig_make_u128(zig_bit_reverse_u64(zig_lo_u128(val), UINT8_C(64)),
1786 zig_bit_reverse_u64(zig_hi_u128(val), zig_as_u8(64))),1898 zig_bit_reverse_u64(zig_hi_u128(val), UINT8_C(64))),
1787 zig_as_u8(128) - bits);1899 UINT8_C(128) - bits);
1788}1900}
17891901
1790static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, zig_u8 bits) {1902static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, uint8_t bits) {
1791 return zig_bitcast_i128(zig_bit_reverse_u128(zig_bitcast_u128(val), bits));1903 return zig_bitcast_i128(zig_bit_reverse_u128(zig_bitcast_u128(val), bits));
1792}1904}
17931905
...@@ -1810,85 +1922,87 @@ static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, zig_u8 bits) {...@@ -1810,85 +1922,87 @@ static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, zig_u8 bits) {
18101922
1811#if (zig_has_builtin(nan) && zig_has_builtin(nans) && zig_has_builtin(inf)) || defined(zig_gnuc)1923#if (zig_has_builtin(nan) && zig_has_builtin(nans) && zig_has_builtin(inf)) || defined(zig_gnuc)
1812#define zig_has_float_builtins 11924#define zig_has_float_builtins 1
1813#define zig_as_special_f16(sign, name, arg, repr) sign zig_as_f16(__builtin_##name, )(arg)1925#define zig_make_special_f16(sign, name, arg, repr) sign zig_make_f16(__builtin_##name, )(arg)
1814#define zig_as_special_f32(sign, name, arg, repr) sign zig_as_f32(__builtin_##name, )(arg)1926#define zig_make_special_f32(sign, name, arg, repr) sign zig_make_f32(__builtin_##name, )(arg)
1815#define zig_as_special_f64(sign, name, arg, repr) sign zig_as_f64(__builtin_##name, )(arg)1927#define zig_make_special_f64(sign, name, arg, repr) sign zig_make_f64(__builtin_##name, )(arg)
1816#define zig_as_special_f80(sign, name, arg, repr) sign zig_as_f80(__builtin_##name, )(arg)1928#define zig_make_special_f80(sign, name, arg, repr) sign zig_make_f80(__builtin_##name, )(arg)
1817#define zig_as_special_f128(sign, name, arg, repr) sign zig_as_f128(__builtin_##name, )(arg)1929#define zig_make_special_f128(sign, name, arg, repr) sign zig_make_f128(__builtin_##name, )(arg)
1818#define zig_as_special_c_longdouble(sign, name, arg, repr) sign zig_as_c_longdouble(__builtin_##name, )(arg)1930#define zig_make_special_c_longdouble(sign, name, arg, repr) sign zig_make_c_longdouble(__builtin_##name, )(arg)
1819#else1931#else
1820#define zig_has_float_builtins 01932#define zig_has_float_builtins 0
1821#define zig_as_special_f16(sign, name, arg, repr) zig_float_from_repr_f16(repr)1933#define zig_make_special_f16(sign, name, arg, repr) zig_float_from_repr_f16(repr)
1822#define zig_as_special_f32(sign, name, arg, repr) zig_float_from_repr_f32(repr)1934#define zig_make_special_f32(sign, name, arg, repr) zig_float_from_repr_f32(repr)
1823#define zig_as_special_f64(sign, name, arg, repr) zig_float_from_repr_f64(repr)1935#define zig_make_special_f64(sign, name, arg, repr) zig_float_from_repr_f64(repr)
1824#define zig_as_special_f80(sign, name, arg, repr) zig_float_from_repr_f80(repr)1936#define zig_make_special_f80(sign, name, arg, repr) zig_float_from_repr_f80(repr)
1825#define zig_as_special_f128(sign, name, arg, repr) zig_float_from_repr_f128(repr)1937#define zig_make_special_f128(sign, name, arg, repr) zig_float_from_repr_f128(repr)
1826#define zig_as_special_c_longdouble(sign, name, arg, repr) zig_float_from_repr_c_longdouble(repr)1938#define zig_make_special_c_longdouble(sign, name, arg, repr) zig_float_from_repr_c_longdouble(repr)
1827#endif1939#endif
18281940
1829#define zig_has_f16 11941#define zig_has_f16 1
1830#define zig_bitSizeOf_f16 161942#define zig_bitSizeOf_f16 16
1831#define zig_libc_name_f16(name) __##name##h1943#define zig_libc_name_f16(name) __##name##h
1832#define zig_as_special_constant_f16(sign, name, arg, repr) zig_as_special_f16(sign, name, arg, repr)1944#define zig_make_special_constant_f16(sign, name, arg, repr) zig_make_special_f16(sign, name, arg, repr)
1833#if FLT_MANT_DIG == 111945#if FLT_MANT_DIG == 11
1834typedef float zig_f16;1946typedef float zig_f16;
1835#define zig_as_f16(fp, repr) fp##f1947#define zig_make_f16(fp, repr) fp##f
1836#elif DBL_MANT_DIG == 111948#elif DBL_MANT_DIG == 11
1837typedef double zig_f16;1949typedef double zig_f16;
1838#define zig_as_f16(fp, repr) fp1950#define zig_make_f16(fp, repr) fp
1839#elif LDBL_MANT_DIG == 111951#elif LDBL_MANT_DIG == 11
1840#define zig_bitSizeOf_c_longdouble 161952#define zig_bitSizeOf_c_longdouble 16
1953typedef uint16_t zig_repr_c_longdouble;
1841typedef long double zig_f16;1954typedef long double zig_f16;
1842#define zig_as_f16(fp, repr) fp##l1955#define zig_make_f16(fp, repr) fp##l
1843#elif FLT16_MANT_DIG == 11 && (zig_has_builtin(inff16) || defined(zig_gnuc))1956#elif FLT16_MANT_DIG == 11 && (zig_has_builtin(inff16) || defined(zig_gnuc))
1844typedef _Float16 zig_f16;1957typedef _Float16 zig_f16;
1845#define zig_as_f16(fp, repr) fp##f161958#define zig_make_f16(fp, repr) fp##f16
1846#elif defined(__SIZEOF_FP16__)1959#elif defined(__SIZEOF_FP16__)
1847typedef __fp16 zig_f16;1960typedef __fp16 zig_f16;
1848#define zig_as_f16(fp, repr) fp##f161961#define zig_make_f16(fp, repr) fp##f16
1849#else1962#else
1850#undef zig_has_f161963#undef zig_has_f16
1851#define zig_has_f16 01964#define zig_has_f16 0
1852#define zig_repr_f16 i161965#define zig_bitSizeOf_repr_f16 16
1853typedef zig_i16 zig_f16;1966typedef int16_t zig_f16;
1854#define zig_as_f16(fp, repr) repr1967#define zig_make_f16(fp, repr) repr
1855#undef zig_as_special_f161968#undef zig_make_special_f16
1856#define zig_as_special_f16(sign, name, arg, repr) repr1969#define zig_make_special_f16(sign, name, arg, repr) repr
1857#undef zig_as_special_constant_f161970#undef zig_make_special_constant_f16
1858#define zig_as_special_constant_f16(sign, name, arg, repr) repr1971#define zig_make_special_constant_f16(sign, name, arg, repr) repr
1859#endif1972#endif
18601973
1861#define zig_has_f32 11974#define zig_has_f32 1
1862#define zig_bitSizeOf_f32 321975#define zig_bitSizeOf_f32 32
1863#define zig_libc_name_f32(name) name##f1976#define zig_libc_name_f32(name) name##f
1864#if _MSC_VER1977#if _MSC_VER
1865#define zig_as_special_constant_f32(sign, name, arg, repr) sign zig_as_f32(zig_msvc_flt_##name, )1978#define zig_make_special_constant_f32(sign, name, arg, repr) sign zig_make_f32(zig_msvc_flt_##name, )
1866#else1979#else
1867#define zig_as_special_constant_f32(sign, name, arg, repr) zig_as_special_f32(sign, name, arg, repr)1980#define zig_make_special_constant_f32(sign, name, arg, repr) zig_make_special_f32(sign, name, arg, repr)
1868#endif1981#endif
1869#if FLT_MANT_DIG == 241982#if FLT_MANT_DIG == 24
1870typedef float zig_f32;1983typedef float zig_f32;
1871#define zig_as_f32(fp, repr) fp##f1984#define zig_make_f32(fp, repr) fp##f
1872#elif DBL_MANT_DIG == 241985#elif DBL_MANT_DIG == 24
1873typedef double zig_f32;1986typedef double zig_f32;
1874#define zig_as_f32(fp, repr) fp1987#define zig_make_f32(fp, repr) fp
1875#elif LDBL_MANT_DIG == 241988#elif LDBL_MANT_DIG == 24
1876#define zig_bitSizeOf_c_longdouble 321989#define zig_bitSizeOf_c_longdouble 32
1990typedef uint32_t zig_repr_c_longdouble;
1877typedef long double zig_f32;1991typedef long double zig_f32;
1878#define zig_as_f32(fp, repr) fp##l1992#define zig_make_f32(fp, repr) fp##l
1879#elif FLT32_MANT_DIG == 241993#elif FLT32_MANT_DIG == 24
1880typedef _Float32 zig_f32;1994typedef _Float32 zig_f32;
1881#define zig_as_f32(fp, repr) fp##f321995#define zig_make_f32(fp, repr) fp##f32
1882#else1996#else
1883#undef zig_has_f321997#undef zig_has_f32
1884#define zig_has_f32 01998#define zig_has_f32 0
1885#define zig_repr_f32 i321999#define zig_bitSizeOf_repr_f32 32
1886typedef zig_i32 zig_f32;2000typedef int32_t zig_f32;
1887#define zig_as_f32(fp, repr) repr2001#define zig_make_f32(fp, repr) repr
1888#undef zig_as_special_f322002#undef zig_make_special_f32
1889#define zig_as_special_f32(sign, name, arg, repr) repr2003#define zig_make_special_f32(sign, name, arg, repr) repr
1890#undef zig_as_special_constant_f322004#undef zig_make_special_constant_f32
1891#define zig_as_special_constant_f32(sign, name, arg, repr) repr2005#define zig_make_special_constant_f32(sign, name, arg, repr) repr
1892#endif2006#endif
18932007
1894#define zig_has_f64 12008#define zig_has_f64 1
...@@ -1897,109 +2011,113 @@ typedef zig_i32 zig_f32;...@@ -1897,109 +2011,113 @@ typedef zig_i32 zig_f32;
1897#if _MSC_VER2011#if _MSC_VER
1898#ifdef ZIG_TARGET_ABI_MSVC2012#ifdef ZIG_TARGET_ABI_MSVC
1899#define zig_bitSizeOf_c_longdouble 642013#define zig_bitSizeOf_c_longdouble 64
2014typedef uint64_t zig_repr_c_longdouble;
1900#endif2015#endif
1901#define zig_as_special_constant_f64(sign, name, arg, repr) sign zig_as_f64(zig_msvc_flt_##name, )2016#define zig_make_special_constant_f64(sign, name, arg, repr) sign zig_make_f64(zig_msvc_flt_##name, )
1902#else /* _MSC_VER */2017#else /* _MSC_VER */
1903#define zig_as_special_constant_f64(sign, name, arg, repr) zig_as_special_f64(sign, name, arg, repr)2018#define zig_make_special_constant_f64(sign, name, arg, repr) zig_make_special_f64(sign, name, arg, repr)
1904#endif /* _MSC_VER */2019#endif /* _MSC_VER */
1905#if FLT_MANT_DIG == 532020#if FLT_MANT_DIG == 53
1906typedef float zig_f64;2021typedef float zig_f64;
1907#define zig_as_f64(fp, repr) fp##f2022#define zig_make_f64(fp, repr) fp##f
1908#elif DBL_MANT_DIG == 532023#elif DBL_MANT_DIG == 53
1909typedef double zig_f64;2024typedef double zig_f64;
1910#define zig_as_f64(fp, repr) fp2025#define zig_make_f64(fp, repr) fp
1911#elif LDBL_MANT_DIG == 532026#elif LDBL_MANT_DIG == 53
1912#define zig_bitSizeOf_c_longdouble 642027#define zig_bitSizeOf_c_longdouble 64
2028typedef uint64_t zig_repr_c_longdouble;
1913typedef long double zig_f64;2029typedef long double zig_f64;
1914#define zig_as_f64(fp, repr) fp##l2030#define zig_make_f64(fp, repr) fp##l
1915#elif FLT64_MANT_DIG == 532031#elif FLT64_MANT_DIG == 53
1916typedef _Float64 zig_f64;2032typedef _Float64 zig_f64;
1917#define zig_as_f64(fp, repr) fp##f642033#define zig_make_f64(fp, repr) fp##f64
1918#elif FLT32X_MANT_DIG == 532034#elif FLT32X_MANT_DIG == 53
1919typedef _Float32x zig_f64;2035typedef _Float32x zig_f64;
1920#define zig_as_f64(fp, repr) fp##f32x2036#define zig_make_f64(fp, repr) fp##f32x
1921#else2037#else
1922#undef zig_has_f642038#undef zig_has_f64
1923#define zig_has_f64 02039#define zig_has_f64 0
1924#define zig_repr_f64 i642040#define zig_bitSizeOf_repr_f64 64
1925typedef zig_i64 zig_f64;2041typedef int64_t zig_f64;
1926#define zig_as_f64(fp, repr) repr2042#define zig_make_f64(fp, repr) repr
1927#undef zig_as_special_f642043#undef zig_make_special_f64
1928#define zig_as_special_f64(sign, name, arg, repr) repr2044#define zig_make_special_f64(sign, name, arg, repr) repr
1929#undef zig_as_special_constant_f642045#undef zig_make_special_constant_f64
1930#define zig_as_special_constant_f64(sign, name, arg, repr) repr2046#define zig_make_special_constant_f64(sign, name, arg, repr) repr
1931#endif2047#endif
19322048
1933#define zig_has_f80 12049#define zig_has_f80 1
1934#define zig_bitSizeOf_f80 802050#define zig_bitSizeOf_f80 80
1935#define zig_libc_name_f80(name) __##name##x2051#define zig_libc_name_f80(name) __##name##x
1936#define zig_as_special_constant_f80(sign, name, arg, repr) zig_as_special_f80(sign, name, arg, repr)2052#define zig_make_special_constant_f80(sign, name, arg, repr) zig_make_special_f80(sign, name, arg, repr)
1937#if FLT_MANT_DIG == 642053#if FLT_MANT_DIG == 64
1938typedef float zig_f80;2054typedef float zig_f80;
1939#define zig_as_f80(fp, repr) fp##f2055#define zig_make_f80(fp, repr) fp##f
1940#elif DBL_MANT_DIG == 642056#elif DBL_MANT_DIG == 64
1941typedef double zig_f80;2057typedef double zig_f80;
1942#define zig_as_f80(fp, repr) fp2058#define zig_make_f80(fp, repr) fp
1943#elif LDBL_MANT_DIG == 642059#elif LDBL_MANT_DIG == 64
1944#define zig_bitSizeOf_c_longdouble 802060#define zig_bitSizeOf_c_longdouble 80
2061typedef zig_u128 zig_repr_c_longdouble;
1945typedef long double zig_f80;2062typedef long double zig_f80;
1946#define zig_as_f80(fp, repr) fp##l2063#define zig_make_f80(fp, repr) fp##l
1947#elif FLT80_MANT_DIG == 642064#elif FLT80_MANT_DIG == 64
1948typedef _Float80 zig_f80;2065typedef _Float80 zig_f80;
1949#define zig_as_f80(fp, repr) fp##f802066#define zig_make_f80(fp, repr) fp##f80
1950#elif FLT64X_MANT_DIG == 642067#elif FLT64X_MANT_DIG == 64
1951typedef _Float64x zig_f80;2068typedef _Float64x zig_f80;
1952#define zig_as_f80(fp, repr) fp##f64x2069#define zig_make_f80(fp, repr) fp##f64x
1953#elif defined(__SIZEOF_FLOAT80__)2070#elif defined(__SIZEOF_FLOAT80__)
1954typedef __float80 zig_f80;2071typedef __float80 zig_f80;
1955#define zig_as_f80(fp, repr) fp##l2072#define zig_make_f80(fp, repr) fp##l
1956#else2073#else
1957#undef zig_has_f802074#undef zig_has_f80
1958#define zig_has_f80 02075#define zig_has_f80 0
1959#define zig_repr_f80 i1282076#define zig_bitSizeOf_repr_f80 128
1960typedef zig_i128 zig_f80;2077typedef zig_i128 zig_f80;
1961#define zig_as_f80(fp, repr) repr2078#define zig_make_f80(fp, repr) repr
1962#undef zig_as_special_f802079#undef zig_make_special_f80
1963#define zig_as_special_f80(sign, name, arg, repr) repr2080#define zig_make_special_f80(sign, name, arg, repr) repr
1964#undef zig_as_special_constant_f802081#undef zig_make_special_constant_f80
1965#define zig_as_special_constant_f80(sign, name, arg, repr) repr2082#define zig_make_special_constant_f80(sign, name, arg, repr) repr
1966#endif2083#endif
19672084
1968#define zig_has_f128 12085#define zig_has_f128 1
1969#define zig_bitSizeOf_f128 1282086#define zig_bitSizeOf_f128 128
1970#define zig_libc_name_f128(name) name##q2087#define zig_libc_name_f128(name) name##q
1971#define zig_as_special_constant_f128(sign, name, arg, repr) zig_as_special_f128(sign, name, arg, repr)2088#define zig_make_special_constant_f128(sign, name, arg, repr) zig_make_special_f128(sign, name, arg, repr)
1972#if FLT_MANT_DIG == 1132089#if FLT_MANT_DIG == 113
1973typedef float zig_f128;2090typedef float zig_f128;
1974#define zig_as_f128(fp, repr) fp##f2091#define zig_make_f128(fp, repr) fp##f
1975#elif DBL_MANT_DIG == 1132092#elif DBL_MANT_DIG == 113
1976typedef double zig_f128;2093typedef double zig_f128;
1977#define zig_as_f128(fp, repr) fp2094#define zig_make_f128(fp, repr) fp
1978#elif LDBL_MANT_DIG == 1132095#elif LDBL_MANT_DIG == 113
1979#define zig_bitSizeOf_c_longdouble 1282096#define zig_bitSizeOf_c_longdouble 128
2097typedef zig_u128 zig_repr_c_longdouble;
1980typedef long double zig_f128;2098typedef long double zig_f128;
1981#define zig_as_f128(fp, repr) fp##l2099#define zig_make_f128(fp, repr) fp##l
1982#elif FLT128_MANT_DIG == 1132100#elif FLT128_MANT_DIG == 113
1983typedef _Float128 zig_f128;2101typedef _Float128 zig_f128;
1984#define zig_as_f128(fp, repr) fp##f1282102#define zig_make_f128(fp, repr) fp##f128
1985#elif FLT64X_MANT_DIG == 1132103#elif FLT64X_MANT_DIG == 113
1986typedef _Float64x zig_f128;2104typedef _Float64x zig_f128;
1987#define zig_as_f128(fp, repr) fp##f64x2105#define zig_make_f128(fp, repr) fp##f64x
1988#elif defined(__SIZEOF_FLOAT128__)2106#elif defined(__SIZEOF_FLOAT128__)
1989typedef __float128 zig_f128;2107typedef __float128 zig_f128;
1990#define zig_as_f128(fp, repr) fp##q2108#define zig_make_f128(fp, repr) fp##q
1991#undef zig_as_special_f1282109#undef zig_make_special_f128
1992#define zig_as_special_f128(sign, name, arg, repr) sign __builtin_##name##f128(arg)2110#define zig_make_special_f128(sign, name, arg, repr) sign __builtin_##name##f128(arg)
1993#else2111#else
1994#undef zig_has_f1282112#undef zig_has_f128
1995#define zig_has_f128 02113#define zig_has_f128 0
1996#define zig_repr_f128 i1282114#define zig_bitSizeOf_repr_f128 128
1997typedef zig_i128 zig_f128;2115typedef zig_i128 zig_f128;
1998#define zig_as_f128(fp, repr) repr2116#define zig_make_f128(fp, repr) repr
1999#undef zig_as_special_f1282117#undef zig_make_special_f128
2000#define zig_as_special_f128(sign, name, arg, repr) repr2118#define zig_make_special_f128(sign, name, arg, repr) repr
2001#undef zig_as_special_constant_f1282119#undef zig_make_special_constant_f128
2002#define zig_as_special_constant_f128(sign, name, arg, repr) repr2120#define zig_make_special_constant_f128(sign, name, arg, repr) repr
2003#endif2121#endif
20042122
2005#define zig_has_c_longdouble 12123#define zig_has_c_longdouble 1
...@@ -2010,17 +2128,18 @@ typedef zig_i128 zig_f128;...@@ -2010,17 +2128,18 @@ typedef zig_i128 zig_f128;
2010#define zig_libc_name_c_longdouble(name) name##l2128#define zig_libc_name_c_longdouble(name) name##l
2011#endif2129#endif
20122130
2013#define zig_as_special_constant_c_longdouble(sign, name, arg, repr) zig_as_special_c_longdouble(sign, name, arg, repr)2131#define zig_make_special_constant_c_longdouble(sign, name, arg, repr) zig_make_special_c_longdouble(sign, name, arg, repr)
2014#ifdef zig_bitSizeOf_c_longdouble2132#ifdef zig_bitSizeOf_c_longdouble
20152133
2016#ifdef ZIG_TARGET_ABI_MSVC2134#ifdef ZIG_TARGET_ABI_MSVC
2017typedef double zig_c_longdouble;
2018#undef zig_bitSizeOf_c_longdouble2135#undef zig_bitSizeOf_c_longdouble
2019#define zig_bitSizeOf_c_longdouble 642136#define zig_bitSizeOf_c_longdouble 64
2020#define zig_as_c_longdouble(fp, repr) fp2137typedef uint64_t zig_repr_c_longdouble;
2138typedef zig_f64 zig_c_longdouble;
2139#define zig_make_c_longdouble(fp, repr) fp
2021#else2140#else
2022typedef long double zig_c_longdouble;2141typedef long double zig_c_longdouble;
2023#define zig_as_c_longdouble(fp, repr) fp##l2142#define zig_make_c_longdouble(fp, repr) fp##l
2024#endif2143#endif
20252144
2026#else /* zig_bitSizeOf_c_longdouble */2145#else /* zig_bitSizeOf_c_longdouble */
...@@ -2028,34 +2147,32 @@ typedef long double zig_c_longdouble;...@@ -2028,34 +2147,32 @@ typedef long double zig_c_longdouble;
2028#undef zig_has_c_longdouble2147#undef zig_has_c_longdouble
2029#define zig_has_c_longdouble 02148#define zig_has_c_longdouble 0
2030#define zig_bitSizeOf_c_longdouble 802149#define zig_bitSizeOf_c_longdouble 80
2150typedef zig_u128 zig_repr_c_longdouble;
2031#define zig_compiler_rt_abbrev_c_longdouble zig_compiler_rt_abbrev_f802151#define zig_compiler_rt_abbrev_c_longdouble zig_compiler_rt_abbrev_f80
2032#define zig_repr_c_longdouble i1282152#define zig_bitSizeOf_repr_c_longdouble 128
2033typedef zig_i128 zig_c_longdouble;2153typedef zig_i128 zig_c_longdouble;
2034#define zig_as_c_longdouble(fp, repr) repr2154#define zig_make_c_longdouble(fp, repr) repr
2035#undef zig_as_special_c_longdouble2155#undef zig_make_special_c_longdouble
2036#define zig_as_special_c_longdouble(sign, name, arg, repr) repr2156#define zig_make_special_c_longdouble(sign, name, arg, repr) repr
2037#undef zig_as_special_constant_c_longdouble2157#undef zig_make_special_constant_c_longdouble
2038#define zig_as_special_constant_c_longdouble(sign, name, arg, repr) repr2158#define zig_make_special_constant_c_longdouble(sign, name, arg, repr) repr
20392159
2040#endif /* zig_bitSizeOf_c_longdouble */2160#endif /* zig_bitSizeOf_c_longdouble */
20412161
2042#if !zig_has_float_builtins2162#if !zig_has_float_builtins
2043#define zig_float_from_repr(Type, ReprType) \2163#define zig_float_from_repr(Type, ReprType) \
2044 static inline zig_##Type zig_float_from_repr_##Type(zig_##ReprType repr) { \2164 static inline zig_##Type zig_float_from_repr_##Type(ReprType repr) { \
2045 return *((zig_##Type*)&repr); \2165 zig_##Type result; \
2166 memcpy(&result, &repr, sizeof(result)); \
2167 return result; \
2046 }2168 }
20472169
2048zig_float_from_repr(f16, u16)2170zig_float_from_repr(f16, uint16_t)
2049zig_float_from_repr(f32, u32)2171zig_float_from_repr(f32, uint32_t)
2050zig_float_from_repr(f64, u64)2172zig_float_from_repr(f64, uint64_t)
2051zig_float_from_repr(f80, u128)2173zig_float_from_repr(f80, zig_u128)
2052zig_float_from_repr(f128, u128)2174zig_float_from_repr(f128, zig_u128)
2053#if zig_bitSizeOf_c_longdouble == 802175zig_float_from_repr(c_longdouble, zig_repr_c_longdouble)
2054zig_float_from_repr(c_longdouble, u128)
2055#else
2056#define zig_expand_float_from_repr(Type, ReprType) zig_float_from_repr(Type, ReprType)
2057zig_expand_float_from_repr(c_longdouble, zig_expand_concat(u, zig_bitSizeOf_c_longdouble))
2058#endif
2059#endif2176#endif
20602177
2061#define zig_cast_f16 (zig_f16)2178#define zig_cast_f16 (zig_f16)
...@@ -2073,32 +2190,35 @@ zig_expand_float_from_repr(c_longdouble, zig_expand_concat(u, zig_bitSizeOf_c_lo...@@ -2073,32 +2190,35 @@ zig_expand_float_from_repr(c_longdouble, zig_expand_concat(u, zig_bitSizeOf_c_lo
2073#endif2190#endif
20742191
2075#define zig_convert_builtin(ResType, operation, ArgType, version) \2192#define zig_convert_builtin(ResType, operation, ArgType, version) \
2076 zig_extern zig_##ResType zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \2193 zig_extern ResType zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \
2077 zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(zig_##ArgType);2194 zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(ArgType);
2078zig_convert_builtin(f16, trunc, f32, 2)2195zig_convert_builtin(zig_f16, trunc, zig_f32, 2)
2079zig_convert_builtin(f16, trunc, f64, 2)2196zig_convert_builtin(zig_f16, trunc, zig_f64, 2)
2080zig_convert_builtin(f16, trunc, f80, 2)2197zig_convert_builtin(zig_f16, trunc, zig_f80, 2)
2081zig_convert_builtin(f16, trunc, f128, 2)2198zig_convert_builtin(zig_f16, trunc, zig_f128, 2)
2082zig_convert_builtin(f32, extend, f16, 2)2199zig_convert_builtin(zig_f32, extend, zig_f16, 2)
2083zig_convert_builtin(f32, trunc, f64, 2)2200zig_convert_builtin(zig_f32, trunc, zig_f64, 2)
2084zig_convert_builtin(f32, trunc, f80, 2)2201zig_convert_builtin(zig_f32, trunc, zig_f80, 2)
2085zig_convert_builtin(f32, trunc, f128, 2)2202zig_convert_builtin(zig_f32, trunc, zig_f128, 2)
2086zig_convert_builtin(f64, extend, f16, 2)2203zig_convert_builtin(zig_f64, extend, zig_f16, 2)
2087zig_convert_builtin(f64, extend, f32, 2)2204zig_convert_builtin(zig_f64, extend, zig_f32, 2)
2088zig_convert_builtin(f64, trunc, f80, 2)2205zig_convert_builtin(zig_f64, trunc, zig_f80, 2)
2089zig_convert_builtin(f64, trunc, f128, 2)2206zig_convert_builtin(zig_f64, trunc, zig_f128, 2)
2090zig_convert_builtin(f80, extend, f16, 2)2207zig_convert_builtin(zig_f80, extend, zig_f16, 2)
2091zig_convert_builtin(f80, extend, f32, 2)2208zig_convert_builtin(zig_f80, extend, zig_f32, 2)
2092zig_convert_builtin(f80, extend, f64, 2)2209zig_convert_builtin(zig_f80, extend, zig_f64, 2)
2093zig_convert_builtin(f80, trunc, f128, 2)2210zig_convert_builtin(zig_f80, trunc, zig_f128, 2)
2094zig_convert_builtin(f128, extend, f16, 2)2211zig_convert_builtin(zig_f128, extend, zig_f16, 2)
2095zig_convert_builtin(f128, extend, f32, 2)2212zig_convert_builtin(zig_f128, extend, zig_f32, 2)
2096zig_convert_builtin(f128, extend, f64, 2)2213zig_convert_builtin(zig_f128, extend, zig_f64, 2)
2097zig_convert_builtin(f128, extend, f80, 2)2214zig_convert_builtin(zig_f128, extend, zig_f80, 2)
20982215
2099#define zig_float_negate_builtin_0(Type) \2216#define zig_float_negate_builtin_0(Type) \
2100 static inline zig_##Type zig_neg_##Type(zig_##Type arg) { \2217 static inline zig_##Type zig_neg_##Type(zig_##Type arg) { \
2101 return zig_expand_concat(zig_xor_, zig_repr_##Type)(arg, zig_expand_minInt(zig_repr_##Type, zig_bitSizeOf_##Type)); \2218 return zig_expand_concat(zig_xor_i, zig_bitSizeOf_repr_##Type)( \
2219 arg, \
2220 zig_minInt_i(zig_bitSizeOf_repr_##Type, zig_bitSizeOf_##Type) \
2221 ); \
2102 }2222 }
2103#define zig_float_negate_builtin_1(Type) \2223#define zig_float_negate_builtin_1(Type) \
2104 static inline zig_##Type zig_neg_##Type(zig_##Type arg) { \2224 static inline zig_##Type zig_neg_##Type(zig_##Type arg) { \
...@@ -2106,28 +2226,28 @@ zig_convert_builtin(f128, extend, f80, 2)...@@ -2106,28 +2226,28 @@ zig_convert_builtin(f128, extend, f80, 2)
2106 }2226 }
21072227
2108#define zig_float_less_builtin_0(Type, operation) \2228#define zig_float_less_builtin_0(Type, operation) \
2109 zig_extern zig_i32 zig_expand_concat(zig_expand_concat(__##operation, \2229 zig_extern int32_t zig_expand_concat(zig_expand_concat(__##operation, \
2110 zig_compiler_rt_abbrev_##Type), 2)(zig_##Type, zig_##Type); \2230 zig_compiler_rt_abbrev_zig_##Type), 2)(zig_##Type, zig_##Type); \
2111 static inline zig_i32 zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \2231 static inline int32_t zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \
2112 return zig_expand_concat(zig_expand_concat(__##operation, zig_compiler_rt_abbrev_##Type), 2)(lhs, rhs); \2232 return zig_expand_concat(zig_expand_concat(__##operation, zig_compiler_rt_abbrev_zig_##Type), 2)(lhs, rhs); \
2113 }2233 }
2114#define zig_float_less_builtin_1(Type, operation) \2234#define zig_float_less_builtin_1(Type, operation) \
2115 static inline zig_i32 zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \2235 static inline int32_t zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \
2116 return (!(lhs <= rhs) - (lhs < rhs)); \2236 return (!(lhs <= rhs) - (lhs < rhs)); \
2117 }2237 }
21182238
2119#define zig_float_greater_builtin_0(Type, operation) \2239#define zig_float_greater_builtin_0(Type, operation) \
2120 zig_float_less_builtin_0(Type, operation)2240 zig_float_less_builtin_0(Type, operation)
2121#define zig_float_greater_builtin_1(Type, operation) \2241#define zig_float_greater_builtin_1(Type, operation) \
2122 static inline zig_i32 zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \2242 static inline int32_t zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \
2123 return ((lhs > rhs) - !(lhs >= rhs)); \2243 return ((lhs > rhs) - !(lhs >= rhs)); \
2124 }2244 }
21252245
2126#define zig_float_binary_builtin_0(Type, operation, operator) \2246#define zig_float_binary_builtin_0(Type, operation, operator) \
2127 zig_extern zig_##Type zig_expand_concat(zig_expand_concat(__##operation, \2247 zig_extern zig_##Type zig_expand_concat(zig_expand_concat(__##operation, \
2128 zig_compiler_rt_abbrev_##Type), 3)(zig_##Type, zig_##Type); \2248 zig_compiler_rt_abbrev_zig_##Type), 3)(zig_##Type, zig_##Type); \
2129 static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \2249 static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \
2130 return zig_expand_concat(zig_expand_concat(__##operation, zig_compiler_rt_abbrev_##Type), 3)(lhs, rhs); \2250 return zig_expand_concat(zig_expand_concat(__##operation, zig_compiler_rt_abbrev_zig_##Type), 3)(lhs, rhs); \
2131 }2251 }
2132#define zig_float_binary_builtin_1(Type, operation, operator) \2252#define zig_float_binary_builtin_1(Type, operation, operator) \
2133 static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \2253 static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \
...@@ -2135,18 +2255,18 @@ zig_convert_builtin(f128, extend, f80, 2)...@@ -2135,18 +2255,18 @@ zig_convert_builtin(f128, extend, f80, 2)
2135 }2255 }
21362256
2137#define zig_float_builtins(Type) \2257#define zig_float_builtins(Type) \
2138 zig_convert_builtin(i32, fix, Type, ) \2258 zig_convert_builtin( int32_t, fix, zig_##Type, ) \
2139 zig_convert_builtin(u32, fixuns, Type, ) \2259 zig_convert_builtin(uint32_t, fixuns, zig_##Type, ) \
2140 zig_convert_builtin(i64, fix, Type, ) \2260 zig_convert_builtin( int64_t, fix, zig_##Type, ) \
2141 zig_convert_builtin(u64, fixuns, Type, ) \2261 zig_convert_builtin(uint64_t, fixuns, zig_##Type, ) \
2142 zig_convert_builtin(i128, fix, Type, ) \2262 zig_convert_builtin(zig_i128, fix, zig_##Type, ) \
2143 zig_convert_builtin(u128, fixuns, Type, ) \2263 zig_convert_builtin(zig_u128, fixuns, zig_##Type, ) \
2144 zig_convert_builtin(Type, float, i32, ) \2264 zig_convert_builtin(zig_##Type, float, int32_t, ) \
2145 zig_convert_builtin(Type, floatun, u32, ) \2265 zig_convert_builtin(zig_##Type, floatun, uint32_t, ) \
2146 zig_convert_builtin(Type, float, i64, ) \2266 zig_convert_builtin(zig_##Type, float, int64_t, ) \
2147 zig_convert_builtin(Type, floatun, u64, ) \2267 zig_convert_builtin(zig_##Type, floatun, uint64_t, ) \
2148 zig_convert_builtin(Type, float, i128, ) \2268 zig_convert_builtin(zig_##Type, float, zig_i128, ) \
2149 zig_convert_builtin(Type, floatun, u128, ) \2269 zig_convert_builtin(zig_##Type, floatun, zig_u128, ) \
2150 zig_expand_concat(zig_float_negate_builtin_, zig_has_##Type)(Type) \2270 zig_expand_concat(zig_float_negate_builtin_, zig_has_##Type)(Type) \
2151 zig_expand_concat(zig_float_less_builtin_, zig_has_##Type)(Type, cmp) \2271 zig_expand_concat(zig_float_less_builtin_, zig_has_##Type)(Type, cmp) \
2152 zig_expand_concat(zig_float_less_builtin_, zig_has_##Type)(Type, ne) \2272 zig_expand_concat(zig_float_less_builtin_, zig_has_##Type)(Type, ne) \
...@@ -2200,149 +2320,157 @@ zig_float_builtins(c_longdouble)...@@ -2200,149 +2320,157 @@ zig_float_builtins(c_longdouble)
22002320
2201// TODO: zig_msvc_atomic_load should load 32 bit without interlocked on x86, and load 64 bit without interlocked on x642321// TODO: zig_msvc_atomic_load should load 32 bit without interlocked on x86, and load 64 bit without interlocked on x64
22022322
2203#define zig_msvc_atomics(Type, suffix) \2323#define zig_msvc_atomics(ZigType, Type, suffix) \
2204 static inline bool zig_msvc_cmpxchg_##Type(zig_##Type volatile* obj, zig_##Type* expected, zig_##Type desired) { \2324 static inline bool zig_msvc_cmpxchg_##ZigType(Type volatile* obj, Type* expected, Type desired) { \
2205 zig_##Type comparand = *expected; \2325 Type comparand = *expected; \
2206 zig_##Type initial = _InterlockedCompareExchange##suffix(obj, desired, comparand); \2326 Type initial = _InterlockedCompareExchange##suffix(obj, desired, comparand); \
2207 bool exchanged = initial == comparand; \2327 bool exchanged = initial == comparand; \
2208 if (!exchanged) { \2328 if (!exchanged) { \
2209 *expected = initial; \2329 *expected = initial; \
2210 } \2330 } \
2211 return exchanged; \2331 return exchanged; \
2212 } \2332 } \
2213 static inline zig_##Type zig_msvc_atomicrmw_xchg_##Type(zig_##Type volatile* obj, zig_##Type value) { \2333 static inline Type zig_msvc_atomicrmw_xchg_##ZigType(Type volatile* obj, Type value) { \
2214 return _InterlockedExchange##suffix(obj, value); \2334 return _InterlockedExchange##suffix(obj, value); \
2215 } \2335 } \
2216 static inline zig_##Type zig_msvc_atomicrmw_add_##Type(zig_##Type volatile* obj, zig_##Type value) { \2336 static inline Type zig_msvc_atomicrmw_add_##ZigType(Type volatile* obj, Type value) { \
2217 return _InterlockedExchangeAdd##suffix(obj, value); \2337 return _InterlockedExchangeAdd##suffix(obj, value); \
2218 } \2338 } \
2219 static inline zig_##Type zig_msvc_atomicrmw_sub_##Type(zig_##Type volatile* obj, zig_##Type value) { \2339 static inline Type zig_msvc_atomicrmw_sub_##ZigType(Type volatile* obj, Type value) { \
2220 bool success = false; \2340 bool success = false; \
2221 zig_##Type new; \2341 Type new; \
2222 zig_##Type prev; \2342 Type prev; \
2223 while (!success) { \2343 while (!success) { \
2224 prev = *obj; \2344 prev = *obj; \
2225 new = prev - value; \2345 new = prev - value; \
2226 success = zig_msvc_cmpxchg_##Type(obj, &prev, new); \2346 success = zig_msvc_cmpxchg_##ZigType(obj, &prev, new); \
2227 } \2347 } \
2228 return prev; \2348 return prev; \
2229 } \2349 } \
2230 static inline zig_##Type zig_msvc_atomicrmw_or_##Type(zig_##Type volatile* obj, zig_##Type value) { \2350 static inline Type zig_msvc_atomicrmw_or_##ZigType(Type volatile* obj, Type value) { \
2231 return _InterlockedOr##suffix(obj, value); \2351 return _InterlockedOr##suffix(obj, value); \
2232 } \2352 } \
2233 static inline zig_##Type zig_msvc_atomicrmw_xor_##Type(zig_##Type volatile* obj, zig_##Type value) { \2353 static inline Type zig_msvc_atomicrmw_xor_##ZigType(Type volatile* obj, Type value) { \
2234 return _InterlockedXor##suffix(obj, value); \2354 return _InterlockedXor##suffix(obj, value); \
2235 } \2355 } \
2236 static inline zig_##Type zig_msvc_atomicrmw_and_##Type(zig_##Type volatile* obj, zig_##Type value) { \2356 static inline Type zig_msvc_atomicrmw_and_##ZigType(Type volatile* obj, Type value) { \
2237 return _InterlockedAnd##suffix(obj, value); \2357 return _InterlockedAnd##suffix(obj, value); \
2238 } \2358 } \
2239 static inline zig_##Type zig_msvc_atomicrmw_nand_##Type(zig_##Type volatile* obj, zig_##Type value) { \2359 static inline Type zig_msvc_atomicrmw_nand_##ZigType(Type volatile* obj, Type value) { \
2240 bool success = false; \2360 bool success = false; \
2241 zig_##Type new; \2361 Type new; \
2242 zig_##Type prev; \2362 Type prev; \
2243 while (!success) { \2363 while (!success) { \
2244 prev = *obj; \2364 prev = *obj; \
2245 new = ~(prev & value); \2365 new = ~(prev & value); \
2246 success = zig_msvc_cmpxchg_##Type(obj, &prev, new); \2366 success = zig_msvc_cmpxchg_##ZigType(obj, &prev, new); \
2247 } \2367 } \
2248 return prev; \2368 return prev; \
2249 } \2369 } \
2250 static inline zig_##Type zig_msvc_atomicrmw_min_##Type(zig_##Type volatile* obj, zig_##Type value) { \2370 static inline Type zig_msvc_atomicrmw_min_##ZigType(Type volatile* obj, Type value) { \
2251 bool success = false; \2371 bool success = false; \
2252 zig_##Type new; \2372 Type new; \
2253 zig_##Type prev; \2373 Type prev; \
2254 while (!success) { \2374 while (!success) { \
2255 prev = *obj; \2375 prev = *obj; \
2256 new = value < prev ? value : prev; \2376 new = value < prev ? value : prev; \
2257 success = zig_msvc_cmpxchg_##Type(obj, &prev, new); \2377 success = zig_msvc_cmpxchg_##ZigType(obj, &prev, new); \
2258 } \2378 } \
2259 return prev; \2379 return prev; \
2260 } \2380 } \
2261 static inline zig_##Type zig_msvc_atomicrmw_max_##Type(zig_##Type volatile* obj, zig_##Type value) { \2381 static inline Type zig_msvc_atomicrmw_max_##ZigType(Type volatile* obj, Type value) { \
2262 bool success = false; \2382 bool success = false; \
2263 zig_##Type new; \2383 Type new; \
2264 zig_##Type prev; \2384 Type prev; \
2265 while (!success) { \2385 while (!success) { \
2266 prev = *obj; \2386 prev = *obj; \
2267 new = value > prev ? value : prev; \2387 new = value > prev ? value : prev; \
2268 success = zig_msvc_cmpxchg_##Type(obj, &prev, new); \2388 success = zig_msvc_cmpxchg_##ZigType(obj, &prev, new); \
2269 } \2389 } \
2270 return prev; \2390 return prev; \
2271 } \2391 } \
2272 static inline void zig_msvc_atomic_store_##Type(zig_##Type volatile* obj, zig_##Type value) { \2392 static inline void zig_msvc_atomic_store_##ZigType(Type volatile* obj, Type value) { \
2273 _InterlockedExchange##suffix(obj, value); \2393 _InterlockedExchange##suffix(obj, value); \
2274 } \2394 } \
2275 static inline zig_##Type zig_msvc_atomic_load_##Type(zig_##Type volatile* obj) { \2395 static inline Type zig_msvc_atomic_load_##ZigType(Type volatile* obj) { \
2276 return _InterlockedOr##suffix(obj, 0); \2396 return _InterlockedOr##suffix(obj, 0); \
2277 }2397 }
22782398
2279zig_msvc_atomics(u8, 8)2399zig_msvc_atomics( u8, uint8_t, 8)
2280zig_msvc_atomics(i8, 8)2400zig_msvc_atomics( i8, int8_t, 8)
2281zig_msvc_atomics(u16, 16)2401zig_msvc_atomics(u16, uint16_t, 16)
2282zig_msvc_atomics(i16, 16)2402zig_msvc_atomics(i16, int16_t, 16)
2283zig_msvc_atomics(u32, )2403zig_msvc_atomics(u32, uint32_t, )
2284zig_msvc_atomics(i32, )2404zig_msvc_atomics(i32, int32_t, )
22852405
2286#if _M_X642406#if _M_X64
2287zig_msvc_atomics(u64, 64)2407zig_msvc_atomics(u64, uint64_t, 64)
2288zig_msvc_atomics(i64, 64)2408zig_msvc_atomics(i64, int64_t, 64)
2289#endif2409#endif
22902410
2291#define zig_msvc_flt_atomics(Type, ReprType, suffix) \2411#define zig_msvc_flt_atomics(Type, ReprType, suffix) \
2292 static inline bool zig_msvc_cmpxchg_##Type(zig_##Type volatile* obj, zig_##Type* expected, zig_##Type desired) { \2412 static inline bool zig_msvc_cmpxchg_##Type(zig_##Type volatile* obj, zig_##Type* expected, zig_##Type desired) { \
2293 zig_##ReprType comparand = *((zig_##ReprType*)expected); \2413 ReprType exchange; \
2294 zig_##ReprType initial = _InterlockedCompareExchange##suffix((zig_##ReprType volatile*)obj, *((zig_##ReprType*)&desired), comparand); \2414 ReprType comparand; \
2295 bool exchanged = initial == comparand; \2415 ReprType initial; \
2296 if (!exchanged) { \2416 bool success; \
2297 *expected = *((zig_##Type*)&initial); \2417 memcpy(&comparand, expected, sizeof(comparand)); \
2298 } \2418 memcpy(&exchange, &desired, sizeof(exchange)); \
2299 return exchanged; \2419 initial = _InterlockedCompareExchange##suffix((ReprType volatile*)obj, exchange, comparand); \
2420 success = initial == comparand; \
2421 if (!success) memcpy(expected, &initial, sizeof(*expected)); \
2422 return success; \
2300 } \2423 } \
2301 static inline zig_##Type zig_msvc_atomicrmw_xchg_##Type(zig_##Type volatile* obj, zig_##Type value) { \2424 static inline zig_##Type zig_msvc_atomicrmw_xchg_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2302 zig_##ReprType initial = _InterlockedExchange##suffix((zig_##ReprType volatile*)obj, *((zig_##ReprType*)&value)); \2425 ReprType repr; \
2303 return *((zig_##Type*)&initial); \2426 ReprType initial; \
2427 zig_##Type result; \
2428 memcpy(&repr, &value, sizeof(repr)); \
2429 initial = _InterlockedExchange##suffix((ReprType volatile*)obj, repr); \
2430 memcpy(&result, &initial, sizeof(result)); \
2431 return result; \
2304 } \2432 } \
2305 static inline zig_##Type zig_msvc_atomicrmw_add_##Type(zig_##Type volatile* obj, zig_##Type value) { \2433 static inline zig_##Type zig_msvc_atomicrmw_add_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2306 bool success = false; \2434 ReprType repr; \
2307 zig_##ReprType new; \2435 zig_##Type expected; \
2308 zig_##Type prev; \2436 zig_##Type desired; \
2309 while (!success) { \2437 repr = *(ReprType volatile*)obj; \
2310 prev = *obj; \2438 memcpy(&expected, &repr, sizeof(expected)); \
2311 new = prev + value; \2439 do { \
2312 success = zig_msvc_cmpxchg_##Type(obj, &prev, *((zig_##ReprType*)&new)); \2440 desired = expected + value; \
2313 } \2441 } while (!zig_msvc_cmpxchg_##Type(obj, &expected, desired)); \
2314 return prev; \2442 return expected; \
2315 } \2443 } \
2316 static inline zig_##Type zig_msvc_atomicrmw_sub_##Type(zig_##Type volatile* obj, zig_##Type value) { \2444 static inline zig_##Type zig_msvc_atomicrmw_sub_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2317 bool success = false; \2445 ReprType repr; \
2318 zig_##ReprType new; \2446 zig_##Type expected; \
2319 zig_##Type prev; \2447 zig_##Type desired; \
2320 while (!success) { \2448 repr = *(ReprType volatile*)obj; \
2321 prev = *obj; \2449 memcpy(&expected, &repr, sizeof(expected)); \
2322 new = prev - value; \2450 do { \
2323 success = zig_msvc_cmpxchg_##Type(obj, &prev, *((zig_##ReprType*)&new)); \2451 desired = expected - value; \
2324 } \2452 } while (!zig_msvc_cmpxchg_##Type(obj, &expected, desired)); \
2325 return prev; \2453 return expected; \
2326 }2454 }
23272455
2328zig_msvc_flt_atomics(f32, u32, )2456zig_msvc_flt_atomics(f32, uint32_t, )
2329#if _M_X642457#if _M_X64
2330zig_msvc_flt_atomics(f64, u64, 64)2458zig_msvc_flt_atomics(f64, uint64_t, 64)
2331#endif2459#endif
23322460
2333#if _M_IX862461#if _M_IX86
2334static inline void zig_msvc_atomic_barrier() {2462static inline void zig_msvc_atomic_barrier() {
2335 zig_i32 barrier;2463 int32_t barrier;
2336 __asm {2464 __asm {
2337 xchg barrier, eax2465 xchg barrier, eax
2338 }2466 }
2339}2467}
23402468
2341static inline void* zig_msvc_atomicrmw_xchg_p32(void** obj, zig_u32* arg) {2469static inline void* zig_msvc_atomicrmw_xchg_p32(void** obj, void* arg) {
2342 return _InterlockedExchangePointer(obj, arg);2470 return _InterlockedExchangePointer(obj, arg);
2343}2471}
23442472
2345static inline void zig_msvc_atomic_store_p32(void** obj, zig_u32* arg) {2473static inline void zig_msvc_atomic_store_p32(void** obj, void* arg) {
2346 _InterlockedExchangePointer(obj, arg);2474 _InterlockedExchangePointer(obj, arg);
2347}2475}
23482476
...@@ -2360,11 +2488,11 @@ static inline bool zig_msvc_cmpxchg_p32(void** obj, void** expected, void* desir...@@ -2360,11 +2488,11 @@ static inline bool zig_msvc_cmpxchg_p32(void** obj, void** expected, void* desir
2360 return exchanged;2488 return exchanged;
2361}2489}
2362#else /* _M_IX86 */2490#else /* _M_IX86 */
2363static inline void* zig_msvc_atomicrmw_xchg_p64(void** obj, zig_u64* arg) {2491static inline void* zig_msvc_atomicrmw_xchg_p64(void** obj, void* arg) {
2364 return _InterlockedExchangePointer(obj, arg);2492 return _InterlockedExchangePointer(obj, arg);
2365}2493}
23662494
2367static inline void zig_msvc_atomic_store_p64(void** obj, zig_u64* arg) {2495static inline void zig_msvc_atomic_store_p64(void** obj, void* arg) {
2368 _InterlockedExchangePointer(obj, arg);2496 _InterlockedExchangePointer(obj, arg);
2369}2497}
23702498
...@@ -2383,11 +2511,11 @@ static inline bool zig_msvc_cmpxchg_p64(void** obj, void** expected, void* desir...@@ -2383,11 +2511,11 @@ static inline bool zig_msvc_cmpxchg_p64(void** obj, void** expected, void* desir
2383}2511}
23842512
2385static inline bool zig_msvc_cmpxchg_u128(zig_u128 volatile* obj, zig_u128* expected, zig_u128 desired) {2513static inline bool zig_msvc_cmpxchg_u128(zig_u128 volatile* obj, zig_u128* expected, zig_u128 desired) {
2386 return _InterlockedCompareExchange128((zig_i64 volatile*)obj, desired.hi, desired.lo, (zig_i64*)expected);2514 return _InterlockedCompareExchange128((int64_t volatile*)obj, desired.hi, desired.lo, (int64_t*)expected);
2387}2515}
23882516
2389static inline bool zig_msvc_cmpxchg_i128(zig_i128 volatile* obj, zig_i128* expected, zig_i128 desired) {2517static inline bool zig_msvc_cmpxchg_i128(zig_i128 volatile* obj, zig_i128* expected, zig_i128 desired) {
2390 return _InterlockedCompareExchange128((zig_i64 volatile*)obj, desired.hi, desired.lo, (zig_u64*)expected);2518 return _InterlockedCompareExchange128((int64_t volatile*)obj, desired.hi, desired.lo, (uint64_t*)expected);
2391}2519}
23922520
2393#define zig_msvc_atomics_128xchg(Type) \2521#define zig_msvc_atomics_128xchg(Type) \
...@@ -2429,7 +2557,7 @@ zig_msvc_atomics_128op(u128, max)...@@ -2429,7 +2557,7 @@ zig_msvc_atomics_128op(u128, max)
24292557
2430#endif /* _MSC_VER && (_M_IX86 || _M_X64) */2558#endif /* _MSC_VER && (_M_IX86 || _M_X64) */
24312559
2432/* ========================= Special Case Intrinsics ========================= */2560/* ======================== Special Case Intrinsics ========================= */
24332561
2434#if (_MSC_VER && _M_X64) || defined(__x86_64__)2562#if (_MSC_VER && _M_X64) || defined(__x86_64__)
24352563
...@@ -2459,8 +2587,8 @@ static inline void* zig_x86_windows_teb(void) {...@@ -2459,8 +2587,8 @@ static inline void* zig_x86_windows_teb(void) {
24592587
2460#if (_MSC_VER && (_M_IX86 || _M_X64)) || defined(__i386__) || defined(__x86_64__)2588#if (_MSC_VER && (_M_IX86 || _M_X64)) || defined(__i386__) || defined(__x86_64__)
24612589
2462static inline void zig_x86_cpuid(zig_u32 leaf_id, zig_u32 subid, zig_u32* eax, zig_u32* ebx, zig_u32* ecx, zig_u32* edx) {2590static inline void zig_x86_cpuid(uint32_t leaf_id, uint32_t subid, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) {
2463 zig_u32 cpu_info[4];2591 uint32_t cpu_info[4];
2464#if _MSC_VER2592#if _MSC_VER
2465 __cpuidex(cpu_info, leaf_id, subid);2593 __cpuidex(cpu_info, leaf_id, subid);
2466#else2594#else
...@@ -2472,12 +2600,12 @@ static inline void zig_x86_cpuid(zig_u32 leaf_id, zig_u32 subid, zig_u32* eax, z...@@ -2472,12 +2600,12 @@ static inline void zig_x86_cpuid(zig_u32 leaf_id, zig_u32 subid, zig_u32* eax, z
2472 *edx = cpu_info[3];2600 *edx = cpu_info[3];
2473}2601}
24742602
2475static inline zig_u32 zig_x86_get_xcr0(void) {2603static inline uint32_t zig_x86_get_xcr0(void) {
2476#if _MSC_VER2604#if _MSC_VER
2477 return (zig_u32)_xgetbv(0);2605 return (uint32_t)_xgetbv(0);
2478#else2606#else
2479 zig_u32 eax;2607 uint32_t eax;
2480 zig_u32 edx;2608 uint32_t edx;
2481 __asm__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0));2609 __asm__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0));
2482 return eax;2610 return eax;
2483#endif2611#endif
src/Autodoc.zig+2-10
...@@ -860,17 +860,9 @@ fn walkInstruction(...@@ -860,17 +860,9 @@ fn walkInstruction(
860 const str_tok = data[inst_index].str_tok;860 const str_tok = data[inst_index].str_tok;
861 var path = str_tok.get(file.zir);861 var path = str_tok.get(file.zir);
862862
863 const maybe_other_package: ?*Package = blk: {
864 if (self.module.main_pkg_is_std and std.mem.eql(u8, path, "std")) {
865 path = "std";
866 break :blk self.module.main_pkg;
867 } else {
868 break :blk file.pkg.table.get(path);
869 }
870 };
871 // importFile cannot error out since all files863 // importFile cannot error out since all files
872 // are already loaded at this point864 // are already loaded at this point
873 if (maybe_other_package) |other_package| {865 if (file.pkg.table.get(path)) |other_package| {
874 const result = try self.packages.getOrPut(self.arena, other_package);866 const result = try self.packages.getOrPut(self.arena, other_package);
875867
876 // Immediately add this package to the import table of our868 // Immediately add this package to the import table of our
...@@ -3629,7 +3621,7 @@ fn tryResolveRefPath(...@@ -3629,7 +3621,7 @@ fn tryResolveRefPath(
3629 }3621 }
36303622
3631 if (self.pending_ref_paths.get(&path[path.len - 1])) |waiter_list| {3623 if (self.pending_ref_paths.get(&path[path.len - 1])) |waiter_list| {
3632 // It's important to de-register oureslves as pending before3624 // It's important to de-register ourselves as pending before
3633 // attempting to resolve any other decl.3625 // attempting to resolve any other decl.
3634 _ = self.pending_ref_paths.remove(&path[path.len - 1]);3626 _ = self.pending_ref_paths.remove(&path[path.len - 1]);
36353627
src/Compilation.zig+145-91
...@@ -1596,36 +1596,53 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1596,36 +1596,53 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
15961596
1597 const builtin_pkg = try Package.createWithDir(1597 const builtin_pkg = try Package.createWithDir(
1598 gpa,1598 gpa,
1599 "builtin",
1600 zig_cache_artifact_directory,1599 zig_cache_artifact_directory,
1601 null,1600 null,
1602 "builtin.zig",1601 "builtin.zig",
1603 );1602 );
1604 errdefer builtin_pkg.destroy(gpa);1603 errdefer builtin_pkg.destroy(gpa);
16051604
1606 const std_pkg = try Package.createWithDir(1605 // When you're testing std, the main module is std. In that case, we'll just set the std
1607 gpa,1606 // module to the main one, since avoiding the errors caused by duplicating it is more
1608 "std",1607 // effort than it's worth.
1609 options.zig_lib_directory,1608 const main_pkg_is_std = m: {
1610 "std",1609 const std_path = try std.fs.path.resolve(arena, &[_][]const u8{
1611 "std.zig",1610 options.zig_lib_directory.path orelse ".",
1612 );1611 "std",
1613 errdefer std_pkg.destroy(gpa);1612 "std.zig",
1613 });
1614 defer arena.free(std_path);
1615 const main_path = try std.fs.path.resolve(arena, &[_][]const u8{
1616 main_pkg.root_src_directory.path orelse ".",
1617 main_pkg.root_src_path,
1618 });
1619 defer arena.free(main_path);
1620 break :m mem.eql(u8, main_path, std_path);
1621 };
1622
1623 const std_pkg = if (main_pkg_is_std)
1624 main_pkg
1625 else
1626 try Package.createWithDir(
1627 gpa,
1628 options.zig_lib_directory,
1629 "std",
1630 "std.zig",
1631 );
1632
1633 errdefer if (!main_pkg_is_std) std_pkg.destroy(gpa);
16141634
1615 const root_pkg = if (options.is_test) root_pkg: {1635 const root_pkg = if (options.is_test) root_pkg: {
1616 // TODO: we currently have two packages named 'root' here, which is weird. This
1617 // should be changed as part of the resolution of #12201
1618 const test_pkg = if (options.test_runner_path) |test_runner| test_pkg: {1636 const test_pkg = if (options.test_runner_path) |test_runner| test_pkg: {
1619 const test_dir = std.fs.path.dirname(test_runner);1637 const test_dir = std.fs.path.dirname(test_runner);
1620 const basename = std.fs.path.basename(test_runner);1638 const basename = std.fs.path.basename(test_runner);
1621 const pkg = try Package.create(gpa, "root", test_dir, basename);1639 const pkg = try Package.create(gpa, test_dir, basename);
16221640
1623 // copy package table from main_pkg to root_pkg1641 // copy package table from main_pkg to root_pkg
1624 pkg.table = try main_pkg.table.clone(gpa);1642 pkg.table = try main_pkg.table.clone(gpa);
1625 break :test_pkg pkg;1643 break :test_pkg pkg;
1626 } else try Package.createWithDir(1644 } else try Package.createWithDir(
1627 gpa,1645 gpa,
1628 "root",
1629 options.zig_lib_directory,1646 options.zig_lib_directory,
1630 null,1647 null,
1631 "test_runner.zig",1648 "test_runner.zig",
...@@ -1639,7 +1656,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1639,7 +1656,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1639 const compiler_rt_pkg = if (include_compiler_rt and options.output_mode == .Obj) compiler_rt_pkg: {1656 const compiler_rt_pkg = if (include_compiler_rt and options.output_mode == .Obj) compiler_rt_pkg: {
1640 break :compiler_rt_pkg try Package.createWithDir(1657 break :compiler_rt_pkg try Package.createWithDir(
1641 gpa,1658 gpa,
1642 "compiler_rt",
1643 options.zig_lib_directory,1659 options.zig_lib_directory,
1644 null,1660 null,
1645 "compiler_rt.zig",1661 "compiler_rt.zig",
...@@ -1647,28 +1663,14 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1647,28 +1663,14 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1647 } else null;1663 } else null;
1648 errdefer if (compiler_rt_pkg) |p| p.destroy(gpa);1664 errdefer if (compiler_rt_pkg) |p| p.destroy(gpa);
16491665
1650 try main_pkg.addAndAdopt(gpa, builtin_pkg);1666 try main_pkg.add(gpa, "builtin", builtin_pkg);
1651 try main_pkg.add(gpa, root_pkg);1667 try main_pkg.add(gpa, "root", root_pkg);
1652 try main_pkg.addAndAdopt(gpa, std_pkg);1668 try main_pkg.add(gpa, "std", std_pkg);
16531669
1654 if (compiler_rt_pkg) |p| {1670 if (compiler_rt_pkg) |p| {
1655 try main_pkg.addAndAdopt(gpa, p);1671 try main_pkg.add(gpa, "compiler_rt", p);
1656 }1672 }
16571673
1658 const main_pkg_is_std = m: {
1659 const std_path = try std.fs.path.resolve(arena, &[_][]const u8{
1660 std_pkg.root_src_directory.path orelse ".",
1661 std_pkg.root_src_path,
1662 });
1663 defer arena.free(std_path);
1664 const main_path = try std.fs.path.resolve(arena, &[_][]const u8{
1665 main_pkg.root_src_directory.path orelse ".",
1666 main_pkg.root_src_path,
1667 });
1668 defer arena.free(main_path);
1669 break :m mem.eql(u8, main_path, std_path);
1670 };
1671
1672 // Pre-open the directory handles for cached ZIR code so that it does not need1674 // Pre-open the directory handles for cached ZIR code so that it does not need
1673 // to redundantly happen for each AstGen operation.1675 // to redundantly happen for each AstGen operation.
1674 const zir_sub_dir = "z";1676 const zir_sub_dir = "z";
...@@ -1705,7 +1707,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1705,7 +1707,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1705 .gpa = gpa,1707 .gpa = gpa,
1706 .comp = comp,1708 .comp = comp,
1707 .main_pkg = main_pkg,1709 .main_pkg = main_pkg,
1708 .main_pkg_is_std = main_pkg_is_std,
1709 .root_pkg = root_pkg,1710 .root_pkg = root_pkg,
1710 .zig_cache_artifact_directory = zig_cache_artifact_directory,1711 .zig_cache_artifact_directory = zig_cache_artifact_directory,
1711 .global_zir_cache = global_zir_cache,1712 .global_zir_cache = global_zir_cache,
...@@ -2772,6 +2773,111 @@ fn emitOthers(comp: *Compilation) void {...@@ -2772,6 +2773,111 @@ fn emitOthers(comp: *Compilation) void {
2772 }2773 }
2773}2774}
27742775
2776fn reportMultiModuleErrors(mod: *Module) !void {
2777 // Some cases can give you a whole bunch of multi-module errors, which it's not helpful to
2778 // print all of, so we'll cap the number of these to emit.
2779 var num_errors: u32 = 0;
2780 const max_errors = 5;
2781 // Attach the "some omitted" note to the final error message
2782 var last_err: ?*Module.ErrorMsg = null;
2783
2784 for (mod.import_table.values()) |file| {
2785 if (!file.multi_pkg) continue;
2786
2787 num_errors += 1;
2788 if (num_errors > max_errors) continue;
2789
2790 const err = err_blk: {
2791 // Like with errors, let's cap the number of notes to prevent a huge error spew.
2792 const max_notes = 5;
2793 const omitted = file.references.items.len -| max_notes;
2794 const num_notes = file.references.items.len - omitted;
2795
2796 const notes = try mod.gpa.alloc(Module.ErrorMsg, if (omitted > 0) num_notes + 1 else num_notes);
2797 errdefer mod.gpa.free(notes);
2798
2799 for (notes[0..num_notes], file.references.items[0..num_notes], 0..) |*note, ref, i| {
2800 errdefer for (notes[0..i]) |*n| n.deinit(mod.gpa);
2801 note.* = switch (ref) {
2802 .import => |loc| blk: {
2803 const name = try loc.file_scope.pkg.getName(mod.gpa, mod.*);
2804 defer mod.gpa.free(name);
2805 break :blk try Module.ErrorMsg.init(
2806 mod.gpa,
2807 loc,
2808 "imported from module {s}",
2809 .{name},
2810 );
2811 },
2812 .root => |pkg| blk: {
2813 const name = try pkg.getName(mod.gpa, mod.*);
2814 defer mod.gpa.free(name);
2815 break :blk try Module.ErrorMsg.init(
2816 mod.gpa,
2817 .{ .file_scope = file, .parent_decl_node = 0, .lazy = .entire_file },
2818 "root of module {s}",
2819 .{name},
2820 );
2821 },
2822 };
2823 }
2824 errdefer for (notes[0..num_notes]) |*n| n.deinit(mod.gpa);
2825
2826 if (omitted > 0) {
2827 notes[num_notes] = try Module.ErrorMsg.init(
2828 mod.gpa,
2829 .{ .file_scope = file, .parent_decl_node = 0, .lazy = .entire_file },
2830 "{} more references omitted",
2831 .{omitted},
2832 );
2833 }
2834 errdefer if (omitted > 0) notes[num_notes].deinit(mod.gpa);
2835
2836 const err = try Module.ErrorMsg.create(
2837 mod.gpa,
2838 .{ .file_scope = file, .parent_decl_node = 0, .lazy = .entire_file },
2839 "file exists in multiple modules",
2840 .{},
2841 );
2842 err.notes = notes;
2843 break :err_blk err;
2844 };
2845 errdefer err.destroy(mod.gpa);
2846 try mod.failed_files.putNoClobber(mod.gpa, file, err);
2847 last_err = err;
2848 }
2849
2850 // If we omitted any errors, add a note saying that
2851 if (num_errors > max_errors) {
2852 const err = last_err.?;
2853
2854 // There isn't really any meaningful place to put this note, so just attach it to the
2855 // last failed file
2856 var note = try Module.ErrorMsg.init(
2857 mod.gpa,
2858 err.src_loc,
2859 "{} more errors omitted",
2860 .{num_errors - max_errors},
2861 );
2862 errdefer note.deinit(mod.gpa);
2863
2864 const i = err.notes.len;
2865 err.notes = try mod.gpa.realloc(err.notes, i + 1);
2866 err.notes[i] = note;
2867 }
2868
2869 // Now that we've reported the errors, we need to deal with
2870 // dependencies. Any file referenced by a multi_pkg file should also be
2871 // marked multi_pkg and have its status set to astgen_failure, as it's
2872 // ambiguous which package they should be analyzed as a part of. We need
2873 // to add this flag after reporting the errors however, as otherwise
2874 // we'd get an error for every single downstream file, which wouldn't be
2875 // very useful.
2876 for (mod.import_table.values()) |file| {
2877 if (file.multi_pkg) file.recursiveMarkMultiPkg(mod);
2878 }
2879}
2880
2775/// Having the file open for writing is problematic as far as executing the2881/// Having the file open for writing is problematic as far as executing the
2776/// binary is concerned. This will remove the write flag, or close the file,2882/// binary is concerned. This will remove the write flag, or close the file,
2777/// or whatever is needed so that it can be executed.2883/// or whatever is needed so that it can be executed.
...@@ -3098,54 +3204,7 @@ pub fn performAllTheWork(...@@ -3098,54 +3204,7 @@ pub fn performAllTheWork(
3098 }3204 }
30993205
3100 if (comp.bin_file.options.module) |mod| {3206 if (comp.bin_file.options.module) |mod| {
3101 for (mod.import_table.values()) |file| {3207 try reportMultiModuleErrors(mod);
3102 if (!file.multi_pkg) continue;
3103 const err = err_blk: {
3104 const notes = try mod.gpa.alloc(Module.ErrorMsg, file.references.items.len);
3105 errdefer mod.gpa.free(notes);
3106
3107 for (notes, 0..) |*note, i| {
3108 errdefer for (notes[0..i]) |*n| n.deinit(mod.gpa);
3109 note.* = switch (file.references.items[i]) {
3110 .import => |loc| try Module.ErrorMsg.init(
3111 mod.gpa,
3112 loc,
3113 "imported from package {s}",
3114 .{loc.file_scope.pkg.name},
3115 ),
3116 .root => |pkg| try Module.ErrorMsg.init(
3117 mod.gpa,
3118 .{ .file_scope = file, .parent_decl_node = 0, .lazy = .entire_file },
3119 "root of package {s}",
3120 .{pkg.name},
3121 ),
3122 };
3123 }
3124 errdefer for (notes) |*n| n.deinit(mod.gpa);
3125
3126 const err = try Module.ErrorMsg.create(
3127 mod.gpa,
3128 .{ .file_scope = file, .parent_decl_node = 0, .lazy = .entire_file },
3129 "file exists in multiple packages",
3130 .{},
3131 );
3132 err.notes = notes;
3133 break :err_blk err;
3134 };
3135 errdefer err.destroy(mod.gpa);
3136 try mod.failed_files.putNoClobber(mod.gpa, file, err);
3137 }
3138
3139 // Now that we've reported the errors, we need to deal with
3140 // dependencies. Any file referenced by a multi_pkg file should also be
3141 // marked multi_pkg and have its status set to astgen_failure, as it's
3142 // ambiguous which package they should be analyzed as a part of. We need
3143 // to add this flag after reporting the errors however, as otherwise
3144 // we'd get an error for every single downstream file, which wouldn't be
3145 // very useful.
3146 for (mod.import_table.values()) |file| {
3147 if (file.multi_pkg) file.recursiveMarkMultiPkg(mod);
3148 }
3149 }3208 }
31503209
3151 {3210 {
...@@ -3266,24 +3325,20 @@ fn processOneJob(comp: *Compilation, job: Job) !void {...@@ -3266,24 +3325,20 @@ fn processOneJob(comp: *Compilation, job: Job) !void {
3266 const decl_emit_h = emit_h.declPtr(decl_index);3325 const decl_emit_h = emit_h.declPtr(decl_index);
3267 const fwd_decl = &decl_emit_h.fwd_decl;3326 const fwd_decl = &decl_emit_h.fwd_decl;
3268 fwd_decl.shrinkRetainingCapacity(0);3327 fwd_decl.shrinkRetainingCapacity(0);
3269 var typedefs_arena = std.heap.ArenaAllocator.init(gpa);3328 var ctypes_arena = std.heap.ArenaAllocator.init(gpa);
3270 defer typedefs_arena.deinit();3329 defer ctypes_arena.deinit();
32713330
3272 var dg: c_codegen.DeclGen = .{3331 var dg: c_codegen.DeclGen = .{
3273 .gpa = gpa,3332 .gpa = gpa,
3274 .module = module,3333 .module = module,
3275 .error_msg = null,3334 .error_msg = null,
3276 .decl_index = decl_index,3335 .decl_index = decl_index.toOptional(),
3277 .decl = decl,3336 .decl = decl,
3278 .fwd_decl = fwd_decl.toManaged(gpa),3337 .fwd_decl = fwd_decl.toManaged(gpa),
3279 .typedefs = c_codegen.TypedefMap.initContext(gpa, .{ .mod = module }),3338 .ctypes = .{},
3280 .typedefs_arena = typedefs_arena.allocator(),
3281 };3339 };
3282 defer {3340 defer {
3283 for (dg.typedefs.values()) |typedef| {3341 dg.ctypes.deinit(gpa);
3284 module.gpa.free(typedef.rendered);
3285 }
3286 dg.typedefs.deinit();
3287 dg.fwd_decl.deinit();3342 dg.fwd_decl.deinit();
3288 }3343 }
32893344
...@@ -5415,7 +5470,6 @@ fn buildOutputFromZig(...@@ -5415,7 +5470,6 @@ fn buildOutputFromZig(
5415 var main_pkg: Package = .{5470 var main_pkg: Package = .{
5416 .root_src_directory = comp.zig_lib_directory,5471 .root_src_directory = comp.zig_lib_directory,
5417 .root_src_path = src_basename,5472 .root_src_path = src_basename,
5418 .name = "root",
5419 };5473 };
5420 defer main_pkg.deinitTable(comp.gpa);5474 defer main_pkg.deinitTable(comp.gpa);
5421 const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];5475 const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];
src/Module.zig+46-23
...@@ -144,10 +144,6 @@ stage1_flags: packed struct {...@@ -144,10 +144,6 @@ stage1_flags: packed struct {
144} = .{},144} = .{},
145145
146job_queued_update_builtin_zig: bool = true,146job_queued_update_builtin_zig: bool = true,
147/// This makes it so that we can run `zig test` on the standard library.
148/// Otherwise, the logic for scanning test decls skips all of them because
149/// `main_pkg != std_pkg`.
150main_pkg_is_std: bool,
151147
152compile_log_text: ArrayListUnmanaged(u8) = .{},148compile_log_text: ArrayListUnmanaged(u8) = .{},
153149
...@@ -1950,7 +1946,7 @@ pub const File = struct {...@@ -1950,7 +1946,7 @@ pub const File = struct {
1950 prev_zir: ?*Zir = null,1946 prev_zir: ?*Zir = null,
19511947
1952 /// A single reference to a file.1948 /// A single reference to a file.
1953 const Reference = union(enum) {1949 pub const Reference = union(enum) {
1954 /// The file is imported directly (i.e. not as a package) with @import.1950 /// The file is imported directly (i.e. not as a package) with @import.
1955 import: SrcLoc,1951 import: SrcLoc,
1956 /// The file is the root of a package.1952 /// The file is the root of a package.
...@@ -2113,7 +2109,27 @@ pub const File = struct {...@@ -2113,7 +2109,27 @@ pub const File = struct {
21132109
2114 /// Add a reference to this file during AstGen.2110 /// Add a reference to this file during AstGen.
2115 pub fn addReference(file: *File, mod: Module, ref: Reference) !void {2111 pub fn addReference(file: *File, mod: Module, ref: Reference) !void {
2116 try file.references.append(mod.gpa, ref);2112 // Don't add the same module root twice. Note that since we always add module roots at the
2113 // front of the references array (see below), this loop is actually O(1) on valid code.
2114 if (ref == .root) {
2115 for (file.references.items) |other| {
2116 switch (other) {
2117 .root => |r| if (ref.root == r) return,
2118 else => break, // reached the end of the "is-root" references
2119 }
2120 }
2121 }
2122
2123 switch (ref) {
2124 // We put root references at the front of the list both to make the above loop fast and
2125 // to make multi-module errors more helpful (since "root-of" notes are generally more
2126 // informative than "imported-from" notes). This path is hit very rarely, so the speed
2127 // of the insert operation doesn't matter too much.
2128 .root => try file.references.insert(mod.gpa, 0, ref),
2129
2130 // Other references we'll just put at the end.
2131 else => try file.references.append(mod.gpa, ref),
2132 }
21172133
2118 const pkg = switch (ref) {2134 const pkg = switch (ref) {
2119 .import => |loc| loc.file_scope.pkg,2135 .import => |loc| loc.file_scope.pkg,
...@@ -2128,7 +2144,10 @@ pub const File = struct {...@@ -2128,7 +2144,10 @@ pub const File = struct {
2128 file.multi_pkg = true;2144 file.multi_pkg = true;
2129 file.status = .astgen_failure;2145 file.status = .astgen_failure;
21302146
2131 std.debug.assert(file.zir_loaded);2147 // We can only mark children as failed if the ZIR is loaded, which may not
2148 // be the case if there were other astgen failures in this file
2149 if (!file.zir_loaded) return;
2150
2132 const imports_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.imports)];2151 const imports_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.imports)];
2133 if (imports_index == 0) return;2152 if (imports_index == 0) return;
2134 const extra = file.zir.extraData(Zir.Inst.Imports, imports_index);2153 const extra = file.zir.extraData(Zir.Inst.Imports, imports_index);
...@@ -3323,10 +3342,19 @@ pub fn deinit(mod: *Module) void {...@@ -3323,10 +3342,19 @@ pub fn deinit(mod: *Module) void {
3323 // The callsite of `Compilation.create` owns the `main_pkg`, however3342 // The callsite of `Compilation.create` owns the `main_pkg`, however
3324 // Module owns the builtin and std packages that it adds.3343 // Module owns the builtin and std packages that it adds.
3325 if (mod.main_pkg.table.fetchRemove("builtin")) |kv| {3344 if (mod.main_pkg.table.fetchRemove("builtin")) |kv| {
3345 gpa.free(kv.key);
3326 kv.value.destroy(gpa);3346 kv.value.destroy(gpa);
3327 }3347 }
3328 if (mod.main_pkg.table.fetchRemove("std")) |kv| {3348 if (mod.main_pkg.table.fetchRemove("std")) |kv| {
3329 kv.value.destroy(gpa);3349 gpa.free(kv.key);
3350 // It's possible for main_pkg to be std when running 'zig test'! In this case, we must not
3351 // destroy it, since it would lead to a double-free.
3352 if (kv.value != mod.main_pkg) {
3353 kv.value.destroy(gpa);
3354 }
3355 }
3356 if (mod.main_pkg.table.fetchRemove("root")) |kv| {
3357 gpa.free(kv.key);
3330 }3358 }
3331 if (mod.root_pkg != mod.main_pkg) {3359 if (mod.root_pkg != mod.main_pkg) {
3332 mod.root_pkg.destroy(gpa);3360 mod.root_pkg.destroy(gpa);
...@@ -4808,11 +4836,14 @@ pub fn importPkg(mod: *Module, pkg: *Package) !ImportFileResult {...@@ -4808,11 +4836,14 @@ pub fn importPkg(mod: *Module, pkg: *Package) !ImportFileResult {
48084836
4809 const gop = try mod.import_table.getOrPut(gpa, resolved_path);4837 const gop = try mod.import_table.getOrPut(gpa, resolved_path);
4810 errdefer _ = mod.import_table.pop();4838 errdefer _ = mod.import_table.pop();
4811 if (gop.found_existing) return ImportFileResult{4839 if (gop.found_existing) {
4812 .file = gop.value_ptr.*,4840 try gop.value_ptr.*.addReference(mod.*, .{ .root = pkg });
4813 .is_new = false,4841 return ImportFileResult{
4814 .is_pkg = true,4842 .file = gop.value_ptr.*,
4815 };4843 .is_new = false,
4844 .is_pkg = true,
4845 };
4846 }
48164847
4817 const sub_file_path = try gpa.dupe(u8, pkg.root_src_path);4848 const sub_file_path = try gpa.dupe(u8, pkg.root_src_path);
4818 errdefer gpa.free(sub_file_path);4849 errdefer gpa.free(sub_file_path);
...@@ -5208,22 +5239,14 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err...@@ -5208,22 +5239,14 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err
5208 // test decl with no name. Skip the part where we check against5239 // test decl with no name. Skip the part where we check against
5209 // the test name filter.5240 // the test name filter.
5210 if (!comp.bin_file.options.is_test) break :blk false;5241 if (!comp.bin_file.options.is_test) break :blk false;
5211 if (decl_pkg != mod.main_pkg) {5242 if (decl_pkg != mod.main_pkg) break :blk false;
5212 if (!mod.main_pkg_is_std) break :blk false;
5213 const std_pkg = mod.main_pkg.table.get("std").?;
5214 if (std_pkg != decl_pkg) break :blk false;
5215 }
5216 try mod.test_functions.put(gpa, new_decl_index, {});5243 try mod.test_functions.put(gpa, new_decl_index, {});
5217 break :blk true;5244 break :blk true;
5218 },5245 },
5219 else => blk: {5246 else => blk: {
5220 if (!is_named_test) break :blk false;5247 if (!is_named_test) break :blk false;
5221 if (!comp.bin_file.options.is_test) break :blk false;5248 if (!comp.bin_file.options.is_test) break :blk false;
5222 if (decl_pkg != mod.main_pkg) {5249 if (decl_pkg != mod.main_pkg) break :blk false;
5223 if (!mod.main_pkg_is_std) break :blk false;
5224 const std_pkg = mod.main_pkg.table.get("std").?;
5225 if (std_pkg != decl_pkg) break :blk false;
5226 }
5227 if (comp.test_filter) |test_filter| {5250 if (comp.test_filter) |test_filter| {
5228 if (mem.indexOf(u8, decl_name, test_filter) == null) {5251 if (mem.indexOf(u8, decl_name, test_filter) == null) {
5229 break :blk false;5252 break :blk false;
src/Package.zig+127-35
...@@ -22,17 +22,16 @@ pub const Table = std.StringHashMapUnmanaged(*Package);...@@ -22,17 +22,16 @@ pub const Table = std.StringHashMapUnmanaged(*Package);
22root_src_directory: Compilation.Directory,22root_src_directory: Compilation.Directory,
23/// Relative to `root_src_directory`. May contain path separators.23/// Relative to `root_src_directory`. May contain path separators.
24root_src_path: []const u8,24root_src_path: []const u8,
25/// The dependency table of this module. Shared dependencies such as 'std', 'builtin', and 'root'
26/// are not specified in every dependency table, but instead only in the table of `main_pkg`.
27/// `Module.importFile` is responsible for detecting these names and using the correct package.
25table: Table = .{},28table: Table = .{},
26parent: ?*Package = null,
27/// Whether to free `root_src_directory` on `destroy`.29/// Whether to free `root_src_directory` on `destroy`.
28root_src_directory_owned: bool = false,30root_src_directory_owned: bool = false,
29/// This information can be recovered from 'table', but it's more convenient to store on the package.
30name: []const u8,
3131
32/// Allocate a Package. No references to the slices passed are kept.32/// Allocate a Package. No references to the slices passed are kept.
33pub fn create(33pub fn create(
34 gpa: Allocator,34 gpa: Allocator,
35 name: []const u8,
36 /// Null indicates the current working directory35 /// Null indicates the current working directory
37 root_src_dir_path: ?[]const u8,36 root_src_dir_path: ?[]const u8,
38 /// Relative to root_src_dir_path37 /// Relative to root_src_dir_path
...@@ -47,9 +46,6 @@ pub fn create(...@@ -47,9 +46,6 @@ pub fn create(
47 const owned_src_path = try gpa.dupe(u8, root_src_path);46 const owned_src_path = try gpa.dupe(u8, root_src_path);
48 errdefer gpa.free(owned_src_path);47 errdefer gpa.free(owned_src_path);
4948
50 const owned_name = try gpa.dupe(u8, name);
51 errdefer gpa.free(owned_name);
52
53 ptr.* = .{49 ptr.* = .{
54 .root_src_directory = .{50 .root_src_directory = .{
55 .path = owned_dir_path,51 .path = owned_dir_path,
...@@ -57,7 +53,6 @@ pub fn create(...@@ -57,7 +53,6 @@ pub fn create(
57 },53 },
58 .root_src_path = owned_src_path,54 .root_src_path = owned_src_path,
59 .root_src_directory_owned = true,55 .root_src_directory_owned = true,
60 .name = owned_name,
61 };56 };
6257
63 return ptr;58 return ptr;
...@@ -65,7 +60,6 @@ pub fn create(...@@ -65,7 +60,6 @@ pub fn create(
6560
66pub fn createWithDir(61pub fn createWithDir(
67 gpa: Allocator,62 gpa: Allocator,
68 name: []const u8,
69 directory: Compilation.Directory,63 directory: Compilation.Directory,
70 /// Relative to `directory`. If null, means `directory` is the root src dir64 /// Relative to `directory`. If null, means `directory` is the root src dir
71 /// and is owned externally.65 /// and is owned externally.
...@@ -79,9 +73,6 @@ pub fn createWithDir(...@@ -79,9 +73,6 @@ pub fn createWithDir(
79 const owned_src_path = try gpa.dupe(u8, root_src_path);73 const owned_src_path = try gpa.dupe(u8, root_src_path);
80 errdefer gpa.free(owned_src_path);74 errdefer gpa.free(owned_src_path);
8175
82 const owned_name = try gpa.dupe(u8, name);
83 errdefer gpa.free(owned_name);
84
85 if (root_src_dir_path) |p| {76 if (root_src_dir_path) |p| {
86 const owned_dir_path = try directory.join(gpa, &[1][]const u8{p});77 const owned_dir_path = try directory.join(gpa, &[1][]const u8{p});
87 errdefer gpa.free(owned_dir_path);78 errdefer gpa.free(owned_dir_path);
...@@ -93,14 +84,12 @@ pub fn createWithDir(...@@ -93,14 +84,12 @@ pub fn createWithDir(
93 },84 },
94 .root_src_directory_owned = true,85 .root_src_directory_owned = true,
95 .root_src_path = owned_src_path,86 .root_src_path = owned_src_path,
96 .name = owned_name,
97 };87 };
98 } else {88 } else {
99 ptr.* = .{89 ptr.* = .{
100 .root_src_directory = directory,90 .root_src_directory = directory,
101 .root_src_directory_owned = false,91 .root_src_directory_owned = false,
102 .root_src_path = owned_src_path,92 .root_src_path = owned_src_path,
103 .name = owned_name,
104 };93 };
105 }94 }
106 return ptr;95 return ptr;
...@@ -110,7 +99,6 @@ pub fn createWithDir(...@@ -110,7 +99,6 @@ pub fn createWithDir(
110/// inside its table; the caller is responsible for calling destroy() on them.99/// inside its table; the caller is responsible for calling destroy() on them.
111pub fn destroy(pkg: *Package, gpa: Allocator) void {100pub fn destroy(pkg: *Package, gpa: Allocator) void {
112 gpa.free(pkg.root_src_path);101 gpa.free(pkg.root_src_path);
113 gpa.free(pkg.name);
114102
115 if (pkg.root_src_directory_owned) {103 if (pkg.root_src_directory_owned) {
116 // If root_src_directory.path is null then the handle is the cwd()104 // If root_src_directory.path is null then the handle is the cwd()
...@@ -130,15 +118,97 @@ pub fn deinitTable(pkg: *Package, gpa: Allocator) void {...@@ -130,15 +118,97 @@ pub fn deinitTable(pkg: *Package, gpa: Allocator) void {
130 pkg.table.deinit(gpa);118 pkg.table.deinit(gpa);
131}119}
132120
133pub fn add(pkg: *Package, gpa: Allocator, package: *Package) !void {121pub fn add(pkg: *Package, gpa: Allocator, name: []const u8, package: *Package) !void {
134 try pkg.table.ensureUnusedCapacity(gpa, 1);122 try pkg.table.ensureUnusedCapacity(gpa, 1);
135 pkg.table.putAssumeCapacityNoClobber(package.name, package);123 const name_dupe = try gpa.dupe(u8, name);
124 pkg.table.putAssumeCapacityNoClobber(name_dupe, package);
136}125}
137126
138pub fn addAndAdopt(parent: *Package, gpa: Allocator, child: *Package) !void {127/// Compute a readable name for the package. The returned name should be freed from gpa. This
139 assert(child.parent == null); // make up your mind, who is the parent??128/// function is very slow, as it traverses the whole package hierarchy to find a path to this
140 child.parent = parent;129/// package. It should only be used for error output.
141 return parent.add(gpa, child);130pub fn getName(target: *const Package, gpa: Allocator, mod: Module) ![]const u8 {
131 // we'll do a breadth-first search from the root module to try and find a short name for this
132 // module, using a TailQueue of module/parent pairs. note that the "parent" there is just the
133 // first-found shortest path - a module may be children of arbitrarily many other modules.
134 // also, this path may vary between executions due to hashmap iteration order, but that doesn't
135 // matter too much.
136 var node_arena = std.heap.ArenaAllocator.init(gpa);
137 defer node_arena.deinit();
138 const Parented = struct {
139 parent: ?*const @This(),
140 mod: *const Package,
141 };
142 const Queue = std.TailQueue(Parented);
143 var to_check: Queue = .{};
144
145 {
146 const new = try node_arena.allocator().create(Queue.Node);
147 new.* = .{ .data = .{ .parent = null, .mod = mod.root_pkg } };
148 to_check.prepend(new);
149 }
150
151 if (mod.main_pkg != mod.root_pkg) {
152 const new = try node_arena.allocator().create(Queue.Node);
153 // TODO: once #12201 is resolved, we may want a way of indicating a different name for this
154 new.* = .{ .data = .{ .parent = null, .mod = mod.main_pkg } };
155 to_check.prepend(new);
156 }
157
158 // set of modules we've already checked to prevent loops
159 var checked = std.AutoHashMap(*const Package, void).init(gpa);
160 defer checked.deinit();
161
162 const linked = while (to_check.pop()) |node| {
163 const check = &node.data;
164
165 if (checked.contains(check.mod)) continue;
166 try checked.put(check.mod, {});
167
168 if (check.mod == target) break check;
169
170 var it = check.mod.table.iterator();
171 while (it.next()) |kv| {
172 var new = try node_arena.allocator().create(Queue.Node);
173 new.* = .{ .data = .{
174 .parent = check,
175 .mod = kv.value_ptr.*,
176 } };
177 to_check.prepend(new);
178 }
179 } else {
180 // this can happen for e.g. @cImport packages
181 return gpa.dupe(u8, "<unnamed>");
182 };
183
184 // we found a path to the module! unfortunately, we can only traverse *up* it, so we have to put
185 // all the names into a buffer so we can then print them in order.
186 var names = std.ArrayList([]const u8).init(gpa);
187 defer names.deinit();
188
189 var cur: *const Parented = linked;
190 while (cur.parent) |parent| : (cur = parent) {
191 // find cur's name in parent
192 var it = parent.mod.table.iterator();
193 const name = while (it.next()) |kv| {
194 if (kv.value_ptr.* == cur.mod) {
195 break kv.key_ptr.*;
196 }
197 } else unreachable;
198 try names.append(name);
199 }
200
201 // finally, print the names into a buffer!
202 var buf = std.ArrayList(u8).init(gpa);
203 defer buf.deinit();
204 try buf.writer().writeAll("root");
205 var i: usize = names.items.len;
206 while (i > 0) {
207 i -= 1;
208 try buf.writer().print(".{s}", .{names.items[i]});
209 }
210
211 return buf.toOwnedSlice();
142}212}
143213
144pub const build_zig_basename = "build.zig";214pub const build_zig_basename = "build.zig";
...@@ -236,7 +306,7 @@ pub fn fetchAndAddDependencies(...@@ -236,7 +306,7 @@ pub fn fetchAndAddDependencies(
236 color,306 color,
237 );307 );
238308
239 try addAndAdopt(pkg, gpa, sub_pkg);309 try add(pkg, gpa, fqn, sub_pkg);
240310
241 try dependencies_source.writer().print(" pub const {s} = @import(\"{}\");\n", .{311 try dependencies_source.writer().print(" pub const {s} = @import(\"{}\");\n", .{
242 std.zig.fmtId(fqn), std.zig.fmtEscapes(fqn),312 std.zig.fmtId(fqn), std.zig.fmtEscapes(fqn),
...@@ -248,7 +318,6 @@ pub fn fetchAndAddDependencies(...@@ -248,7 +318,6 @@ pub fn fetchAndAddDependencies(
248318
249pub fn createFilePkg(319pub fn createFilePkg(
250 gpa: Allocator,320 gpa: Allocator,
251 name: []const u8,
252 cache_directory: Compilation.Directory,321 cache_directory: Compilation.Directory,
253 basename: []const u8,322 basename: []const u8,
254 contents: []const u8,323 contents: []const u8,
...@@ -269,7 +338,7 @@ pub fn createFilePkg(...@@ -269,7 +338,7 @@ pub fn createFilePkg(
269 const o_dir_sub_path = "o" ++ fs.path.sep_str ++ hex_digest;338 const o_dir_sub_path = "o" ++ fs.path.sep_str ++ hex_digest;
270 try renameTmpIntoCache(cache_directory.handle, tmp_dir_sub_path, o_dir_sub_path);339 try renameTmpIntoCache(cache_directory.handle, tmp_dir_sub_path, o_dir_sub_path);
271340
272 return createWithDir(gpa, name, cache_directory, o_dir_sub_path, basename);341 return createWithDir(gpa, cache_directory, o_dir_sub_path, basename);
273}342}
274343
275const Report = struct {344const Report = struct {
...@@ -363,9 +432,6 @@ fn fetchAndUnpack(...@@ -363,9 +432,6 @@ fn fetchAndUnpack(
363 const owned_src_path = try gpa.dupe(u8, build_zig_basename);432 const owned_src_path = try gpa.dupe(u8, build_zig_basename);
364 errdefer gpa.free(owned_src_path);433 errdefer gpa.free(owned_src_path);
365434
366 const owned_name = try gpa.dupe(u8, fqn);
367 errdefer gpa.free(owned_name);
368
369 const build_root = try global_cache_directory.join(gpa, &.{pkg_dir_sub_path});435 const build_root = try global_cache_directory.join(gpa, &.{pkg_dir_sub_path});
370 errdefer gpa.free(build_root);436 errdefer gpa.free(build_root);
371437
...@@ -380,7 +446,6 @@ fn fetchAndUnpack(...@@ -380,7 +446,6 @@ fn fetchAndUnpack(
380 },446 },
381 .root_src_directory_owned = true,447 .root_src_directory_owned = true,
382 .root_src_path = owned_src_path,448 .root_src_path = owned_src_path,
383 .name = owned_name,
384 };449 };
385450
386 return ptr;451 return ptr;
...@@ -428,6 +493,11 @@ fn fetchAndUnpack(...@@ -428,6 +493,11 @@ fn fetchAndUnpack(
428 // apply those rules directly to the filesystem right here. This ensures that files493 // apply those rules directly to the filesystem right here. This ensures that files
429 // not protected by the hash are not present on the file system.494 // not protected by the hash are not present on the file system.
430495
496 // TODO: raise an error for files that have illegal paths on some operating systems.
497 // For example, on Linux a path with a backslash should raise an error here.
498 // Of course, if the ignore rules above omit the file from the package, then everything
499 // is fine and no error should be raised.
500
431 break :a try computePackageHash(thread_pool, .{ .dir = tmp_directory.handle });501 break :a try computePackageHash(thread_pool, .{ .dir = tmp_directory.handle });
432 };502 };
433503
...@@ -455,7 +525,7 @@ fn fetchAndUnpack(...@@ -455,7 +525,7 @@ fn fetchAndUnpack(
455 std.zig.fmtId(fqn), std.zig.fmtEscapes(build_root),525 std.zig.fmtId(fqn), std.zig.fmtEscapes(build_root),
456 });526 });
457527
458 return createWithDir(gpa, fqn, global_cache_directory, pkg_dir_sub_path, build_zig_basename);528 return createWithDir(gpa, global_cache_directory, pkg_dir_sub_path, build_zig_basename);
459}529}
460530
461fn unpackTarball(531fn unpackTarball(
...@@ -481,7 +551,8 @@ fn unpackTarball(...@@ -481,7 +551,8 @@ fn unpackTarball(
481}551}
482552
483const HashedFile = struct {553const HashedFile = struct {
484 path: []const u8,554 fs_path: []const u8,
555 normalized_path: []const u8,
485 hash: [Manifest.Hash.digest_length]u8,556 hash: [Manifest.Hash.digest_length]u8,
486 failure: Error!void,557 failure: Error!void,
487558
...@@ -489,7 +560,7 @@ const HashedFile = struct {...@@ -489,7 +560,7 @@ const HashedFile = struct {
489560
490 fn lessThan(context: void, lhs: *const HashedFile, rhs: *const HashedFile) bool {561 fn lessThan(context: void, lhs: *const HashedFile, rhs: *const HashedFile) bool {
491 _ = context;562 _ = context;
492 return mem.lessThan(u8, lhs.path, rhs.path);563 return mem.lessThan(u8, lhs.normalized_path, rhs.normalized_path);
493 }564 }
494};565};
495566
...@@ -525,8 +596,10 @@ fn computePackageHash(...@@ -525,8 +596,10 @@ fn computePackageHash(
525 else => return error.IllegalFileTypeInPackage,596 else => return error.IllegalFileTypeInPackage,
526 }597 }
527 const hashed_file = try arena.create(HashedFile);598 const hashed_file = try arena.create(HashedFile);
599 const fs_path = try arena.dupe(u8, entry.path);
528 hashed_file.* = .{600 hashed_file.* = .{
529 .path = try arena.dupe(u8, entry.path),601 .fs_path = fs_path,
602 .normalized_path = try normalizePath(arena, fs_path),
530 .hash = undefined, // to be populated by the worker603 .hash = undefined, // to be populated by the worker
531 .failure = undefined, // to be populated by the worker604 .failure = undefined, // to be populated by the worker
532 };605 };
...@@ -544,7 +617,7 @@ fn computePackageHash(...@@ -544,7 +617,7 @@ fn computePackageHash(
544 for (all_files.items) |hashed_file| {617 for (all_files.items) |hashed_file| {
545 hashed_file.failure catch |err| {618 hashed_file.failure catch |err| {
546 any_failures = true;619 any_failures = true;
547 std.log.err("unable to hash '{s}': {s}", .{ hashed_file.path, @errorName(err) });620 std.log.err("unable to hash '{s}': {s}", .{ hashed_file.fs_path, @errorName(err) });
548 };621 };
549 hasher.update(&hashed_file.hash);622 hasher.update(&hashed_file.hash);
550 }623 }
...@@ -552,6 +625,24 @@ fn computePackageHash(...@@ -552,6 +625,24 @@ fn computePackageHash(
552 return hasher.finalResult();625 return hasher.finalResult();
553}626}
554627
628/// Make a file system path identical independently of operating system path inconsistencies.
629/// This converts backslashes into forward slashes.
630fn normalizePath(arena: Allocator, fs_path: []const u8) ![]const u8 {
631 const canonical_sep = '/';
632
633 if (fs.path.sep == canonical_sep)
634 return fs_path;
635
636 const normalized = try arena.dupe(u8, fs_path);
637 for (normalized) |*byte| {
638 switch (byte.*) {
639 fs.path.sep => byte.* = canonical_sep,
640 else => continue,
641 }
642 }
643 return normalized;
644}
645
555fn workerHashFile(dir: fs.Dir, hashed_file: *HashedFile, wg: *WaitGroup) void {646fn workerHashFile(dir: fs.Dir, hashed_file: *HashedFile, wg: *WaitGroup) void {
556 defer wg.finish();647 defer wg.finish();
557 hashed_file.failure = hashFileFallible(dir, hashed_file);648 hashed_file.failure = hashFileFallible(dir, hashed_file);
...@@ -559,9 +650,10 @@ fn workerHashFile(dir: fs.Dir, hashed_file: *HashedFile, wg: *WaitGroup) void {...@@ -559,9 +650,10 @@ fn workerHashFile(dir: fs.Dir, hashed_file: *HashedFile, wg: *WaitGroup) void {
559650
560fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void {651fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void {
561 var buf: [8000]u8 = undefined;652 var buf: [8000]u8 = undefined;
562 var file = try dir.openFile(hashed_file.path, .{});653 var file = try dir.openFile(hashed_file.fs_path, .{});
654 defer file.close();
563 var hasher = Manifest.Hash.init(.{});655 var hasher = Manifest.Hash.init(.{});
564 hasher.update(hashed_file.path);656 hasher.update(hashed_file.normalized_path);
565 hasher.update(&.{ 0, @boolToInt(try isExecutable(file)) });657 hasher.update(&.{ 0, @boolToInt(try isExecutable(file)) });
566 while (true) {658 while (true) {
567 const bytes_read = try file.read(&buf);659 const bytes_read = try file.read(&buf);
src/Sema.zig+67-44
...@@ -2529,7 +2529,7 @@ fn coerceResultPtr(...@@ -2529,7 +2529,7 @@ fn coerceResultPtr(
2529 _ = try block.addBinOp(.store, new_ptr, null_inst);2529 _ = try block.addBinOp(.store, new_ptr, null_inst);
2530 return Air.Inst.Ref.void_value;2530 return Air.Inst.Ref.void_value;
2531 }2531 }
2532 return sema.bitCast(block, ptr_ty, new_ptr, src);2532 return sema.bitCast(block, ptr_ty, new_ptr, src, null);
2533 }2533 }
25342534
2535 const trash_inst = trash_block.instructions.pop();2535 const trash_inst = trash_block.instructions.pop();
...@@ -2545,7 +2545,7 @@ fn coerceResultPtr(...@@ -2545,7 +2545,7 @@ fn coerceResultPtr(
2545 if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| {2545 if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| {
2546 new_ptr = try sema.addConstant(ptr_operand_ty, ptr_val);2546 new_ptr = try sema.addConstant(ptr_operand_ty, ptr_val);
2547 } else {2547 } else {
2548 new_ptr = try sema.bitCast(block, ptr_operand_ty, new_ptr, src);2548 new_ptr = try sema.bitCast(block, ptr_operand_ty, new_ptr, src, null);
2549 }2549 }
2550 },2550 },
2551 .wrap_optional => {2551 .wrap_optional => {
...@@ -5311,7 +5311,6 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -5311,7 +5311,6 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
5311 }5311 }
5312 const c_import_pkg = Package.create(5312 const c_import_pkg = Package.create(
5313 sema.gpa,5313 sema.gpa,
5314 "c_import", // TODO: should we make this unique?
5315 null,5314 null,
5316 c_import_res.out_zig_path,5315 c_import_res.out_zig_path,
5317 ) catch |err| switch (err) {5316 ) catch |err| switch (err) {
...@@ -9655,7 +9654,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -9655,7 +9654,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
9655 .Vector,9654 .Vector,
9656 => {},9655 => {},
9657 }9656 }
9658 return sema.bitCast(block, dest_ty, operand, operand_src);9657 return sema.bitCast(block, dest_ty, operand, inst_data.src(), operand_src);
9659}9658}
96609659
9661fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {9660fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -9888,7 +9887,7 @@ fn zirSwitchCapture(...@@ -9888,7 +9887,7 @@ fn zirSwitchCapture(
98889887
9889 switch (operand_ty.zigTypeTag()) {9888 switch (operand_ty.zigTypeTag()) {
9890 .ErrorSet => if (block.switch_else_err_ty) |some| {9889 .ErrorSet => if (block.switch_else_err_ty) |some| {
9891 return sema.bitCast(block, some, operand, operand_src);9890 return sema.bitCast(block, some, operand, operand_src, null);
9892 } else {9891 } else {
9893 try block.addUnreachable(false);9892 try block.addUnreachable(false);
9894 return Air.Inst.Ref.unreachable_value;9893 return Air.Inst.Ref.unreachable_value;
...@@ -9988,14 +9987,14 @@ fn zirSwitchCapture(...@@ -9988,14 +9987,14 @@ fn zirSwitchCapture(
9988 Module.ErrorSet.sortNames(&names);9987 Module.ErrorSet.sortNames(&names);
9989 const else_error_ty = try Type.Tag.error_set_merged.create(sema.arena, names);9988 const else_error_ty = try Type.Tag.error_set_merged.create(sema.arena, names);
99909989
9991 return sema.bitCast(block, else_error_ty, operand, operand_src);9990 return sema.bitCast(block, else_error_ty, operand, operand_src, null);
9992 } else {9991 } else {
9993 const item_ref = try sema.resolveInst(items[0]);9992 const item_ref = try sema.resolveInst(items[0]);
9994 // Previous switch validation ensured this will succeed9993 // Previous switch validation ensured this will succeed
9995 const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable;9994 const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable;
99969995
9997 const item_ty = try Type.Tag.error_set_single.create(sema.arena, item_val.getError().?);9996 const item_ty = try Type.Tag.error_set_single.create(sema.arena, item_val.getError().?);
9998 return sema.bitCast(block, item_ty, operand, operand_src);9997 return sema.bitCast(block, item_ty, operand, operand_src, null);
9999 }9998 }
10000 },9999 },
10001 else => {10000 else => {
...@@ -11793,8 +11792,9 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -11793,8 +11792,9 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
11793 return sema.fail(block, operand_src, "import of file outside package path: '{s}'", .{operand});11792 return sema.fail(block, operand_src, "import of file outside package path: '{s}'", .{operand});
11794 },11793 },
11795 error.PackageNotFound => {11794 error.PackageNotFound => {
11796 const cur_pkg = block.getFileScope().pkg;11795 const name = try block.getFileScope().pkg.getName(sema.gpa, mod.*);
11797 return sema.fail(block, operand_src, "no package named '{s}' available within package '{s}'", .{ operand, cur_pkg.name });11796 defer sema.gpa.free(name);
11797 return sema.fail(block, operand_src, "no package named '{s}' available within package '{s}'", .{ operand, name });
11798 },11798 },
11799 else => {11799 else => {
11800 // TODO: these errors are file system errors; make sure an update() will11800 // TODO: these errors are file system errors; make sure an update() will
...@@ -19953,7 +19953,7 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -19953,7 +19953,7 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
19953 } else is_aligned;19953 } else is_aligned;
19954 try sema.addSafetyCheck(block, ok, .incorrect_alignment);19954 try sema.addSafetyCheck(block, ok, .incorrect_alignment);
19955 }19955 }
19956 return sema.bitCast(block, dest_ty, ptr, ptr_src);19956 return sema.bitCast(block, dest_ty, ptr, ptr_src, null);
19957}19957}
1995819958
19959fn zirBitCount(19959fn zirBitCount(
...@@ -21482,24 +21482,32 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -21482,24 +21482,32 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
21482 const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };21482 const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
21483 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };21483 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
2148421484
21485 const struct_ty = try sema.resolveType(block, ty_src, extra.parent_type);21485 const parent_ty = try sema.resolveType(block, ty_src, extra.parent_type);
21486 const field_name = try sema.resolveConstString(block, name_src, extra.field_name, "field name must be comptime-known");21486 const field_name = try sema.resolveConstString(block, name_src, extra.field_name, "field name must be comptime-known");
21487 const field_ptr = try sema.resolveInst(extra.field_ptr);21487 const field_ptr = try sema.resolveInst(extra.field_ptr);
21488 const field_ptr_ty = sema.typeOf(field_ptr);21488 const field_ptr_ty = sema.typeOf(field_ptr);
2148921489
21490 if (struct_ty.zigTypeTag() != .Struct) {21490 if (parent_ty.zigTypeTag() != .Struct and parent_ty.zigTypeTag() != .Union) {
21491 return sema.fail(block, ty_src, "expected struct type, found '{}'", .{struct_ty.fmt(sema.mod)});21491 return sema.fail(block, ty_src, "expected struct or union type, found '{}'", .{parent_ty.fmt(sema.mod)});
21492 }21492 }
21493 try sema.resolveTypeLayout(struct_ty);21493 try sema.resolveTypeLayout(parent_ty);
2149421494
21495 const field_index = if (struct_ty.isTuple()) blk: {21495 const field_index = switch (parent_ty.zigTypeTag()) {
21496 if (mem.eql(u8, field_name, "len")) {21496 .Struct => blk: {
21497 return sema.fail(block, src, "cannot get @fieldParentPtr of 'len' field of tuple", .{});21497 if (parent_ty.isTuple()) {
21498 }21498 if (mem.eql(u8, field_name, "len")) {
21499 break :blk try sema.tupleFieldIndex(block, struct_ty, field_name, name_src);21499 return sema.fail(block, src, "cannot get @fieldParentPtr of 'len' field of tuple", .{});
21500 } else try sema.structFieldIndex(block, struct_ty, field_name, name_src);21500 }
21501 break :blk try sema.tupleFieldIndex(block, parent_ty, field_name, name_src);
21502 } else {
21503 break :blk try sema.structFieldIndex(block, parent_ty, field_name, name_src);
21504 }
21505 },
21506 .Union => try sema.unionFieldIndex(block, parent_ty, field_name, name_src),
21507 else => unreachable,
21508 };
2150121509
21502 if (struct_ty.structFieldIsComptime(field_index)) {21510 if (parent_ty.zigTypeTag() == .Struct and parent_ty.structFieldIsComptime(field_index)) {
21503 return sema.fail(block, src, "cannot get @fieldParentPtr of a comptime field", .{});21511 return sema.fail(block, src, "cannot get @fieldParentPtr of a comptime field", .{});
21504 }21512 }
2150521513
...@@ -21507,23 +21515,29 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -21507,23 +21515,29 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
21507 const field_ptr_ty_info = field_ptr_ty.ptrInfo().data;21515 const field_ptr_ty_info = field_ptr_ty.ptrInfo().data;
2150821516
21509 var ptr_ty_data: Type.Payload.Pointer.Data = .{21517 var ptr_ty_data: Type.Payload.Pointer.Data = .{
21510 .pointee_type = struct_ty.structFieldType(field_index),21518 .pointee_type = parent_ty.structFieldType(field_index),
21511 .mutable = field_ptr_ty_info.mutable,21519 .mutable = field_ptr_ty_info.mutable,
21512 .@"addrspace" = field_ptr_ty_info.@"addrspace",21520 .@"addrspace" = field_ptr_ty_info.@"addrspace",
21513 };21521 };
2151421522
21515 if (struct_ty.containerLayout() == .Packed) {21523 if (parent_ty.containerLayout() == .Packed) {
21516 return sema.fail(block, src, "TODO handle packed structs with @fieldParentPtr", .{});21524 return sema.fail(block, src, "TODO handle packed structs/unions with @fieldParentPtr", .{});
21517 } else {21525 } else {
21518 ptr_ty_data.@"align" = if (struct_ty.castTag(.@"struct")) |struct_obj| b: {21526 ptr_ty_data.@"align" = blk: {
21519 break :b struct_obj.data.fields.values()[field_index].abi_align;21527 if (parent_ty.castTag(.@"struct")) |struct_obj| {
21520 } else 0;21528 break :blk struct_obj.data.fields.values()[field_index].abi_align;
21529 } else if (parent_ty.cast(Type.Payload.Union)) |union_obj| {
21530 break :blk union_obj.data.fields.values()[field_index].abi_align;
21531 } else {
21532 break :blk 0;
21533 }
21534 };
21521 }21535 }
2152221536
21523 const actual_field_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_ty_data);21537 const actual_field_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_ty_data);
21524 const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, ptr_src);21538 const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, ptr_src);
2152521539
21526 ptr_ty_data.pointee_type = struct_ty;21540 ptr_ty_data.pointee_type = parent_ty;
21527 const result_ptr = try Type.ptr(sema.arena, sema.mod, ptr_ty_data);21541 const result_ptr = try Type.ptr(sema.arena, sema.mod, ptr_ty_data);
2152821542
21529 if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| {21543 if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| {
...@@ -21540,11 +21554,11 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -21540,11 +21554,11 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
21540 field_name,21554 field_name,
21541 field_index,21555 field_index,
21542 payload.data.field_index,21556 payload.data.field_index,
21543 struct_ty.fmt(sema.mod),21557 parent_ty.fmt(sema.mod),
21544 },21558 },
21545 );21559 );
21546 errdefer msg.destroy(sema.gpa);21560 errdefer msg.destroy(sema.gpa);
21547 try sema.addDeclaredHereNote(msg, struct_ty);21561 try sema.addDeclaredHereNote(msg, parent_ty);
21548 break :msg msg;21562 break :msg msg;
21549 };21563 };
21550 return sema.failWithOwnedErrorMsg(msg);21564 return sema.failWithOwnedErrorMsg(msg);
...@@ -24141,8 +24155,9 @@ fn unionFieldVal(...@@ -24141,8 +24155,9 @@ fn unionFieldVal(
24141 return sema.addConstant(field.ty, tag_and_val.val);24155 return sema.addConstant(field.ty, tag_and_val.val);
24142 } else {24156 } else {
24143 const old_ty = union_ty.unionFieldType(tag_and_val.tag, sema.mod);24157 const old_ty = union_ty.unionFieldType(tag_and_val.tag, sema.mod);
24144 const new_val = try sema.bitCastVal(block, src, tag_and_val.val, old_ty, field.ty, 0);24158 if (try sema.bitCastVal(block, src, tag_and_val.val, old_ty, field.ty, 0)) |new_val| {
24145 return sema.addConstant(field.ty, new_val);24159 return sema.addConstant(field.ty, new_val);
24160 }
24146 }24161 }
24147 },24162 },
24148 }24163 }
...@@ -26514,8 +26529,12 @@ fn storePtrVal(...@@ -26514,8 +26529,12 @@ fn storePtrVal(
26514 const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(target));26529 const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(target));
26515 const buffer = try sema.gpa.alloc(u8, abi_size);26530 const buffer = try sema.gpa.alloc(u8, abi_size);
26516 defer sema.gpa.free(buffer);26531 defer sema.gpa.free(buffer);
26517 reinterpret.val_ptr.*.writeToMemory(mut_kit.ty, sema.mod, buffer);26532 reinterpret.val_ptr.*.writeToMemory(mut_kit.ty, sema.mod, buffer) catch |err| switch (err) {
26518 operand_val.writeToMemory(operand_ty, sema.mod, buffer[reinterpret.byte_offset..]);26533 error.ReinterpretDeclRef => unreachable,
26534 };
26535 operand_val.writeToMemory(operand_ty, sema.mod, buffer[reinterpret.byte_offset..]) catch |err| switch (err) {
26536 error.ReinterpretDeclRef => unreachable,
26537 };
2651926538
26520 const arena = mut_kit.beginArena(sema.mod);26539 const arena = mut_kit.beginArena(sema.mod);
26521 defer mut_kit.finishArena(sema.mod);26540 defer mut_kit.finishArena(sema.mod);
...@@ -27398,6 +27417,7 @@ fn bitCast(...@@ -27398,6 +27417,7 @@ fn bitCast(
27398 dest_ty_unresolved: Type,27417 dest_ty_unresolved: Type,
27399 inst: Air.Inst.Ref,27418 inst: Air.Inst.Ref,
27400 inst_src: LazySrcLoc,27419 inst_src: LazySrcLoc,
27420 operand_src: ?LazySrcLoc,
27401) CompileError!Air.Inst.Ref {27421) CompileError!Air.Inst.Ref {
27402 const dest_ty = try sema.resolveTypeFields(dest_ty_unresolved);27422 const dest_ty = try sema.resolveTypeFields(dest_ty_unresolved);
27403 try sema.resolveTypeLayout(dest_ty);27423 try sema.resolveTypeLayout(dest_ty);
...@@ -27419,10 +27439,11 @@ fn bitCast(...@@ -27419,10 +27439,11 @@ fn bitCast(
27419 }27439 }
2742027440
27421 if (try sema.resolveMaybeUndefVal(inst)) |val| {27441 if (try sema.resolveMaybeUndefVal(inst)) |val| {
27422 const result_val = try sema.bitCastVal(block, inst_src, val, old_ty, dest_ty, 0);27442 if (try sema.bitCastVal(block, inst_src, val, old_ty, dest_ty, 0)) |result_val| {
27423 return sema.addConstant(dest_ty, result_val);27443 return sema.addConstant(dest_ty, result_val);
27444 }
27424 }27445 }
27425 try sema.requireRuntimeBlock(block, inst_src, null);27446 try sema.requireRuntimeBlock(block, inst_src, operand_src);
27426 return block.addBitCast(dest_ty, inst);27447 return block.addBitCast(dest_ty, inst);
27427}27448}
2742827449
...@@ -27434,7 +27455,7 @@ fn bitCastVal(...@@ -27434,7 +27455,7 @@ fn bitCastVal(
27434 old_ty: Type,27455 old_ty: Type,
27435 new_ty: Type,27456 new_ty: Type,
27436 buffer_offset: usize,27457 buffer_offset: usize,
27437) !Value {27458) !?Value {
27438 const target = sema.mod.getTarget();27459 const target = sema.mod.getTarget();
27439 if (old_ty.eql(new_ty, sema.mod)) return val;27460 if (old_ty.eql(new_ty, sema.mod)) return val;
2744027461
...@@ -27443,8 +27464,10 @@ fn bitCastVal(...@@ -27443,8 +27464,10 @@ fn bitCastVal(
27443 const abi_size = try sema.usizeCast(block, src, old_ty.abiSize(target));27464 const abi_size = try sema.usizeCast(block, src, old_ty.abiSize(target));
27444 const buffer = try sema.gpa.alloc(u8, abi_size);27465 const buffer = try sema.gpa.alloc(u8, abi_size);
27445 defer sema.gpa.free(buffer);27466 defer sema.gpa.free(buffer);
27446 val.writeToMemory(old_ty, sema.mod, buffer);27467 val.writeToMemory(old_ty, sema.mod, buffer) catch |err| switch (err) {
27447 return Value.readFromMemory(new_ty, sema.mod, buffer[buffer_offset..], sema.arena);27468 error.ReinterpretDeclRef => return null,
27469 };
27470 return try Value.readFromMemory(new_ty, sema.mod, buffer[buffer_offset..], sema.arena);
27448}27471}
2744927472
27450fn coerceArrayPtrToSlice(27473fn coerceArrayPtrToSlice(
...@@ -27551,7 +27574,7 @@ fn coerceCompatiblePtrs(...@@ -27551,7 +27574,7 @@ fn coerceCompatiblePtrs(
27551 } else is_non_zero;27574 } else is_non_zero;
27552 try sema.addSafetyCheck(block, ok, .cast_to_null);27575 try sema.addSafetyCheck(block, ok, .cast_to_null);
27553 }27576 }
27554 return sema.bitCast(block, dest_ty, inst, inst_src);27577 return sema.bitCast(block, dest_ty, inst, inst_src, null);
27555}27578}
2755627579
27557fn coerceEnumToUnion(27580fn coerceEnumToUnion(
...@@ -28291,7 +28314,7 @@ fn analyzeRef(...@@ -28291,7 +28314,7 @@ fn analyzeRef(
28291 try sema.storePtr(block, src, alloc, operand);28314 try sema.storePtr(block, src, alloc, operand);
2829228315
28293 // TODO: Replace with sema.coerce when that supports adding pointer constness.28316 // TODO: Replace with sema.coerce when that supports adding pointer constness.
28294 return sema.bitCast(block, ptr_type, alloc, src);28317 return sema.bitCast(block, ptr_type, alloc, src, null);
28295}28318}
2829628319
28297fn analyzeLoad(28320fn analyzeLoad(
...@@ -32327,11 +32350,11 @@ fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value...@@ -32327,11 +32350,11 @@ fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value
3232732350
32328 // Try the smaller bit-cast first, since that's more efficient than using the larger `parent`32351 // Try the smaller bit-cast first, since that's more efficient than using the larger `parent`
32329 if (deref.pointee) |tv| if (load_sz <= try sema.typeAbiSize(tv.ty))32352 if (deref.pointee) |tv| if (load_sz <= try sema.typeAbiSize(tv.ty))
32330 return DerefResult{ .val = try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0) };32353 return DerefResult{ .val = (try sema.bitCastVal(block, src, tv.val, tv.ty, load_ty, 0)) orelse return .runtime_load };
3233132354
32332 // If that fails, try to bit-cast from the largest parent value with a well-defined layout32355 // If that fails, try to bit-cast from the largest parent value with a well-defined layout
32333 if (deref.parent) |parent| if (load_sz + parent.byte_offset <= try sema.typeAbiSize(parent.tv.ty))32356 if (deref.parent) |parent| if (load_sz + parent.byte_offset <= try sema.typeAbiSize(parent.tv.ty))
32334 return DerefResult{ .val = try sema.bitCastVal(block, src, parent.tv.val, parent.tv.ty, load_ty, parent.byte_offset) };32357 return DerefResult{ .val = (try sema.bitCastVal(block, src, parent.tv.val, parent.tv.ty, load_ty, parent.byte_offset)) orelse return .runtime_load };
3233532358
32336 if (deref.ty_without_well_defined_layout) |bad_ty| {32359 if (deref.ty_without_well_defined_layout) |bad_ty| {
32337 // We got no parent for bit-casting, or the parent we got was too small. Either way, the problem32360 // We got no parent for bit-casting, or the parent we got was too small. Either way, the problem
src/arch/aarch64/CodeGen.zig+19-2
...@@ -3958,7 +3958,9 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -3958,7 +3958,9 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
39583958
3959 switch (value) {3959 switch (value) {
3960 .dead => unreachable,3960 .dead => unreachable,
3961 .undef => unreachable,3961 .undef => {
3962 try self.genSetReg(value_ty, addr_reg, value);
3963 },
3962 .register => |value_reg| {3964 .register => |value_reg| {
3963 log.debug("store: register {} to {}", .{ value_reg, addr_reg });3965 log.debug("store: register {} to {}", .{ value_reg, addr_reg });
3964 try self.genStrRegister(value_reg, addr_reg, value_ty);3966 try self.genStrRegister(value_reg, addr_reg, value_ty);
...@@ -5870,7 +5872,22 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {...@@ -5870,7 +5872,22 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {
58705872
5871fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {5873fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
5872 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5874 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5873 const result = try self.resolveInst(ty_op.operand);5875 const result = if (self.liveness.isUnused(inst)) .dead else result: {
5876 const operand = try self.resolveInst(ty_op.operand);
5877 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand;
5878
5879 const operand_lock = switch (operand) {
5880 .register => |reg| self.register_manager.lockReg(reg),
5881 .register_with_overflow => |rwo| self.register_manager.lockReg(rwo.reg),
5882 else => null,
5883 };
5884 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
5885
5886 const dest_ty = self.air.typeOfIndex(inst);
5887 const dest = try self.allocRegOrMem(dest_ty, true, inst);
5888 try self.setRegOrMem(dest_ty, dest, operand);
5889 break :result dest;
5890 };
5874 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });5891 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
5875}5892}
58765893
src/arch/arm/CodeGen.zig+26-2
...@@ -2765,7 +2765,9 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2765,7 +2765,9 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
27652765
2766 switch (value) {2766 switch (value) {
2767 .dead => unreachable,2767 .dead => unreachable,
2768 .undef => unreachable,2768 .undef => {
2769 try self.genSetReg(value_ty, addr_reg, value);
2770 },
2769 .register => |value_reg| {2771 .register => |value_reg| {
2770 try self.genStrRegister(value_reg, addr_reg, value_ty);2772 try self.genStrRegister(value_reg, addr_reg, value_ty);
2771 },2773 },
...@@ -2971,6 +2973,11 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2971,6 +2973,11 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
2971 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2973 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2972 const field_ptr = try self.resolveInst(extra.field_ptr);2974 const field_ptr = try self.resolveInst(extra.field_ptr);
2973 const struct_ty = self.air.getRefType(ty_pl.ty).childType();2975 const struct_ty = self.air.getRefType(ty_pl.ty).childType();
2976
2977 if (struct_ty.zigTypeTag() == .Union) {
2978 return self.fail("TODO implement @fieldParentPtr codegen for unions", .{});
2979 }
2980
2974 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(extra.field_index, self.target.*));2981 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(extra.field_index, self.target.*));
2975 switch (field_ptr) {2982 switch (field_ptr) {
2976 .ptr_stack_offset => |off| {2983 .ptr_stack_offset => |off| {
...@@ -5816,7 +5823,24 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {...@@ -5816,7 +5823,24 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {
58165823
5817fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {5824fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
5818 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5825 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5819 const result = try self.resolveInst(ty_op.operand);5826 const result = if (self.liveness.isUnused(inst)) .dead else result: {
5827 const operand = try self.resolveInst(ty_op.operand);
5828 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand;
5829
5830 const operand_lock = switch (operand) {
5831 .register,
5832 .register_c_flag,
5833 .register_v_flag,
5834 => |reg| self.register_manager.lockReg(reg),
5835 else => null,
5836 };
5837 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
5838
5839 const dest_ty = self.air.typeOfIndex(inst);
5840 const dest = try self.allocRegOrMem(dest_ty, true, inst);
5841 try self.setRegOrMem(dest_ty, dest, operand);
5842 break :result dest;
5843 };
5820 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });5844 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
5821}5845}
58225846
src/arch/riscv64/CodeGen.zig+14-1
...@@ -2338,7 +2338,20 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {...@@ -2338,7 +2338,20 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {
23382338
2339fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {2339fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
2340 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2340 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2341 const result = try self.resolveInst(ty_op.operand);2341 const result = if (self.liveness.isUnused(inst)) .dead else result: {
2342 const operand = try self.resolveInst(ty_op.operand);
2343 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand;
2344
2345 const operand_lock = switch (operand) {
2346 .register => |reg| self.register_manager.lockReg(reg),
2347 else => null,
2348 };
2349 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
2350
2351 const dest = try self.allocRegOrMem(inst, true);
2352 try self.setRegOrMem(self.air.typeOfIndex(inst), dest, operand);
2353 break :result dest;
2354 };
2342 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2355 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2343}2356}
23442357
src/arch/sparc64/CodeGen.zig+15-1
...@@ -1091,7 +1091,21 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void...@@ -1091,7 +1091,21 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void
10911091
1092fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {1092fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
1093 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1093 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1094 const result = try self.resolveInst(ty_op.operand);1094 const result = if (self.liveness.isUnused(inst)) .dead else result: {
1095 const operand = try self.resolveInst(ty_op.operand);
1096 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand;
1097
1098 const operand_lock = switch (operand) {
1099 .register => |reg| self.register_manager.lockReg(reg),
1100 .register_with_overflow => |rwo| self.register_manager.lockReg(rwo.reg),
1101 else => null,
1102 };
1103 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
1104
1105 const dest = try self.allocRegOrMem(inst, true);
1106 try self.setRegOrMem(self.air.typeOfIndex(inst), dest, operand);
1107 break :result dest;
1108 };
1095 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1109 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1096}1110}
10971111
src/arch/wasm/CodeGen.zig+4-4
...@@ -2896,7 +2896,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {...@@ -2896,7 +2896,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
2896 const struct_obj = ty.castTag(.@"struct").?.data;2896 const struct_obj = ty.castTag(.@"struct").?.data;
2897 assert(struct_obj.layout == .Packed);2897 assert(struct_obj.layout == .Packed);
2898 var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer2898 var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer
2899 val.writeToPackedMemory(ty, func.bin_file.base.options.module.?, &buf, 0);2899 val.writeToPackedMemory(ty, func.bin_file.base.options.module.?, &buf, 0) catch unreachable;
2900 var payload: Value.Payload.U64 = .{2900 var payload: Value.Payload.U64 = .{
2901 .base = .{ .tag = .int_u64 },2901 .base = .{ .tag = .int_u64 },
2902 .data = std.mem.readIntLittle(u64, &buf),2902 .data = std.mem.readIntLittle(u64, &buf),
...@@ -2907,7 +2907,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {...@@ -2907,7 +2907,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
2907 .Vector => {2907 .Vector => {
2908 assert(determineSimdStoreStrategy(ty, target) == .direct);2908 assert(determineSimdStoreStrategy(ty, target) == .direct);
2909 var buf: [16]u8 = undefined;2909 var buf: [16]u8 = undefined;
2910 val.writeToMemory(ty, func.bin_file.base.options.module.?, &buf);2910 val.writeToMemory(ty, func.bin_file.base.options.module.?, &buf) catch unreachable;
2911 return func.storeSimdImmd(buf);2911 return func.storeSimdImmd(buf);
2912 },2912 },
2913 else => |zig_type| return func.fail("Wasm TODO: LowerConstant for zigTypeTag {}", .{zig_type}),2913 else => |zig_type| return func.fail("Wasm TODO: LowerConstant for zigTypeTag {}", .{zig_type}),
...@@ -4944,8 +4944,8 @@ fn airFieldParentPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4944,8 +4944,8 @@ fn airFieldParentPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4944 if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{extra.field_ptr});4944 if (func.liveness.isUnused(inst)) return func.finishAir(inst, .none, &.{extra.field_ptr});
49454945
4946 const field_ptr = try func.resolveInst(extra.field_ptr);4946 const field_ptr = try func.resolveInst(extra.field_ptr);
4947 const struct_ty = func.air.getRefType(ty_pl.ty).childType();4947 const parent_ty = func.air.getRefType(ty_pl.ty).childType();
4948 const field_offset = struct_ty.structFieldOffset(extra.field_index, func.target);4948 const field_offset = parent_ty.structFieldOffset(extra.field_index, func.target);
49494949
4950 const result = if (field_offset != 0) result: {4950 const result = if (field_offset != 0) result: {
4951 const base = try func.buildPointerOffset(field_ptr, 0, .new);4951 const base = try func.buildPointerOffset(field_ptr, 0, .new);
src/arch/x86_64/CodeGen.zig+57-10
...@@ -920,9 +920,6 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -920,9 +920,6 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
920 const mod = self.bin_file.options.module.?;920 const mod = self.bin_file.options.module.?;
921 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)});921 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)});
922 };922 };
923 const abi_align = elem_ty.abiAlignment(self.target.*);
924 if (abi_align > self.stack_align)
925 self.stack_align = abi_align;
926923
927 if (reg_ok) {924 if (reg_ok) {
928 switch (elem_ty.zigTypeTag()) {925 switch (elem_ty.zigTypeTag()) {
...@@ -951,6 +948,10 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {...@@ -951,6 +948,10 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
951 },948 },
952 }949 }
953 }950 }
951
952 const abi_align = elem_ty.abiAlignment(self.target.*);
953 if (abi_align > self.stack_align)
954 self.stack_align = abi_align;
954 const stack_offset = try self.allocMem(inst, abi_size, abi_align);955 const stack_offset = try self.allocMem(inst, abi_size, abi_align);
955 return MCValue{ .stack_offset = @intCast(i32, stack_offset) };956 return MCValue{ .stack_offset = @intCast(i32, stack_offset) };
956}957}
...@@ -990,7 +991,7 @@ fn revertState(self: *Self, state: State) void {...@@ -990,7 +991,7 @@ fn revertState(self: *Self, state: State) void {
990991
991pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {992pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {
992 const stack_mcv = try self.allocRegOrMem(inst, false);993 const stack_mcv = try self.allocRegOrMem(inst, false);
993 log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv });994 log.debug("spilling %{d} to stack mcv {any}", .{ inst, stack_mcv });
994 const reg_mcv = self.getResolvedInstValue(inst);995 const reg_mcv = self.getResolvedInstValue(inst);
995 switch (reg_mcv) {996 switch (reg_mcv) {
996 .register => |other| {997 .register => |other| {
...@@ -1016,7 +1017,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void {...@@ -1016,7 +1017,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void {
1016 };1017 };
10171018
1018 try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv);1019 try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv);
1019 log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv });1020 log.debug("spilling %{d} to mcv {any}", .{ inst_to_save, new_mcv });
10201021
1021 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];1022 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
1022 try branch.inst_table.put(self.gpa, inst_to_save, new_mcv);1023 try branch.inst_table.put(self.gpa, inst_to_save, new_mcv);
...@@ -2114,6 +2115,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {...@@ -2114,6 +2115,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
2114 };2115 };
2115 break :result dst_mcv;2116 break :result dst_mcv;
2116 };2117 };
2118 log.debug("airSliceLen(%{d}): {}", .{ inst, result });
2117 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2119 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2118}2120}
21192121
...@@ -2641,6 +2643,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -2641,6 +2643,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
2641fn airLoad(self: *Self, inst: Air.Inst.Index) !void {2643fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
2642 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2644 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2643 const elem_ty = self.air.typeOfIndex(inst);2645 const elem_ty = self.air.typeOfIndex(inst);
2646 const elem_size = elem_ty.abiSize(self.target.*);
2644 const result: MCValue = result: {2647 const result: MCValue = result: {
2645 if (!elem_ty.hasRuntimeBitsIgnoreComptime())2648 if (!elem_ty.hasRuntimeBitsIgnoreComptime())
2646 break :result MCValue.none;2649 break :result MCValue.none;
...@@ -2651,13 +2654,14 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -2651,13 +2654,14 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
2651 break :result MCValue.dead;2654 break :result MCValue.dead;
26522655
2653 const dst_mcv: MCValue = blk: {2656 const dst_mcv: MCValue = blk: {
2654 if (self.reuseOperand(inst, ty_op.operand, 0, ptr)) {2657 if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr)) {
2655 // The MCValue that holds the pointer can be re-used as the value.2658 // The MCValue that holds the pointer can be re-used as the value.
2656 break :blk ptr;2659 break :blk ptr;
2657 } else {2660 } else {
2658 break :blk try self.allocRegOrMem(inst, true);2661 break :blk try self.allocRegOrMem(inst, true);
2659 }2662 }
2660 };2663 };
2664 log.debug("airLoad(%{d}): {} <- {}", .{ inst, dst_mcv, ptr });
2661 try self.load(dst_mcv, ptr, self.air.typeOf(ty_op.operand));2665 try self.load(dst_mcv, ptr, self.air.typeOf(ty_op.operand));
2662 break :result dst_mcv;2666 break :result dst_mcv;
2663 };2667 };
...@@ -2728,10 +2732,12 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2728,10 +2732,12 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
27282732
2729 switch (value) {2733 switch (value) {
2730 .none => unreachable,2734 .none => unreachable,
2731 .undef => unreachable,
2732 .dead => unreachable,2735 .dead => unreachable,
2733 .unreach => unreachable,2736 .unreach => unreachable,
2734 .eflags => unreachable,2737 .eflags => unreachable,
2738 .undef => {
2739 try self.genSetReg(value_ty, reg, value);
2740 },
2735 .immediate => |imm| {2741 .immediate => |imm| {
2736 switch (abi_size) {2742 switch (abi_size) {
2737 1, 2, 4 => {2743 1, 2, 4 => {
...@@ -2773,6 +2779,30 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2773,6 +2779,30 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2773 .register => |src_reg| {2779 .register => |src_reg| {
2774 try self.genInlineMemcpyRegisterRegister(value_ty, reg, src_reg, 0);2780 try self.genInlineMemcpyRegisterRegister(value_ty, reg, src_reg, 0);
2775 },2781 },
2782 .register_overflow => |ro| {
2783 const ro_reg_lock = self.register_manager.lockReg(ro.reg);
2784 defer if (ro_reg_lock) |lock| self.register_manager.unlockReg(lock);
2785
2786 const wrapped_ty = value_ty.structFieldType(0);
2787 try self.genInlineMemcpyRegisterRegister(wrapped_ty, reg, ro.reg, 0);
2788
2789 const overflow_bit_ty = value_ty.structFieldType(1);
2790 const overflow_bit_offset = value_ty.structFieldOffset(1, self.target.*);
2791 const tmp_reg = try self.register_manager.allocReg(null, gp);
2792 _ = try self.addInst(.{
2793 .tag = .cond_set_byte,
2794 .ops = Mir.Inst.Ops.encode(.{
2795 .reg1 = tmp_reg.to8(),
2796 }),
2797 .data = .{ .cc = ro.eflags },
2798 });
2799 try self.genInlineMemcpyRegisterRegister(
2800 overflow_bit_ty,
2801 reg,
2802 tmp_reg,
2803 -@intCast(i32, overflow_bit_offset),
2804 );
2805 },
2776 .linker_load,2806 .linker_load,
2777 .memory,2807 .memory,
2778 .stack_offset,2808 .stack_offset,
...@@ -2787,8 +2817,9 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2787,8 +2817,9 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2787 .dest_stack_base = reg.to64(),2817 .dest_stack_base = reg.to64(),
2788 });2818 });
2789 },2819 },
2790 else => |other| {2820 .ptr_stack_offset => {
2791 return self.fail("TODO implement set pointee with {}", .{other});2821 const tmp_reg = try self.copyToTmpRegister(value_ty, value);
2822 return self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
2792 },2823 },
2793 }2824 }
2794 },2825 },
...@@ -2902,6 +2933,7 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {...@@ -2902,6 +2933,7 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {
2902 const ptr_ty = self.air.typeOf(bin_op.lhs);2933 const ptr_ty = self.air.typeOf(bin_op.lhs);
2903 const value = try self.resolveInst(bin_op.rhs);2934 const value = try self.resolveInst(bin_op.rhs);
2904 const value_ty = self.air.typeOf(bin_op.rhs);2935 const value_ty = self.air.typeOf(bin_op.rhs);
2936 log.debug("airStore(%{d}): {} <- {}", .{ inst, ptr, value });
2905 try self.store(ptr, value, ptr_ty, value_ty);2937 try self.store(ptr, value, ptr_ty, value_ty);
2906 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });2938 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
2907}2939}
...@@ -6321,7 +6353,22 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {...@@ -6321,7 +6353,22 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {
63216353
6322fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {6354fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
6323 const ty_op = self.air.instructions.items(.data)[inst].ty_op;6355 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
6324 const result = try self.resolveInst(ty_op.operand);6356 const result = if (self.liveness.isUnused(inst)) .dead else result: {
6357 const operand = try self.resolveInst(ty_op.operand);
6358 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand;
6359
6360 const operand_lock = switch (operand) {
6361 .register => |reg| self.register_manager.lockReg(reg),
6362 .register_overflow => |ro| self.register_manager.lockReg(ro.reg),
6363 else => null,
6364 };
6365 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
6366
6367 const dest = try self.allocRegOrMem(inst, true);
6368 try self.setRegOrMem(self.air.typeOfIndex(inst), dest, operand);
6369 break :result dest;
6370 };
6371 log.debug("airBitCast(%{d}): {}", .{ inst, result });
6325 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });6372 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
6326}6373}
63276374
src/codegen.zig+1-1
...@@ -527,7 +527,7 @@ pub fn generateSymbol(...@@ -527,7 +527,7 @@ pub fn generateSymbol(
527 .fail => |em| return Result{ .fail = em },527 .fail => |em| return Result{ .fail = em },
528 }528 }
529 } else {529 } else {
530 field_val.writeToPackedMemory(field_ty, mod, code.items[current_pos..], bits);530 field_val.writeToPackedMemory(field_ty, mod, code.items[current_pos..], bits) catch unreachable;
531 }531 }
532 bits += @intCast(u16, field_ty.bitSize(target));532 bits += @intCast(u16, field_ty.bitSize(target));
533 }533 }
src/codegen/c.zig+1617-1689
...@@ -23,12 +23,14 @@ const libcFloatSuffix = target_util.libcFloatSuffix;...@@ -23,12 +23,14 @@ const libcFloatSuffix = target_util.libcFloatSuffix;
23const compilerRtFloatAbbrev = target_util.compilerRtFloatAbbrev;23const compilerRtFloatAbbrev = target_util.compilerRtFloatAbbrev;
24const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev;24const compilerRtIntAbbrev = target_util.compilerRtIntAbbrev;
2525
26const Mutability = enum { Const, ConstArgument, Mut };
27const BigIntLimb = std.math.big.Limb;26const BigIntLimb = std.math.big.Limb;
28const BigInt = std.math.big.int;27const BigInt = std.math.big.int;
2928
29pub const CType = @import("c/type.zig").CType;
30
30pub const CValue = union(enum) {31pub const CValue = union(enum) {
31 none: void,32 none: void,
33 new_local: LocalIndex,
32 local: LocalIndex,34 local: LocalIndex,
33 /// Address of a local.35 /// Address of a local.
34 local_ref: LocalIndex,36 local_ref: LocalIndex,
...@@ -36,6 +38,8 @@ pub const CValue = union(enum) {...@@ -36,6 +38,8 @@ pub const CValue = union(enum) {
36 constant: Air.Inst.Ref,38 constant: Air.Inst.Ref,
37 /// Index into the parameters39 /// Index into the parameters
38 arg: usize,40 arg: usize,
41 /// The array field of a parameter
42 arg_array: usize,
39 /// Index into a tuple's fields43 /// Index into a tuple's fields
40 field: usize,44 field: usize,
41 /// By-value45 /// By-value
...@@ -45,6 +49,8 @@ pub const CValue = union(enum) {...@@ -45,6 +49,8 @@ pub const CValue = union(enum) {
45 undef: Type,49 undef: Type,
46 /// Render the slice as an identifier (using fmtIdent)50 /// Render the slice as an identifier (using fmtIdent)
47 identifier: []const u8,51 identifier: []const u8,
52 /// Render the slice as an payload.identifier (using fmtIdent)
53 payload_identifier: []const u8,
48 /// Render these bytes literally.54 /// Render these bytes literally.
49 /// TODO make this a [*:0]const u8 to save memory55 /// TODO make this a [*:0]const u8 to save memory
50 bytes: []const u8,56 bytes: []const u8,
...@@ -55,37 +61,43 @@ const BlockData = struct {...@@ -55,37 +61,43 @@ const BlockData = struct {
55 result: CValue,61 result: CValue,
56};62};
5763
58const TypedefKind = enum {
59 Forward,
60 Complete,
61};
62
63pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue);64pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue);
64pub const TypedefMap = std.ArrayHashMap(65
65 Type,66pub const LazyFnKey = union(enum) {
66 struct { name: []const u8, rendered: []u8 },67 tag_name: Decl.Index,
67 Type.HashContext32,68 never_tail: Decl.Index,
68 true,69 never_inline: Decl.Index,
69);70};
71pub const LazyFnValue = struct {
72 fn_name: []const u8,
73 data: Data,
74
75 pub const Data = union {
76 tag_name: Type,
77 never_tail: void,
78 never_inline: void,
79 };
80};
81pub const LazyFnMap = std.AutoArrayHashMapUnmanaged(LazyFnKey, LazyFnValue);
7082
71const LoopDepth = u16;83const LoopDepth = u16;
72const Local = struct {84const Local = struct {
73 ty: Type,85 cty_idx: CType.Index,
74 alignment: u32,
75 /// How many loops the last definition was nested in.86 /// How many loops the last definition was nested in.
76 loop_depth: LoopDepth,87 loop_depth: LoopDepth,
88 alignas: CType.AlignAs,
89
90 pub fn getType(local: Local) LocalType {
91 return .{ .cty_idx = local.cty_idx, .alignas = local.alignas };
92 }
77};93};
7894
79const LocalIndex = u16;95const LocalIndex = u16;
80const LocalsList = std.ArrayListUnmanaged(LocalIndex);96const LocalType = struct { cty_idx: CType.Index, alignas: CType.AlignAs };
81const LocalsMap = std.ArrayHashMapUnmanaged(Type, LocalsList, Type.HashContext32, true);97const LocalsList = std.AutoArrayHashMapUnmanaged(LocalIndex, void);
98const LocalsMap = std.AutoArrayHashMapUnmanaged(LocalType, LocalsList);
82const LocalsStack = std.ArrayListUnmanaged(LocalsMap);99const LocalsStack = std.ArrayListUnmanaged(LocalsMap);
83100
84const FormatTypeAsCIdentContext = struct {
85 ty: Type,
86 mod: *Module,
87};
88
89const ValueRenderLocation = enum {101const ValueRenderLocation = enum {
90 FunctionArgument,102 FunctionArgument,
91 Initializer,103 Initializer,
...@@ -106,26 +118,6 @@ const BuiltinInfo = enum {...@@ -106,26 +118,6 @@ const BuiltinInfo = enum {
106 Bits,118 Bits,
107};119};
108120
109fn formatTypeAsCIdentifier(
110 data: FormatTypeAsCIdentContext,
111 comptime fmt: []const u8,
112 options: std.fmt.FormatOptions,
113 writer: anytype,
114) !void {
115 var stack = std.heap.stackFallback(128, data.mod.gpa);
116 const allocator = stack.get();
117 const str = std.fmt.allocPrint(allocator, "{}", .{data.ty.fmt(data.mod)}) catch "";
118 defer allocator.free(str);
119 return formatIdent(str, fmt, options, writer);
120}
121
122pub fn typeToCIdentifier(ty: Type, mod: *Module) std.fmt.Formatter(formatTypeAsCIdentifier) {
123 return .{ .data = .{
124 .ty = ty,
125 .mod = mod,
126 } };
127}
128
129const reserved_idents = std.ComptimeStringMap(void, .{121const reserved_idents = std.ComptimeStringMap(void, .{
130 // C language122 // C language
131 .{ "alignas", {123 .{ "alignas", {
...@@ -224,6 +216,15 @@ const reserved_idents = std.ComptimeStringMap(void, .{...@@ -224,6 +216,15 @@ const reserved_idents = std.ComptimeStringMap(void, .{
224 .{ "volatile", {} },216 .{ "volatile", {} },
225 .{ "while ", {} },217 .{ "while ", {} },
226218
219 // stdarg.h
220 .{ "va_start", {} },
221 .{ "va_arg", {} },
222 .{ "va_end", {} },
223 .{ "va_copy", {} },
224
225 // stddef.h
226 .{ "offsetof", {} },
227
227 // windows.h228 // windows.h
228 .{ "max", {} },229 .{ "max", {} },
229 .{ "min", {} },230 .{ "min", {} },
...@@ -281,6 +282,7 @@ pub const Function = struct {...@@ -281,6 +282,7 @@ pub const Function = struct {
281 next_arg_index: usize = 0,282 next_arg_index: usize = 0,
282 next_block_index: usize = 0,283 next_block_index: usize = 0,
283 object: Object,284 object: Object,
285 lazy_fns: LazyFnMap,
284 func: *Module.Fn,286 func: *Module.Fn,
285 /// All the locals, to be emitted at the top of the function.287 /// All the locals, to be emitted at the top of the function.
286 locals: std.ArrayListUnmanaged(Local) = .{},288 locals: std.ArrayListUnmanaged(Local) = .{},
...@@ -299,10 +301,6 @@ pub const Function = struct {...@@ -299,10 +301,6 @@ pub const Function = struct {
299 /// Needed for memory used by the keys of free_locals_stack entries.301 /// Needed for memory used by the keys of free_locals_stack entries.
300 arena: std.heap.ArenaAllocator,302 arena: std.heap.ArenaAllocator,
301303
302 fn tyHashCtx(f: Function) Type.HashContext32 {
303 return .{ .mod = f.object.dg.module };
304 }
305
306 fn resolveInst(f: *Function, inst: Air.Inst.Ref) !CValue {304 fn resolveInst(f: *Function, inst: Air.Inst.Ref) !CValue {
307 const gop = try f.value_map.getOrPut(inst);305 const gop = try f.value_map.getOrPut(inst);
308 if (gop.found_existing) return gop.value_ptr.*;306 if (gop.found_existing) return gop.value_ptr.*;
...@@ -310,19 +308,19 @@ pub const Function = struct {...@@ -310,19 +308,19 @@ pub const Function = struct {
310 const val = f.air.value(inst).?;308 const val = f.air.value(inst).?;
311 const ty = f.air.typeOf(inst);309 const ty = f.air.typeOf(inst);
312310
313 const result = if (lowersToArray(ty, f.object.dg.module.getTarget())) result: {311 const result: CValue = if (lowersToArray(ty, f.object.dg.module.getTarget())) result: {
314 const writer = f.object.code_header.writer();312 const writer = f.object.code_header.writer();
315 const alignment = 0;313 const alignment = 0;
316 const decl_c_value = try f.allocLocalValue(ty, alignment);314 const decl_c_value = try f.allocLocalValue(ty, alignment);
317 const gpa = f.object.dg.gpa;315 const gpa = f.object.dg.gpa;
318 try f.allocs.put(gpa, decl_c_value.local, true);316 try f.allocs.put(gpa, decl_c_value.new_local, true);
319 try writer.writeAll("static ");317 try writer.writeAll("static ");
320 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, alignment, .Complete);318 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, alignment, .complete);
321 try writer.writeAll(" = ");319 try writer.writeAll(" = ");
322 try f.object.dg.renderValue(writer, ty, val, .StaticInitializer);320 try f.object.dg.renderValue(writer, ty, val, .StaticInitializer);
323 try writer.writeAll(";\n ");321 try writer.writeAll(";\n ");
324 break :result decl_c_value;322 break :result decl_c_value;
325 } else CValue{ .constant = inst };323 } else .{ .constant = inst };
326324
327 gop.value_ptr.* = result;325 gop.value_ptr.* = result;
328 return result;326 return result;
...@@ -342,32 +340,32 @@ pub const Function = struct {...@@ -342,32 +340,32 @@ pub const Function = struct {
342 /// Skips the reuse logic.340 /// Skips the reuse logic.
343 fn allocLocalValue(f: *Function, ty: Type, alignment: u32) !CValue {341 fn allocLocalValue(f: *Function, ty: Type, alignment: u32) !CValue {
344 const gpa = f.object.dg.gpa;342 const gpa = f.object.dg.gpa;
343 const target = f.object.dg.module.getTarget();
345 try f.locals.append(gpa, .{344 try f.locals.append(gpa, .{
346 .ty = ty,345 .cty_idx = try f.typeToIndex(ty, .complete),
347 .alignment = alignment,
348 .loop_depth = @intCast(LoopDepth, f.free_locals_stack.items.len - 1),346 .loop_depth = @intCast(LoopDepth, f.free_locals_stack.items.len - 1),
347 .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(target)),
349 });348 });
350 return CValue{ .local = @intCast(LocalIndex, f.locals.items.len - 1) };349 return .{ .new_local = @intCast(LocalIndex, f.locals.items.len - 1) };
351 }350 }
352351
353 fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue {352 fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue {
354 const result = try f.allocAlignedLocal(ty, .Mut, 0);353 const result = try f.allocAlignedLocal(ty, .{}, 0);
355 log.debug("%{d}: allocating t{d}", .{ inst, result.local });354 log.debug("%{d}: allocating t{d}", .{ inst, result.new_local });
356 return result;355 return result;
357 }356 }
358357
359 /// Only allocates the local; does not print anything.358 /// Only allocates the local; does not print anything.
360 fn allocAlignedLocal(f: *Function, ty: Type, mutability: Mutability, alignment: u32) !CValue {359 fn allocAlignedLocal(f: *Function, ty: Type, _: CQualifiers, alignment: u32) !CValue {
361 _ = mutability;360 const target = f.object.dg.module.getTarget();
362361 if (f.getFreeLocals().getPtr(.{
363 if (f.getFreeLocals().getPtrContext(ty, f.tyHashCtx())) |locals_list| {362 .cty_idx = try f.typeToIndex(ty, .complete),
364 for (locals_list.items, 0..) |local_index, i| {363 .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(target)),
365 const local = &f.locals.items[local_index];364 })) |locals_list| {
366 if (local.alignment >= alignment) {365 if (locals_list.popOrNull()) |local_entry| {
367 local.loop_depth = @intCast(LoopDepth, f.free_locals_stack.items.len - 1);366 const local = &f.locals.items[local_entry.key];
368 _ = locals_list.swapRemove(i);367 local.loop_depth = @intCast(LoopDepth, f.free_locals_stack.items.len - 1);
369 return CValue{ .local = local_index };368 return .{ .new_local = local_entry.key };
370 }
371 }369 }
372 }370 }
373371
...@@ -430,12 +428,20 @@ pub const Function = struct {...@@ -430,12 +428,20 @@ pub const Function = struct {
430 return f.object.dg.fail(format, args);428 return f.object.dg.fail(format, args);
431 }429 }
432430
433 fn renderType(f: *Function, w: anytype, t: Type) !void {431 fn indexToCType(f: *Function, idx: CType.Index) CType {
434 return f.object.dg.renderType(w, t, .Complete);432 return f.object.dg.indexToCType(idx);
435 }433 }
436434
437 fn renderTypecast(f: *Function, w: anytype, t: Type) !void {435 fn typeToIndex(f: *Function, ty: Type, kind: CType.Kind) !CType.Index {
438 return f.object.dg.renderTypecast(w, t);436 return f.object.dg.typeToIndex(ty, kind);
437 }
438
439 fn typeToCType(f: *Function, ty: Type, kind: CType.Kind) !CType {
440 return f.object.dg.typeToCType(ty, kind);
441 }
442
443 fn renderType(f: *Function, w: anytype, t: Type) !void {
444 return f.object.dg.renderType(w, t);
439 }445 }
440446
441 fn renderIntCast(f: *Function, w: anytype, dest_ty: Type, src: CValue, src_ty: Type, location: ValueRenderLocation) !void {447 fn renderIntCast(f: *Function, w: anytype, dest_ty: Type, src: CValue, src_ty: Type, location: ValueRenderLocation) !void {
...@@ -446,7 +452,39 @@ pub const Function = struct {...@@ -446,7 +452,39 @@ pub const Function = struct {
446 return f.object.dg.fmtIntLiteral(ty, val);452 return f.object.dg.fmtIntLiteral(ty, val);
447 }453 }
448454
449 pub fn deinit(f: *Function, gpa: mem.Allocator) void {455 fn getLazyFnName(f: *Function, key: LazyFnKey, data: LazyFnValue.Data) ![]const u8 {
456 const gpa = f.object.dg.gpa;
457 const gop = try f.lazy_fns.getOrPut(gpa, key);
458 if (!gop.found_existing) {
459 errdefer _ = f.lazy_fns.pop();
460
461 var promoted = f.object.dg.ctypes.promote(gpa);
462 defer f.object.dg.ctypes.demote(promoted);
463 const arena = promoted.arena.allocator();
464
465 gop.value_ptr.* = .{
466 .fn_name = switch (key) {
467 .tag_name,
468 .never_tail,
469 .never_inline,
470 => |owner_decl| try std.fmt.allocPrint(arena, "zig_{s}_{}__{d}", .{
471 @tagName(key),
472 fmtIdent(mem.span(f.object.dg.module.declPtr(owner_decl).name)),
473 @enumToInt(owner_decl),
474 }),
475 },
476 .data = switch (key) {
477 .tag_name => .{ .tag_name = try data.tag_name.copy(arena) },
478 .never_tail => .{ .never_tail = data.never_tail },
479 .never_inline => .{ .never_inline = data.never_inline },
480 },
481 };
482 }
483 return gop.value_ptr.fn_name;
484 }
485
486 pub fn deinit(f: *Function) void {
487 const gpa = f.object.dg.gpa;
450 f.allocs.deinit(gpa);488 f.allocs.deinit(gpa);
451 f.locals.deinit(gpa);489 f.locals.deinit(gpa);
452 for (f.free_locals_stack.items) |*free_locals| {490 for (f.free_locals_stack.items) |*free_locals| {
...@@ -455,11 +493,9 @@ pub const Function = struct {...@@ -455,11 +493,9 @@ pub const Function = struct {
455 f.free_locals_stack.deinit(gpa);493 f.free_locals_stack.deinit(gpa);
456 f.blocks.deinit(gpa);494 f.blocks.deinit(gpa);
457 f.value_map.deinit();495 f.value_map.deinit();
496 f.lazy_fns.deinit(gpa);
458 f.object.code.deinit();497 f.object.code.deinit();
459 for (f.object.dg.typedefs.values()) |typedef| {498 f.object.dg.ctypes.deinit(gpa);
460 gpa.free(typedef.rendered);
461 }
462 f.object.dg.typedefs.deinit();
463 f.object.dg.fwd_decl.deinit();499 f.object.dg.fwd_decl.deinit();
464 f.arena.deinit();500 f.arena.deinit();
465 }501 }
...@@ -483,30 +519,20 @@ pub const Object = struct {...@@ -483,30 +519,20 @@ pub const Object = struct {
483pub const DeclGen = struct {519pub const DeclGen = struct {
484 gpa: std.mem.Allocator,520 gpa: std.mem.Allocator,
485 module: *Module,521 module: *Module,
486 decl: *Decl,522 decl: ?*Decl,
487 decl_index: Decl.Index,523 decl_index: Decl.OptionalIndex,
488 fwd_decl: std.ArrayList(u8),524 fwd_decl: std.ArrayList(u8),
489 error_msg: ?*Module.ErrorMsg,525 error_msg: ?*Module.ErrorMsg,
490 /// The key of this map is Type which has references to typedefs_arena.526 ctypes: CType.Store,
491 typedefs: TypedefMap,
492 typedefs_arena: std.mem.Allocator,
493527
494 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {528 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
495 @setCold(true);529 @setCold(true);
496 const src = LazySrcLoc.nodeOffset(0);530 const src = LazySrcLoc.nodeOffset(0);
497 const src_loc = src.toSrcLoc(dg.decl);531 const src_loc = src.toSrcLoc(dg.decl.?);
498 dg.error_msg = try Module.ErrorMsg.create(dg.gpa, src_loc, format, args);532 dg.error_msg = try Module.ErrorMsg.create(dg.gpa, src_loc, format, args);
499 return error.AnalysisFail;533 return error.AnalysisFail;
500 }534 }
501535
502 fn getTypedefName(dg: *DeclGen, t: Type) ?[]const u8 {
503 if (dg.typedefs.get(t)) |typedef| {
504 return typedef.name;
505 } else {
506 return null;
507 }
508 }
509
510 fn renderDeclValue(536 fn renderDeclValue(
511 dg: *DeclGen,537 dg: *DeclGen,
512 writer: anytype,538 writer: anytype,
...@@ -520,7 +546,7 @@ pub const DeclGen = struct {...@@ -520,7 +546,7 @@ pub const DeclGen = struct {
520546
521 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.547 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
522 if (ty.isPtrAtRuntime() and !decl.ty.isFnOrHasRuntimeBits()) {548 if (ty.isPtrAtRuntime() and !decl.ty.isFnOrHasRuntimeBits()) {
523 return dg.writeCValue(writer, CValue{ .undef = ty });549 return dg.writeCValue(writer, .{ .undef = ty });
524 }550 }
525551
526 // Chase function values in order to be able to reference the original function.552 // Chase function values in order to be able to reference the original function.
...@@ -534,7 +560,7 @@ pub const DeclGen = struct {...@@ -534,7 +560,7 @@ pub const DeclGen = struct {
534 try writer.writeByte('{');560 try writer.writeByte('{');
535 } else {561 } else {
536 try writer.writeByte('(');562 try writer.writeByte('(');
537 try dg.renderTypecast(writer, ty);563 try dg.renderType(writer, ty);
538 try writer.writeAll("){ .ptr = ");564 try writer.writeAll("){ .ptr = ");
539 }565 }
540566
...@@ -561,7 +587,7 @@ pub const DeclGen = struct {...@@ -561,7 +587,7 @@ pub const DeclGen = struct {
561 const need_typecast = if (ty.castPtrToFn()) |_| false else !ty.eql(decl.ty, dg.module);587 const need_typecast = if (ty.castPtrToFn()) |_| false else !ty.eql(decl.ty, dg.module);
562 if (need_typecast) {588 if (need_typecast) {
563 try writer.writeAll("((");589 try writer.writeAll("((");
564 try dg.renderTypecast(writer, ty);590 try dg.renderType(writer, ty);
565 try writer.writeByte(')');591 try writer.writeByte(')');
566 }592 }
567 try writer.writeByte('&');593 try writer.writeByte('&');
...@@ -576,7 +602,7 @@ pub const DeclGen = struct {...@@ -576,7 +602,7 @@ pub const DeclGen = struct {
576 fn renderParentPtr(dg: *DeclGen, writer: anytype, ptr_val: Value, ptr_ty: Type, location: ValueRenderLocation) error{ OutOfMemory, AnalysisFail }!void {602 fn renderParentPtr(dg: *DeclGen, writer: anytype, ptr_val: Value, ptr_ty: Type, location: ValueRenderLocation) error{ OutOfMemory, AnalysisFail }!void {
577 if (!ptr_ty.isSlice()) {603 if (!ptr_ty.isSlice()) {
578 try writer.writeByte('(');604 try writer.writeByte('(');
579 try dg.renderTypecast(writer, ptr_ty);605 try dg.renderType(writer, ptr_ty);
580 try writer.writeByte(')');606 try writer.writeByte(')');
581 }607 }
582 switch (ptr_val.tag()) {608 switch (ptr_val.tag()) {
...@@ -591,90 +617,71 @@ pub const DeclGen = struct {...@@ -591,90 +617,71 @@ pub const DeclGen = struct {
591 try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index, location);617 try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index, location);
592 },618 },
593 .field_ptr => {619 .field_ptr => {
594 const ptr_info = ptr_ty.ptrInfo();620 const target = dg.module.getTarget();
595 const field_ptr = ptr_val.castTag(.field_ptr).?.data;621 const field_ptr = ptr_val.castTag(.field_ptr).?.data;
596 const container_ty = field_ptr.container_ty;
597 const index = field_ptr.field_index;
598
599 var container_ptr_ty_pl: Type.Payload.ElemType = .{
600 .base = .{ .tag = .c_mut_pointer },
601 .data = field_ptr.container_ty,
602 };
603 const container_ptr_ty = Type.initPayload(&container_ptr_ty_pl.base);
604
605 const FieldInfo = struct { name: []const u8, ty: Type };
606 const field_info: FieldInfo = switch (container_ty.zigTypeTag()) {
607 .Struct => switch (container_ty.containerLayout()) {
608 .Auto, .Extern => FieldInfo{
609 .name = container_ty.structFields().keys()[index],
610 .ty = container_ty.structFields().values()[index].ty,
611 },
612 .Packed => if (ptr_info.data.host_size == 0) {
613 const target = dg.module.getTarget();
614
615 const byte_offset = container_ty.packedStructFieldByteOffset(index, target);
616 var byte_offset_pl = Value.Payload.U64{
617 .base = .{ .tag = .int_u64 },
618 .data = byte_offset,
619 };
620 const byte_offset_val = Value.initPayload(&byte_offset_pl.base);
621
622 var u8_ptr_pl = ptr_info;
623 u8_ptr_pl.data.pointee_type = Type.u8;
624 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
625
626 try writer.writeAll("&((");
627 try dg.renderTypecast(writer, u8_ptr_ty);
628 try writer.writeByte(')');
629 try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location);
630 return writer.print(")[{}]", .{try dg.fmtIntLiteral(Type.usize, byte_offset_val)});
631 } else {
632 var host_pl = Type.Payload.Bits{
633 .base = .{ .tag = .int_unsigned },
634 .data = ptr_info.data.host_size * 8,
635 };
636 const host_ty = Type.initPayload(&host_pl.base);
637622
638 try writer.writeByte('(');623 // Ensure complete type definition is visible before accessing fields.
639 try dg.renderTypecast(writer, ptr_ty);624 _ = try dg.typeToIndex(field_ptr.container_ty, .complete);
640 try writer.writeByte(')');625
641 return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty, location);626 var container_ptr_pl = ptr_ty.ptrInfo();
642 },627 container_ptr_pl.data.pointee_type = field_ptr.container_ty;
643 },628 const container_ptr_ty = Type.initPayload(&container_ptr_pl.base);
644 .Union => switch (container_ty.containerLayout()) {629
645 .Auto, .Extern => FieldInfo{630 switch (fieldLocation(
646 .name = container_ty.unionFields().keys()[index],631 field_ptr.container_ty,
647 .ty = container_ty.unionFields().values()[index].ty,632 ptr_ty,
648 },633 @intCast(u32, field_ptr.field_index),
649 .Packed => {634 target,
650 return dg.renderParentPtr(writer, field_ptr.container_ptr, ptr_ty, location);635 )) {
651 },636 .begin => try dg.renderParentPtr(
637 writer,
638 field_ptr.container_ptr,
639 container_ptr_ty,
640 location,
641 ),
642 .field => |field| {
643 try writer.writeAll("&(");
644 try dg.renderParentPtr(
645 writer,
646 field_ptr.container_ptr,
647 container_ptr_ty,
648 location,
649 );
650 try writer.writeAll(")->");
651 try dg.writeCValue(writer, field);
652 },652 },
653 .Pointer => field_info: {653 .byte_offset => |byte_offset| {
654 assert(container_ty.isSlice());654 var u8_ptr_pl = ptr_ty.ptrInfo();
655 break :field_info switch (index) {655 u8_ptr_pl.data.pointee_type = Type.u8;
656 0 => FieldInfo{ .name = "ptr", .ty = container_ty.childType() },656 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
657 1 => FieldInfo{ .name = "len", .ty = Type.usize },657
658 else => unreachable,658 var byte_offset_pl = Value.Payload.U64{
659 .base = .{ .tag = .int_u64 },
660 .data = byte_offset,
659 };661 };
660 },662 const byte_offset_val = Value.initPayload(&byte_offset_pl.base);
661 else => unreachable,
662 };
663663
664 if (field_info.ty.hasRuntimeBitsIgnoreComptime()) {664 try writer.writeAll("((");
665 // Ensure complete type definition is visible before accessing fields.665 try dg.renderType(writer, u8_ptr_ty);
666 try dg.renderType(std.io.null_writer, field_ptr.container_ty, .Complete);666 try writer.writeByte(')');
667667 try dg.renderParentPtr(
668 try writer.writeAll("&(");668 writer,
669 try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location);669 field_ptr.container_ptr,
670 try writer.writeAll(")->");670 container_ptr_ty,
671 switch (field_ptr.container_ty.tag()) {671 location,
672 .union_tagged, .union_safety_tagged => try writer.writeAll("payload."),672 );
673 else => {},673 try writer.print(" + {})", .{try dg.fmtIntLiteral(Type.usize, byte_offset_val)});
674 }674 },
675 try writer.print("{ }", .{fmtIdent(field_info.name)});675 .end => {
676 } else {676 try writer.writeAll("((");
677 try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty, location);677 try dg.renderParentPtr(
678 writer,
679 field_ptr.container_ptr,
680 container_ptr_ty,
681 location,
682 );
683 try writer.print(") + {})", .{try dg.fmtIntLiteral(Type.usize, Value.one)});
684 },
678 }685 }
679 },686 },
680 .elem_ptr => {687 .elem_ptr => {
...@@ -698,7 +705,7 @@ pub const DeclGen = struct {...@@ -698,7 +705,7 @@ pub const DeclGen = struct {
698 const container_ptr_ty = Type.initPayload(&container_ptr_ty_pl.base);705 const container_ptr_ty = Type.initPayload(&container_ptr_ty_pl.base);
699706
700 // Ensure complete type definition is visible before accessing fields.707 // Ensure complete type definition is visible before accessing fields.
701 try dg.renderType(std.io.null_writer, payload_ptr.container_ty, .Complete);708 _ = try dg.typeToIndex(payload_ptr.container_ty, .complete);
702709
703 try writer.writeAll("&(");710 try writer.writeAll("&(");
704 try dg.renderParentPtr(writer, payload_ptr.container_ptr, container_ptr_ty, location);711 try dg.renderParentPtr(writer, payload_ptr.container_ptr, container_ptr_ty, location);
...@@ -747,7 +754,7 @@ pub const DeclGen = struct {...@@ -747,7 +754,7 @@ pub const DeclGen = struct {
747754
748 try writer.writeAll("zig_cast_");755 try writer.writeAll("zig_cast_");
749 try dg.renderTypeForBuiltinFnName(writer, ty);756 try dg.renderTypeForBuiltinFnName(writer, ty);
750 try writer.writeAll(" zig_as_");757 try writer.writeAll(" zig_make_");
751 try dg.renderTypeForBuiltinFnName(writer, ty);758 try dg.renderTypeForBuiltinFnName(writer, ty);
752 try writer.writeByte('(');759 try writer.writeByte('(');
753 switch (bits) {760 switch (bits) {
...@@ -765,18 +772,18 @@ pub const DeclGen = struct {...@@ -765,18 +772,18 @@ pub const DeclGen = struct {
765 .Pointer => if (ty.isSlice()) {772 .Pointer => if (ty.isSlice()) {
766 if (!location.isInitializer()) {773 if (!location.isInitializer()) {
767 try writer.writeByte('(');774 try writer.writeByte('(');
768 try dg.renderTypecast(writer, ty);775 try dg.renderType(writer, ty);
769 try writer.writeByte(')');776 try writer.writeByte(')');
770 }777 }
771778
772 try writer.writeAll("{(");779 try writer.writeAll("{(");
773 var buf: Type.SlicePtrFieldTypeBuffer = undefined;780 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
774 const ptr_ty = ty.slicePtrFieldType(&buf);781 const ptr_ty = ty.slicePtrFieldType(&buf);
775 try dg.renderTypecast(writer, ptr_ty);782 try dg.renderType(writer, ptr_ty);
776 return writer.print("){x}, {0x}}}", .{try dg.fmtIntLiteral(Type.usize, val)});783 return writer.print("){x}, {0x}}}", .{try dg.fmtIntLiteral(Type.usize, val)});
777 } else {784 } else {
778 try writer.writeAll("((");785 try writer.writeAll("((");
779 try dg.renderTypecast(writer, ty);786 try dg.renderType(writer, ty);
780 return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val)});787 return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val)});
781 },788 },
782 .Optional => {789 .Optional => {
...@@ -793,7 +800,7 @@ pub const DeclGen = struct {...@@ -793,7 +800,7 @@ pub const DeclGen = struct {
793800
794 if (!location.isInitializer()) {801 if (!location.isInitializer()) {
795 try writer.writeByte('(');802 try writer.writeByte('(');
796 try dg.renderTypecast(writer, ty);803 try dg.renderType(writer, ty);
797 try writer.writeByte(')');804 try writer.writeByte(')');
798 }805 }
799806
...@@ -807,7 +814,7 @@ pub const DeclGen = struct {...@@ -807,7 +814,7 @@ pub const DeclGen = struct {
807 .Auto, .Extern => {814 .Auto, .Extern => {
808 if (!location.isInitializer()) {815 if (!location.isInitializer()) {
809 try writer.writeByte('(');816 try writer.writeByte('(');
810 try dg.renderTypecast(writer, ty);817 try dg.renderType(writer, ty);
811 try writer.writeByte(')');818 try writer.writeByte(')');
812 }819 }
813820
...@@ -821,7 +828,7 @@ pub const DeclGen = struct {...@@ -821,7 +828,7 @@ pub const DeclGen = struct {
821828
822 empty = false;829 empty = false;
823 }830 }
824 if (empty) try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)});831
825 return writer.writeByte('}');832 return writer.writeByte('}');
826 },833 },
827 .Packed => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, Value.undef)}),834 .Packed => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, Value.undef)}),
...@@ -829,7 +836,7 @@ pub const DeclGen = struct {...@@ -829,7 +836,7 @@ pub const DeclGen = struct {
829 .Union => {836 .Union => {
830 if (!location.isInitializer()) {837 if (!location.isInitializer()) {
831 try writer.writeByte('(');838 try writer.writeByte('(');
832 try dg.renderTypecast(writer, ty);839 try dg.renderType(writer, ty);
833 try writer.writeByte(')');840 try writer.writeByte(')');
834 }841 }
835842
...@@ -854,7 +861,7 @@ pub const DeclGen = struct {...@@ -854,7 +861,7 @@ pub const DeclGen = struct {
854 .ErrorUnion => {861 .ErrorUnion => {
855 if (!location.isInitializer()) {862 if (!location.isInitializer()) {
856 try writer.writeByte('(');863 try writer.writeByte('(');
857 try dg.renderTypecast(writer, ty);864 try dg.renderType(writer, ty);
858 try writer.writeByte(')');865 try writer.writeByte(')');
859 }866 }
860867
...@@ -867,7 +874,7 @@ pub const DeclGen = struct {...@@ -867,7 +874,7 @@ pub const DeclGen = struct {
867 .Array, .Vector => {874 .Array, .Vector => {
868 if (!location.isInitializer()) {875 if (!location.isInitializer()) {
869 try writer.writeByte('(');876 try writer.writeByte('(');
870 try dg.renderTypecast(writer, ty);877 try dg.renderType(writer, ty);
871 try writer.writeByte(')');878 try writer.writeByte(')');
872 }879 }
873880
...@@ -876,14 +883,14 @@ pub const DeclGen = struct {...@@ -876,14 +883,14 @@ pub const DeclGen = struct {
876 var literal = stringLiteral(writer);883 var literal = stringLiteral(writer);
877 try literal.start();884 try literal.start();
878 const c_len = ty.arrayLenIncludingSentinel();885 const c_len = ty.arrayLenIncludingSentinel();
879 var index: usize = 0;886 var index: u64 = 0;
880 while (index < c_len) : (index += 1)887 while (index < c_len) : (index += 1)
881 try literal.writeChar(0xaa);888 try literal.writeChar(0xaa);
882 return literal.end();889 return literal.end();
883 } else {890 } else {
884 try writer.writeByte('{');891 try writer.writeByte('{');
885 const c_len = ty.arrayLenIncludingSentinel();892 const c_len = ty.arrayLenIncludingSentinel();
886 var index: usize = 0;893 var index: u64 = 0;
887 while (index < c_len) : (index += 1) {894 while (index < c_len) : (index += 1) {
888 if (index > 0) try writer.writeAll(", ");895 if (index > 0) try writer.writeAll(", ");
889 try dg.renderValue(writer, ty.childType(), val, initializer_type);896 try dg.renderValue(writer, ty.childType(), val, initializer_type);
...@@ -957,7 +964,7 @@ pub const DeclGen = struct {...@@ -957,7 +964,7 @@ pub const DeclGen = struct {
957 try writer.writeByte(' ');964 try writer.writeByte(' ');
958 var empty = true;965 var empty = true;
959 if (std.math.isFinite(f128_val)) {966 if (std.math.isFinite(f128_val)) {
960 try writer.writeAll("zig_as_");967 try writer.writeAll("zig_make_");
961 try dg.renderTypeForBuiltinFnName(writer, ty);968 try dg.renderTypeForBuiltinFnName(writer, ty);
962 try writer.writeByte('(');969 try writer.writeByte('(');
963 switch (bits) {970 switch (bits) {
...@@ -992,7 +999,7 @@ pub const DeclGen = struct {...@@ -992,7 +999,7 @@ pub const DeclGen = struct {
992 // return dg.fail("Only quiet nans are supported in global variable initializers", .{});999 // return dg.fail("Only quiet nans are supported in global variable initializers", .{});
993 }1000 }
9941001
995 try writer.writeAll("zig_as_special_");1002 try writer.writeAll("zig_make_special_");
996 if (location == .StaticInitializer) try writer.writeAll("constant_");1003 if (location == .StaticInitializer) try writer.writeAll("constant_");
997 try dg.renderTypeForBuiltinFnName(writer, ty);1004 try dg.renderTypeForBuiltinFnName(writer, ty);
998 try writer.writeByte('(');1005 try writer.writeByte('(');
...@@ -1028,7 +1035,7 @@ pub const DeclGen = struct {...@@ -1028,7 +1035,7 @@ pub const DeclGen = struct {
1028 return dg.renderValue(writer, ty, slice_val, location);1035 return dg.renderValue(writer, ty, slice_val, location);
1029 } else {1036 } else {
1030 try writer.writeAll("((");1037 try writer.writeAll("((");
1031 try dg.renderTypecast(writer, ty);1038 try dg.renderType(writer, ty);
1032 try writer.writeAll(")NULL)");1039 try writer.writeAll(")NULL)");
1033 },1040 },
1034 .variable => {1041 .variable => {
...@@ -1038,7 +1045,7 @@ pub const DeclGen = struct {...@@ -1038,7 +1045,7 @@ pub const DeclGen = struct {
1038 .slice => {1045 .slice => {
1039 if (!location.isInitializer()) {1046 if (!location.isInitializer()) {
1040 try writer.writeByte('(');1047 try writer.writeByte('(');
1041 try dg.renderTypecast(writer, ty);1048 try dg.renderType(writer, ty);
1042 try writer.writeByte(')');1049 try writer.writeByte(')');
1043 }1050 }
10441051
...@@ -1061,7 +1068,7 @@ pub const DeclGen = struct {...@@ -1061,7 +1068,7 @@ pub const DeclGen = struct {
1061 },1068 },
1062 .int_u64, .one => {1069 .int_u64, .one => {
1063 try writer.writeAll("((");1070 try writer.writeAll("((");
1064 try dg.renderTypecast(writer, ty);1071 try dg.renderType(writer, ty);
1065 return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val)});1072 return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val)});
1066 },1073 },
1067 .field_ptr,1074 .field_ptr,
...@@ -1076,15 +1083,15 @@ pub const DeclGen = struct {...@@ -1076,15 +1083,15 @@ pub const DeclGen = struct {
1076 .Array, .Vector => {1083 .Array, .Vector => {
1077 if (location == .FunctionArgument) {1084 if (location == .FunctionArgument) {
1078 try writer.writeByte('(');1085 try writer.writeByte('(');
1079 try dg.renderTypecast(writer, ty);1086 try dg.renderType(writer, ty);
1080 try writer.writeByte(')');1087 try writer.writeByte(')');
1081 }1088 }
10821089
1083 // First try specific tag representations for more efficiency.1090 // First try specific tag representations for more efficiency.
1084 switch (val.tag()) {1091 switch (val.tag()) {
1085 .undef, .empty_struct_value, .empty_array => {1092 .undef, .empty_struct_value, .empty_array => {
1086 try writer.writeByte('{');
1087 const ai = ty.arrayInfo();1093 const ai = ty.arrayInfo();
1094 try writer.writeByte('{');
1088 if (ai.sentinel) |s| {1095 if (ai.sentinel) |s| {
1089 try dg.renderValue(writer, ai.elem_type, s, initializer_type);1096 try dg.renderValue(writer, ai.elem_type, s, initializer_type);
1090 } else {1097 } else {
...@@ -1092,13 +1099,19 @@ pub const DeclGen = struct {...@@ -1092,13 +1099,19 @@ pub const DeclGen = struct {
1092 }1099 }
1093 try writer.writeByte('}');1100 try writer.writeByte('}');
1094 },1101 },
1095 .bytes => {1102 .bytes, .str_lit => |t| {
1096 try writer.print("{s}", .{fmtStringLiteral(val.castTag(.bytes).?.data)});1103 const bytes = switch (t) {
1097 },1104 .bytes => val.castTag(.bytes).?.data,
1098 .str_lit => {1105 .str_lit => bytes: {
1099 const str_lit = val.castTag(.str_lit).?.data;1106 const str_lit = val.castTag(.str_lit).?.data;
1100 const bytes = dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len];1107 break :bytes dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
1101 try writer.print("{s}", .{fmtStringLiteral(bytes)});1108 },
1109 else => unreachable,
1110 };
1111 const sentinel = if (ty.sentinel()) |sentinel| @intCast(u8, sentinel.toUnsignedInt(target)) else null;
1112 try writer.print("{s}", .{
1113 fmtStringLiteral(bytes[0..@intCast(usize, ty.arrayLen())], sentinel),
1114 });
1102 },1115 },
1103 else => {1116 else => {
1104 // Fall back to generic implementation.1117 // Fall back to generic implementation.
...@@ -1122,7 +1135,7 @@ pub const DeclGen = struct {...@@ -1122,7 +1135,7 @@ pub const DeclGen = struct {
1122 }1135 }
1123 if (ai.sentinel) |s| {1136 if (ai.sentinel) |s| {
1124 const s_u8 = @intCast(u8, s.toUnsignedInt(target));1137 const s_u8 = @intCast(u8, s.toUnsignedInt(target));
1125 try literal.writeChar(s_u8);1138 if (s_u8 != 0) try literal.writeChar(s_u8);
1126 }1139 }
1127 try literal.end();1140 try literal.end();
1128 } else {1141 } else {
...@@ -1179,7 +1192,7 @@ pub const DeclGen = struct {...@@ -1179,7 +1192,7 @@ pub const DeclGen = struct {
11791192
1180 if (!location.isInitializer()) {1193 if (!location.isInitializer()) {
1181 try writer.writeByte('(');1194 try writer.writeByte('(');
1182 try dg.renderTypecast(writer, ty);1195 try dg.renderType(writer, ty);
1183 try writer.writeByte(')');1196 try writer.writeByte(')');
1184 }1197 }
11851198
...@@ -1213,7 +1226,7 @@ pub const DeclGen = struct {...@@ -1213,7 +1226,7 @@ pub const DeclGen = struct {
12131226
1214 if (!location.isInitializer()) {1227 if (!location.isInitializer()) {
1215 try writer.writeByte('(');1228 try writer.writeByte('(');
1216 try dg.renderTypecast(writer, ty);1229 try dg.renderType(writer, ty);
1217 try writer.writeByte(')');1230 try writer.writeByte(')');
1218 }1231 }
12191232
...@@ -1277,7 +1290,7 @@ pub const DeclGen = struct {...@@ -1277,7 +1290,7 @@ pub const DeclGen = struct {
12771290
1278 if (!location.isInitializer()) {1291 if (!location.isInitializer()) {
1279 try writer.writeByte('(');1292 try writer.writeByte('(');
1280 try dg.renderTypecast(writer, ty);1293 try dg.renderType(writer, ty);
1281 try writer.writeByte(')');1294 try writer.writeByte(')');
1282 }1295 }
12831296
...@@ -1292,7 +1305,6 @@ pub const DeclGen = struct {...@@ -1292,7 +1305,6 @@ pub const DeclGen = struct {
12921305
1293 empty = false;1306 empty = false;
1294 }1307 }
1295 if (empty) try writer.print("{}", .{try dg.fmtIntLiteral(Type.u8, Value.zero)});
1296 try writer.writeByte('}');1308 try writer.writeByte('}');
1297 },1309 },
1298 .Packed => {1310 .Packed => {
...@@ -1309,7 +1321,7 @@ pub const DeclGen = struct {...@@ -1309,7 +1321,7 @@ pub const DeclGen = struct {
1309 const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);1321 const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);
13101322
1311 var eff_num_fields: usize = 0;1323 var eff_num_fields: usize = 0;
1312 for (field_vals, 0..) |_, index| {1324 for (0..field_vals.len) |index| {
1313 const field_ty = ty.structFieldType(index);1325 const field_ty = ty.structFieldType(index);
1314 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;1326 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
13151327
...@@ -1365,7 +1377,7 @@ pub const DeclGen = struct {...@@ -1365,7 +1377,7 @@ pub const DeclGen = struct {
13651377
1366 if (!empty) try writer.writeAll(" | ");1378 if (!empty) try writer.writeAll(" | ");
1367 try writer.writeByte('(');1379 try writer.writeByte('(');
1368 try dg.renderTypecast(writer, ty);1380 try dg.renderType(writer, ty);
1369 try writer.writeByte(')');1381 try writer.writeByte(')');
13701382
1371 if (bit_offset_val_pl.data != 0) {1383 if (bit_offset_val_pl.data != 0) {
...@@ -1388,7 +1400,7 @@ pub const DeclGen = struct {...@@ -1388,7 +1400,7 @@ pub const DeclGen = struct {
13881400
1389 if (!location.isInitializer()) {1401 if (!location.isInitializer()) {
1390 try writer.writeByte('(');1402 try writer.writeByte('(');
1391 try dg.renderTypecast(writer, ty);1403 try dg.renderType(writer, ty);
1392 try writer.writeByte(')');1404 try writer.writeByte(')');
1393 }1405 }
13941406
...@@ -1399,11 +1411,11 @@ pub const DeclGen = struct {...@@ -1399,11 +1411,11 @@ pub const DeclGen = struct {
1399 if (field_ty.hasRuntimeBits()) {1411 if (field_ty.hasRuntimeBits()) {
1400 if (field_ty.isPtrAtRuntime()) {1412 if (field_ty.isPtrAtRuntime()) {
1401 try writer.writeByte('(');1413 try writer.writeByte('(');
1402 try dg.renderTypecast(writer, ty);1414 try dg.renderType(writer, ty);
1403 try writer.writeByte(')');1415 try writer.writeByte(')');
1404 } else if (field_ty.zigTypeTag() == .Float) {1416 } else if (field_ty.zigTypeTag() == .Float) {
1405 try writer.writeByte('(');1417 try writer.writeByte('(');
1406 try dg.renderTypecast(writer, ty);1418 try dg.renderType(writer, ty);
1407 try writer.writeByte(')');1419 try writer.writeByte(')');
1408 }1420 }
1409 try dg.renderValue(writer, field_ty, union_obj.val, initializer_type);1421 try dg.renderValue(writer, field_ty, union_obj.val, initializer_type);
...@@ -1413,6 +1425,7 @@ pub const DeclGen = struct {...@@ -1413,6 +1425,7 @@ pub const DeclGen = struct {
1413 return;1425 return;
1414 }1426 }
14151427
1428 var has_payload_init = false;
1416 try writer.writeByte('{');1429 try writer.writeByte('{');
1417 if (ty.unionTagTypeSafety()) |tag_ty| {1430 if (ty.unionTagTypeSafety()) |tag_ty| {
1418 const layout = ty.unionGetLayout(target);1431 const layout = ty.unionGetLayout(target);
...@@ -1421,7 +1434,10 @@ pub const DeclGen = struct {...@@ -1421,7 +1434,10 @@ pub const DeclGen = struct {
1421 try dg.renderValue(writer, tag_ty, union_obj.tag, initializer_type);1434 try dg.renderValue(writer, tag_ty, union_obj.tag, initializer_type);
1422 try writer.writeAll(", ");1435 try writer.writeAll(", ");
1423 }1436 }
1424 try writer.writeAll(".payload = {");1437 if (!ty.unionHasAllZeroBitFieldTypes()) {
1438 try writer.writeAll(".payload = {");
1439 has_payload_init = true;
1440 }
1425 }1441 }
14261442
1427 var it = ty.unionFields().iterator();1443 var it = ty.unionFields().iterator();
...@@ -1433,8 +1449,8 @@ pub const DeclGen = struct {...@@ -1433,8 +1449,8 @@ pub const DeclGen = struct {
1433 try writer.print(".{ } = ", .{fmtIdent(field.key_ptr.*)});1449 try writer.print(".{ } = ", .{fmtIdent(field.key_ptr.*)});
1434 try dg.renderValue(writer, field.value_ptr.ty, Value.undef, initializer_type);1450 try dg.renderValue(writer, field.value_ptr.ty, Value.undef, initializer_type);
1435 break;1451 break;
1436 } else try writer.writeAll(".empty_union = 0");1452 }
1437 if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}');1453 if (has_payload_init) try writer.writeByte('}');
1438 try writer.writeByte('}');1454 try writer.writeByte('}');
1439 },1455 },
14401456
...@@ -1456,778 +1472,112 @@ pub const DeclGen = struct {...@@ -1456,778 +1472,112 @@ pub const DeclGen = struct {
1456 }1472 }
1457 }1473 }
14581474
1459 fn renderFunctionSignature(dg: *DeclGen, w: anytype, kind: TypedefKind, export_index: u32) !void {1475 fn renderFunctionSignature(
1460 const fn_info = dg.decl.ty.fnInfo();
1461 if (fn_info.cc == .Naked) {
1462 switch (kind) {
1463 .Forward => try w.writeAll("zig_naked_decl "),
1464 .Complete => try w.writeAll("zig_naked "),
1465 }
1466 }
1467 if (dg.decl.val.castTag(.function)) |func_payload|
1468 if (func_payload.data.is_cold) try w.writeAll("zig_cold ");
1469
1470 const target = dg.module.getTarget();
1471 var ret_buf: LowerFnRetTyBuffer = undefined;
1472 const ret_ty = lowerFnRetTy(fn_info.return_type, &ret_buf, target);
1473
1474 try dg.renderType(w, ret_ty, kind);
1475 try w.writeByte(' ');
1476
1477 if (toCallingConvention(fn_info.cc)) |call_conv| {
1478 try w.print("zig_callconv({s}) ", .{call_conv});
1479 }
1480
1481 if (fn_info.alignment > 0 and kind == .Complete) try w.print(" zig_align_fn({})", .{fn_info.alignment});
1482
1483 try dg.renderDeclName(w, dg.decl_index, export_index);
1484 try w.writeByte('(');
1485
1486 var index: usize = 0;
1487 for (fn_info.param_types) |param_type| {
1488 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
1489 if (index > 0) try w.writeAll(", ");
1490 const name = CValue{ .arg = index };
1491 try dg.renderTypeAndName(w, param_type, name, .ConstArgument, 0, kind);
1492 index += 1;
1493 }
1494
1495 if (fn_info.is_var_args) {
1496 if (index > 0) try w.writeAll(", ");
1497 try w.writeAll("...");
1498 } else if (index == 0) {
1499 try dg.renderType(w, Type.void, kind);
1500 }
1501 try w.writeByte(')');
1502 if (fn_info.alignment > 0 and kind == .Forward) try w.print(" zig_align_fn({})", .{fn_info.alignment});
1503 }
1504
1505 fn renderPtrToFnTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1506 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1507 defer buffer.deinit();
1508 const bw = buffer.writer();
1509
1510 const fn_info = t.fnInfo();
1511
1512 const target = dg.module.getTarget();
1513 var ret_buf: LowerFnRetTyBuffer = undefined;
1514 const ret_ty = lowerFnRetTy(fn_info.return_type, &ret_buf, target);
1515
1516 try bw.writeAll("typedef ");
1517 try dg.renderType(bw, ret_ty, .Forward);
1518 try bw.writeAll(" (*");
1519 const name_begin = buffer.items.len;
1520 try bw.print("zig_F_{}", .{typeToCIdentifier(t, dg.module)});
1521 const name_end = buffer.items.len;
1522 try bw.writeAll(")(");
1523
1524 const param_len = fn_info.param_types.len;
1525
1526 var params_written: usize = 0;
1527 var index: usize = 0;
1528 while (index < param_len) : (index += 1) {
1529 const param_ty = fn_info.param_types[index];
1530 if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;
1531 if (params_written > 0) {
1532 try bw.writeAll(", ");
1533 }
1534 try dg.renderTypeAndName(bw, param_ty, .{ .bytes = "" }, .Mut, 0, .Forward);
1535 params_written += 1;
1536 }
1537
1538 if (fn_info.is_var_args) {
1539 if (params_written != 0) try bw.writeAll(", ");
1540 try bw.writeAll("...");
1541 } else if (params_written == 0) {
1542 try dg.renderType(bw, Type.void, .Forward);
1543 }
1544 try bw.writeAll(");\n");
1545
1546 const rendered = try buffer.toOwnedSlice();
1547 errdefer dg.typedefs.allocator.free(rendered);
1548 const name = rendered[name_begin..name_end];
1549
1550 try dg.typedefs.ensureUnusedCapacity(1);
1551 dg.typedefs.putAssumeCapacityNoClobber(
1552 try t.copy(dg.typedefs_arena),
1553 .{ .name = name, .rendered = rendered },
1554 );
1555
1556 return name;
1557 }
1558
1559 fn renderSliceTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1560 std.debug.assert(t.sentinel() == null); // expected canonical type
1561
1562 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1563 defer buffer.deinit();
1564 const bw = buffer.writer();
1565
1566 var ptr_ty_buf: Type.SlicePtrFieldTypeBuffer = undefined;
1567 const ptr_ty = t.slicePtrFieldType(&ptr_ty_buf);
1568 const ptr_name = CValue{ .identifier = "ptr" };
1569 const len_ty = Type.usize;
1570 const len_name = CValue{ .identifier = "len" };
1571
1572 try bw.writeAll("typedef struct {\n ");
1573 try dg.renderTypeAndName(bw, ptr_ty, ptr_name, .Mut, 0, .Complete);
1574 try bw.writeAll(";\n ");
1575 try dg.renderTypeAndName(bw, len_ty, len_name, .Mut, 0, .Complete);
1576
1577 try bw.writeAll(";\n} ");
1578 const name_begin = buffer.items.len;
1579 try bw.print("zig_{c}_{}", .{
1580 @as(u8, if (t.isConstPtr()) 'L' else 'M'),
1581 typeToCIdentifier(t.childType(), dg.module),
1582 });
1583 const name_end = buffer.items.len;
1584 try bw.writeAll(";\n");
1585
1586 const rendered = try buffer.toOwnedSlice();
1587 errdefer dg.typedefs.allocator.free(rendered);
1588 const name = rendered[name_begin..name_end];
1589
1590 try dg.typedefs.ensureUnusedCapacity(1);
1591 dg.typedefs.putAssumeCapacityNoClobber(
1592 try t.copy(dg.typedefs_arena),
1593 .{ .name = name, .rendered = rendered },
1594 );
1595
1596 return name;
1597 }
1598
1599 fn renderFwdTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1600 // The forward declaration for T is stored with a key of *const T.
1601 const child_ty = t.childType();
1602
1603 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1604 defer buffer.deinit();
1605 const bw = buffer.writer();
1606
1607 const tag = switch (child_ty.zigTypeTag()) {
1608 .Struct, .ErrorUnion, .Optional => "struct",
1609 .Union => if (child_ty.unionTagTypeSafety()) |_| "struct" else "union",
1610 else => unreachable,
1611 };
1612 try bw.writeAll("typedef ");
1613 try bw.writeAll(tag);
1614 const name_begin = buffer.items.len + " ".len;
1615 try bw.writeAll(" zig_");
1616 switch (child_ty.zigTypeTag()) {
1617 .Struct, .Union => {
1618 var fqn_buf = std.ArrayList(u8).init(dg.typedefs.allocator);
1619 defer fqn_buf.deinit();
1620
1621 const owner_decl_index = child_ty.getOwnerDecl();
1622 const owner_decl = dg.module.declPtr(owner_decl_index);
1623 try owner_decl.renderFullyQualifiedName(dg.module, fqn_buf.writer());
1624
1625 try bw.print("S_{}__{d}", .{ fmtIdent(fqn_buf.items), @enumToInt(owner_decl_index) });
1626 },
1627 .ErrorUnion => {
1628 try bw.print("E_{}", .{typeToCIdentifier(child_ty.errorUnionPayload(), dg.module)});
1629 },
1630 .Optional => {
1631 var opt_buf: Type.Payload.ElemType = undefined;
1632 try bw.print("Q_{}", .{typeToCIdentifier(child_ty.optionalChild(&opt_buf), dg.module)});
1633 },
1634 else => unreachable,
1635 }
1636 const name_end = buffer.items.len;
1637 try buffer.ensureUnusedCapacity(" ".len + (name_end - name_begin) + ";\n".len);
1638 buffer.appendAssumeCapacity(' ');
1639 buffer.appendSliceAssumeCapacity(buffer.items[name_begin..name_end]);
1640 buffer.appendSliceAssumeCapacity(";\n");
1641
1642 const rendered = try buffer.toOwnedSlice();
1643 errdefer dg.typedefs.allocator.free(rendered);
1644 const name = rendered[name_begin..name_end];
1645
1646 try dg.typedefs.ensureUnusedCapacity(1);
1647 dg.typedefs.putAssumeCapacityNoClobber(
1648 try t.copy(dg.typedefs_arena),
1649 .{ .name = name, .rendered = rendered },
1650 );
1651
1652 return name;
1653 }
1654
1655 fn renderStructTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1656 var ptr_pl = Type.Payload.ElemType{ .base = .{ .tag = .single_const_pointer }, .data = t };
1657 const ptr_ty = Type.initPayload(&ptr_pl.base);
1658 const name = dg.getTypedefName(ptr_ty) orelse
1659 try dg.renderFwdTypedef(ptr_ty);
1660
1661 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1662 defer buffer.deinit();
1663
1664 try buffer.appendSlice("struct ");
1665
1666 var needs_pack_attr = false;
1667 {
1668 var it = t.structFields().iterator();
1669 while (it.next()) |field| {
1670 const field_ty = field.value_ptr.ty;
1671 if (!field_ty.hasRuntimeBits()) continue;
1672 const alignment = field.value_ptr.abi_align;
1673 if (alignment != 0 and alignment < field_ty.abiAlignment(dg.module.getTarget())) {
1674 needs_pack_attr = true;
1675 try buffer.appendSlice("zig_packed(");
1676 break;
1677 }
1678 }
1679 }
1680
1681 try buffer.appendSlice(name);
1682 try buffer.appendSlice(" {\n");
1683 {
1684 var it = t.structFields().iterator();
1685 var empty = true;
1686 while (it.next()) |field| {
1687 const field_ty = field.value_ptr.ty;
1688 if (!field_ty.hasRuntimeBits()) continue;
1689
1690 const alignment = field.value_ptr.alignment(dg.module.getTarget(), t.containerLayout());
1691 const field_name = CValue{ .identifier = field.key_ptr.* };
1692 try buffer.append(' ');
1693 try dg.renderTypeAndName(buffer.writer(), field_ty, field_name, .Mut, alignment, .Complete);
1694 try buffer.appendSlice(";\n");
1695
1696 empty = false;
1697 }
1698 if (empty) try buffer.appendSlice(" char empty_struct;\n");
1699 }
1700 if (needs_pack_attr) try buffer.appendSlice("});\n") else try buffer.appendSlice("};\n");
1701
1702 const rendered = try buffer.toOwnedSlice();
1703 errdefer dg.typedefs.allocator.free(rendered);
1704
1705 try dg.typedefs.ensureUnusedCapacity(1);
1706 dg.typedefs.putAssumeCapacityNoClobber(
1707 try t.copy(dg.typedefs_arena),
1708 .{ .name = name, .rendered = rendered },
1709 );
1710
1711 return name;
1712 }
1713
1714 fn renderTupleTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1715 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1716 defer buffer.deinit();
1717
1718 try buffer.appendSlice("typedef struct {\n");
1719 {
1720 const fields = t.tupleFields();
1721 var field_id: usize = 0;
1722 for (fields.types, 0..) |field_ty, i| {
1723 if (!field_ty.hasRuntimeBits() or fields.values[i].tag() != .unreachable_value) continue;
1724
1725 try buffer.append(' ');
1726 try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .field = field_id }, .Mut, 0, .Complete);
1727 try buffer.appendSlice(";\n");
1728
1729 field_id += 1;
1730 }
1731 if (field_id == 0) try buffer.appendSlice(" char empty_tuple;\n");
1732 }
1733 const name_begin = buffer.items.len + "} ".len;
1734 try buffer.writer().print("}} zig_T_{}_{d};\n", .{ typeToCIdentifier(t, dg.module), @truncate(u16, t.hash(dg.module)) });
1735 const name_end = buffer.items.len - ";\n".len;
1736
1737 const rendered = try buffer.toOwnedSlice();
1738 errdefer dg.typedefs.allocator.free(rendered);
1739 const name = rendered[name_begin..name_end];
1740
1741 try dg.typedefs.ensureUnusedCapacity(1);
1742 dg.typedefs.putAssumeCapacityNoClobber(
1743 try t.copy(dg.typedefs_arena),
1744 .{ .name = name, .rendered = rendered },
1745 );
1746
1747 return name;
1748 }
1749
1750 fn renderUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1751 var ptr_pl = Type.Payload.ElemType{ .base = .{ .tag = .single_const_pointer }, .data = t };
1752 const ptr_ty = Type.initPayload(&ptr_pl.base);
1753 const name = dg.getTypedefName(ptr_ty) orelse
1754 try dg.renderFwdTypedef(ptr_ty);
1755
1756 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1757 defer buffer.deinit();
1758
1759 try buffer.appendSlice(if (t.unionTagTypeSafety()) |_| "struct " else "union ");
1760 try buffer.appendSlice(name);
1761 try buffer.appendSlice(" {\n");
1762
1763 const indent = if (t.unionTagTypeSafety()) |tag_ty| indent: {
1764 const target = dg.module.getTarget();
1765 const layout = t.unionGetLayout(target);
1766 if (layout.tag_size != 0) {
1767 try buffer.append(' ');
1768 try dg.renderTypeAndName(buffer.writer(), tag_ty, .{ .identifier = "tag" }, .Mut, 0, .Complete);
1769 try buffer.appendSlice(";\n");
1770 }
1771 try buffer.appendSlice(" union {\n");
1772 break :indent " ";
1773 } else " ";
1774
1775 {
1776 var it = t.unionFields().iterator();
1777 var empty = true;
1778 while (it.next()) |field| {
1779 const field_ty = field.value_ptr.ty;
1780 if (!field_ty.hasRuntimeBits()) continue;
1781
1782 const alignment = field.value_ptr.abi_align;
1783 const field_name = CValue{ .identifier = field.key_ptr.* };
1784 try buffer.appendSlice(indent);
1785 try dg.renderTypeAndName(buffer.writer(), field_ty, field_name, .Mut, alignment, .Complete);
1786 try buffer.appendSlice(";\n");
1787
1788 empty = false;
1789 }
1790 if (empty) {
1791 try buffer.appendSlice(indent);
1792 try buffer.appendSlice("char empty_union;\n");
1793 }
1794 }
1795
1796 if (t.unionTagTypeSafety()) |_| try buffer.appendSlice(" } payload;\n");
1797 try buffer.appendSlice("};\n");
1798
1799 const rendered = try buffer.toOwnedSlice();
1800 errdefer dg.typedefs.allocator.free(rendered);
1801
1802 try dg.typedefs.ensureUnusedCapacity(1);
1803 dg.typedefs.putAssumeCapacityNoClobber(
1804 try t.copy(dg.typedefs_arena),
1805 .{ .name = name, .rendered = rendered },
1806 );
1807
1808 return name;
1809 }
1810
1811 fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1812 assert(t.errorUnionSet().tag() == .anyerror);
1813
1814 var ptr_pl = Type.Payload.ElemType{ .base = .{ .tag = .single_const_pointer }, .data = t };
1815 const ptr_ty = Type.initPayload(&ptr_pl.base);
1816 const name = dg.getTypedefName(ptr_ty) orelse
1817 try dg.renderFwdTypedef(ptr_ty);
1818
1819 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1820 defer buffer.deinit();
1821 const bw = buffer.writer();
1822
1823 const payload_ty = t.errorUnionPayload();
1824 const payload_name = CValue{ .identifier = "payload" };
1825 const error_ty = t.errorUnionSet();
1826 const error_name = CValue{ .identifier = "error" };
1827
1828 const target = dg.module.getTarget();
1829 const payload_align = payload_ty.abiAlignment(target);
1830 const error_align = error_ty.abiAlignment(target);
1831 try bw.writeAll("struct ");
1832 try bw.writeAll(name);
1833 try bw.writeAll(" {\n ");
1834 if (error_align > payload_align) {
1835 try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete);
1836 try bw.writeAll(";\n ");
1837 try dg.renderTypeAndName(bw, error_ty, error_name, .Mut, 0, .Complete);
1838 } else {
1839 try dg.renderTypeAndName(bw, error_ty, error_name, .Mut, 0, .Complete);
1840 try bw.writeAll(";\n ");
1841 try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete);
1842 }
1843 try bw.writeAll(";\n};\n");
1844
1845 const rendered = try buffer.toOwnedSlice();
1846 errdefer dg.typedefs.allocator.free(rendered);
1847
1848 try dg.typedefs.ensureUnusedCapacity(1);
1849 dg.typedefs.putAssumeCapacityNoClobber(
1850 try t.copy(dg.typedefs_arena),
1851 .{ .name = name, .rendered = rendered },
1852 );
1853
1854 return name;
1855 }
1856
1857 fn renderArrayTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1858 const info = t.arrayInfo();
1859 std.debug.assert(info.sentinel == null); // expected canonical type
1860
1861 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1862 defer buffer.deinit();
1863 const bw = buffer.writer();
1864
1865 try bw.writeAll("typedef ");
1866 try dg.renderType(bw, info.elem_type, .Complete);
1867
1868 const name_begin = buffer.items.len + " ".len;
1869 try bw.print(" zig_A_{}_{d}", .{ typeToCIdentifier(info.elem_type, dg.module), info.len });
1870 const name_end = buffer.items.len;
1871
1872 const c_len = if (info.len > 0) info.len else 1;
1873 var c_len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = c_len };
1874 const c_len_val = Value.initPayload(&c_len_pl.base);
1875 try bw.print("[{}];\n", .{try dg.fmtIntLiteral(Type.usize, c_len_val)});
1876
1877 const rendered = try buffer.toOwnedSlice();
1878 errdefer dg.typedefs.allocator.free(rendered);
1879 const name = rendered[name_begin..name_end];
1880
1881 try dg.typedefs.ensureUnusedCapacity(1);
1882 dg.typedefs.putAssumeCapacityNoClobber(
1883 try t.copy(dg.typedefs_arena),
1884 .{ .name = name, .rendered = rendered },
1885 );
1886
1887 return name;
1888 }
1889
1890 fn renderOptionalTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1891 var ptr_pl = Type.Payload.ElemType{ .base = .{ .tag = .single_const_pointer }, .data = t };
1892 const ptr_ty = Type.initPayload(&ptr_pl.base);
1893 const name = dg.getTypedefName(ptr_ty) orelse
1894 try dg.renderFwdTypedef(ptr_ty);
1895
1896 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1897 defer buffer.deinit();
1898 const bw = buffer.writer();
1899
1900 var opt_buf: Type.Payload.ElemType = undefined;
1901 const child_ty = t.optionalChild(&opt_buf);
1902
1903 try bw.writeAll("struct ");
1904 try bw.writeAll(name);
1905 try bw.writeAll(" {\n");
1906 try dg.renderTypeAndName(bw, child_ty, .{ .identifier = "payload" }, .Mut, 0, .Complete);
1907 try bw.writeAll(";\n ");
1908 try dg.renderTypeAndName(bw, Type.bool, .{ .identifier = "is_null" }, .Mut, 0, .Complete);
1909 try bw.writeAll(";\n};\n");
1910
1911 const rendered = try buffer.toOwnedSlice();
1912 errdefer dg.typedefs.allocator.free(rendered);
1913
1914 try dg.typedefs.ensureUnusedCapacity(1);
1915 dg.typedefs.putAssumeCapacityNoClobber(
1916 try t.copy(dg.typedefs_arena),
1917 .{ .name = name, .rendered = rendered },
1918 );
1919
1920 return name;
1921 }
1922
1923 fn renderOpaqueTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1924 const opaque_ty = t.cast(Type.Payload.Opaque).?.data;
1925 const unqualified_name = dg.module.declPtr(opaque_ty.owner_decl).name;
1926 const fqn = try opaque_ty.getFullyQualifiedName(dg.module);
1927 defer dg.typedefs.allocator.free(fqn);
1928
1929 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1930 defer buffer.deinit();
1931
1932 try buffer.writer().print("typedef struct { } ", .{fmtIdent(std.mem.span(unqualified_name))});
1933
1934 const name_begin = buffer.items.len;
1935 try buffer.writer().print("zig_O_{}", .{fmtIdent(fqn)});
1936 const name_end = buffer.items.len;
1937 try buffer.appendSlice(";\n");
1938
1939 const rendered = try buffer.toOwnedSlice();
1940 errdefer dg.typedefs.allocator.free(rendered);
1941 const name = rendered[name_begin..name_end];
1942
1943 try dg.typedefs.ensureUnusedCapacity(1);
1944 dg.typedefs.putAssumeCapacityNoClobber(
1945 try t.copy(dg.typedefs_arena),
1946 .{ .name = name, .rendered = rendered },
1947 );
1948
1949 return name;
1950 }
1951
1952 /// Renders a type as a single identifier, generating intermediate typedefs
1953 /// if necessary.
1954 ///
1955 /// This is guaranteed to be valid in both typedefs and declarations/definitions.
1956 ///
1957 /// There are three type formats in total that we support rendering:
1958 /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) |
1959 /// |---------------------|-----------------|---------------------|
1960 /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" |
1961 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
1962 /// | `renderType` | "uint8_t *" | "zig_A_uint8_t_10" |
1963 ///
1964 fn renderType(
1965 dg: *DeclGen,1476 dg: *DeclGen,
1966 w: anytype,1477 w: anytype,
1967 t: Type,1478 fn_decl_index: Decl.Index,
1968 kind: TypedefKind,1479 kind: CType.Kind,
1969 ) error{ OutOfMemory, AnalysisFail }!void {1480 name: union(enum) {
1970 const target = dg.module.getTarget();1481 export_index: u32,
19711482 string: []const u8,
1972 switch (t.zigTypeTag()) {1483 },
1973 .Void => try w.writeAll("void"),1484 ) !void {
1974 .Bool => try w.writeAll("bool"),1485 const store = &dg.ctypes.set;
1975 .NoReturn, .Float => {1486 const module = dg.module;
1976 try w.writeAll("zig_");
1977 try t.print(w, dg.module);
1978 },
1979 .Int => {
1980 if (t.isNamedInt()) {
1981 try w.writeAll("zig_");
1982 try t.print(w, dg.module);
1983 } else {
1984 return renderTypeUnnamed(dg, w, t, kind);
1985 }
1986 },
1987 .ErrorSet => {
1988 return renderTypeUnnamed(dg, w, t, kind);
1989 },
1990 .Pointer => {
1991 const ptr_info = t.ptrInfo().data;
1992 if (ptr_info.size == .Slice) {
1993 var slice_pl = Type.Payload.ElemType{
1994 .base = .{ .tag = if (t.ptrIsMutable()) .mut_slice else .const_slice },
1995 .data = ptr_info.pointee_type,
1996 };
1997 const slice_ty = Type.initPayload(&slice_pl.base);
1998
1999 const name = dg.getTypedefName(slice_ty) orelse
2000 try dg.renderSliceTypedef(slice_ty);
2001
2002 return w.writeAll(name);
2003 }
2004
2005 if (ptr_info.pointee_type.zigTypeTag() == .Fn) {
2006 const name = dg.getTypedefName(ptr_info.pointee_type) orelse
2007 try dg.renderPtrToFnTypedef(ptr_info.pointee_type);
2008
2009 return w.writeAll(name);
2010 }
2011
2012 if (ptr_info.host_size != 0) {
2013 var host_pl = Type.Payload.Bits{
2014 .base = .{ .tag = .int_unsigned },
2015 .data = ptr_info.host_size * 8,
2016 };
2017 const host_ty = Type.initPayload(&host_pl.base);
2018
2019 try dg.renderType(w, host_ty, .Forward);
2020 } else if (t.isCPtr() and ptr_info.pointee_type.eql(Type.u8, dg.module) and
2021 (dg.decl.val.tag() == .extern_fn or
2022 std.mem.eql(u8, std.mem.span(dg.decl.name), "main")))
2023 {
2024 // This is a hack, since the c compiler expects a lot of external
2025 // library functions to have char pointers in their signatures, but
2026 // u8 and i8 produce unsigned char and signed char respectively,
2027 // which in C are (not very usefully) different than char.
2028 try w.writeAll("char");
2029 } else try dg.renderType(w, switch (ptr_info.pointee_type.tag()) {
2030 .anyopaque => Type.void,
2031 else => ptr_info.pointee_type,
2032 }, .Forward);
2033 if (t.isConstPtr()) try w.writeAll(" const");
2034 if (t.isVolatilePtr()) try w.writeAll(" volatile");
2035 return w.writeAll(" *");
2036 },
2037 .Array, .Vector => {
2038 var array_pl = Type.Payload.Array{ .base = .{ .tag = .array }, .data = .{
2039 .len = t.arrayLenIncludingSentinel(),
2040 .elem_type = t.childType(),
2041 } };
2042 const array_ty = Type.initPayload(&array_pl.base);
2043
2044 const name = dg.getTypedefName(array_ty) orelse
2045 try dg.renderArrayTypedef(array_ty);
2046
2047 return w.writeAll(name);
2048 },
2049 .Optional => {
2050 var opt_buf: Type.Payload.ElemType = undefined;
2051 const child_ty = t.optionalChild(&opt_buf);
2052
2053 if (!child_ty.hasRuntimeBitsIgnoreComptime())
2054 return dg.renderType(w, Type.bool, kind);
2055
2056 if (t.optionalReprIsPayload())
2057 return dg.renderType(w, child_ty, kind);
2058
2059 switch (kind) {
2060 .Complete => {
2061 const name = dg.getTypedefName(t) orelse
2062 try dg.renderOptionalTypedef(t);
2063
2064 try w.writeAll(name);
2065 },
2066 .Forward => {
2067 var ptr_pl = Type.Payload.ElemType{
2068 .base = .{ .tag = .single_const_pointer },
2069 .data = t,
2070 };
2071 const ptr_ty = Type.initPayload(&ptr_pl.base);
2072
2073 const name = dg.getTypedefName(ptr_ty) orelse
2074 try dg.renderFwdTypedef(ptr_ty);
2075
2076 try w.writeAll(name);
2077 },
2078 }
2079 },
2080 .ErrorUnion => {
2081 const payload_ty = t.errorUnionPayload();
2082
2083 if (!payload_ty.hasRuntimeBitsIgnoreComptime())
2084 return dg.renderType(w, Type.anyerror, kind);
2085
2086 var error_union_pl = Type.Payload.ErrorUnion{
2087 .data = .{ .error_set = Type.anyerror, .payload = payload_ty },
2088 };
2089 const error_union_ty = Type.initPayload(&error_union_pl.base);
2090
2091 switch (kind) {
2092 .Complete => {
2093 const name = dg.getTypedefName(error_union_ty) orelse
2094 try dg.renderErrorUnionTypedef(error_union_ty);
2095
2096 try w.writeAll(name);
2097 },
2098 .Forward => {
2099 var ptr_pl = Type.Payload.ElemType{
2100 .base = .{ .tag = .single_const_pointer },
2101 .data = error_union_ty,
2102 };
2103 const ptr_ty = Type.initPayload(&ptr_pl.base);
2104
2105 const name = dg.getTypedefName(ptr_ty) orelse
2106 try dg.renderFwdTypedef(ptr_ty);
2107
2108 try w.writeAll(name);
2109 },
2110 }
2111 },
2112 .Struct, .Union => |tag| if (t.containerLayout() == .Packed) {
2113 if (t.castTag(.@"struct")) |struct_obj| {
2114 try dg.renderType(w, struct_obj.data.backing_int_ty, kind);
2115 } else {
2116 var buf: Type.Payload.Bits = .{
2117 .base = .{ .tag = .int_unsigned },
2118 .data = @intCast(u16, t.bitSize(target)),
2119 };
2120 try dg.renderType(w, Type.initPayload(&buf.base), kind);
2121 }
2122 } else if (t.isSimpleTupleOrAnonStruct()) {
2123 const ExpectedContents = struct { types: [8]Type, values: [8]Value };
2124 var stack align(@alignOf(ExpectedContents)) =
2125 std.heap.stackFallback(@sizeOf(ExpectedContents), dg.gpa);
2126 const allocator = stack.get();
2127
2128 var tuple_storage = std.MultiArrayList(struct { type: Type, value: Value }){};
2129 defer tuple_storage.deinit(allocator);
2130 try tuple_storage.ensureTotalCapacity(allocator, t.structFieldCount());
2131
2132 const fields = t.tupleFields();
2133 for (fields.values, 0..) |value, index|
2134 if (value.tag() == .unreachable_value)
2135 tuple_storage.appendAssumeCapacity(.{
2136 .type = fields.types[index],
2137 .value = value,
2138 });
21391487
2140 const tuple_slice = tuple_storage.slice();1488 const fn_decl = module.declPtr(fn_decl_index);
2141 var tuple_pl = Type.Payload.Tuple{ .data = .{1489 const fn_cty_idx = try dg.typeToIndex(fn_decl.ty, kind);
2142 .types = tuple_slice.items(.type),
2143 .values = tuple_slice.items(.value),
2144 } };
2145 const tuple_ty = Type.initPayload(&tuple_pl.base);
2146
2147 const name = dg.getTypedefName(tuple_ty) orelse
2148 try dg.renderTupleTypedef(tuple_ty);
2149
2150 try w.writeAll(name);
2151 } else switch (kind) {
2152 .Complete => {
2153 const name = dg.getTypedefName(t) orelse switch (tag) {
2154 .Struct => try dg.renderStructTypedef(t),
2155 .Union => try dg.renderUnionTypedef(t),
2156 else => unreachable,
2157 };
21581490
2159 try w.writeAll(name);1491 const fn_info = fn_decl.ty.fnInfo();
2160 },1492 if (fn_info.cc == .Naked) {
2161 .Forward => {1493 switch (kind) {
2162 var ptr_pl = Type.Payload.ElemType{1494 .forward => try w.writeAll("zig_naked_decl "),
2163 .base = .{ .tag = .single_const_pointer },1495 .complete => try w.writeAll("zig_naked "),
2164 .data = t,1496 else => unreachable,
2165 };1497 }
2166 const ptr_ty = Type.initPayload(&ptr_pl.base);1498 }
1499 if (fn_decl.val.castTag(.function)) |func_payload|
1500 if (func_payload.data.is_cold) try w.writeAll("zig_cold ");
1501 if (fn_info.return_type.tag() == .noreturn) try w.writeAll("zig_noreturn ");
1502
1503 const trailing = try renderTypePrefix(
1504 dg.decl_index,
1505 store.*,
1506 module,
1507 w,
1508 fn_cty_idx,
1509 .suffix,
1510 .{},
1511 );
1512 try w.print("{}", .{trailing});
21671513
2168 const name = dg.getTypedefName(ptr_ty) orelse1514 if (toCallingConvention(fn_info.cc)) |call_conv| {
2169 try dg.renderFwdTypedef(ptr_ty);1515 try w.print("zig_callconv({s}) ", .{call_conv});
1516 }
21701517
2171 try w.writeAll(name);1518 switch (kind) {
2172 },1519 .forward => {},
2173 },1520 .complete => if (fn_info.alignment > 0)
2174 .Enum => {1521 try w.print(" zig_align_fn({})", .{fn_info.alignment}),
2175 // For enums, we simply use the integer tag type.1522 else => unreachable,
2176 var int_tag_buf: Type.Payload.Bits = undefined;1523 }
2177 const int_tag_ty = t.intTagType(&int_tag_buf);
21781524
2179 try dg.renderType(w, int_tag_ty, kind);1525 switch (name) {
2180 },1526 .export_index => |export_index| try dg.renderDeclName(w, fn_decl_index, export_index),
2181 .Opaque => switch (t.tag()) {1527 .string => |string| try w.writeAll(string),
2182 .@"opaque" => {1528 }
2183 const name = dg.getTypedefName(t) orelse
2184 try dg.renderOpaqueTypedef(t);
21851529
2186 try w.writeAll(name);1530 try renderTypeSuffix(
2187 },1531 dg.decl_index,
1532 store.*,
1533 module,
1534 w,
1535 fn_cty_idx,
1536 .suffix,
1537 CQualifiers.init(.{ .@"const" = switch (kind) {
1538 .forward => false,
1539 .complete => true,
2188 else => unreachable,1540 else => unreachable,
2189 },1541 } }),
1542 );
21901543
2191 .Frame,1544 switch (kind) {
2192 .AnyFrame,1545 .forward => if (fn_info.alignment > 0)
2193 => |tag| return dg.fail("TODO: C backend: implement value of type {s}", .{1546 try w.print(" zig_align_fn({})", .{fn_info.alignment}),
2194 @tagName(tag),1547 .complete => {},
2195 }),1548 else => unreachable,
1549 }
1550 }
21961551
2197 .Fn => unreachable, // This is a function body, not a function pointer.1552 fn indexToCType(dg: *DeclGen, idx: CType.Index) CType {
1553 return dg.ctypes.indexToCType(idx);
1554 }
21981555
2199 .Null,1556 fn typeToIndex(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType.Index {
2200 .Undefined,1557 return dg.ctypes.typeToIndex(dg.gpa, ty, dg.module, kind);
2201 .EnumLiteral,
2202 .ComptimeFloat,
2203 .ComptimeInt,
2204 .Type,
2205 => unreachable, // must be const or comptime
2206 }
2207 }1558 }
22081559
2209 fn renderTypeUnnamed(1560 fn typeToCType(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType {
2210 dg: *DeclGen,1561 return dg.ctypes.typeToCType(dg.gpa, ty, dg.module, kind);
2211 w: anytype,1562 }
2212 t: Type,
2213 kind: TypedefKind,
2214 ) error{ OutOfMemory, AnalysisFail }!void {
2215 const target = dg.module.getTarget();
2216 const int_info = t.intInfo(target);
2217 if (toCIntBits(int_info.bits)) |c_bits|
2218 return w.print("zig_{c}{d}", .{ signAbbrev(int_info.signedness), c_bits })
2219 else if (loweredArrayInfo(t, target)) |array_info| {
2220 assert(array_info.sentinel == null);
2221 var array_pl = Type.Payload.Array{
2222 .base = .{ .tag = .array },
2223 .data = .{ .len = array_info.len, .elem_type = array_info.elem_type },
2224 };
2225 const array_ty = Type.initPayload(&array_pl.base);
22261563
2227 return dg.renderType(w, array_ty, kind);1564 /// Renders a type as a single identifier, generating intermediate typedefs
2228 } else return dg.fail("C backend: Unable to lower unnamed integer type {}", .{1565 /// if necessary.
2229 t.fmt(dg.module),1566 ///
2230 });1567 /// This is guaranteed to be valid in both typedefs and declarations/definitions.
1568 ///
1569 /// There are three type formats in total that we support rendering:
1570 /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) |
1571 /// |---------------------|-----------------|---------------------|
1572 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
1573 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
1574 ///
1575 fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void {
1576 const store = &dg.ctypes.set;
1577 const module = dg.module;
1578 const idx = try dg.typeToIndex(t, .complete);
1579 _ = try renderTypePrefix(dg.decl_index, store.*, module, w, idx, .suffix, .{});
1580 try renderTypeSuffix(dg.decl_index, store.*, module, w, idx, .suffix, .{});
2231 }1581 }
22321582
2233 const IntCastContext = union(enum) {1583 const IntCastContext = union(enum) {
...@@ -2254,16 +1604,16 @@ pub const DeclGen = struct {...@@ -2254,16 +1604,16 @@ pub const DeclGen = struct {
2254 /// Renders a cast to an int type, from either an int or a pointer.1604 /// Renders a cast to an int type, from either an int or a pointer.
2255 ///1605 ///
2256 /// Some platforms don't have 128 bit integers, so we need to use1606 /// Some platforms don't have 128 bit integers, so we need to use
2257 /// the zig_as_ and zig_lo_ macros in those cases.1607 /// the zig_make_ and zig_lo_ macros in those cases.
2258 ///1608 ///
2259 /// | Dest type bits | Src type | Result1609 /// | Dest type bits | Src type | Result
2260 /// |------------------|------------------|---------------------------|1610 /// |------------------|------------------|---------------------------|
2261 /// | < 64 bit integer | pointer | (zig_<dest_ty>)(zig_<u|i>size)src1611 /// | < 64 bit integer | pointer | (zig_<dest_ty>)(zig_<u|i>size)src
2262 /// | < 64 bit integer | < 64 bit integer | (zig_<dest_ty>)src1612 /// | < 64 bit integer | < 64 bit integer | (zig_<dest_ty>)src
2263 /// | < 64 bit integer | > 64 bit integer | zig_lo(src)1613 /// | < 64 bit integer | > 64 bit integer | zig_lo(src)
2264 /// | > 64 bit integer | pointer | zig_as_<dest_ty>(0, (zig_<u|i>size)src)1614 /// | > 64 bit integer | pointer | zig_make_<dest_ty>(0, (zig_<u|i>size)src)
2265 /// | > 64 bit integer | < 64 bit integer | zig_as_<dest_ty>(0, src)1615 /// | > 64 bit integer | < 64 bit integer | zig_make_<dest_ty>(0, src)
2266 /// | > 64 bit integer | > 64 bit integer | zig_as_<dest_ty>(zig_hi_<src_ty>(src), zig_lo_<src_ty>(src))1616 /// | > 64 bit integer | > 64 bit integer | zig_make_<dest_ty>(zig_hi_<src_ty>(src), zig_lo_<src_ty>(src))
2267 fn renderIntCast(dg: *DeclGen, w: anytype, dest_ty: Type, context: IntCastContext, src_ty: Type, location: ValueRenderLocation) !void {1617 fn renderIntCast(dg: *DeclGen, w: anytype, dest_ty: Type, context: IntCastContext, src_ty: Type, location: ValueRenderLocation) !void {
2268 const target = dg.module.getTarget();1618 const target = dg.module.getTarget();
2269 const dest_bits = dest_ty.bitSize(target);1619 const dest_bits = dest_ty.bitSize(target);
...@@ -2284,36 +1634,41 @@ pub const DeclGen = struct {...@@ -2284,36 +1634,41 @@ pub const DeclGen = struct {
22841634
2285 if (needs_cast) {1635 if (needs_cast) {
2286 try w.writeByte('(');1636 try w.writeByte('(');
2287 try dg.renderTypecast(w, dest_ty);1637 try dg.renderType(w, dest_ty);
2288 try w.writeByte(')');1638 try w.writeByte(')');
2289 }1639 }
2290 if (src_is_ptr) {1640 if (src_is_ptr) {
2291 try w.writeByte('(');1641 try w.writeByte('(');
2292 try dg.renderTypecast(w, src_eff_ty);1642 try dg.renderType(w, src_eff_ty);
2293 try w.writeByte(')');1643 try w.writeByte(')');
2294 }1644 }
2295 try context.writeValue(dg, w, src_ty, location);1645 try context.writeValue(dg, w, src_ty, location);
2296 } else if (dest_bits <= 64 and src_bits > 64) {1646 } else if (dest_bits <= 64 and src_bits > 64) {
2297 assert(!src_is_ptr);1647 assert(!src_is_ptr);
1648 if (dest_bits < 64) {
1649 try w.writeByte('(');
1650 try dg.renderType(w, dest_ty);
1651 try w.writeByte(')');
1652 }
2298 try w.writeAll("zig_lo_");1653 try w.writeAll("zig_lo_");
2299 try dg.renderTypeForBuiltinFnName(w, src_eff_ty);1654 try dg.renderTypeForBuiltinFnName(w, src_eff_ty);
2300 try w.writeByte('(');1655 try w.writeByte('(');
2301 try context.writeValue(dg, w, src_ty, .FunctionArgument);1656 try context.writeValue(dg, w, src_ty, .FunctionArgument);
2302 try w.writeByte(')');1657 try w.writeByte(')');
2303 } else if (dest_bits > 64 and src_bits <= 64) {1658 } else if (dest_bits > 64 and src_bits <= 64) {
2304 try w.writeAll("zig_as_");1659 try w.writeAll("zig_make_");
2305 try dg.renderTypeForBuiltinFnName(w, dest_ty);1660 try dg.renderTypeForBuiltinFnName(w, dest_ty);
2306 try w.writeAll("(0, "); // TODO: Should the 0 go through fmtIntLiteral?1661 try w.writeAll("(0, "); // TODO: Should the 0 go through fmtIntLiteral?
2307 if (src_is_ptr) {1662 if (src_is_ptr) {
2308 try w.writeByte('(');1663 try w.writeByte('(');
2309 try dg.renderTypecast(w, src_eff_ty);1664 try dg.renderType(w, src_eff_ty);
2310 try w.writeByte(')');1665 try w.writeByte(')');
2311 }1666 }
2312 try context.writeValue(dg, w, src_ty, .FunctionArgument);1667 try context.writeValue(dg, w, src_ty, .FunctionArgument);
2313 try w.writeByte(')');1668 try w.writeByte(')');
2314 } else {1669 } else {
2315 assert(!src_is_ptr);1670 assert(!src_is_ptr);
2316 try w.writeAll("zig_as_");1671 try w.writeAll("zig_make_");
2317 try dg.renderTypeForBuiltinFnName(w, dest_ty);1672 try dg.renderTypeForBuiltinFnName(w, dest_ty);
2318 try w.writeAll("(zig_hi_");1673 try w.writeAll("(zig_hi_");
2319 try dg.renderTypeForBuiltinFnName(w, src_eff_ty);1674 try dg.renderTypeForBuiltinFnName(w, src_eff_ty);
...@@ -2327,151 +1682,50 @@ pub const DeclGen = struct {...@@ -2327,151 +1682,50 @@ pub const DeclGen = struct {
2327 }1682 }
2328 }1683 }
23291684
2330 /// Renders a type in C typecast format.
2331 ///
2332 /// This is guaranteed to be valid in a typecast expression, but not
2333 /// necessarily in a variable/field declaration.
2334 ///
2335 /// There are three type formats in total that we support rendering:
2336 /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) |
2337 /// |---------------------|-----------------|---------------------|
2338 /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" |
2339 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
2340 /// | `renderType` | "uint8_t *" | "zig_A_uint8_t_10" |
2341 ///
2342 fn renderTypecast(dg: *DeclGen, w: anytype, ty: Type) error{ OutOfMemory, AnalysisFail }!void {
2343 return renderTypeAndName(dg, w, ty, .{ .bytes = "" }, .Mut, 0, .Complete);
2344 }
2345
2346 /// Renders a type and name in field declaration/definition format.1685 /// Renders a type and name in field declaration/definition format.
2347 ///1686 ///
2348 /// There are three type formats in total that we support rendering:1687 /// There are three type formats in total that we support rendering:
2349 /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) |1688 /// | Function | Example 1 (*u8) | Example 2 ([10]*u8) |
2350 /// |---------------------|-----------------|---------------------|1689 /// |---------------------|-----------------|---------------------|
2351 /// | `renderTypecast` | "uint8_t *" | "uint8_t *[10]" |
2352 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |1690 /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
2353 /// | `renderType` | "uint8_t *" | "zig_A_uint8_t_10" |1691 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
2354 ///1692 ///
2355 fn renderTypeAndName(1693 fn renderTypeAndName(
2356 dg: *DeclGen,1694 dg: *DeclGen,
2357 w: anytype,1695 w: anytype,
2358 ty: Type,1696 ty: Type,
2359 name: CValue,1697 name: CValue,
2360 mutability: Mutability,1698 qualifiers: CQualifiers,
2361 alignment: u32,1699 alignment: u32,
2362 kind: TypedefKind,1700 kind: CType.Kind,
2363 ) error{ OutOfMemory, AnalysisFail }!void {1701 ) error{ OutOfMemory, AnalysisFail }!void {
2364 var suffix = std.ArrayList(u8).init(dg.gpa);
2365 defer suffix.deinit();
2366 const suffix_writer = suffix.writer();
2367
2368 // Any top-level array types are rendered here as a suffix, which
2369 // avoids creating typedefs for every array type
2370 const target = dg.module.getTarget();1702 const target = dg.module.getTarget();
2371 var render_ty = ty;1703 const alignas = CType.AlignAs.init(alignment, ty.abiAlignment(target));
2372 var depth: u32 = 0;1704 try dg.renderCTypeAndName(w, try dg.typeToIndex(ty, kind), name, qualifiers, alignas);
2373 while (loweredArrayInfo(render_ty, target)) |array_info| {
2374 const c_len = array_info.len + @boolToInt(array_info.sentinel != null);
2375 var c_len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = c_len };
2376 const c_len_val = Value.initPayload(&c_len_pl.base);
2377
2378 try suffix_writer.writeByte('[');
2379 if (mutability == .ConstArgument and depth == 0) try suffix_writer.writeAll("zig_const_arr ");
2380 try suffix.writer().print("{}]", .{try dg.fmtIntLiteral(Type.usize, c_len_val)});
2381 render_ty = array_info.elem_type;
2382 depth += 1;
2383 }
2384
2385 if (alignment != 0) {
2386 const abi_alignment = ty.abiAlignment(target);
2387 if (alignment < abi_alignment) {
2388 try w.print("zig_under_align({}) ", .{alignment});
2389 } else if (alignment > abi_alignment) {
2390 try w.print("zig_align({}) ", .{alignment});
2391 }
2392 }
2393 try dg.renderType(w, render_ty, kind);
2394
2395 const const_prefix = switch (mutability) {
2396 .Const, .ConstArgument => "const ",
2397 .Mut => "",
2398 };
2399 try w.print(" {s}", .{const_prefix});
2400 try dg.writeCValue(w, name);
2401 try w.writeAll(suffix.items);
2402 }1705 }
24031706
2404 fn renderTagNameFn(dg: *DeclGen, enum_ty: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {1707 fn renderCTypeAndName(
2405 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);1708 dg: *DeclGen,
2406 defer buffer.deinit();1709 w: anytype,
2407 const bw = buffer.writer();1710 cty_idx: CType.Index,
24081711 name: CValue,
2409 const name_slice_ty = Type.initTag(.const_slice_u8_sentinel_0);1712 qualifiers: CQualifiers,
24101713 alignas: CType.AlignAs,
2411 try buffer.appendSlice("static ");1714 ) error{ OutOfMemory, AnalysisFail }!void {
2412 try dg.renderType(bw, name_slice_ty, .Complete);1715 const store = &dg.ctypes.set;
2413 const name_begin = buffer.items.len + " ".len;1716 const module = dg.module;
2414 try bw.print(" zig_tagName_{}_{d}(", .{ typeToCIdentifier(enum_ty, dg.module), @enumToInt(enum_ty.getOwnerDecl()) });
2415 const name_end = buffer.items.len - "(".len;
2416 try dg.renderTypeAndName(bw, enum_ty, .{ .identifier = "tag" }, .Const, 0, .Complete);
2417 try buffer.appendSlice(") {\n switch (tag) {\n");
2418 for (enum_ty.enumFields().keys(), 0..) |name, index| {
2419 const name_z = try dg.typedefs.allocator.dupeZ(u8, name);
2420 defer dg.typedefs.allocator.free(name_z);
2421 const name_bytes = name_z[0 .. name_z.len + 1];
2422
2423 var tag_pl: Value.Payload.U32 = .{
2424 .base = .{ .tag = .enum_field_index },
2425 .data = @intCast(u32, index),
2426 };
2427 const tag_val = Value.initPayload(&tag_pl.base);
2428
2429 var int_pl: Value.Payload.U64 = undefined;
2430 const int_val = tag_val.enumToInt(enum_ty, &int_pl);
2431
2432 var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len };
2433 const name_ty = Type.initPayload(&name_ty_pl.base);
2434
2435 var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name_bytes };
2436 const name_val = Value.initPayload(&name_pl.base);
2437
2438 var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len };
2439 const len_val = Value.initPayload(&len_pl.base);
2440
2441 try bw.print(" case {}: {{\n static ", .{try dg.fmtIntLiteral(enum_ty, int_val)});
2442 try dg.renderTypeAndName(bw, name_ty, .{ .identifier = "name" }, .Const, 0, .Complete);
2443 try buffer.appendSlice(" = ");
2444 try dg.renderValue(bw, name_ty, name_val, .Initializer);
2445 try buffer.appendSlice(";\n return (");
2446 try dg.renderTypecast(bw, name_slice_ty);
2447 try bw.print("){{{}, {}}};\n", .{
2448 fmtIdent("name"), try dg.fmtIntLiteral(Type.usize, len_val),
2449 });
24501717
2451 try buffer.appendSlice(" }\n");1718 switch (std.math.order(alignas.@"align", alignas.abi)) {
1719 .lt => try w.print("zig_under_align({}) ", .{alignas.getAlign()}),
1720 .eq => {},
1721 .gt => try w.print("zig_align({}) ", .{alignas.getAlign()}),
2452 }1722 }
2453 try buffer.appendSlice(" }\n while (");
2454 try dg.renderValue(bw, Type.bool, Value.true, .Other);
2455 try buffer.appendSlice(") ");
2456 _ = try airBreakpoint(bw);
2457 try buffer.appendSlice("}\n");
2458
2459 const rendered = try buffer.toOwnedSlice();
2460 errdefer dg.typedefs.allocator.free(rendered);
2461 const name = rendered[name_begin..name_end];
2462
2463 try dg.typedefs.ensureUnusedCapacity(1);
2464 dg.typedefs.putAssumeCapacityNoClobber(
2465 try enum_ty.copy(dg.typedefs_arena),
2466 .{ .name = name, .rendered = rendered },
2467 );
2468
2469 return name;
2470 }
24711723
2472 fn getTagNameFn(dg: *DeclGen, enum_ty: Type) ![]const u8 {1724 const trailing =
2473 return dg.getTypedefName(enum_ty) orelse1725 try renderTypePrefix(dg.decl_index, store.*, module, w, cty_idx, .suffix, qualifiers);
2474 try dg.renderTagNameFn(enum_ty);1726 try w.print("{}", .{trailing});
1727 try dg.writeCValue(w, name);
1728 try renderTypeSuffix(dg.decl_index, store.*, module, w, cty_idx, .suffix, .{});
2475 }1729 }
24761730
2477 fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool {1731 fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool {
...@@ -2492,10 +1746,11 @@ pub const DeclGen = struct {...@@ -2492,10 +1746,11 @@ pub const DeclGen = struct {
2492 fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void {1746 fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void {
2493 switch (c_value) {1747 switch (c_value) {
2494 .none => unreachable,1748 .none => unreachable,
2495 .local => |i| return w.print("t{d}", .{i}),1749 .local, .new_local => |i| return w.print("t{d}", .{i}),
2496 .local_ref => |i| return w.print("&t{d}", .{i}),1750 .local_ref => |i| return w.print("&t{d}", .{i}),
2497 .constant => unreachable,1751 .constant => unreachable,
2498 .arg => |i| return w.print("a{d}", .{i}),1752 .arg => |i| return w.print("a{d}", .{i}),
1753 .arg_array => |i| return dg.writeCValueMember(w, .{ .arg = i }, .{ .identifier = "array" }),
2499 .field => |i| return w.print("f{d}", .{i}),1754 .field => |i| return w.print("f{d}", .{i}),
2500 .decl => |decl| return dg.renderDeclName(w, decl, 0),1755 .decl => |decl| return dg.renderDeclName(w, decl, 0),
2501 .decl_ref => |decl| {1756 .decl_ref => |decl| {
...@@ -2504,6 +1759,10 @@ pub const DeclGen = struct {...@@ -2504,6 +1759,10 @@ pub const DeclGen = struct {
2504 },1759 },
2505 .undef => |ty| return dg.renderValue(w, ty, Value.undef, .Other),1760 .undef => |ty| return dg.renderValue(w, ty, Value.undef, .Other),
2506 .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}),1761 .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}),
1762 .payload_identifier => |ident| return w.print("{ }.{ }", .{
1763 fmtIdent("payload"),
1764 fmtIdent(ident),
1765 }),
2507 .bytes => |bytes| return w.writeAll(bytes),1766 .bytes => |bytes| return w.writeAll(bytes),
2508 }1767 }
2509 }1768 }
...@@ -2511,10 +1770,15 @@ pub const DeclGen = struct {...@@ -2511,10 +1770,15 @@ pub const DeclGen = struct {
2511 fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void {1770 fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void {
2512 switch (c_value) {1771 switch (c_value) {
2513 .none => unreachable,1772 .none => unreachable,
2514 .local => |i| return w.print("(*t{d})", .{i}),1773 .local, .new_local => |i| return w.print("(*t{d})", .{i}),
2515 .local_ref => |i| return w.print("t{d}", .{i}),1774 .local_ref => |i| return w.print("t{d}", .{i}),
2516 .constant => unreachable,1775 .constant => unreachable,
2517 .arg => |i| return w.print("(*a{d})", .{i}),1776 .arg => |i| return w.print("(*a{d})", .{i}),
1777 .arg_array => |i| {
1778 try w.writeAll("(*");
1779 try dg.writeCValueMember(w, .{ .arg = i }, .{ .identifier = "array" });
1780 return w.writeByte(')');
1781 },
2518 .field => |i| return w.print("f{d}", .{i}),1782 .field => |i| return w.print("f{d}", .{i}),
2519 .decl => |decl| {1783 .decl => |decl| {
2520 try w.writeAll("(*");1784 try w.writeAll("(*");
...@@ -2524,6 +1788,10 @@ pub const DeclGen = struct {...@@ -2524,6 +1788,10 @@ pub const DeclGen = struct {
2524 .decl_ref => |decl| return dg.renderDeclName(w, decl, 0),1788 .decl_ref => |decl| return dg.renderDeclName(w, decl, 0),
2525 .undef => unreachable,1789 .undef => unreachable,
2526 .identifier => |ident| return w.print("(*{ })", .{fmtIdent(ident)}),1790 .identifier => |ident| return w.print("(*{ })", .{fmtIdent(ident)}),
1791 .payload_identifier => |ident| return w.print("(*{ }.{ })", .{
1792 fmtIdent("payload"),
1793 fmtIdent(ident),
1794 }),
2527 .bytes => |bytes| {1795 .bytes => |bytes| {
2528 try w.writeAll("(*");1796 try w.writeAll("(*");
2529 try w.writeAll(bytes);1797 try w.writeAll(bytes);
...@@ -2541,7 +1809,7 @@ pub const DeclGen = struct {...@@ -2541,7 +1809,7 @@ pub const DeclGen = struct {
2541 fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void {1809 fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void {
2542 switch (c_value) {1810 switch (c_value) {
2543 .none, .constant, .field, .undef => unreachable,1811 .none, .constant, .field, .undef => unreachable,
2544 .local, .arg, .decl, .identifier, .bytes => {1812 .new_local, .local, .arg, .arg_array, .decl, .identifier, .payload_identifier, .bytes => {
2545 try dg.writeCValue(writer, c_value);1813 try dg.writeCValue(writer, c_value);
2546 try writer.writeAll("->");1814 try writer.writeAll("->");
2547 },1815 },
...@@ -2668,13 +1936,466 @@ pub const DeclGen = struct {...@@ -2668,13 +1936,466 @@ pub const DeclGen = struct {
2668 }1936 }
2669};1937};
26701938
2671pub fn genGlobalAsm(mod: *Module, code: *std.ArrayList(u8)) !void {1939const CTypeFix = enum { prefix, suffix };
2672 var it = mod.global_assembly.valueIterator();1940const CQualifiers = std.enums.EnumSet(enum { @"const", @"volatile", restrict });
2673 while (it.next()) |asm_source| {1941const Const = CQualifiers.init(.{ .@"const" = true });
2674 try code.writer().print("__asm({s});\n", .{fmtStringLiteral(asm_source.*)});1942const RenderCTypeTrailing = enum {
1943 no_space,
1944 maybe_space,
1945
1946 pub fn format(
1947 self: @This(),
1948 comptime fmt: []const u8,
1949 _: std.fmt.FormatOptions,
1950 w: anytype,
1951 ) @TypeOf(w).Error!void {
1952 if (fmt.len != 0)
1953 @compileError("invalid format string '" ++ fmt ++ "' for type '" ++
1954 @typeName(@This()) ++ "'");
1955 comptime assert(fmt.len == 0);
1956 switch (self) {
1957 .no_space => {},
1958 .maybe_space => try w.writeByte(' '),
1959 }
1960 }
1961};
1962fn renderTypeName(
1963 mod: *Module,
1964 w: anytype,
1965 idx: CType.Index,
1966 cty: CType,
1967 attributes: []const u8,
1968) !void {
1969 switch (cty.tag()) {
1970 else => unreachable,
1971
1972 .fwd_anon_struct,
1973 .fwd_anon_union,
1974 => |tag| try w.print("{s} {s}anon__lazy_{d}", .{
1975 @tagName(tag)["fwd_anon_".len..],
1976 attributes,
1977 idx,
1978 }),
1979
1980 .fwd_struct,
1981 .fwd_union,
1982 => |tag| {
1983 const owner_decl = cty.cast(CType.Payload.FwdDecl).?.data;
1984 try w.print("{s} {s}{}__{d}", .{
1985 @tagName(tag)["fwd_".len..],
1986 attributes,
1987 fmtIdent(mem.span(mod.declPtr(owner_decl).name)),
1988 @enumToInt(owner_decl),
1989 });
1990 },
1991 }
1992}
1993fn renderTypePrefix(
1994 decl: Decl.OptionalIndex,
1995 store: CType.Store.Set,
1996 mod: *Module,
1997 w: anytype,
1998 idx: CType.Index,
1999 parent_fix: CTypeFix,
2000 qualifiers: CQualifiers,
2001) @TypeOf(w).Error!RenderCTypeTrailing {
2002 var trailing = RenderCTypeTrailing.maybe_space;
2003
2004 const cty = store.indexToCType(idx);
2005 switch (cty.tag()) {
2006 .void,
2007 .char,
2008 .@"signed char",
2009 .short,
2010 .int,
2011 .long,
2012 .@"long long",
2013 ._Bool,
2014 .@"unsigned char",
2015 .@"unsigned short",
2016 .@"unsigned int",
2017 .@"unsigned long",
2018 .@"unsigned long long",
2019 .float,
2020 .double,
2021 .@"long double",
2022 .bool,
2023 .size_t,
2024 .ptrdiff_t,
2025 .uint8_t,
2026 .int8_t,
2027 .uint16_t,
2028 .int16_t,
2029 .uint32_t,
2030 .int32_t,
2031 .uint64_t,
2032 .int64_t,
2033 .uintptr_t,
2034 .intptr_t,
2035 .zig_u128,
2036 .zig_i128,
2037 .zig_f16,
2038 .zig_f32,
2039 .zig_f64,
2040 .zig_f80,
2041 .zig_f128,
2042 .zig_c_longdouble,
2043 => |tag| try w.writeAll(@tagName(tag)),
2044
2045 .pointer,
2046 .pointer_const,
2047 .pointer_volatile,
2048 .pointer_const_volatile,
2049 => |tag| {
2050 const child_idx = cty.cast(CType.Payload.Child).?.data;
2051 const child_trailing = try renderTypePrefix(
2052 decl,
2053 store,
2054 mod,
2055 w,
2056 child_idx,
2057 .prefix,
2058 CQualifiers.init(.{ .@"const" = switch (tag) {
2059 .pointer, .pointer_volatile => false,
2060 .pointer_const, .pointer_const_volatile => true,
2061 else => unreachable,
2062 }, .@"volatile" = switch (tag) {
2063 .pointer, .pointer_const => false,
2064 .pointer_volatile, .pointer_const_volatile => true,
2065 else => unreachable,
2066 } }),
2067 );
2068 try w.print("{}*", .{child_trailing});
2069 trailing = .no_space;
2070 },
2071
2072 .array,
2073 .vector,
2074 => {
2075 const child_idx = cty.cast(CType.Payload.Sequence).?.data.elem_type;
2076 const child_trailing = try renderTypePrefix(
2077 decl,
2078 store,
2079 mod,
2080 w,
2081 child_idx,
2082 .suffix,
2083 qualifiers,
2084 );
2085 switch (parent_fix) {
2086 .prefix => {
2087 try w.print("{}(", .{child_trailing});
2088 return .no_space;
2089 },
2090 .suffix => return child_trailing,
2091 }
2092 },
2093
2094 .fwd_anon_struct,
2095 .fwd_anon_union,
2096 => if (decl.unwrap()) |decl_index|
2097 try w.print("anon__{d}_{d}", .{ @enumToInt(decl_index), idx })
2098 else
2099 try renderTypeName(mod, w, idx, cty, ""),
2100
2101 .fwd_struct,
2102 .fwd_union,
2103 => try renderTypeName(mod, w, idx, cty, ""),
2104
2105 .unnamed_struct,
2106 .unnamed_union,
2107 .packed_unnamed_struct,
2108 .packed_unnamed_union,
2109 => |tag| {
2110 try w.print("{s} {s}", .{
2111 @tagName(tag)["unnamed_".len..],
2112 if (cty.isPacked()) "zig_packed(" else "",
2113 });
2114 try renderAggregateFields(mod, w, store, cty, 1);
2115 if (cty.isPacked()) try w.writeByte(')');
2116 },
2117
2118 .anon_struct,
2119 .anon_union,
2120 .@"struct",
2121 .@"union",
2122 .packed_struct,
2123 .packed_union,
2124 => return renderTypePrefix(
2125 decl,
2126 store,
2127 mod,
2128 w,
2129 cty.cast(CType.Payload.Aggregate).?.data.fwd_decl,
2130 parent_fix,
2131 qualifiers,
2132 ),
2133
2134 .function,
2135 .varargs_function,
2136 => {
2137 const child_trailing = try renderTypePrefix(
2138 decl,
2139 store,
2140 mod,
2141 w,
2142 cty.cast(CType.Payload.Function).?.data.return_type,
2143 .suffix,
2144 .{},
2145 );
2146 switch (parent_fix) {
2147 .prefix => {
2148 try w.print("{}(", .{child_trailing});
2149 return .no_space;
2150 },
2151 .suffix => return child_trailing,
2152 }
2153 },
2154 }
2155
2156 var qualifier_it = qualifiers.iterator();
2157 while (qualifier_it.next()) |qualifier| {
2158 try w.print("{}{s}", .{ trailing, @tagName(qualifier) });
2159 trailing = .maybe_space;
2160 }
2161
2162 return trailing;
2163}
2164fn renderTypeSuffix(
2165 decl: Decl.OptionalIndex,
2166 store: CType.Store.Set,
2167 mod: *Module,
2168 w: anytype,
2169 idx: CType.Index,
2170 parent_fix: CTypeFix,
2171 qualifiers: CQualifiers,
2172) @TypeOf(w).Error!void {
2173 const cty = store.indexToCType(idx);
2174 switch (cty.tag()) {
2175 .void,
2176 .char,
2177 .@"signed char",
2178 .short,
2179 .int,
2180 .long,
2181 .@"long long",
2182 ._Bool,
2183 .@"unsigned char",
2184 .@"unsigned short",
2185 .@"unsigned int",
2186 .@"unsigned long",
2187 .@"unsigned long long",
2188 .float,
2189 .double,
2190 .@"long double",
2191 .bool,
2192 .size_t,
2193 .ptrdiff_t,
2194 .uint8_t,
2195 .int8_t,
2196 .uint16_t,
2197 .int16_t,
2198 .uint32_t,
2199 .int32_t,
2200 .uint64_t,
2201 .int64_t,
2202 .uintptr_t,
2203 .intptr_t,
2204 .zig_u128,
2205 .zig_i128,
2206 .zig_f16,
2207 .zig_f32,
2208 .zig_f64,
2209 .zig_f80,
2210 .zig_f128,
2211 .zig_c_longdouble,
2212 => {},
2213
2214 .pointer,
2215 .pointer_const,
2216 .pointer_volatile,
2217 .pointer_const_volatile,
2218 => try renderTypeSuffix(
2219 decl,
2220 store,
2221 mod,
2222 w,
2223 cty.cast(CType.Payload.Child).?.data,
2224 .prefix,
2225 .{},
2226 ),
2227
2228 .array,
2229 .vector,
2230 => {
2231 switch (parent_fix) {
2232 .prefix => try w.writeByte(')'),
2233 .suffix => {},
2234 }
2235
2236 try w.print("[{}]", .{cty.cast(CType.Payload.Sequence).?.data.len});
2237 try renderTypeSuffix(
2238 decl,
2239 store,
2240 mod,
2241 w,
2242 cty.cast(CType.Payload.Sequence).?.data.elem_type,
2243 .suffix,
2244 .{},
2245 );
2246 },
2247
2248 .fwd_anon_struct,
2249 .fwd_anon_union,
2250 .fwd_struct,
2251 .fwd_union,
2252 .unnamed_struct,
2253 .unnamed_union,
2254 .packed_unnamed_struct,
2255 .packed_unnamed_union,
2256 .anon_struct,
2257 .anon_union,
2258 .@"struct",
2259 .@"union",
2260 .packed_struct,
2261 .packed_union,
2262 => {},
2263
2264 .function,
2265 .varargs_function,
2266 => |tag| {
2267 switch (parent_fix) {
2268 .prefix => try w.writeByte(')'),
2269 .suffix => {},
2270 }
2271
2272 const data = cty.cast(CType.Payload.Function).?.data;
2273
2274 try w.writeByte('(');
2275 var need_comma = false;
2276 for (data.param_types, 0..) |param_type, param_i| {
2277 if (need_comma) try w.writeAll(", ");
2278 need_comma = true;
2279 const trailing =
2280 try renderTypePrefix(decl, store, mod, w, param_type, .suffix, qualifiers);
2281 if (qualifiers.contains(.@"const")) try w.print("{}a{d}", .{ trailing, param_i });
2282 try renderTypeSuffix(decl, store, mod, w, param_type, .suffix, .{});
2283 }
2284 switch (tag) {
2285 .function => {},
2286 .varargs_function => {
2287 if (need_comma) try w.writeAll(", ");
2288 need_comma = true;
2289 try w.writeAll("...");
2290 },
2291 else => unreachable,
2292 }
2293 if (!need_comma) try w.writeAll("void");
2294 try w.writeByte(')');
2295
2296 try renderTypeSuffix(decl, store, mod, w, data.return_type, .suffix, .{});
2297 },
2298 }
2299}
2300fn renderAggregateFields(
2301 mod: *Module,
2302 writer: anytype,
2303 store: CType.Store.Set,
2304 cty: CType,
2305 indent: usize,
2306) !void {
2307 try writer.writeAll("{\n");
2308 const fields = cty.fields();
2309 for (fields) |field| {
2310 try writer.writeByteNTimes(' ', indent + 1);
2311 switch (std.math.order(field.alignas.@"align", field.alignas.abi)) {
2312 .lt => try writer.print("zig_under_align({}) ", .{field.alignas.getAlign()}),
2313 .eq => {},
2314 .gt => try writer.print("zig_align({}) ", .{field.alignas.getAlign()}),
2315 }
2316 const trailing = try renderTypePrefix(.none, store, mod, writer, field.type, .suffix, .{});
2317 try writer.print("{}{ }", .{ trailing, fmtIdent(mem.span(field.name)) });
2318 try renderTypeSuffix(.none, store, mod, writer, field.type, .suffix, .{});
2319 try writer.writeAll(";\n");
2320 }
2321 try writer.writeByteNTimes(' ', indent);
2322 try writer.writeByte('}');
2323}
2324
2325pub fn genTypeDecl(
2326 mod: *Module,
2327 writer: anytype,
2328 global_store: CType.Store.Set,
2329 global_idx: CType.Index,
2330 decl: Decl.OptionalIndex,
2331 decl_store: CType.Store.Set,
2332 decl_idx: CType.Index,
2333 found_existing: bool,
2334) !void {
2335 const global_cty = global_store.indexToCType(global_idx);
2336 switch (global_cty.tag()) {
2337 .fwd_anon_struct => if (decl != .none) {
2338 try writer.writeAll("typedef ");
2339 _ = try renderTypePrefix(.none, global_store, mod, writer, global_idx, .suffix, .{});
2340 try writer.writeByte(' ');
2341 _ = try renderTypePrefix(decl, decl_store, mod, writer, decl_idx, .suffix, .{});
2342 try writer.writeAll(";\n");
2343 },
2344
2345 .fwd_struct,
2346 .fwd_union,
2347 .anon_struct,
2348 .anon_union,
2349 .@"struct",
2350 .@"union",
2351 .packed_struct,
2352 .packed_union,
2353 => |tag| if (!found_existing) {
2354 switch (tag) {
2355 .fwd_struct,
2356 .fwd_union,
2357 => {
2358 const owner_decl = global_cty.cast(CType.Payload.FwdDecl).?.data;
2359 _ = try renderTypePrefix(.none, global_store, mod, writer, global_idx, .suffix, .{});
2360 try writer.writeAll("; // ");
2361 try mod.declPtr(owner_decl).renderFullyQualifiedName(mod, writer);
2362 try writer.writeByte('\n');
2363 },
2364
2365 .anon_struct,
2366 .anon_union,
2367 .@"struct",
2368 .@"union",
2369 .packed_struct,
2370 .packed_union,
2371 => {
2372 const fwd_idx = global_cty.cast(CType.Payload.Aggregate).?.data.fwd_decl;
2373 try renderTypeName(
2374 mod,
2375 writer,
2376 fwd_idx,
2377 global_store.indexToCType(fwd_idx),
2378 if (global_cty.isPacked()) "zig_packed(" else "",
2379 );
2380 try writer.writeByte(' ');
2381 try renderAggregateFields(mod, writer, global_store, global_cty, 0);
2382 if (global_cty.isPacked()) try writer.writeByte(')');
2383 try writer.writeAll(";\n");
2384 },
2385
2386 else => unreachable,
2387 }
2388 },
2389
2390 else => {},
2675 }2391 }
2676}2392}
26772393
2394pub fn genGlobalAsm(mod: *Module, writer: anytype) !void {
2395 var it = mod.global_assembly.valueIterator();
2396 while (it.next()) |asm_source| try writer.print("__asm({s});\n", .{fmtStringLiteral(asm_source.*, null)});
2397}
2398
2678pub fn genErrDecls(o: *Object) !void {2399pub fn genErrDecls(o: *Object) !void {
2679 const writer = o.writer();2400 const writer = o.writer();
26802401
...@@ -2690,26 +2411,24 @@ pub fn genErrDecls(o: *Object) !void {...@@ -2690,26 +2411,24 @@ pub fn genErrDecls(o: *Object) !void {
2690 o.indent_writer.popIndent();2411 o.indent_writer.popIndent();
2691 try writer.writeAll("};\n");2412 try writer.writeAll("};\n");
26922413
2693 const name_prefix = "zig_errorName";2414 const array_identifier = "zig_errorName";
2694 const name_buf = try o.dg.gpa.alloc(u8, name_prefix.len + "_".len + max_name_len + 1);2415 const name_prefix = array_identifier ++ "_";
2416 const name_buf = try o.dg.gpa.alloc(u8, name_prefix.len + max_name_len);
2695 defer o.dg.gpa.free(name_buf);2417 defer o.dg.gpa.free(name_buf);
26962418
2697 std.mem.copy(u8, name_buf, name_prefix ++ "_");2419 std.mem.copy(u8, name_buf, name_prefix);
2698 for (o.dg.module.error_name_list.items) |name| {2420 for (o.dg.module.error_name_list.items) |name| {
2699 std.mem.copy(u8, name_buf[name_prefix.len + "_".len ..], name);2421 std.mem.copy(u8, name_buf[name_prefix.len..], name);
2700 name_buf[name_prefix.len + "_".len + name.len] = 0;2422 const identifier = name_buf[0 .. name_prefix.len + name.len];
2701
2702 const identifier = name_buf[0 .. name_prefix.len + "_".len + name.len :0];
2703 const name_z = identifier[name_prefix.len + "_".len ..];
27042423
2705 var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len };2424 var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len };
2706 const name_ty = Type.initPayload(&name_ty_pl.base);2425 const name_ty = Type.initPayload(&name_ty_pl.base);
27072426
2708 var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name_z };2427 var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name };
2709 const name_val = Value.initPayload(&name_pl.base);2428 const name_val = Value.initPayload(&name_pl.base);
27102429
2711 try writer.writeAll("static ");2430 try writer.writeAll("static ");
2712 try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .Const, 0, .Complete);2431 try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, Const, 0, .complete);
2713 try writer.writeAll(" = ");2432 try writer.writeAll(" = ");
2714 try o.dg.renderValue(writer, name_ty, name_val, .StaticInitializer);2433 try o.dg.renderValue(writer, name_ty, name_val, .StaticInitializer);
2715 try writer.writeAll(";\n");2434 try writer.writeAll(";\n");
...@@ -2722,7 +2441,7 @@ pub fn genErrDecls(o: *Object) !void {...@@ -2722,7 +2441,7 @@ pub fn genErrDecls(o: *Object) !void {
2722 const name_array_ty = Type.initPayload(&name_array_ty_pl.base);2441 const name_array_ty = Type.initPayload(&name_array_ty_pl.base);
27232442
2724 try writer.writeAll("static ");2443 try writer.writeAll("static ");
2725 try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = name_prefix }, .Const, 0, .Complete);2444 try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = array_identifier }, Const, 0, .complete);
2726 try writer.writeAll(" = {");2445 try writer.writeAll(" = {");
2727 for (o.dg.module.error_name_list.items, 0..) |name, value| {2446 for (o.dg.module.error_name_list.items, 0..) |name, value| {
2728 if (value != 0) try writer.writeByte(',');2447 if (value != 0) try writer.writeByte(',');
...@@ -2730,7 +2449,7 @@ pub fn genErrDecls(o: *Object) !void {...@@ -2730,7 +2449,7 @@ pub fn genErrDecls(o: *Object) !void {
2730 var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len };2449 var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len };
2731 const len_val = Value.initPayload(&len_pl.base);2450 const len_val = Value.initPayload(&len_pl.base);
27322451
2733 try writer.print("{{" ++ name_prefix ++ "_{}, {}}}", .{2452 try writer.print("{{" ++ name_prefix ++ "{}, {}}}", .{
2734 fmtIdent(name), try o.dg.fmtIntLiteral(Type.usize, len_val),2453 fmtIdent(name), try o.dg.fmtIntLiteral(Type.usize, len_val),
2735 });2454 });
2736 }2455 }
...@@ -2742,14 +2461,95 @@ fn genExports(o: *Object) !void {...@@ -2742,14 +2461,95 @@ fn genExports(o: *Object) !void {
2742 defer tracy.end();2461 defer tracy.end();
27432462
2744 const fwd_decl_writer = o.dg.fwd_decl.writer();2463 const fwd_decl_writer = o.dg.fwd_decl.writer();
2745 if (o.dg.module.decl_exports.get(o.dg.decl_index)) |exports| for (exports.items[1..], 0..) |@"export", i| {2464 if (o.dg.module.decl_exports.get(o.dg.decl_index.unwrap().?)) |exports| {
2746 try fwd_decl_writer.writeAll("zig_export(");2465 for (exports.items[1..], 1..) |@"export", i| {
2747 try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward, @intCast(u32, 1 + i));2466 try fwd_decl_writer.writeAll("zig_export(");
2748 try fwd_decl_writer.print(", {s}, {s});\n", .{2467 try o.dg.renderFunctionSignature(fwd_decl_writer, o.dg.decl_index.unwrap().?, .forward, .{ .export_index = @intCast(u32, i) });
2749 fmtStringLiteral(exports.items[0].options.name),2468 try fwd_decl_writer.print(", {s}, {s});\n", .{
2750 fmtStringLiteral(@"export".options.name),2469 fmtStringLiteral(exports.items[0].options.name, null),
2751 });2470 fmtStringLiteral(@"export".options.name, null),
2752 };2471 });
2472 }
2473 }
2474}
2475
2476pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
2477 const w = o.writer();
2478 const key = lazy_fn.key_ptr.*;
2479 const val = lazy_fn.value_ptr;
2480 const fn_name = val.fn_name;
2481 switch (key) {
2482 .tag_name => {
2483 const enum_ty = val.data.tag_name;
2484
2485 const name_slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
2486
2487 try w.writeAll("static ");
2488 try o.dg.renderType(w, name_slice_ty);
2489 try w.writeByte(' ');
2490 try w.writeAll(fn_name);
2491 try w.writeByte('(');
2492 try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, 0, .complete);
2493 try w.writeAll(") {\n switch (tag) {\n");
2494 for (enum_ty.enumFields().keys(), 0..) |name, index| {
2495 var tag_pl: Value.Payload.U32 = .{
2496 .base = .{ .tag = .enum_field_index },
2497 .data = @intCast(u32, index),
2498 };
2499 const tag_val = Value.initPayload(&tag_pl.base);
2500
2501 var int_pl: Value.Payload.U64 = undefined;
2502 const int_val = tag_val.enumToInt(enum_ty, &int_pl);
2503
2504 var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len };
2505 const name_ty = Type.initPayload(&name_ty_pl.base);
2506
2507 var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name };
2508 const name_val = Value.initPayload(&name_pl.base);
2509
2510 var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len };
2511 const len_val = Value.initPayload(&len_pl.base);
2512
2513 try w.print(" case {}: {{\n static ", .{try o.dg.fmtIntLiteral(enum_ty, int_val)});
2514 try o.dg.renderTypeAndName(w, name_ty, .{ .identifier = "name" }, Const, 0, .complete);
2515 try w.writeAll(" = ");
2516 try o.dg.renderValue(w, name_ty, name_val, .Initializer);
2517 try w.writeAll(";\n return (");
2518 try o.dg.renderType(w, name_slice_ty);
2519 try w.print("){{{}, {}}};\n", .{
2520 fmtIdent("name"), try o.dg.fmtIntLiteral(Type.usize, len_val),
2521 });
2522
2523 try w.writeAll(" }\n");
2524 }
2525 try w.writeAll(" }\n while (");
2526 try o.dg.renderValue(w, Type.bool, Value.true, .Other);
2527 try w.writeAll(") ");
2528 _ = try airBreakpoint(w);
2529 try w.writeAll("}\n");
2530 },
2531 .never_tail, .never_inline => |fn_decl_index| {
2532 const fn_decl = o.dg.module.declPtr(fn_decl_index);
2533 const fn_cty = try o.dg.typeToCType(fn_decl.ty, .complete);
2534 const fn_info = fn_cty.cast(CType.Payload.Function).?.data;
2535
2536 const fwd_decl_writer = o.dg.fwd_decl.writer();
2537 try fwd_decl_writer.print("static zig_{s} ", .{@tagName(key)});
2538 try o.dg.renderFunctionSignature(fwd_decl_writer, fn_decl_index, .forward, .{ .string = fn_name });
2539 try fwd_decl_writer.writeAll(";\n");
2540
2541 try w.print("static zig_{s} ", .{@tagName(key)});
2542 try o.dg.renderFunctionSignature(w, fn_decl_index, .complete, .{ .string = fn_name });
2543 try w.writeAll(" {\n return ");
2544 try o.dg.renderDeclName(w, fn_decl_index, 0);
2545 try w.writeByte('(');
2546 for (0..fn_info.param_types.len) |arg| {
2547 if (arg > 0) try w.writeAll(", ");
2548 try o.dg.writeCValue(w, .{ .arg = arg });
2549 }
2550 try w.writeAll(");\n}\n");
2551 },
2552 }
2753}2553}
27542554
2755pub fn genFunc(f: *Function) !void {2555pub fn genFunc(f: *Function) !void {
...@@ -2758,9 +2558,10 @@ pub fn genFunc(f: *Function) !void {...@@ -2758,9 +2558,10 @@ pub fn genFunc(f: *Function) !void {
27582558
2759 const o = &f.object;2559 const o = &f.object;
2760 const gpa = o.dg.gpa;2560 const gpa = o.dg.gpa;
2561 const decl_index = o.dg.decl_index.unwrap().?;
2761 const tv: TypedValue = .{2562 const tv: TypedValue = .{
2762 .ty = o.dg.decl.ty,2563 .ty = o.dg.decl.?.ty,
2763 .val = o.dg.decl.val,2564 .val = o.dg.decl.?.val,
2764 };2565 };
27652566
2766 o.code_header = std.ArrayList(u8).init(gpa);2567 o.code_header = std.ArrayList(u8).init(gpa);
...@@ -2769,13 +2570,13 @@ pub fn genFunc(f: *Function) !void {...@@ -2769,13 +2570,13 @@ pub fn genFunc(f: *Function) !void {
2769 const is_global = o.dg.declIsGlobal(tv);2570 const is_global = o.dg.declIsGlobal(tv);
2770 const fwd_decl_writer = o.dg.fwd_decl.writer();2571 const fwd_decl_writer = o.dg.fwd_decl.writer();
2771 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");2572 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
2772 try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward, 0);2573 try o.dg.renderFunctionSignature(fwd_decl_writer, decl_index, .forward, .{ .export_index = 0 });
2773 try fwd_decl_writer.writeAll(";\n");2574 try fwd_decl_writer.writeAll(";\n");
2774 try genExports(o);2575 try genExports(o);
27752576
2776 try o.indent_writer.insertNewline();2577 try o.indent_writer.insertNewline();
2777 if (!is_global) try o.writer().writeAll("static ");2578 if (!is_global) try o.writer().writeAll("static ");
2778 try o.dg.renderFunctionSignature(o.writer(), .Complete, 0);2579 try o.dg.renderFunctionSignature(o.writer(), decl_index, .complete, .{ .export_index = 0 });
2779 try o.writer().writeByte(' ');2580 try o.writer().writeByte(' ');
27802581
2781 // In case we need to use the header, populate it with a copy of the function2582 // In case we need to use the header, populate it with a copy of the function
...@@ -2799,41 +2600,31 @@ pub fn genFunc(f: *Function) !void {...@@ -2799,41 +2600,31 @@ pub fn genFunc(f: *Function) !void {
2799 // missing. These are added now to complete the map. Then we can sort by2600 // missing. These are added now to complete the map. Then we can sort by
2800 // alignment, descending.2601 // alignment, descending.
2801 const free_locals = f.getFreeLocals();2602 const free_locals = f.getFreeLocals();
2802 const values = f.allocs.values();2603 for (f.allocs.keys(), f.allocs.values()) |local_index, value| {
2803 for (f.allocs.keys(), 0..) |local_index, i| {2604 if (value) continue; // static
2804 if (values[i]) continue; // static
2805 const local = f.locals.items[local_index];2605 const local = f.locals.items[local_index];
2806 log.debug("inserting local {d} into free_locals", .{local_index});2606 log.debug("inserting local {d} into free_locals", .{local_index});
2807 const gop = try free_locals.getOrPutContext(gpa, local.ty, f.tyHashCtx());2607 const gop = try free_locals.getOrPut(gpa, local.getType());
2808 if (!gop.found_existing) gop.value_ptr.* = .{};2608 if (!gop.found_existing) gop.value_ptr.* = .{};
2809 try gop.value_ptr.append(gpa, local_index);2609 try gop.value_ptr.putNoClobber(gpa, local_index, {});
2810 }2610 }
28112611
2812 const SortContext = struct {2612 const SortContext = struct {
2813 target: std.Target,2613 keys: []const LocalType,
2814 keys: []const Type,
28152614
2816 pub fn lessThan(ctx: @This(), a_index: usize, b_index: usize) bool {2615 pub fn lessThan(ctx: @This(), lhs_index: usize, rhs_index: usize) bool {
2817 const a_ty = ctx.keys[a_index];2616 const lhs_ty = ctx.keys[lhs_index];
2818 const b_ty = ctx.keys[b_index];2617 const rhs_ty = ctx.keys[rhs_index];
2819 return b_ty.abiAlignment(ctx.target) < a_ty.abiAlignment(ctx.target);2618 return lhs_ty.alignas.getAlign() > rhs_ty.alignas.getAlign();
2820 }2619 }
2821 };2620 };
2822 const target = o.dg.module.getTarget();2621 free_locals.sort(SortContext{ .keys = free_locals.keys() });
2823 free_locals.sort(SortContext{ .target = target, .keys = free_locals.keys() });
28242622
2825 const w = o.code_header.writer();2623 const w = o.code_header.writer();
2826 for (free_locals.values()) |list| {2624 for (free_locals.values()) |list| {
2827 for (list.items) |local_index| {2625 for (list.keys()) |local_index| {
2828 const local = f.locals.items[local_index];2626 const local = f.locals.items[local_index];
2829 try o.dg.renderTypeAndName(2627 try o.dg.renderCTypeAndName(w, local.cty_idx, .{ .local = local_index }, .{}, local.alignas);
2830 w,
2831 local.ty,
2832 .{ .local = local_index },
2833 .Mut,
2834 local.alignment,
2835 .Complete,
2836 );
2837 try w.writeAll(";\n ");2628 try w.writeAll(";\n ");
2838 }2629 }
2839 }2630 }
...@@ -2850,15 +2641,15 @@ pub fn genDecl(o: *Object) !void {...@@ -2850,15 +2641,15 @@ pub fn genDecl(o: *Object) !void {
2850 const tracy = trace(@src());2641 const tracy = trace(@src());
2851 defer tracy.end();2642 defer tracy.end();
28522643
2853 const tv: TypedValue = .{2644 const decl = o.dg.decl.?;
2854 .ty = o.dg.decl.ty,2645 const decl_c_value = .{ .decl = o.dg.decl_index.unwrap().? };
2855 .val = o.dg.decl.val,2646 const tv: TypedValue = .{ .ty = decl.ty, .val = decl.val };
2856 };2647
2857 if (!tv.ty.isFnOrHasRuntimeBitsIgnoreComptime()) return;2648 if (!tv.ty.isFnOrHasRuntimeBitsIgnoreComptime()) return;
2858 if (tv.val.tag() == .extern_fn) {2649 if (tv.val.tag() == .extern_fn) {
2859 const fwd_decl_writer = o.dg.fwd_decl.writer();2650 const fwd_decl_writer = o.dg.fwd_decl.writer();
2860 try fwd_decl_writer.writeAll("zig_extern ");2651 try fwd_decl_writer.writeAll("zig_extern ");
2861 try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward, 0);2652 try o.dg.renderFunctionSignature(fwd_decl_writer, decl_c_value.decl, .forward, .{ .export_index = 0 });
2862 try fwd_decl_writer.writeAll(";\n");2653 try fwd_decl_writer.writeAll(";\n");
2863 try genExports(o);2654 try genExports(o);
2864 } else if (tv.val.castTag(.variable)) |var_payload| {2655 } else if (tv.val.castTag(.variable)) |var_payload| {
...@@ -2867,11 +2658,9 @@ pub fn genDecl(o: *Object) !void {...@@ -2867,11 +2658,9 @@ pub fn genDecl(o: *Object) !void {
2867 const is_global = o.dg.declIsGlobal(tv) or variable.is_extern;2658 const is_global = o.dg.declIsGlobal(tv) or variable.is_extern;
2868 const fwd_decl_writer = o.dg.fwd_decl.writer();2659 const fwd_decl_writer = o.dg.fwd_decl.writer();
28692660
2870 const decl_c_value = CValue{ .decl = o.dg.decl_index };
2871
2872 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");2661 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
2873 if (variable.is_threadlocal) try fwd_decl_writer.writeAll("zig_threadlocal ");2662 if (variable.is_threadlocal) try fwd_decl_writer.writeAll("zig_threadlocal ");
2874 try o.dg.renderTypeAndName(fwd_decl_writer, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete);2663 try o.dg.renderTypeAndName(fwd_decl_writer, decl.ty, decl_c_value, .{}, decl.@"align", .complete);
2875 try fwd_decl_writer.writeAll(";\n");2664 try fwd_decl_writer.writeAll(";\n");
2876 try genExports(o);2665 try genExports(o);
28772666
...@@ -2880,27 +2669,26 @@ pub fn genDecl(o: *Object) !void {...@@ -2880,27 +2669,26 @@ pub fn genDecl(o: *Object) !void {
2880 const w = o.writer();2669 const w = o.writer();
2881 if (!is_global) try w.writeAll("static ");2670 if (!is_global) try w.writeAll("static ");
2882 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");2671 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");
2883 if (o.dg.decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});2672 if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});
2884 try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete);2673 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.@"align", .complete);
2885 if (o.dg.decl.@"linksection" != null) try w.writeAll(", read, write)");2674 if (decl.@"linksection" != null) try w.writeAll(", read, write)");
2886 try w.writeAll(" = ");2675 try w.writeAll(" = ");
2887 try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer);2676 try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer);
2888 try w.writeByte(';');2677 try w.writeByte(';');
2889 try o.indent_writer.insertNewline();2678 try o.indent_writer.insertNewline();
2890 } else {2679 } else {
2891 const is_global = o.dg.module.decl_exports.contains(o.dg.decl_index);2680 const is_global = o.dg.module.decl_exports.contains(decl_c_value.decl);
2892 const fwd_decl_writer = o.dg.fwd_decl.writer();2681 const fwd_decl_writer = o.dg.fwd_decl.writer();
2893 const decl_c_value: CValue = .{ .decl = o.dg.decl_index };
28942682
2895 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");2683 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
2896 try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, .Const, o.dg.decl.@"align", .Complete);2684 try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, decl.@"align", .complete);
2897 try fwd_decl_writer.writeAll(";\n");2685 try fwd_decl_writer.writeAll(";\n");
28982686
2899 const w = o.writer();2687 const w = o.writer();
2900 if (!is_global) try w.writeAll("static ");2688 if (!is_global) try w.writeAll("static ");
2901 if (o.dg.decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});2689 if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section});
2902 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .Const, o.dg.decl.@"align", .Complete);2690 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, Const, decl.@"align", .complete);
2903 if (o.dg.decl.@"linksection" != null) try w.writeAll(", read)");2691 if (decl.@"linksection" != null) try w.writeAll(", read)");
2904 try w.writeAll(" = ");2692 try w.writeAll(" = ");
2905 try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);2693 try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);
2906 try w.writeAll(";\n");2694 try w.writeAll(";\n");
...@@ -2912,8 +2700,8 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {...@@ -2912,8 +2700,8 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
2912 defer tracy.end();2700 defer tracy.end();
29132701
2914 const tv: TypedValue = .{2702 const tv: TypedValue = .{
2915 .ty = dg.decl.ty,2703 .ty = dg.decl.?.ty,
2916 .val = dg.decl.val,2704 .val = dg.decl.?.val,
2917 };2705 };
2918 const writer = dg.fwd_decl.writer();2706 const writer = dg.fwd_decl.writer();
29192707
...@@ -2922,7 +2710,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {...@@ -2922,7 +2710,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
2922 const is_global = dg.declIsGlobal(tv);2710 const is_global = dg.declIsGlobal(tv);
2923 if (is_global) {2711 if (is_global) {
2924 try writer.writeAll("zig_extern ");2712 try writer.writeAll("zig_extern ");
2925 try dg.renderFunctionSignature(writer, .Complete, 0);2713 try dg.renderFunctionSignature(writer, dg.decl_index.unwrap().?, .complete, .{ .export_index = 0 });
2926 try dg.fwd_decl.appendSlice(";\n");2714 try dg.fwd_decl.appendSlice(";\n");
2927 }2715 }
2928 },2716 },
...@@ -2951,7 +2739,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -2951,7 +2739,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
2951 // zig fmt: off2739 // zig fmt: off
2952 .constant => unreachable, // excluded from function bodies2740 .constant => unreachable, // excluded from function bodies
2953 .const_ty => unreachable, // excluded from function bodies2741 .const_ty => unreachable, // excluded from function bodies
2954 .arg => airArg(f),2742 .arg => try airArg(f, inst),
29552743
2956 .breakpoint => try airBreakpoint(f.object.writer()),2744 .breakpoint => try airBreakpoint(f.object.writer()),
2957 .ret_addr => try airRetAddr(f, inst),2745 .ret_addr => try airRetAddr(f, inst),
...@@ -3112,10 +2900,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -3112,10 +2900,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
31122900
3113 .dbg_block_begin,2901 .dbg_block_begin,
3114 .dbg_block_end,2902 .dbg_block_end,
3115 => CValue{ .none = {} },2903 => .none,
31162904
3117 .call => try airCall(f, inst, .auto),2905 .call => try airCall(f, inst, .auto),
3118 .call_always_tail => try airCall(f, inst, .always_tail),2906 .call_always_tail => .none,
3119 .call_never_tail => try airCall(f, inst, .never_tail),2907 .call_never_tail => try airCall(f, inst, .never_tail),
3120 .call_never_inline => try airCall(f, inst, .never_inline),2908 .call_never_inline => try airCall(f, inst, .never_inline),
31212909
...@@ -3194,19 +2982,20 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -3194,19 +2982,20 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
3194 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),2982 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
3195 .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}),2983 .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}),
31962984
3197 .c_va_arg => return f.fail("TODO implement c_va_arg", .{}),2985 .c_va_start => try airCVaStart(f, inst),
3198 .c_va_copy => return f.fail("TODO implement c_va_copy", .{}),2986 .c_va_arg => try airCVaArg(f, inst),
3199 .c_va_end => return f.fail("TODO implement c_va_end", .{}),2987 .c_va_end => try airCVaEnd(f, inst),
3200 .c_va_start => return f.fail("TODO implement c_va_start", .{}),2988 .c_va_copy => try airCVaCopy(f, inst),
3201 // zig fmt: on2989 // zig fmt: on
3202 };2990 };
3203 if (result_value == .local) {2991 if (result_value == .new_local) {
3204 log.debug("map %{d} to t{d}", .{ inst, result_value.local });2992 log.debug("map %{d} to t{d}", .{ inst, result_value.new_local });
3205 }
3206 switch (result_value) {
3207 .none => {},
3208 else => try f.value_map.putNoClobber(Air.indexToRef(inst), result_value),
3209 }2993 }
2994 try f.value_map.putNoClobber(Air.indexToRef(inst), switch (result_value) {
2995 .none => continue,
2996 .new_local => |i| .{ .local = i },
2997 else => result_value,
2998 });
3210 }2999 }
3211}3000}
32123001
...@@ -3215,7 +3004,7 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [...@@ -3215,7 +3004,7 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [
32153004
3216 if (f.liveness.isUnused(inst)) {3005 if (f.liveness.isUnused(inst)) {
3217 try reap(f, inst, &.{ty_op.operand});3006 try reap(f, inst, &.{ty_op.operand});
3218 return CValue.none;3007 return .none;
3219 }3008 }
32203009
3221 const inst_ty = f.air.typeOfIndex(inst);3010 const inst_ty = f.air.typeOfIndex(inst);
...@@ -3241,7 +3030,7 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3241,7 +3030,7 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
3241 !inst_ty.hasRuntimeBitsIgnoreComptime())3030 !inst_ty.hasRuntimeBitsIgnoreComptime())
3242 {3031 {
3243 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3032 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3244 return CValue.none;3033 return .none;
3245 }3034 }
32463035
3247 const ptr = try f.resolveInst(bin_op.lhs);3036 const ptr = try f.resolveInst(bin_op.lhs);
...@@ -3267,7 +3056,7 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3267,7 +3056,7 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
3267 try writer.writeByte(']');3056 try writer.writeByte(']');
3268 if (is_array) {3057 if (is_array) {
3269 try writer.writeAll(", sizeof(");3058 try writer.writeAll(", sizeof(");
3270 try f.renderTypecast(writer, inst_ty);3059 try f.renderType(writer, inst_ty);
3271 try writer.writeAll("))");3060 try writer.writeAll("))");
3272 }3061 }
3273 try writer.writeAll(";\n");3062 try writer.writeAll(";\n");
...@@ -3280,9 +3069,10 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3280,9 +3069,10 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
32803069
3281 if (f.liveness.isUnused(inst)) {3070 if (f.liveness.isUnused(inst)) {
3282 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3071 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3283 return CValue.none;3072 return .none;
3284 }3073 }
32853074
3075 const inst_ty = f.air.typeOfIndex(inst);
3286 const ptr_ty = f.air.typeOf(bin_op.lhs);3076 const ptr_ty = f.air.typeOf(bin_op.lhs);
3287 const child_ty = ptr_ty.childType();3077 const child_ty = ptr_ty.childType();
32883078
...@@ -3297,7 +3087,9 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3297,7 +3087,9 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3297 const writer = f.object.writer();3087 const writer = f.object.writer();
3298 const local = try f.allocLocal(inst, f.air.typeOfIndex(inst));3088 const local = try f.allocLocal(inst, f.air.typeOfIndex(inst));
3299 try f.writeCValue(writer, local, .Other);3089 try f.writeCValue(writer, local, .Other);
3300 try writer.writeAll(" = &(");3090 try writer.writeAll(" = (");
3091 try f.renderType(writer, inst_ty);
3092 try writer.writeAll(")&(");
3301 if (ptr_ty.ptrSize() == .One) {3093 if (ptr_ty.ptrSize() == .One) {
3302 // It's a pointer to an array, so we need to de-reference.3094 // It's a pointer to an array, so we need to de-reference.
3303 try f.writeCValueDeref(writer, ptr);3095 try f.writeCValueDeref(writer, ptr);
...@@ -3318,7 +3110,7 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3318,7 +3110,7 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
3318 !inst_ty.hasRuntimeBitsIgnoreComptime())3110 !inst_ty.hasRuntimeBitsIgnoreComptime())
3319 {3111 {
3320 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3112 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3321 return CValue.none;3113 return .none;
3322 }3114 }
33233115
3324 const slice = try f.resolveInst(bin_op.lhs);3116 const slice = try f.resolveInst(bin_op.lhs);
...@@ -3344,7 +3136,7 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3344,7 +3136,7 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
3344 try writer.writeByte(']');3136 try writer.writeByte(']');
3345 if (is_array) {3137 if (is_array) {
3346 try writer.writeAll(", sizeof(");3138 try writer.writeAll(", sizeof(");
3347 try f.renderTypecast(writer, inst_ty);3139 try f.renderType(writer, inst_ty);
3348 try writer.writeAll("))");3140 try writer.writeAll("))");
3349 }3141 }
3350 try writer.writeAll(";\n");3142 try writer.writeAll(";\n");
...@@ -3357,7 +3149,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3357,7 +3149,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
33573149
3358 if (f.liveness.isUnused(inst)) {3150 if (f.liveness.isUnused(inst)) {
3359 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3151 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3360 return CValue.none;3152 return .none;
3361 }3153 }
33623154
3363 const slice_ty = f.air.typeOf(bin_op.lhs);3155 const slice_ty = f.air.typeOf(bin_op.lhs);
...@@ -3387,7 +3179,7 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3387,7 +3179,7 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
3387 const inst_ty = f.air.typeOfIndex(inst);3179 const inst_ty = f.air.typeOfIndex(inst);
3388 if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBitsIgnoreComptime()) {3180 if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBitsIgnoreComptime()) {
3389 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3181 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3390 return CValue.none;3182 return .none;
3391 }3183 }
33923184
3393 const array = try f.resolveInst(bin_op.lhs);3185 const array = try f.resolveInst(bin_op.lhs);
...@@ -3413,7 +3205,7 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3413,7 +3205,7 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
3413 try writer.writeByte(']');3205 try writer.writeByte(']');
3414 if (is_array) {3206 if (is_array) {
3415 try writer.writeAll(", sizeof(");3207 try writer.writeAll(", sizeof(");
3416 try f.renderTypecast(writer, inst_ty);3208 try f.renderType(writer, inst_ty);
3417 try writer.writeAll("))");3209 try writer.writeAll("))");
3418 }3210 }
3419 try writer.writeAll(";\n");3211 try writer.writeAll(";\n");
...@@ -3425,16 +3217,19 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3425,16 +3217,19 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
34253217
3426 const elem_type = inst_ty.elemType();3218 const elem_type = inst_ty.elemType();
3427 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) {3219 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) {
3428 return CValue{ .undef = inst_ty };3220 return .{ .undef = inst_ty };
3429 }3221 }
34303222
3431 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;
3432 const target = f.object.dg.module.getTarget();3223 const target = f.object.dg.module.getTarget();
3433 const local = try f.allocAlignedLocal(elem_type, mutability, inst_ty.ptrAlignment(target));3224 const local = try f.allocAlignedLocal(
3434 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.local });3225 elem_type,
3226 CQualifiers.init(.{ .@"const" = inst_ty.isConstPtr() }),
3227 inst_ty.ptrAlignment(target),
3228 );
3229 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
3435 const gpa = f.object.dg.module.gpa;3230 const gpa = f.object.dg.module.gpa;
3436 try f.allocs.put(gpa, local.local, false);3231 try f.allocs.put(gpa, local.new_local, false);
3437 return CValue{ .local_ref = local.local };3232 return .{ .local_ref = local.new_local };
3438}3233}
34393234
3440fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {3235fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -3442,22 +3237,31 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3442,22 +3237,31 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
34423237
3443 const elem_ty = inst_ty.elemType();3238 const elem_ty = inst_ty.elemType();
3444 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {3239 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
3445 return CValue{ .undef = inst_ty };3240 return .{ .undef = inst_ty };
3446 }3241 }
34473242
3448 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;
3449 const target = f.object.dg.module.getTarget();3243 const target = f.object.dg.module.getTarget();
3450 const local = try f.allocAlignedLocal(elem_ty, mutability, inst_ty.ptrAlignment(target));3244 const local = try f.allocAlignedLocal(
3451 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.local });3245 elem_ty,
3246 CQualifiers.init(.{ .@"const" = inst_ty.isConstPtr() }),
3247 inst_ty.ptrAlignment(target),
3248 );
3249 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
3452 const gpa = f.object.dg.module.gpa;3250 const gpa = f.object.dg.module.gpa;
3453 try f.allocs.put(gpa, local.local, false);3251 try f.allocs.put(gpa, local.new_local, false);
3454 return CValue{ .local_ref = local.local };3252 return .{ .local_ref = local.new_local };
3455}3253}
34563254
3457fn airArg(f: *Function) CValue {3255fn airArg(f: *Function, inst: Air.Inst.Index) !CValue {
3256 const inst_ty = f.air.typeOfIndex(inst);
3257 const inst_cty = try f.typeToIndex(inst_ty, .parameter);
3258
3458 const i = f.next_arg_index;3259 const i = f.next_arg_index;
3459 f.next_arg_index += 1;3260 f.next_arg_index += 1;
3460 return .{ .arg = i };3261 return if (inst_cty != try f.typeToIndex(inst_ty, .complete))
3262 .{ .arg_array = i }
3263 else
3264 .{ .arg = i };
3461}3265}
34623266
3463fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {3267fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -3469,7 +3273,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3469,7 +3273,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
3469 (!ptr_info.@"volatile" and f.liveness.isUnused(inst)))3273 (!ptr_info.@"volatile" and f.liveness.isUnused(inst)))
3470 {3274 {
3471 try reap(f, inst, &.{ty_op.operand});3275 try reap(f, inst, &.{ty_op.operand});
3472 return CValue.none;3276 return .none;
3473 }3277 }
34743278
3475 const operand = try f.resolveInst(ty_op.operand);3279 const operand = try f.resolveInst(ty_op.operand);
...@@ -3491,7 +3295,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3491,7 +3295,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
3491 try writer.writeAll(", (const char *)");3295 try writer.writeAll(", (const char *)");
3492 try f.writeCValue(writer, operand, .Other);3296 try f.writeCValue(writer, operand, .Other);
3493 try writer.writeAll(", sizeof(");3297 try writer.writeAll(", sizeof(");
3494 try f.renderTypecast(writer, src_ty);3298 try f.renderType(writer, src_ty);
3495 try writer.writeAll("))");3299 try writer.writeAll("))");
3496 } else if (ptr_info.host_size != 0) {3300 } else if (ptr_info.host_size != 0) {
3497 var host_pl = Type.Payload.Bits{3301 var host_pl = Type.Payload.Bits{
...@@ -3520,11 +3324,11 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3520,11 +3324,11 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
35203324
3521 try f.writeCValue(writer, local, .Other);3325 try f.writeCValue(writer, local, .Other);
3522 try writer.writeAll(" = (");3326 try writer.writeAll(" = (");
3523 try f.renderTypecast(writer, src_ty);3327 try f.renderType(writer, src_ty);
3524 try writer.writeAll(")zig_wrap_");3328 try writer.writeAll(")zig_wrap_");
3525 try f.object.dg.renderTypeForBuiltinFnName(writer, field_ty);3329 try f.object.dg.renderTypeForBuiltinFnName(writer, field_ty);
3526 try writer.writeAll("((");3330 try writer.writeAll("((");
3527 try f.renderTypecast(writer, field_ty);3331 try f.renderType(writer, field_ty);
3528 try writer.writeByte(')');3332 try writer.writeByte(')');
3529 const cant_cast = host_ty.isInt() and host_ty.bitSize(target) > 64;3333 const cant_cast = host_ty.isInt() and host_ty.bitSize(target) > 64;
3530 if (cant_cast) {3334 if (cant_cast) {
...@@ -3554,20 +3358,24 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {...@@ -3554,20 +3358,24 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
3554 const un_op = f.air.instructions.items(.data)[inst].un_op;3358 const un_op = f.air.instructions.items(.data)[inst].un_op;
3555 const writer = f.object.writer();3359 const writer = f.object.writer();
3556 const target = f.object.dg.module.getTarget();3360 const target = f.object.dg.module.getTarget();
3361 const op_inst = Air.refToIndex(un_op);
3557 const op_ty = f.air.typeOf(un_op);3362 const op_ty = f.air.typeOf(un_op);
3558 const ret_ty = if (is_ptr) op_ty.childType() else op_ty;3363 const ret_ty = if (is_ptr) op_ty.childType() else op_ty;
3559 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;3364 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;
3560 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);3365 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);
35613366
3562 if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) {3367 if (op_inst != null and f.air.instructions.items(.tag)[op_inst.?] == .call_always_tail) {
3563 var deref = is_ptr;3368 try reap(f, inst, &.{un_op});
3369 _ = try airCall(f, op_inst.?, .always_tail);
3370 } else if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) {
3564 const operand = try f.resolveInst(un_op);3371 const operand = try f.resolveInst(un_op);
3565 try reap(f, inst, &.{un_op});3372 try reap(f, inst, &.{un_op});
3373 var deref = is_ptr;
3566 const is_array = lowersToArray(ret_ty, target);3374 const is_array = lowersToArray(ret_ty, target);
3567 const ret_val = if (is_array) ret_val: {3375 const ret_val = if (is_array) ret_val: {
3568 const array_local = try f.allocLocal(inst, try lowered_ret_ty.copy(f.arena.allocator()));3376 const array_local = try f.allocLocal(inst, try lowered_ret_ty.copy(f.arena.allocator()));
3569 try writer.writeAll("memcpy(");3377 try writer.writeAll("memcpy(");
3570 try f.writeCValueMember(writer, array_local, .{ .field = 0 });3378 try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });
3571 try writer.writeAll(", ");3379 try writer.writeAll(", ");
3572 if (deref)3380 if (deref)
3573 try f.writeCValueDeref(writer, operand)3381 try f.writeCValueDeref(writer, operand)
...@@ -3575,7 +3383,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {...@@ -3575,7 +3383,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
3575 try f.writeCValue(writer, operand, .FunctionArgument);3383 try f.writeCValue(writer, operand, .FunctionArgument);
3576 deref = false;3384 deref = false;
3577 try writer.writeAll(", sizeof(");3385 try writer.writeAll(", sizeof(");
3578 try f.renderTypecast(writer, ret_ty);3386 try f.renderType(writer, ret_ty);
3579 try writer.writeAll("));\n");3387 try writer.writeAll("));\n");
3580 break :ret_val array_local;3388 break :ret_val array_local;
3581 } else operand;3389 } else operand;
...@@ -3587,16 +3395,15 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {...@@ -3587,16 +3395,15 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
3587 try f.writeCValue(writer, ret_val, .Other);3395 try f.writeCValue(writer, ret_val, .Other);
3588 try writer.writeAll(";\n");3396 try writer.writeAll(";\n");
3589 if (is_array) {3397 if (is_array) {
3590 try freeLocal(f, inst, ret_val.local, 0);3398 try freeLocal(f, inst, ret_val.new_local, 0);
3591 }3399 }
3592 } else {3400 } else {
3593 try reap(f, inst, &.{un_op});3401 try reap(f, inst, &.{un_op});
3594 if (f.object.dg.decl.ty.fnCallingConvention() != .Naked) {3402 // Not even allowed to return void in a naked function.
3595 // Not even allowed to return void in a naked function.3403 if (if (f.object.dg.decl) |decl| decl.ty.fnCallingConvention() != .Naked else true)
3596 try writer.writeAll("return;\n");3404 try writer.writeAll("return;\n");
3597 }
3598 }3405 }
3599 return CValue.none;3406 return .none;
3600}3407}
36013408
3602fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {3409fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -3604,7 +3411,7 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3604,7 +3411,7 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
36043411
3605 if (f.liveness.isUnused(inst)) {3412 if (f.liveness.isUnused(inst)) {
3606 try reap(f, inst, &.{ty_op.operand});3413 try reap(f, inst, &.{ty_op.operand});
3607 return CValue.none;3414 return .none;
3608 }3415 }
36093416
3610 const operand = try f.resolveInst(ty_op.operand);3417 const operand = try f.resolveInst(ty_op.operand);
...@@ -3625,7 +3432,7 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3625,7 +3432,7 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
3625 const ty_op = f.air.instructions.items(.data)[inst].ty_op;3432 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
3626 if (f.liveness.isUnused(inst)) {3433 if (f.liveness.isUnused(inst)) {
3627 try reap(f, inst, &.{ty_op.operand});3434 try reap(f, inst, &.{ty_op.operand});
3628 return CValue.none;3435 return .none;
3629 }3436 }
36303437
3631 const operand = try f.resolveInst(ty_op.operand);3438 const operand = try f.resolveInst(ty_op.operand);
...@@ -3644,15 +3451,17 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3644,15 +3451,17 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
3644 try f.writeCValue(writer, local, .Other);3451 try f.writeCValue(writer, local, .Other);
3645 try writer.writeAll(" = ");3452 try writer.writeAll(" = ");
36463453
3454 if (dest_c_bits < 64) {
3455 try writer.writeByte('(');
3456 try f.renderType(writer, inst_ty);
3457 try writer.writeByte(')');
3458 }
3459
3647 const needs_lo = operand_int_info.bits > 64 and dest_bits <= 64;3460 const needs_lo = operand_int_info.bits > 64 and dest_bits <= 64;
3648 if (needs_lo) {3461 if (needs_lo) {
3649 try writer.writeAll("zig_lo_");3462 try writer.writeAll("zig_lo_");
3650 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);3463 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
3651 try writer.writeByte('(');3464 try writer.writeByte('(');
3652 } else if (dest_c_bits <= 64) {
3653 try writer.writeByte('(');
3654 try f.renderTypecast(writer, inst_ty);
3655 try writer.writeByte(')');
3656 }3465 }
36573466
3658 if (dest_bits >= 8 and std.math.isPowerOfTwo(dest_bits)) {3467 if (dest_bits >= 8 and std.math.isPowerOfTwo(dest_bits)) {
...@@ -3712,7 +3521,7 @@ fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3712,7 +3521,7 @@ fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue {
3712 const un_op = f.air.instructions.items(.data)[inst].un_op;3521 const un_op = f.air.instructions.items(.data)[inst].un_op;
3713 if (f.liveness.isUnused(inst)) {3522 if (f.liveness.isUnused(inst)) {
3714 try reap(f, inst, &.{un_op});3523 try reap(f, inst, &.{un_op});
3715 return CValue.none;3524 return .none;
3716 }3525 }
3717 const operand = try f.resolveInst(un_op);3526 const operand = try f.resolveInst(un_op);
3718 try reap(f, inst, &.{un_op});3527 try reap(f, inst, &.{un_op});
...@@ -3732,10 +3541,10 @@ fn storeUndefined(f: *Function, lhs_child_ty: Type, dest_ptr: CValue) !CValue {...@@ -3732,10 +3541,10 @@ fn storeUndefined(f: *Function, lhs_child_ty: Type, dest_ptr: CValue) !CValue {
3732 try writer.writeAll("memset(");3541 try writer.writeAll("memset(");
3733 try f.writeCValue(writer, dest_ptr, .FunctionArgument);3542 try f.writeCValue(writer, dest_ptr, .FunctionArgument);
3734 try writer.print(", {x}, sizeof(", .{try f.fmtIntLiteral(Type.u8, Value.undef)});3543 try writer.print(", {x}, sizeof(", .{try f.fmtIntLiteral(Type.u8, Value.undef)});
3735 try f.renderTypecast(writer, lhs_child_ty);3544 try f.renderType(writer, lhs_child_ty);
3736 try writer.writeAll("));\n");3545 try writer.writeAll("));\n");
3737 }3546 }
3738 return CValue.none;3547 return .none;
3739}3548}
37403549
3741fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {3550fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -3744,7 +3553,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3744,7 +3553,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
3744 const ptr_info = f.air.typeOf(bin_op.lhs).ptrInfo().data;3553 const ptr_info = f.air.typeOf(bin_op.lhs).ptrInfo().data;
3745 if (!ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime()) {3554 if (!ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime()) {
3746 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3555 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3747 return CValue.none;3556 return .none;
3748 }3557 }
37493558
3750 const ptr_val = try f.resolveInst(bin_op.lhs);3559 const ptr_val = try f.resolveInst(bin_op.lhs);
...@@ -3793,10 +3602,10 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3793,10 +3602,10 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
3793 if (!is_array) try writer.writeByte('&');3602 if (!is_array) try writer.writeByte('&');
3794 try f.writeCValue(writer, array_src, .FunctionArgument);3603 try f.writeCValue(writer, array_src, .FunctionArgument);
3795 try writer.writeAll(", sizeof(");3604 try writer.writeAll(", sizeof(");
3796 try f.renderTypecast(writer, src_ty);3605 try f.renderType(writer, src_ty);
3797 try writer.writeAll("))");3606 try writer.writeAll("))");
3798 if (src_val == .constant) {3607 if (src_val == .constant) {
3799 try freeLocal(f, inst, array_src.local, 0);3608 try freeLocal(f, inst, array_src.new_local, 0);
3800 }3609 }
3801 } else if (ptr_info.host_size != 0) {3610 } else if (ptr_info.host_size != 0) {
3802 const host_bits = ptr_info.host_size * 8;3611 const host_bits = ptr_info.host_size * 8;
...@@ -3847,18 +3656,18 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3847,18 +3656,18 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
3847 const cant_cast = host_ty.isInt() and host_ty.bitSize(target) > 64;3656 const cant_cast = host_ty.isInt() and host_ty.bitSize(target) > 64;
3848 if (cant_cast) {3657 if (cant_cast) {
3849 if (src_ty.bitSize(target) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{});3658 if (src_ty.bitSize(target) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{});
3850 try writer.writeAll("zig_as_");3659 try writer.writeAll("zig_make_");
3851 try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);3660 try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty);
3852 try writer.writeAll("(0, ");3661 try writer.writeAll("(0, ");
3853 } else {3662 } else {
3854 try writer.writeByte('(');3663 try writer.writeByte('(');
3855 try f.renderTypecast(writer, host_ty);3664 try f.renderType(writer, host_ty);
3856 try writer.writeByte(')');3665 try writer.writeByte(')');
3857 }3666 }
38583667
3859 if (src_ty.isPtrAtRuntime()) {3668 if (src_ty.isPtrAtRuntime()) {
3860 try writer.writeByte('(');3669 try writer.writeByte('(');
3861 try f.renderTypecast(writer, Type.usize);3670 try f.renderType(writer, Type.usize);
3862 try writer.writeByte(')');3671 try writer.writeByte(')');
3863 }3672 }
3864 try f.writeCValue(writer, src_val, .Other);3673 try f.writeCValue(writer, src_val, .Other);
...@@ -3870,7 +3679,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3870,7 +3679,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
3870 try f.writeCValue(writer, src_val, .Other);3679 try f.writeCValue(writer, src_val, .Other);
3871 }3680 }
3872 try writer.writeAll(";\n");3681 try writer.writeAll(";\n");
3873 return CValue.none;3682 return .none;
3874}3683}
38753684
3876fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: BuiltinInfo) !CValue {3685fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: BuiltinInfo) !CValue {
...@@ -3879,7 +3688,7 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:...@@ -3879,7 +3688,7 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:
38793688
3880 if (f.liveness.isUnused(inst)) {3689 if (f.liveness.isUnused(inst)) {
3881 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3690 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3882 return CValue.none;3691 return .none;
3883 }3692 }
38843693
3885 const lhs = try f.resolveInst(bin_op.lhs);3694 const lhs = try f.resolveInst(bin_op.lhs);
...@@ -3935,7 +3744,7 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3935,7 +3744,7 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
39353744
3936 if (f.liveness.isUnused(inst)) {3745 if (f.liveness.isUnused(inst)) {
3937 try reap(f, inst, &.{ty_op.operand});3746 try reap(f, inst, &.{ty_op.operand});
3938 return CValue.none;3747 return .none;
3939 }3748 }
39403749
3941 const op = try f.resolveInst(ty_op.operand);3750 const op = try f.resolveInst(ty_op.operand);
...@@ -3970,7 +3779,7 @@ fn airBinOp(...@@ -3970,7 +3779,7 @@ fn airBinOp(
39703779
3971 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3780 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
39723781
3973 if (f.liveness.isUnused(inst)) return CValue.none;3782 if (f.liveness.isUnused(inst)) return .none;
39743783
3975 const inst_ty = f.air.typeOfIndex(inst);3784 const inst_ty = f.air.typeOfIndex(inst);
39763785
...@@ -3993,7 +3802,7 @@ fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation:...@@ -3993,7 +3802,7 @@ fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation:
39933802
3994 if (f.liveness.isUnused(inst)) {3803 if (f.liveness.isUnused(inst)) {
3995 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3804 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3996 return CValue.none;3805 return .none;
3997 }3806 }
39983807
3999 const operand_ty = f.air.typeOf(bin_op.lhs);3808 const operand_ty = f.air.typeOf(bin_op.lhs);
...@@ -4033,7 +3842,7 @@ fn airEquality(...@@ -4033,7 +3842,7 @@ fn airEquality(
40333842
4034 if (f.liveness.isUnused(inst)) {3843 if (f.liveness.isUnused(inst)) {
4035 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3844 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
4036 return CValue.none;3845 return .none;
4037 }3846 }
40383847
4039 const operand_ty = f.air.typeOf(bin_op.lhs);3848 const operand_ty = f.air.typeOf(bin_op.lhs);
...@@ -4089,7 +3898,7 @@ fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4089,7 +3898,7 @@ fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {
40893898
4090 if (f.liveness.isUnused(inst)) {3899 if (f.liveness.isUnused(inst)) {
4091 try reap(f, inst, &.{un_op});3900 try reap(f, inst, &.{un_op});
4092 return CValue.none;3901 return .none;
4093 }3902 }
40943903
4095 const inst_ty = f.air.typeOfIndex(inst);3904 const inst_ty = f.air.typeOfIndex(inst);
...@@ -4110,7 +3919,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {...@@ -4110,7 +3919,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
4110 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;3919 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
4111 if (f.liveness.isUnused(inst)) {3920 if (f.liveness.isUnused(inst)) {
4112 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3921 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
4113 return CValue.none;3922 return .none;
4114 }3923 }
41153924
4116 const lhs = try f.resolveInst(bin_op.lhs);3925 const lhs = try f.resolveInst(bin_op.lhs);
...@@ -4118,32 +3927,31 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {...@@ -4118,32 +3927,31 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
4118 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3927 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
41193928
4120 const inst_ty = f.air.typeOfIndex(inst);3929 const inst_ty = f.air.typeOfIndex(inst);
4121 const elem_ty = switch (inst_ty.ptrSize()) {3930 const elem_ty = inst_ty.elemType2();
4122 .One => blk: {
4123 const array_ty = inst_ty.childType();
4124 break :blk array_ty.childType();
4125 },
4126 else => inst_ty.childType(),
4127 };
41283931
4129 // We must convert to and from integer types to prevent UB if the operation3932 const local = try f.allocLocal(inst, inst_ty);
4130 // results in a NULL pointer, or if LHS is NULL. The operation is only UB3933 const writer = f.object.writer();
4131 // if the result is NULL and then dereferenced.3934 try f.writeCValue(writer, local, .Other);
4132 const local = try f.allocLocal(inst, inst_ty);3935 try writer.writeAll(" = ");
4133 const writer = f.object.writer();3936
4134 try f.writeCValue(writer, local, .Other);3937 if (elem_ty.hasRuntimeBitsIgnoreComptime()) {
4135 try writer.writeAll(" = (");3938 // We must convert to and from integer types to prevent UB if the operation
4136 try f.renderTypecast(writer, inst_ty);3939 // results in a NULL pointer, or if LHS is NULL. The operation is only UB
4137 try writer.writeAll(")(((uintptr_t)");3940 // if the result is NULL and then dereferenced.
4138 try f.writeCValue(writer, lhs, .Other);3941 try writer.writeByte('(');
4139 try writer.writeAll(") ");3942 try f.renderType(writer, inst_ty);
4140 try writer.writeByte(operator);3943 try writer.writeAll(")(((uintptr_t)");
4141 try writer.writeAll(" (");3944 try f.writeCValue(writer, lhs, .Other);
4142 try f.writeCValue(writer, rhs, .Other);3945 try writer.writeAll(") ");
4143 try writer.writeAll("*sizeof(");3946 try writer.writeByte(operator);
4144 try f.renderTypecast(writer, elem_ty);3947 try writer.writeAll(" (");
4145 try writer.writeAll(")));\n");3948 try f.writeCValue(writer, rhs, .Other);
3949 try writer.writeAll("*sizeof(");
3950 try f.renderType(writer, elem_ty);
3951 try writer.writeAll(")))");
3952 } else try f.writeCValue(writer, lhs, .Initializer);
41463953
3954 try writer.writeAll(";\n");
4147 return local;3955 return local;
4148}3956}
41493957
...@@ -4152,7 +3960,7 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons...@@ -4152,7 +3960,7 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons
41523960
4153 if (f.liveness.isUnused(inst)) {3961 if (f.liveness.isUnused(inst)) {
4154 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });3962 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
4155 return CValue.none;3963 return .none;
4156 }3964 }
41573965
4158 const inst_ty = f.air.typeOfIndex(inst);3966 const inst_ty = f.air.typeOfIndex(inst);
...@@ -4191,7 +3999,7 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4191,7 +3999,7 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
41913999
4192 if (f.liveness.isUnused(inst)) {4000 if (f.liveness.isUnused(inst)) {
4193 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });4001 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
4194 return CValue.none;4002 return .none;
4195 }4003 }
41964004
4197 const ptr = try f.resolveInst(bin_op.lhs);4005 const ptr = try f.resolveInst(bin_op.lhs);
...@@ -4204,7 +4012,7 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4204,7 +4012,7 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
4204 try f.writeCValue(writer, local, .Other);4012 try f.writeCValue(writer, local, .Other);
4205 try writer.writeAll(".ptr = (");4013 try writer.writeAll(".ptr = (");
4206 var buf: Type.SlicePtrFieldTypeBuffer = undefined;4014 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
4207 try f.renderTypecast(writer, inst_ty.slicePtrFieldType(&buf));4015 try f.renderType(writer, inst_ty.slicePtrFieldType(&buf));
4208 try writer.writeByte(')');4016 try writer.writeByte(')');
4209 try f.writeCValue(writer, ptr, .Other);4017 try f.writeCValue(writer, ptr, .Other);
4210 try writer.writeAll("; ");4018 try writer.writeAll("; ");
...@@ -4222,24 +4030,41 @@ fn airCall(...@@ -4222,24 +4030,41 @@ fn airCall(
4222 modifier: std.builtin.CallModifier,4030 modifier: std.builtin.CallModifier,
4223) !CValue {4031) !CValue {
4224 // Not even allowed to call panic in a naked function.4032 // Not even allowed to call panic in a naked function.
4225 if (f.object.dg.decl.ty.fnCallingConvention() == .Naked) return .none;4033 if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention() == .Naked) return .none;
4034
4226 const gpa = f.object.dg.gpa;4035 const gpa = f.object.dg.gpa;
4036 const module = f.object.dg.module;
4037 const target = module.getTarget();
4038 const writer = f.object.writer();
42274039
4228 switch (modifier) {
4229 .auto => {},
4230 .always_tail => return f.fail("TODO: C backend: call with always_tail attribute", .{}),
4231 .never_tail => return f.fail("TODO: C backend: call with never_tail attribute", .{}),
4232 .never_inline => return f.fail("TODO: C backend: call with never_inline attribute", .{}),
4233 else => unreachable,
4234 }
4235 const pl_op = f.air.instructions.items(.data)[inst].pl_op;4040 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
4236 const extra = f.air.extraData(Air.Call, pl_op.payload);4041 const extra = f.air.extraData(Air.Call, pl_op.payload);
4237 const args = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]);4042 const args = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]);
42384043
4239 const resolved_args = try gpa.alloc(CValue, args.len);4044 const resolved_args = try gpa.alloc(CValue, args.len);
4240 defer gpa.free(resolved_args);4045 defer gpa.free(resolved_args);
4241 for (args, 0..) |arg, i| {4046 for (resolved_args, args) |*resolved_arg, arg| {
4242 resolved_args[i] = try f.resolveInst(arg);4047 const arg_ty = f.air.typeOf(arg);
4048 const arg_cty = try f.typeToIndex(arg_ty, .parameter);
4049 if (f.indexToCType(arg_cty).tag() == .void) {
4050 resolved_arg.* = .none;
4051 continue;
4052 }
4053 resolved_arg.* = try f.resolveInst(arg);
4054 if (arg_cty != try f.typeToIndex(arg_ty, .complete)) {
4055 var lowered_arg_buf: LowerFnRetTyBuffer = undefined;
4056 const lowered_arg_ty = lowerFnRetTy(arg_ty, &lowered_arg_buf, target);
4057
4058 const array_local = try f.allocLocal(inst, try lowered_arg_ty.copy(f.arena.allocator()));
4059 try writer.writeAll("memcpy(");
4060 try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });
4061 try writer.writeAll(", ");
4062 try f.writeCValue(writer, resolved_arg.*, .FunctionArgument);
4063 try writer.writeAll(", sizeof(");
4064 try f.renderType(writer, lowered_arg_ty);
4065 try writer.writeAll("));\n");
4066 resolved_arg.* = array_local;
4067 }
4243 }4068 }
42444069
4245 const callee = try f.resolveInst(pl_op.operand);4070 const callee = try f.resolveInst(pl_op.operand);
...@@ -4256,18 +4081,19 @@ fn airCall(...@@ -4256,18 +4081,19 @@ fn airCall(
4256 .Pointer => callee_ty.childType(),4081 .Pointer => callee_ty.childType(),
4257 else => unreachable,4082 else => unreachable,
4258 };4083 };
4259 const writer = f.object.writer();
42604084
4261 const target = f.object.dg.module.getTarget();
4262 const ret_ty = fn_ty.fnReturnType();4085 const ret_ty = fn_ty.fnReturnType();
4263 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;4086 var lowered_ret_buf: LowerFnRetTyBuffer = undefined;
4264 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);4087 const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target);
42654088
4266 const result_local: CValue = if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime())4089 const result_local = if (modifier == .always_tail) r: {
4090 try writer.writeAll("zig_always_tail return ");
4091 break :r .none;
4092 } else if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime())
4267 .none4093 .none
4268 else if (f.liveness.isUnused(inst)) r: {4094 else if (f.liveness.isUnused(inst)) r: {
4269 try writer.writeByte('(');4095 try writer.writeByte('(');
4270 try f.renderTypecast(writer, Type.void);4096 try f.renderType(writer, Type.void);
4271 try writer.writeByte(')');4097 try writer.writeByte(')');
4272 break :r .none;4098 break :r .none;
4273 } else r: {4099 } else r: {
...@@ -4277,48 +4103,44 @@ fn airCall(...@@ -4277,48 +4103,44 @@ fn airCall(
4277 break :r local;4103 break :r local;
4278 };4104 };
42794105
4280 var is_extern = false;
4281 var name: [*:0]const u8 = "";
4282 callee: {4106 callee: {
4283 known: {4107 known: {
4284 const fn_decl = fn_decl: {4108 const fn_decl = fn_decl: {
4285 const callee_val = f.air.value(pl_op.operand) orelse break :known;4109 const callee_val = f.air.value(pl_op.operand) orelse break :known;
4286 break :fn_decl switch (callee_val.tag()) {4110 break :fn_decl switch (callee_val.tag()) {
4287 .extern_fn => blk: {4111 .extern_fn => callee_val.castTag(.extern_fn).?.data.owner_decl,
4288 is_extern = true;
4289 break :blk callee_val.castTag(.extern_fn).?.data.owner_decl;
4290 },
4291 .function => callee_val.castTag(.function).?.data.owner_decl,4112 .function => callee_val.castTag(.function).?.data.owner_decl,
4292 .decl_ref => callee_val.castTag(.decl_ref).?.data,4113 .decl_ref => callee_val.castTag(.decl_ref).?.data,
4293 else => break :known,4114 else => break :known,
4294 };4115 };
4295 };4116 };
4296 name = f.object.dg.module.declPtr(fn_decl).name;4117 switch (modifier) {
4297 try f.object.dg.renderDeclName(writer, fn_decl, 0);4118 .auto, .always_tail => try f.object.dg.renderDeclName(writer, fn_decl, 0),
4119 inline .never_tail, .never_inline => |mod| try writer.writeAll(try f.getLazyFnName(
4120 @unionInit(LazyFnKey, @tagName(mod), fn_decl),
4121 @unionInit(LazyFnValue.Data, @tagName(mod), {}),
4122 )),
4123 else => unreachable,
4124 }
4298 break :callee;4125 break :callee;
4299 }4126 }
4127 switch (modifier) {
4128 .auto, .always_tail => {},
4129 .never_tail => return f.fail("CBE: runtime callee with never_tail attribute unsupported", .{}),
4130 .never_inline => return f.fail("CBE: runtime callee with never_inline attribute unsupported", .{}),
4131 else => unreachable,
4132 }
4300 // Fall back to function pointer call.4133 // Fall back to function pointer call.
4301 try f.writeCValue(writer, callee, .Other);4134 try f.writeCValue(writer, callee, .Other);
4302 }4135 }
43034136
4304 try writer.writeByte('(');4137 try writer.writeByte('(');
4305 var args_written: usize = 0;4138 var args_written: usize = 0;
4306 for (args, 0..) |arg, arg_i| {4139 for (resolved_args) |resolved_arg| {
4307 const ty = f.air.typeOf(arg);4140 if (resolved_arg == .none) continue;
4308 if (!ty.hasRuntimeBitsIgnoreComptime()) continue;4141 if (args_written != 0) try writer.writeAll(", ");
4309 if (args_written != 0) {4142 try f.writeCValue(writer, resolved_arg, .FunctionArgument);
4310 try writer.writeAll(", ");4143 if (resolved_arg == .new_local) try freeLocal(f, inst, resolved_arg.new_local, 0);
4311 }
4312 if ((is_extern or std.mem.eql(u8, std.mem.span(name), "main")) and
4313 ty.isCPtr() and ty.childType().tag() == .u8)
4314 {
4315 // Corresponds with hack in renderType .Pointer case.
4316 try writer.writeAll("(char");
4317 if (ty.isConstPtr()) try writer.writeAll(" const");
4318 if (ty.isVolatilePtr()) try writer.writeAll(" volatile");
4319 try writer.writeAll(" *)");
4320 }
4321 try f.writeCValue(writer, resolved_args[arg_i], .FunctionArgument);
4322 args_written += 1;4144 args_written += 1;
4323 }4145 }
4324 try writer.writeAll(");\n");4146 try writer.writeAll(");\n");
...@@ -4331,11 +4153,11 @@ fn airCall(...@@ -4331,11 +4153,11 @@ fn airCall(
4331 try writer.writeAll("memcpy(");4153 try writer.writeAll("memcpy(");
4332 try f.writeCValue(writer, array_local, .FunctionArgument);4154 try f.writeCValue(writer, array_local, .FunctionArgument);
4333 try writer.writeAll(", ");4155 try writer.writeAll(", ");
4334 try f.writeCValueMember(writer, result_local, .{ .field = 0 });4156 try f.writeCValueMember(writer, result_local, .{ .identifier = "array" });
4335 try writer.writeAll(", sizeof(");4157 try writer.writeAll(", sizeof(");
4336 try f.renderTypecast(writer, ret_ty);4158 try f.renderType(writer, ret_ty);
4337 try writer.writeAll("));\n");4159 try writer.writeAll("));\n");
4338 try freeLocal(f, inst, result_local.local, 0);4160 try freeLocal(f, inst, result_local.new_local, 0);
4339 break :r array_local;4161 break :r array_local;
4340 };4162 };
43414163
...@@ -4354,7 +4176,7 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4354,7 +4176,7 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
4354 // Perhaps an additional compilation option is in order?4176 // Perhaps an additional compilation option is in order?
4355 //try writer.print("#line {d}\n", .{dbg_stmt.line + 1});4177 //try writer.print("#line {d}\n", .{dbg_stmt.line + 1});
4356 try writer.print("/* file:{d}:{d} */\n", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });4178 try writer.print("/* file:{d}:{d} */\n", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });
4357 return CValue.none;4179 return .none;
4358}4180}
43594181
4360fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue {4182fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -4363,7 +4185,7 @@ fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4363,7 +4185,7 @@ fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue {
4363 const function = f.air.values[ty_pl.payload].castTag(.function).?.data;4185 const function = f.air.values[ty_pl.payload].castTag(.function).?.data;
4364 const mod = f.object.dg.module;4186 const mod = f.object.dg.module;
4365 try writer.print("/* dbg func:{s} */\n", .{mod.declPtr(function.owner_decl).name});4187 try writer.print("/* dbg func:{s} */\n", .{mod.declPtr(function.owner_decl).name});
4366 return CValue.none;4188 return .none;
4367}4189}
43684190
4369fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {4191fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -4375,7 +4197,7 @@ fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4375,7 +4197,7 @@ fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
4375 try reap(f, inst, &.{pl_op.operand});4197 try reap(f, inst, &.{pl_op.operand});
4376 const writer = f.object.writer();4198 const writer = f.object.writer();
4377 try writer.print("/* var:{s} */\n", .{name});4199 try writer.print("/* var:{s} */\n", .{name});
4378 return CValue.none;4200 return .none;
4379}4201}
43804202
4381fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {4203fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -4391,7 +4213,7 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4391,7 +4213,7 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
4391 const result = if (inst_ty.tag() != .void and !f.liveness.isUnused(inst))4213 const result = if (inst_ty.tag() != .void and !f.liveness.isUnused(inst))
4392 try f.allocLocal(inst, inst_ty)4214 try f.allocLocal(inst, inst_ty)
4393 else4215 else
4394 CValue{ .none = {} };4216 .none;
43954217
4396 try f.blocks.putNoClobber(f.object.dg.gpa, inst, .{4218 try f.blocks.putNoClobber(f.object.dg.gpa, inst, .{
4397 .block_id = block_id,4219 .block_id = block_id,
...@@ -4400,8 +4222,9 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4400,8 +4222,9 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
44004222
4401 try genBodyInner(f, body);4223 try genBodyInner(f, body);
4402 try f.object.indent_writer.insertNewline();4224 try f.object.indent_writer.insertNewline();
4225 // label might be unused, add a dummy goto
4403 // label must be followed by an expression, add an empty one.4226 // label must be followed by an expression, add an empty one.
4404 try writer.print("zig_block_{d}:;\n", .{block_id});4227 try writer.print("goto zig_block_{d};\nzig_block_{d}: (void)0;\n", .{ block_id, block_id });
4405 return result;4228 return result;
4406}4229}
44074230
...@@ -4460,7 +4283,7 @@ fn lowerTry(...@@ -4460,7 +4283,7 @@ fn lowerTry(
44604283
4461 if (!payload_has_bits) {4284 if (!payload_has_bits) {
4462 if (!operand_is_ptr) {4285 if (!operand_is_ptr) {
4463 return CValue.none;4286 return .none;
4464 } else {4287 } else {
4465 return err_union;4288 return err_union;
4466 }4289 }
...@@ -4469,7 +4292,7 @@ fn lowerTry(...@@ -4469,7 +4292,7 @@ fn lowerTry(
4469 try reap(f, inst, &.{operand});4292 try reap(f, inst, &.{operand});
44704293
4471 if (f.liveness.isUnused(inst)) {4294 if (f.liveness.isUnused(inst)) {
4472 return CValue.none;4295 return .none;
4473 }4296 }
44744297
4475 const target = f.object.dg.module.getTarget();4298 const target = f.object.dg.module.getTarget();
...@@ -4481,7 +4304,7 @@ fn lowerTry(...@@ -4481,7 +4304,7 @@ fn lowerTry(
4481 try writer.writeAll(", ");4304 try writer.writeAll(", ");
4482 try f.writeCValueMember(writer, err_union, .{ .identifier = "payload" });4305 try f.writeCValueMember(writer, err_union, .{ .identifier = "payload" });
4483 try writer.writeAll(", sizeof(");4306 try writer.writeAll(", sizeof(");
4484 try f.renderTypecast(writer, payload_ty);4307 try f.renderType(writer, payload_ty);
4485 try writer.writeAll("));\n");4308 try writer.writeAll("));\n");
4486 } else {4309 } else {
4487 try f.writeCValue(writer, local, .Other);4310 try f.writeCValue(writer, local, .Other);
...@@ -4514,7 +4337,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4514,7 +4337,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
4514 try writer.writeAll(", ");4337 try writer.writeAll(", ");
4515 try f.writeCValue(writer, operand, .FunctionArgument);4338 try f.writeCValue(writer, operand, .FunctionArgument);
4516 try writer.writeAll(", sizeof(");4339 try writer.writeAll(", sizeof(");
4517 try f.renderTypecast(writer, operand_ty);4340 try f.renderType(writer, operand_ty);
4518 try writer.writeAll("))");4341 try writer.writeAll("))");
4519 } else {4342 } else {
4520 try f.writeCValue(writer, result, .Other);4343 try f.writeCValue(writer, result, .Other);
...@@ -4525,7 +4348,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4525,7 +4348,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
4525 }4348 }
45264349
4527 try writer.print("goto zig_block_{d};\n", .{block.block_id});4350 try writer.print("goto zig_block_{d};\n", .{block.block_id});
4528 return CValue.none;4351 return .none;
4529}4352}
45304353
4531fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {4354fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -4535,7 +4358,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4535,7 +4358,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
4535 // https://github.com/ziglang/zig/issues/134104358 // https://github.com/ziglang/zig/issues/13410
4536 if (f.liveness.isUnused(inst) or !dest_ty.hasRuntimeBits()) {4359 if (f.liveness.isUnused(inst) or !dest_ty.hasRuntimeBits()) {
4537 try reap(f, inst, &.{ty_op.operand});4360 try reap(f, inst, &.{ty_op.operand});
4538 return CValue.none;4361 return .none;
4539 }4362 }
45404363
4541 const operand = try f.resolveInst(ty_op.operand);4364 const operand = try f.resolveInst(ty_op.operand);
...@@ -4563,7 +4386,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4563,7 +4386,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
4563 if (dest_ty.isPtrAtRuntime() and operand_ty.isPtrAtRuntime()) {4386 if (dest_ty.isPtrAtRuntime() and operand_ty.isPtrAtRuntime()) {
4564 try f.writeCValue(writer, local, .Other);4387 try f.writeCValue(writer, local, .Other);
4565 try writer.writeAll(" = (");4388 try writer.writeAll(" = (");
4566 try f.renderTypecast(writer, dest_ty);4389 try f.renderType(writer, dest_ty);
4567 try writer.writeByte(')');4390 try writer.writeByte(')');
4568 try f.writeCValue(writer, operand, .Other);4391 try f.writeCValue(writer, operand, .Other);
4569 try writer.writeAll(";\n");4392 try writer.writeAll(";\n");
...@@ -4584,7 +4407,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4584,7 +4407,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
4584 try writer.writeAll(", &");4407 try writer.writeAll(", &");
4585 try f.writeCValue(writer, operand_lval, .Other);4408 try f.writeCValue(writer, operand_lval, .Other);
4586 try writer.writeAll(", sizeof(");4409 try writer.writeAll(", sizeof(");
4587 try f.renderTypecast(writer, dest_ty);4410 try f.renderType(writer, dest_ty);
4588 try writer.writeAll("));\n");4411 try writer.writeAll("));\n");
45894412
4590 // Ensure padding bits have the expected value.4413 // Ensure padding bits have the expected value.
...@@ -4599,7 +4422,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4599,7 +4422,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
4599 }4422 }
46004423
4601 if (operand == .constant) {4424 if (operand == .constant) {
4602 try freeLocal(f, inst, operand_lval.local, 0);4425 try freeLocal(f, inst, operand_lval.new_local, 0);
4603 }4426 }
46044427
4605 return local;4428 return local;
...@@ -4607,27 +4430,27 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4607,27 +4430,27 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
46074430
4608fn airBreakpoint(writer: anytype) !CValue {4431fn airBreakpoint(writer: anytype) !CValue {
4609 try writer.writeAll("zig_breakpoint();\n");4432 try writer.writeAll("zig_breakpoint();\n");
4610 return CValue.none;4433 return .none;
4611}4434}
46124435
4613fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {4436fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {
4614 if (f.liveness.isUnused(inst)) return CValue.none;4437 if (f.liveness.isUnused(inst)) return .none;
4615 const writer = f.object.writer();4438 const writer = f.object.writer();
4616 const local = try f.allocLocal(inst, Type.usize);4439 const local = try f.allocLocal(inst, Type.usize);
4617 try f.writeCValue(writer, local, .Other);4440 try f.writeCValue(writer, local, .Other);
4618 try writer.writeAll(" = (");4441 try writer.writeAll(" = (");
4619 try f.renderTypecast(writer, Type.usize);4442 try f.renderType(writer, Type.usize);
4620 try writer.writeAll(")zig_return_address();\n");4443 try writer.writeAll(")zig_return_address();\n");
4621 return local;4444 return local;
4622}4445}
46234446
4624fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {4447fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {
4625 if (f.liveness.isUnused(inst)) return CValue.none;4448 if (f.liveness.isUnused(inst)) return .none;
4626 const writer = f.object.writer();4449 const writer = f.object.writer();
4627 const local = try f.allocLocal(inst, Type.usize);4450 const local = try f.allocLocal(inst, Type.usize);
4628 try f.writeCValue(writer, local, .Other);4451 try f.writeCValue(writer, local, .Other);
4629 try writer.writeAll(" = (");4452 try writer.writeAll(" = (");
4630 try f.renderTypecast(writer, Type.usize);4453 try f.renderType(writer, Type.usize);
4631 try writer.writeAll(")zig_frame_address();\n");4454 try writer.writeAll(")zig_frame_address();\n");
4632 return local;4455 return local;
4633}4456}
...@@ -4640,15 +4463,15 @@ fn airFence(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4640,15 +4463,15 @@ fn airFence(f: *Function, inst: Air.Inst.Index) !CValue {
4640 try writeMemoryOrder(writer, atomic_order);4463 try writeMemoryOrder(writer, atomic_order);
4641 try writer.writeAll(");\n");4464 try writer.writeAll(");\n");
46424465
4643 return CValue.none;4466 return .none;
4644}4467}
46454468
4646fn airUnreach(f: *Function) !CValue {4469fn airUnreach(f: *Function) !CValue {
4647 // Not even allowed to call unreachable in a naked function.4470 // Not even allowed to call unreachable in a naked function.
4648 if (f.object.dg.decl.ty.fnCallingConvention() == .Naked) return .none;4471 if (f.object.dg.decl) |decl| if (decl.ty.fnCallingConvention() == .Naked) return .none;
46494472
4650 try f.object.writer().writeAll("zig_unreachable();\n");4473 try f.object.writer().writeAll("zig_unreachable();\n");
4651 return CValue.none;4474 return .none;
4652}4475}
46534476
4654fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {4477fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -4669,18 +4492,18 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4669,18 +4492,18 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {
4669 const new_free_locals = f.getFreeLocals();4492 const new_free_locals = f.getFreeLocals();
4670 var it = new_free_locals.iterator();4493 var it = new_free_locals.iterator();
4671 while (it.next()) |entry| {4494 while (it.next()) |entry| {
4672 const gop = try old_free_locals.getOrPutContext(gpa, entry.key_ptr.*, f.tyHashCtx());4495 const gop = try old_free_locals.getOrPut(gpa, entry.key_ptr.*);
4673 if (gop.found_existing) {4496 if (gop.found_existing) {
4674 try gop.value_ptr.appendSlice(gpa, entry.value_ptr.items);4497 try gop.value_ptr.ensureUnusedCapacity(gpa, entry.value_ptr.count());
4675 } else {4498 for (entry.value_ptr.keys()) |local_index| {
4676 gop.value_ptr.* = entry.value_ptr.*;4499 gop.value_ptr.putAssumeCapacityNoClobber(local_index, {});
4677 entry.value_ptr.* = .{};4500 }
4678 }4501 } else gop.value_ptr.* = entry.value_ptr.move();
4679 }4502 }
4680 deinitFreeLocalsMap(gpa, new_free_locals);4503 deinitFreeLocalsMap(gpa, new_free_locals);
4681 new_free_locals.* = old_free_locals.move();4504 new_free_locals.* = old_free_locals.move();
46824505
4683 return CValue.none;4506 return .none;
4684}4507}
46854508
4686fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {4509fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -4705,6 +4528,10 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4705,6 +4528,10 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
4705 // that we can notice and use them in the else branch. Any new locals must4528 // that we can notice and use them in the else branch. Any new locals must
4706 // necessarily be free already after the then branch is complete.4529 // necessarily be free already after the then branch is complete.
4707 const pre_locals_len = @intCast(LocalIndex, f.locals.items.len);4530 const pre_locals_len = @intCast(LocalIndex, f.locals.items.len);
4531 // Remember how many allocs there were before entering the then branch so
4532 // that we can notice and make sure not to use them in the else branch.
4533 // Any new allocs must be removed from the free list.
4534 const pre_allocs_len = @intCast(LocalIndex, f.allocs.count());
4708 const pre_clone_depth = f.free_locals_clone_depth;4535 const pre_clone_depth = f.free_locals_clone_depth;
4709 f.free_locals_clone_depth = @intCast(LoopDepth, f.free_locals_stack.items.len);4536 f.free_locals_clone_depth = @intCast(LoopDepth, f.free_locals_stack.items.len);
47104537
...@@ -4735,7 +4562,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4735,7 +4562,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
4735 try die(f, inst, Air.indexToRef(operand));4562 try die(f, inst, Air.indexToRef(operand));
4736 }4563 }
47374564
4738 try noticeBranchFrees(f, pre_locals_len, inst);4565 try noticeBranchFrees(f, pre_locals_len, pre_allocs_len, inst);
47394566
4740 if (needs_else) {4567 if (needs_else) {
4741 try genBody(f, else_body);4568 try genBody(f, else_body);
...@@ -4745,7 +4572,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4745,7 +4572,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
47454572
4746 try f.object.indent_writer.insertNewline();4573 try f.object.indent_writer.insertNewline();
47474574
4748 return CValue.none;4575 return .none;
4749}4576}
47504577
4751fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {4578fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -4759,11 +4586,11 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4759,11 +4586,11 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
4759 try writer.writeAll("switch (");4586 try writer.writeAll("switch (");
4760 if (condition_ty.zigTypeTag() == .Bool) {4587 if (condition_ty.zigTypeTag() == .Bool) {
4761 try writer.writeByte('(');4588 try writer.writeByte('(');
4762 try f.renderTypecast(writer, Type.u1);4589 try f.renderType(writer, Type.u1);
4763 try writer.writeByte(')');4590 try writer.writeByte(')');
4764 } else if (condition_ty.isPtrAtRuntime()) {4591 } else if (condition_ty.isPtrAtRuntime()) {
4765 try writer.writeByte('(');4592 try writer.writeByte('(');
4766 try f.renderTypecast(writer, Type.usize);4593 try f.renderType(writer, Type.usize);
4767 try writer.writeByte(')');4594 try writer.writeByte(')');
4768 }4595 }
4769 try f.writeCValue(writer, condition, .Other);4596 try f.writeCValue(writer, condition, .Other);
...@@ -4780,8 +4607,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4780,8 +4607,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
4780 const last_case_i = switch_br.data.cases_len - @boolToInt(switch_br.data.else_body_len == 0);4607 const last_case_i = switch_br.data.cases_len - @boolToInt(switch_br.data.else_body_len == 0);
47814608
4782 var extra_index: usize = switch_br.end;4609 var extra_index: usize = switch_br.end;
4783 var case_i: u32 = 0;4610 for (0..switch_br.data.cases_len) |case_i| {
4784 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
4785 const case = f.air.extraData(Air.SwitchBr.Case, extra_index);4611 const case = f.air.extraData(Air.SwitchBr.Case, extra_index);
4786 const items = @ptrCast([]const Air.Inst.Ref, f.air.extra[case.end..][0..case.data.items_len]);4612 const items = @ptrCast([]const Air.Inst.Ref, f.air.extra[case.end..][0..case.data.items_len]);
4787 const case_body = f.air.extra[case.end + items.len ..][0..case.data.body_len];4613 const case_body = f.air.extra[case.end + items.len ..][0..case.data.body_len];
...@@ -4792,7 +4618,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4792,7 +4618,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
4792 try writer.writeAll("case ");4618 try writer.writeAll("case ");
4793 if (condition_ty.isPtrAtRuntime()) {4619 if (condition_ty.isPtrAtRuntime()) {
4794 try writer.writeByte('(');4620 try writer.writeByte('(');
4795 try f.renderTypecast(writer, Type.usize);4621 try f.renderType(writer, Type.usize);
4796 try writer.writeByte(')');4622 try writer.writeByte(')');
4797 }4623 }
4798 try f.object.dg.renderValue(writer, condition_ty, f.air.value(item).?, .Other);4624 try f.object.dg.renderValue(writer, condition_ty, f.air.value(item).?, .Other);
...@@ -4811,6 +4637,10 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4811,6 +4637,10 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
4811 // we can notice and use them in subsequent branches. Any new locals must4637 // we can notice and use them in subsequent branches. Any new locals must
4812 // necessarily be free already after the previous branch is complete.4638 // necessarily be free already after the previous branch is complete.
4813 const pre_locals_len = @intCast(LocalIndex, f.locals.items.len);4639 const pre_locals_len = @intCast(LocalIndex, f.locals.items.len);
4640 // Remember how many allocs there were before entering each branch so that
4641 // we can notice and make sure not to use them in subsequent branches.
4642 // Any new allocs must be removed from the free list.
4643 const pre_allocs_len = @intCast(LocalIndex, f.allocs.count());
4814 const pre_clone_depth = f.free_locals_clone_depth;4644 const pre_clone_depth = f.free_locals_clone_depth;
4815 f.free_locals_clone_depth = @intCast(LoopDepth, f.free_locals_stack.items.len);4645 f.free_locals_clone_depth = @intCast(LoopDepth, f.free_locals_stack.items.len);
48164646
...@@ -4831,7 +4661,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4831,7 +4661,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
4831 try genBody(f, case_body);4661 try genBody(f, case_body);
4832 }4662 }
48334663
4834 try noticeBranchFrees(f, pre_locals_len, inst);4664 try noticeBranchFrees(f, pre_locals_len, pre_allocs_len, inst);
4835 } else {4665 } else {
4836 for (liveness.deaths[case_i]) |operand| {4666 for (liveness.deaths[case_i]) |operand| {
4837 try die(f, inst, Air.indexToRef(operand));4667 try die(f, inst, Air.indexToRef(operand));
...@@ -4858,7 +4688,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4858,7 +4688,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
48584688
4859 f.object.indent_writer.popIndent();4689 f.object.indent_writer.popIndent();
4860 try writer.writeAll("}\n");4690 try writer.writeAll("}\n");
4861 return CValue.none;4691 return .none;
4862}4692}
48634693
4864fn asmInputNeedsLocal(constraint: []const u8, value: CValue) bool {4694fn asmInputNeedsLocal(constraint: []const u8, value: CValue) bool {
...@@ -4880,8 +4710,8 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4880,8 +4710,8 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4880 const inputs = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.inputs_len]);4710 const inputs = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.inputs_len]);
4881 extra_i += inputs.len;4711 extra_i += inputs.len;
48824712
4883 const result: CValue = r: {4713 const result = r: {
4884 if (!is_volatile and f.liveness.isUnused(inst)) break :r CValue.none;4714 if (!is_volatile and f.liveness.isUnused(inst)) break :r .none;
48854715
4886 const writer = f.object.writer();4716 const writer = f.object.writer();
4887 const inst_ty = f.air.typeOfIndex(inst);4717 const inst_ty = f.air.typeOfIndex(inst);
...@@ -4918,14 +4748,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4918,14 +4748,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4918 try writer.writeAll("register ");4748 try writer.writeAll("register ");
4919 const alignment = 0;4749 const alignment = 0;
4920 const local_value = try f.allocLocalValue(output_ty, alignment);4750 const local_value = try f.allocLocalValue(output_ty, alignment);
4921 try f.object.dg.renderTypeAndName(4751 try f.object.dg.renderTypeAndName(writer, output_ty, local_value, .{}, alignment, .complete);
4922 writer,
4923 output_ty,
4924 local_value,
4925 .Mut,
4926 alignment,
4927 .Complete,
4928 );
4929 try writer.writeAll(" __asm(\"");4752 try writer.writeAll(" __asm(\"");
4930 try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);4753 try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);
4931 try writer.writeAll("\")");4754 try writer.writeAll("\")");
...@@ -4957,14 +4780,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4957,14 +4780,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4957 if (is_reg) try writer.writeAll("register ");4780 if (is_reg) try writer.writeAll("register ");
4958 const alignment = 0;4781 const alignment = 0;
4959 const local_value = try f.allocLocalValue(input_ty, alignment);4782 const local_value = try f.allocLocalValue(input_ty, alignment);
4960 try f.object.dg.renderTypeAndName(4783 try f.object.dg.renderTypeAndName(writer, input_ty, local_value, Const, alignment, .complete);
4961 writer,
4962 input_ty,
4963 local_value,
4964 .Const,
4965 alignment,
4966 .Complete,
4967 );
4968 if (is_reg) {4784 if (is_reg) {
4969 try writer.writeAll(" __asm(\"");4785 try writer.writeAll(" __asm(\"");
4970 try writer.writeAll(constraint["{".len .. constraint.len - "}".len]);4786 try writer.writeAll(constraint["{".len .. constraint.len - "}".len]);
...@@ -4975,14 +4791,11 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4975,14 +4791,11 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4975 try writer.writeAll(";\n");4791 try writer.writeAll(";\n");
4976 }4792 }
4977 }4793 }
4978 {4794 for (0..clobbers_len) |_| {
4979 var clobber_i: u32 = 0;4795 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);
4980 while (clobber_i < clobbers_len) : (clobber_i += 1) {4796 // This equation accounts for the fact that even if we have exactly 4 bytes
4981 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);4797 // for the string, we still use the next u32 for the null terminator.
4982 // This equation accounts for the fact that even if we have exactly 4 bytes4798 extra_i += clobber.len / 4 + 1;
4983 // for the string, we still use the next u32 for the null terminator.
4984 extra_i += clobber.len / 4 + 1;
4985 }
4986 }4799 }
49874800
4988 {4801 {
...@@ -5037,7 +4850,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5037,7 +4850,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
50374850
5038 try writer.writeAll("__asm");4851 try writer.writeAll("__asm");
5039 if (is_volatile) try writer.writeAll(" volatile");4852 if (is_volatile) try writer.writeAll(" volatile");
5040 try writer.print("({s}", .{fmtStringLiteral(fixed_asm_source[0..dst_i])});4853 try writer.print("({s}", .{fmtStringLiteral(fixed_asm_source[0..dst_i], null)});
5041 }4854 }
50424855
5043 extra_i = constraints_extra_begin;4856 extra_i = constraints_extra_begin;
...@@ -5055,7 +4868,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5055,7 +4868,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
5055 try writer.writeByte(' ');4868 try writer.writeByte(' ');
5056 if (!std.mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name});4869 if (!std.mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name});
5057 const is_reg = constraint[1] == '{';4870 const is_reg = constraint[1] == '{';
5058 try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "=r" else constraint)});4871 try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "=r" else constraint, null)});
5059 if (is_reg) {4872 if (is_reg) {
5060 try f.writeCValue(writer, .{ .local = locals_index }, .Other);4873 try f.writeCValue(writer, .{ .local = locals_index }, .Other);
5061 locals_index += 1;4874 locals_index += 1;
...@@ -5081,28 +4894,25 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5081,28 +4894,25 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
50814894
5082 const is_reg = constraint[0] == '{';4895 const is_reg = constraint[0] == '{';
5083 const input_val = try f.resolveInst(input);4896 const input_val = try f.resolveInst(input);
5084 try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "r" else constraint)});4897 try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "r" else constraint, null)});
5085 try f.writeCValue(writer, if (asmInputNeedsLocal(constraint, input_val)) local: {4898 try f.writeCValue(writer, if (asmInputNeedsLocal(constraint, input_val)) local: {
5086 const input_local = CValue{ .local = locals_index };4899 const input_local = .{ .local = locals_index };
5087 locals_index += 1;4900 locals_index += 1;
5088 break :local input_local;4901 break :local input_local;
5089 } else input_val, .Other);4902 } else input_val, .Other);
5090 try writer.writeByte(')');4903 try writer.writeByte(')');
5091 }4904 }
5092 try writer.writeByte(':');4905 try writer.writeByte(':');
5093 {4906 for (0..clobbers_len) |clobber_i| {
5094 var clobber_i: u32 = 0;4907 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);
5095 while (clobber_i < clobbers_len) : (clobber_i += 1) {4908 // This equation accounts for the fact that even if we have exactly 4 bytes
5096 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);4909 // for the string, we still use the next u32 for the null terminator.
5097 // This equation accounts for the fact that even if we have exactly 4 bytes4910 extra_i += clobber.len / 4 + 1;
5098 // for the string, we still use the next u32 for the null terminator.
5099 extra_i += clobber.len / 4 + 1;
51004911
5101 if (clobber.len == 0) continue;4912 if (clobber.len == 0) continue;
51024913
5103 if (clobber_i > 0) try writer.writeByte(',');4914 if (clobber_i > 0) try writer.writeByte(',');
5104 try writer.print(" {s}", .{fmtStringLiteral(clobber)});4915 try writer.print(" {s}", .{fmtStringLiteral(clobber, null)});
5105 }
5106 }4916 }
5107 try writer.writeAll(");\n");4917 try writer.writeAll(");\n");
51084918
...@@ -5119,7 +4929,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5119,7 +4929,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
5119 const is_reg = constraint[1] == '{';4929 const is_reg = constraint[1] == '{';
5120 if (is_reg) {4930 if (is_reg) {
5121 try f.writeCValueDeref(writer, if (output == .none)4931 try f.writeCValueDeref(writer, if (output == .none)
5122 CValue{ .local_ref = local.local }4932 .{ .local_ref = local.new_local }
5123 else4933 else
5124 try f.resolveInst(output));4934 try f.resolveInst(output));
5125 try writer.writeAll(" = ");4935 try writer.writeAll(" = ");
...@@ -5154,7 +4964,7 @@ fn airIsNull(...@@ -5154,7 +4964,7 @@ fn airIsNull(
51544964
5155 if (f.liveness.isUnused(inst)) {4965 if (f.liveness.isUnused(inst)) {
5156 try reap(f, inst, &.{un_op});4966 try reap(f, inst, &.{un_op});
5157 return CValue.none;4967 return .none;
5158 }4968 }
51594969
5160 const writer = f.object.writer();4970 const writer = f.object.writer();
...@@ -5204,7 +5014,7 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5204,7 +5014,7 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
52045014
5205 if (f.liveness.isUnused(inst)) {5015 if (f.liveness.isUnused(inst)) {
5206 try reap(f, inst, &.{ty_op.operand});5016 try reap(f, inst, &.{ty_op.operand});
5207 return CValue.none;5017 return .none;
5208 }5018 }
52095019
5210 const operand = try f.resolveInst(ty_op.operand);5020 const operand = try f.resolveInst(ty_op.operand);
...@@ -5215,7 +5025,7 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5215,7 +5025,7 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
5215 const payload_ty = opt_ty.optionalChild(&buf);5025 const payload_ty = opt_ty.optionalChild(&buf);
52165026
5217 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {5027 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
5218 return CValue.none;5028 return .none;
5219 }5029 }
52205030
5221 const inst_ty = f.air.typeOfIndex(inst);5031 const inst_ty = f.air.typeOfIndex(inst);
...@@ -5244,7 +5054,7 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5244,7 +5054,7 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
5244 try f.writeCValueMember(writer, operand, .{ .identifier = "payload" });5054 try f.writeCValueMember(writer, operand, .{ .identifier = "payload" });
5245 if (is_array) {5055 if (is_array) {
5246 try writer.writeAll(", sizeof(");5056 try writer.writeAll(", sizeof(");
5247 try f.renderTypecast(writer, inst_ty);5057 try f.renderType(writer, inst_ty);
5248 try writer.writeAll("))");5058 try writer.writeAll("))");
5249 }5059 }
5250 try writer.writeAll(";\n");5060 try writer.writeAll(";\n");
...@@ -5256,7 +5066,7 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5256,7 +5066,7 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {
52565066
5257 if (f.liveness.isUnused(inst)) {5067 if (f.liveness.isUnused(inst)) {
5258 try reap(f, inst, &.{ty_op.operand});5068 try reap(f, inst, &.{ty_op.operand});
5259 return CValue.none;5069 return .none;
5260 }5070 }
52615071
5262 const writer = f.object.writer();5072 const writer = f.object.writer();
...@@ -5267,7 +5077,7 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5267,7 +5077,7 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {
5267 const inst_ty = f.air.typeOfIndex(inst);5077 const inst_ty = f.air.typeOfIndex(inst);
52685078
5269 if (!inst_ty.childType().hasRuntimeBitsIgnoreComptime()) {5079 if (!inst_ty.childType().hasRuntimeBitsIgnoreComptime()) {
5270 return CValue{ .undef = inst_ty };5080 return .{ .undef = inst_ty };
5271 }5081 }
52725082
5273 const local = try f.allocLocal(inst, inst_ty);5083 const local = try f.allocLocal(inst, inst_ty);
...@@ -5299,7 +5109,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5299,7 +5109,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
52995109
5300 if (opt_ty.optionalReprIsPayload()) {5110 if (opt_ty.optionalReprIsPayload()) {
5301 if (f.liveness.isUnused(inst)) {5111 if (f.liveness.isUnused(inst)) {
5302 return CValue.none;5112 return .none;
5303 }5113 }
5304 const local = try f.allocLocal(inst, inst_ty);5114 const local = try f.allocLocal(inst, inst_ty);
5305 // The payload and the optional are the same value.5115 // The payload and the optional are the same value.
...@@ -5316,7 +5126,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5316,7 +5126,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
5316 try writer.writeAll(";\n");5126 try writer.writeAll(";\n");
53175127
5318 if (f.liveness.isUnused(inst)) {5128 if (f.liveness.isUnused(inst)) {
5319 return CValue.none;5129 return .none;
5320 }5130 }
53215131
5322 const local = try f.allocLocal(inst, inst_ty);5132 const local = try f.allocLocal(inst, inst_ty);
...@@ -5328,6 +5138,62 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5328,6 +5138,62 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
5328 }5138 }
5329}5139}
53305140
5141fn fieldLocation(
5142 container_ty: Type,
5143 field_ptr_ty: Type,
5144 field_index: u32,
5145 target: std.Target,
5146) union(enum) {
5147 begin: void,
5148 field: CValue,
5149 byte_offset: u32,
5150 end: void,
5151} {
5152 return switch (container_ty.zigTypeTag()) {
5153 .Struct => switch (container_ty.containerLayout()) {
5154 .Auto, .Extern => for (field_index..container_ty.structFieldCount()) |next_field_index| {
5155 if (container_ty.structFieldIsComptime(next_field_index)) continue;
5156 const field_ty = container_ty.structFieldType(next_field_index);
5157 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
5158 break .{ .field = if (container_ty.isSimpleTuple())
5159 .{ .field = next_field_index }
5160 else
5161 .{ .identifier = container_ty.structFieldName(next_field_index) } };
5162 } else if (container_ty.hasRuntimeBitsIgnoreComptime()) .end else .begin,
5163 .Packed => if (field_ptr_ty.ptrInfo().data.host_size == 0)
5164 .{ .byte_offset = container_ty.packedStructFieldByteOffset(field_index, target) }
5165 else
5166 .begin,
5167 },
5168 .Union => switch (container_ty.containerLayout()) {
5169 .Auto, .Extern => {
5170 const field_ty = container_ty.structFieldType(field_index);
5171 if (!field_ty.hasRuntimeBitsIgnoreComptime())
5172 return if (container_ty.unionTagTypeSafety() != null and
5173 !container_ty.unionHasAllZeroBitFieldTypes())
5174 .{ .field = .{ .identifier = "payload" } }
5175 else
5176 .begin;
5177 const field_name = container_ty.unionFields().keys()[field_index];
5178 return .{ .field = if (container_ty.unionTagTypeSafety()) |_|
5179 .{ .payload_identifier = field_name }
5180 else
5181 .{ .identifier = field_name } };
5182 },
5183 .Packed => .begin,
5184 },
5185 .Pointer => switch (container_ty.ptrSize()) {
5186 .Slice => switch (field_index) {
5187 0 => .{ .field = .{ .identifier = "ptr" } },
5188 1 => .{ .field = .{ .identifier = "len" } },
5189 else => unreachable,
5190 },
5191 .One, .Many, .C => unreachable,
5192 },
5193 else => unreachable,
5194 };
5195}
5196
5331fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {5197fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {
5332 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;5198 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
5333 const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;5199 const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;
...@@ -5337,10 +5203,10 @@ fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5337,10 +5203,10 @@ fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {
5337 return .none;5203 return .none;
5338 }5204 }
53395205
5340 const struct_ptr = try f.resolveInst(extra.struct_operand);5206 const container_ptr_val = try f.resolveInst(extra.struct_operand);
5341 try reap(f, inst, &.{extra.struct_operand});5207 try reap(f, inst, &.{extra.struct_operand});
5342 const struct_ptr_ty = f.air.typeOf(extra.struct_operand);5208 const container_ptr_ty = f.air.typeOf(extra.struct_operand);
5343 return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, extra.field_index);5209 return fieldPtr(f, inst, container_ptr_ty, container_ptr_val, extra.field_index);
5344}5210}
53455211
5346fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue {5212fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue {
...@@ -5351,10 +5217,10 @@ fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue...@@ -5351,10 +5217,10 @@ fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue
5351 return .none;5217 return .none;
5352 }5218 }
53535219
5354 const struct_ptr = try f.resolveInst(ty_op.operand);5220 const container_ptr_val = try f.resolveInst(ty_op.operand);
5355 try reap(f, inst, &.{ty_op.operand});5221 try reap(f, inst, &.{ty_op.operand});
5356 const struct_ptr_ty = f.air.typeOf(ty_op.operand);5222 const container_ptr_ty = f.air.typeOf(ty_op.operand);
5357 return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, index);5223 return fieldPtr(f, inst, container_ptr_ty, container_ptr_val, index);
5358}5224}
53595225
5360fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {5226fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -5363,137 +5229,119 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5363,137 +5229,119 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
53635229
5364 if (f.liveness.isUnused(inst)) {5230 if (f.liveness.isUnused(inst)) {
5365 try reap(f, inst, &.{extra.field_ptr});5231 try reap(f, inst, &.{extra.field_ptr});
5366 return CValue.none;5232 return .none;
5367 }5233 }
53685234
5369 const struct_ptr_ty = f.air.typeOfIndex(inst);5235 const target = f.object.dg.module.getTarget();
5236 const container_ptr_ty = f.air.typeOfIndex(inst);
5237 const container_ty = container_ptr_ty.childType();
5238
5370 const field_ptr_ty = f.air.typeOf(extra.field_ptr);5239 const field_ptr_ty = f.air.typeOf(extra.field_ptr);
5371 const field_ptr_val = try f.resolveInst(extra.field_ptr);5240 const field_ptr_val = try f.resolveInst(extra.field_ptr);
5372 try reap(f, inst, &.{extra.field_ptr});5241 try reap(f, inst, &.{extra.field_ptr});
53735242
5374 const target = f.object.dg.module.getTarget();
5375 const struct_ty = struct_ptr_ty.childType();
5376 const field_offset = struct_ty.structFieldOffset(extra.field_index, target);
5377
5378 var field_offset_pl = Value.Payload.I64{
5379 .base = .{ .tag = .int_i64 },
5380 .data = -@intCast(i64, field_offset),
5381 };
5382 const field_offset_val = Value.initPayload(&field_offset_pl.base);
5383
5384 var u8_ptr_pl = field_ptr_ty.ptrInfo();
5385 u8_ptr_pl.data.pointee_type = Type.u8;
5386 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
5387
5388 const writer = f.object.writer();5243 const writer = f.object.writer();
5389 const local = try f.allocLocal(inst, struct_ptr_ty);5244 const local = try f.allocLocal(inst, container_ptr_ty);
5390 try f.writeCValue(writer, local, .Other);5245 try f.writeCValue(writer, local, .Other);
5391 try writer.writeAll(" = (");5246 try writer.writeAll(" = (");
5392 try f.renderTypecast(writer, struct_ptr_ty);5247 try f.renderType(writer, container_ptr_ty);
5393 try writer.writeAll(")&((");
5394 try f.renderTypecast(writer, u8_ptr_ty);
5395 try writer.writeByte(')');5248 try writer.writeByte(')');
5396 try f.writeCValue(writer, field_ptr_val, .Other);5249
5397 try writer.print(")[{}];\n", .{try f.fmtIntLiteral(Type.isize, field_offset_val)});5250 switch (fieldLocation(container_ty, field_ptr_ty, extra.field_index, target)) {
5251 .begin => try f.writeCValue(writer, field_ptr_val, .Initializer),
5252 .field => |field| {
5253 var u8_ptr_pl = field_ptr_ty.ptrInfo();
5254 u8_ptr_pl.data.pointee_type = Type.u8;
5255 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
5256
5257 try writer.writeAll("((");
5258 try f.renderType(writer, u8_ptr_ty);
5259 try writer.writeByte(')');
5260 try f.writeCValue(writer, field_ptr_val, .Other);
5261 try writer.writeAll(" - offsetof(");
5262 try f.renderType(writer, container_ty);
5263 try writer.writeAll(", ");
5264 try f.writeCValue(writer, field, .Other);
5265 try writer.writeAll("))");
5266 },
5267 .byte_offset => |byte_offset| {
5268 var u8_ptr_pl = field_ptr_ty.ptrInfo();
5269 u8_ptr_pl.data.pointee_type = Type.u8;
5270 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
5271
5272 var byte_offset_pl = Value.Payload.U64{
5273 .base = .{ .tag = .int_u64 },
5274 .data = byte_offset,
5275 };
5276 const byte_offset_val = Value.initPayload(&byte_offset_pl.base);
5277
5278 try writer.writeAll("((");
5279 try f.renderType(writer, u8_ptr_ty);
5280 try writer.writeByte(')');
5281 try f.writeCValue(writer, field_ptr_val, .Other);
5282 try writer.print(" - {})", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)});
5283 },
5284 .end => {
5285 try f.writeCValue(writer, field_ptr_val, .Other);
5286 try writer.print(" - {}", .{try f.fmtIntLiteral(Type.usize, Value.one)});
5287 },
5288 }
5289
5290 try writer.writeAll(";\n");
5398 return local;5291 return local;
5399}5292}
54005293
5401fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue {5294fn fieldPtr(
5402 const writer = f.object.writer();5295 f: *Function,
5296 inst: Air.Inst.Index,
5297 container_ptr_ty: Type,
5298 container_ptr_val: CValue,
5299 field_index: u32,
5300) !CValue {
5301 const target = f.object.dg.module.getTarget();
5302 const container_ty = container_ptr_ty.elemType();
5403 const field_ptr_ty = f.air.typeOfIndex(inst);5303 const field_ptr_ty = f.air.typeOfIndex(inst);
5404 const field_ptr_info = field_ptr_ty.ptrInfo();
5405 const struct_ty = struct_ptr_ty.elemType();
5406 const field_ty = struct_ty.structFieldType(index);
54075304
5408 // Ensure complete type definition is visible before accessing fields.5305 // Ensure complete type definition is visible before accessing fields.
5409 try f.renderType(std.io.null_writer, struct_ty);5306 _ = try f.typeToIndex(container_ty, .complete);
54105307
5308 const writer = f.object.writer();
5411 const local = try f.allocLocal(inst, field_ptr_ty);5309 const local = try f.allocLocal(inst, field_ptr_ty);
5412 try f.writeCValue(writer, local, .Other);5310 try f.writeCValue(writer, local, .Other);
5413 try writer.writeAll(" = (");5311 try writer.writeAll(" = (");
5414 try f.renderTypecast(writer, field_ptr_ty);5312 try f.renderType(writer, field_ptr_ty);
5415 try writer.writeByte(')');5313 try writer.writeByte(')');
54165314
5417 const extra_name: CValue = switch (struct_ty.tag()) {5315 switch (fieldLocation(container_ty, field_ptr_ty, field_index, target)) {
5418 .union_tagged, .union_safety_tagged => .{ .identifier = "payload" },5316 .begin => try f.writeCValue(writer, container_ptr_val, .Initializer),
5419 else => .none,5317 .field => |field| {
5420 };5318 try writer.writeByte('&');
54215319 try f.writeCValueDerefMember(writer, container_ptr_val, field);
5422 const FieldLoc = union(enum) {5320 },
5423 begin: void,5321 .byte_offset => |byte_offset| {
5424 field: CValue,5322 var u8_ptr_pl = field_ptr_ty.ptrInfo();
5425 end: void,5323 u8_ptr_pl.data.pointee_type = Type.u8;
5426 };5324 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
5427 const field_loc = switch (struct_ty.tag()) {
5428 .@"struct" => switch (struct_ty.containerLayout()) {
5429 .Auto, .Extern => for (struct_ty.structFields().values()[index..], 0..) |field, offset| {
5430 if (field.ty.hasRuntimeBitsIgnoreComptime()) break FieldLoc{ .field = .{
5431 .identifier = struct_ty.structFieldName(index + offset),
5432 } };
5433 } else @as(FieldLoc, .end),
5434 .Packed => if (field_ptr_info.data.host_size == 0) {
5435 const target = f.object.dg.module.getTarget();
5436
5437 const byte_offset = struct_ty.packedStructFieldByteOffset(index, target);
5438 var byte_offset_pl = Value.Payload.U64{
5439 .base = .{ .tag = .int_u64 },
5440 .data = byte_offset,
5441 };
5442 const byte_offset_val = Value.initPayload(&byte_offset_pl.base);
5443
5444 var u8_ptr_pl = field_ptr_info;
5445 u8_ptr_pl.data.pointee_type = Type.u8;
5446 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
54475325
5448 if (!std.mem.isAligned(byte_offset, field_ptr_ty.ptrAlignment(target))) {5326 var byte_offset_pl = Value.Payload.U64{
5449 return f.fail("TODO: CBE: unaligned packed struct field pointer", .{});5327 .base = .{ .tag = .int_u64 },
5450 }5328 .data = byte_offset,
5329 };
5330 const byte_offset_val = Value.initPayload(&byte_offset_pl.base);
54515331
5452 try writer.writeAll("&((");5332 try writer.writeAll("((");
5453 try f.renderTypecast(writer, u8_ptr_ty);5333 try f.renderType(writer, u8_ptr_ty);
5454 try writer.writeByte(')');5334 try writer.writeByte(')');
5455 try f.writeCValue(writer, struct_ptr, .Other);5335 try f.writeCValue(writer, container_ptr_val, .Other);
5456 try writer.print(")[{}];\n", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)});5336 try writer.print(" + {})", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)});
5457 return local;
5458 } else @as(FieldLoc, .begin),
5459 },
5460 .@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout() == .Packed) {
5461 try f.writeCValue(writer, struct_ptr, .Other);
5462 try writer.writeAll(";\n");
5463 return local;
5464 } else if (field_ty.hasRuntimeBitsIgnoreComptime()) FieldLoc{ .field = .{
5465 .identifier = struct_ty.unionFields().keys()[index],
5466 } } else @as(FieldLoc, .end),
5467 .tuple, .anon_struct => field_name: {
5468 const tuple = struct_ty.tupleFields();
5469 if (tuple.values[index].tag() != .unreachable_value) return CValue.none;
5470
5471 var id: usize = 0;
5472 break :field_name for (tuple.values, 0..) |value, i| {
5473 if (value.tag() != .unreachable_value) continue;
5474 if (!tuple.types[i].hasRuntimeBitsIgnoreComptime()) continue;
5475 if (i >= index) break FieldLoc{ .field = .{ .field = id } };
5476 id += 1;
5477 } else @as(FieldLoc, .end);
5478 },5337 },
5479 else => unreachable,5338 .end => {
5480 };
5481
5482 try writer.writeByte('&');
5483 switch (field_loc) {
5484 .begin, .end => {
5485 try writer.writeByte('(');5339 try writer.writeByte('(');
5486 try f.writeCValue(writer, struct_ptr, .Other);5340 try f.writeCValue(writer, container_ptr_val, .Other);
5487 try writer.print(")[{}]", .{5341 try writer.print(" + {})", .{try f.fmtIntLiteral(Type.usize, Value.one)});
5488 @boolToInt(field_loc == .end and struct_ty.hasRuntimeBitsIgnoreComptime()),
5489 });
5490 },5342 },
5491 .field => |field| if (extra_name != .none) {
5492 try f.writeCValueDerefMember(writer, struct_ptr, extra_name);
5493 try writer.writeByte('.');
5494 try f.writeCValue(writer, field, .Other);
5495 } else try f.writeCValueDerefMember(writer, struct_ptr, field),
5496 }5343 }
5344
5497 try writer.writeAll(";\n");5345 try writer.writeAll(";\n");
5498 return local;5346 return local;
5499}5347}
...@@ -5504,13 +5352,13 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5504,13 +5352,13 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
55045352
5505 if (f.liveness.isUnused(inst)) {5353 if (f.liveness.isUnused(inst)) {
5506 try reap(f, inst, &.{extra.struct_operand});5354 try reap(f, inst, &.{extra.struct_operand});
5507 return CValue.none;5355 return .none;
5508 }5356 }
55095357
5510 const inst_ty = f.air.typeOfIndex(inst);5358 const inst_ty = f.air.typeOfIndex(inst);
5511 if (!inst_ty.hasRuntimeBitsIgnoreComptime()) {5359 if (!inst_ty.hasRuntimeBitsIgnoreComptime()) {
5512 try reap(f, inst, &.{extra.struct_operand});5360 try reap(f, inst, &.{extra.struct_operand});
5513 return CValue.none;5361 return .none;
5514 }5362 }
55155363
5516 const target = f.object.dg.module.getTarget();5364 const target = f.object.dg.module.getTarget();
...@@ -5520,16 +5368,14 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5520,16 +5368,14 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5520 const writer = f.object.writer();5368 const writer = f.object.writer();
55215369
5522 // Ensure complete type definition is visible before accessing fields.5370 // Ensure complete type definition is visible before accessing fields.
5523 try f.renderType(std.io.null_writer, struct_ty);5371 _ = try f.typeToIndex(struct_ty, .complete);
5524
5525 const extra_name: CValue = switch (struct_ty.tag()) {
5526 .union_tagged, .union_safety_tagged => .{ .identifier = "payload" },
5527 else => .none,
5528 };
55295372
5530 const field_name: CValue = switch (struct_ty.tag()) {5373 const field_name: CValue = switch (struct_ty.tag()) {
5531 .@"struct" => switch (struct_ty.containerLayout()) {5374 .tuple, .anon_struct, .@"struct" => switch (struct_ty.containerLayout()) {
5532 .Auto, .Extern => .{ .identifier = struct_ty.structFieldName(extra.field_index) },5375 .Auto, .Extern => if (struct_ty.isSimpleTuple())
5376 .{ .field = extra.field_index }
5377 else
5378 .{ .identifier = struct_ty.structFieldName(extra.field_index) },
5533 .Packed => {5379 .Packed => {
5534 const struct_obj = struct_ty.castTag(.@"struct").?.data;5380 const struct_obj = struct_ty.castTag(.@"struct").?.data;
5535 const int_info = struct_ty.intInfo(target);5381 const int_info = struct_ty.intInfo(target);
...@@ -5564,7 +5410,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5564,7 +5410,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5564 try writer.writeAll(" = zig_wrap_");5410 try writer.writeAll(" = zig_wrap_");
5565 try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty);5411 try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty);
5566 try writer.writeAll("((");5412 try writer.writeAll("((");
5567 try f.renderTypecast(writer, field_int_ty);5413 try f.renderType(writer, field_int_ty);
5568 try writer.writeByte(')');5414 try writer.writeByte(')');
5569 const cant_cast = int_info.bits > 64;5415 const cant_cast = int_info.bits > 64;
5570 if (cant_cast) {5416 if (cant_cast) {
...@@ -5587,13 +5433,13 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5587,13 +5433,13 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
55875433
5588 const local = try f.allocLocal(inst, inst_ty);5434 const local = try f.allocLocal(inst, inst_ty);
5589 try writer.writeAll("memcpy(");5435 try writer.writeAll("memcpy(");
5590 try f.writeCValue(writer, .{ .local_ref = local.local }, .FunctionArgument);5436 try f.writeCValue(writer, .{ .local_ref = local.new_local }, .FunctionArgument);
5591 try writer.writeAll(", ");5437 try writer.writeAll(", ");
5592 try f.writeCValue(writer, .{ .local_ref = temp_local.local }, .FunctionArgument);5438 try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument);
5593 try writer.writeAll(", sizeof(");5439 try writer.writeAll(", sizeof(");
5594 try f.renderTypecast(writer, inst_ty);5440 try f.renderType(writer, inst_ty);
5595 try writer.writeAll("));\n");5441 try writer.writeAll("));\n");
5596 try freeLocal(f, inst, temp_local.local, 0);5442 try freeLocal(f, inst, temp_local.new_local, 0);
5597 return local;5443 return local;
5598 },5444 },
5599 },5445 },
...@@ -5613,48 +5459,37 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5613,48 +5459,37 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5613 try writer.writeAll(", &");5459 try writer.writeAll(", &");
5614 try f.writeCValue(writer, operand_lval, .FunctionArgument);5460 try f.writeCValue(writer, operand_lval, .FunctionArgument);
5615 try writer.writeAll(", sizeof(");5461 try writer.writeAll(", sizeof(");
5616 try f.renderTypecast(writer, inst_ty);5462 try f.renderType(writer, inst_ty);
5617 try writer.writeAll("));\n");5463 try writer.writeAll("));\n");
56185464
5619 if (struct_byval == .constant) {5465 if (struct_byval == .constant) {
5620 try freeLocal(f, inst, operand_lval.local, 0);5466 try freeLocal(f, inst, operand_lval.new_local, 0);
5621 }5467 }
56225468
5623 return local;5469 return local;
5624 } else .{5470 } else field_name: {
5625 .identifier = struct_ty.unionFields().keys()[extra.field_index],5471 const name = struct_ty.unionFields().keys()[extra.field_index];
5626 },5472 break :field_name if (struct_ty.unionTagTypeSafety()) |_|
5627 .tuple, .anon_struct => blk: {5473 .{ .payload_identifier = name }
5628 const tuple = struct_ty.tupleFields();5474 else
5629 if (tuple.values[extra.field_index].tag() != .unreachable_value) return CValue.none;5475 .{ .identifier = name };
5630
5631 var id: usize = 0;
5632 for (tuple.values[0..extra.field_index]) |value|
5633 id += @boolToInt(value.tag() == .unreachable_value);
5634 break :blk .{ .field = id };
5635 },5476 },
5636 else => unreachable,5477 else => unreachable,
5637 };5478 };
56385479
5639 const is_array = lowersToArray(inst_ty, target);
5640 const local = try f.allocLocal(inst, inst_ty);5480 const local = try f.allocLocal(inst, inst_ty);
5641 if (is_array) {5481 if (lowersToArray(inst_ty, target)) {
5642 try writer.writeAll("memcpy(");5482 try writer.writeAll("memcpy(");
5643 try f.writeCValue(writer, local, .FunctionArgument);5483 try f.writeCValue(writer, local, .FunctionArgument);
5644 try writer.writeAll(", ");5484 try writer.writeAll(", ");
5485 try f.writeCValueMember(writer, struct_byval, field_name);
5486 try writer.writeAll(", sizeof(");
5487 try f.renderType(writer, inst_ty);
5488 try writer.writeAll("))");
5645 } else {5489 } else {
5646 try f.writeCValue(writer, local, .Other);5490 try f.writeCValue(writer, local, .Other);
5647 try writer.writeAll(" = ");5491 try writer.writeAll(" = ");
5648 }5492 try f.writeCValueMember(writer, struct_byval, field_name);
5649 if (extra_name != .none) {
5650 try f.writeCValueMember(writer, struct_byval, extra_name);
5651 try writer.writeByte('.');
5652 try f.writeCValue(writer, field_name, .Other);
5653 } else try f.writeCValueMember(writer, struct_byval, field_name);
5654 if (is_array) {
5655 try writer.writeAll(", sizeof(");
5656 try f.renderTypecast(writer, inst_ty);
5657 try writer.writeAll("))");
5658 }5493 }
5659 try writer.writeAll(";\n");5494 try writer.writeAll(";\n");
5660 return local;5495 return local;
...@@ -5667,7 +5502,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5667,7 +5502,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
56675502
5668 if (f.liveness.isUnused(inst)) {5503 if (f.liveness.isUnused(inst)) {
5669 try reap(f, inst, &.{ty_op.operand});5504 try reap(f, inst, &.{ty_op.operand});
5670 return CValue.none;5505 return .none;
5671 }5506 }
56725507
5673 const inst_ty = f.air.typeOfIndex(inst);5508 const inst_ty = f.air.typeOfIndex(inst);
...@@ -5704,7 +5539,7 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu...@@ -5704,7 +5539,7 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
57045539
5705 if (f.liveness.isUnused(inst)) {5540 if (f.liveness.isUnused(inst)) {
5706 try reap(f, inst, &.{ty_op.operand});5541 try reap(f, inst, &.{ty_op.operand});
5707 return CValue.none;5542 return .none;
5708 }5543 }
57095544
5710 const inst_ty = f.air.typeOfIndex(inst);5545 const inst_ty = f.air.typeOfIndex(inst);
...@@ -5715,13 +5550,13 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu...@@ -5715,13 +5550,13 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
5715 const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;5550 const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
57165551
5717 if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) {5552 if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) {
5718 if (!is_ptr) return CValue.none;5553 if (!is_ptr) return .none;
57195554
5720 const w = f.object.writer();5555 const w = f.object.writer();
5721 const local = try f.allocLocal(inst, inst_ty);5556 const local = try f.allocLocal(inst, inst_ty);
5722 try f.writeCValue(w, local, .Other);5557 try f.writeCValue(w, local, .Other);
5723 try w.writeAll(" = (");5558 try w.writeAll(" = (");
5724 try f.renderTypecast(w, inst_ty);5559 try f.renderType(w, inst_ty);
5725 try w.writeByte(')');5560 try w.writeByte(')');
5726 try f.writeCValue(w, operand, .Initializer);5561 try f.writeCValue(w, operand, .Initializer);
5727 try w.writeAll(";\n");5562 try w.writeAll(";\n");
...@@ -5746,7 +5581,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5746,7 +5581,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
57465581
5747 if (f.liveness.isUnused(inst)) {5582 if (f.liveness.isUnused(inst)) {
5748 try reap(f, inst, &.{ty_op.operand});5583 try reap(f, inst, &.{ty_op.operand});
5749 return CValue.none;5584 return .none;
5750 }5585 }
57515586
5752 const inst_ty = f.air.typeOfIndex(inst);5587 const inst_ty = f.air.typeOfIndex(inst);
...@@ -5782,7 +5617,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5782,7 +5617,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
5782 try writer.writeAll(", ");5617 try writer.writeAll(", ");
5783 try f.writeCValue(writer, payload, .FunctionArgument);5618 try f.writeCValue(writer, payload, .FunctionArgument);
5784 try writer.writeAll(", sizeof(");5619 try writer.writeAll(", sizeof(");
5785 try f.renderTypecast(writer, payload_ty);5620 try f.renderType(writer, payload_ty);
5786 try writer.writeAll("));\n");5621 try writer.writeAll("));\n");
5787 }5622 }
5788 return local;5623 return local;
...@@ -5792,7 +5627,7 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5792,7 +5627,7 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
5792 const ty_op = f.air.instructions.items(.data)[inst].ty_op;5627 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
5793 if (f.liveness.isUnused(inst)) {5628 if (f.liveness.isUnused(inst)) {
5794 try reap(f, inst, &.{ty_op.operand});5629 try reap(f, inst, &.{ty_op.operand});
5795 return CValue.none;5630 return .none;
5796 }5631 }
57975632
5798 const writer = f.object.writer();5633 const writer = f.object.writer();
...@@ -5846,7 +5681,7 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5846,7 +5681,7 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
5846 try writer.writeAll(";\n");5681 try writer.writeAll(";\n");
58475682
5848 // Then return the payload pointer (only if it is used)5683 // Then return the payload pointer (only if it is used)
5849 if (f.liveness.isUnused(inst)) return CValue.none;5684 if (f.liveness.isUnused(inst)) return .none;
58505685
5851 const local = try f.allocLocal(inst, f.air.typeOfIndex(inst));5686 const local = try f.allocLocal(inst, f.air.typeOfIndex(inst));
5852 try f.writeCValue(writer, local, .Other);5687 try f.writeCValue(writer, local, .Other);
...@@ -5857,7 +5692,7 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5857,7 +5692,7 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
5857}5692}
58585693
5859fn airErrReturnTrace(f: *Function, inst: Air.Inst.Index) !CValue {5694fn airErrReturnTrace(f: *Function, inst: Air.Inst.Index) !CValue {
5860 if (f.liveness.isUnused(inst)) return CValue.none;5695 if (f.liveness.isUnused(inst)) return .none;
5861 return f.fail("TODO: C backend: implement airErrReturnTrace", .{});5696 return f.fail("TODO: C backend: implement airErrReturnTrace", .{});
5862}5697}
58635698
...@@ -5875,7 +5710,7 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5875,7 +5710,7 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
5875 const ty_op = f.air.instructions.items(.data)[inst].ty_op;5710 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
5876 if (f.liveness.isUnused(inst)) {5711 if (f.liveness.isUnused(inst)) {
5877 try reap(f, inst, &.{ty_op.operand});5712 try reap(f, inst, &.{ty_op.operand});
5878 return CValue.none;5713 return .none;
5879 }5714 }
58805715
5881 const inst_ty = f.air.typeOfIndex(inst);5716 const inst_ty = f.air.typeOfIndex(inst);
...@@ -5902,7 +5737,7 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5902,7 +5737,7 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
5902 try writer.writeAll(", ");5737 try writer.writeAll(", ");
5903 try f.writeCValue(writer, payload, .FunctionArgument);5738 try f.writeCValue(writer, payload, .FunctionArgument);
5904 try writer.writeAll(", sizeof(");5739 try writer.writeAll(", sizeof(");
5905 try f.renderTypecast(writer, payload_ty);5740 try f.renderType(writer, payload_ty);
5906 try writer.writeAll("));\n");5741 try writer.writeAll("));\n");
5907 }5742 }
5908 return local;5743 return local;
...@@ -5913,7 +5748,7 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const...@@ -5913,7 +5748,7 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const
59135748
5914 if (f.liveness.isUnused(inst)) {5749 if (f.liveness.isUnused(inst)) {
5915 try reap(f, inst, &.{un_op});5750 try reap(f, inst, &.{un_op});
5916 return CValue.none;5751 return .none;
5917 }5752 }
59185753
5919 const writer = f.object.writer();5754 const writer = f.object.writer();
...@@ -5951,7 +5786,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5951,7 +5786,7 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
59515786
5952 if (f.liveness.isUnused(inst)) {5787 if (f.liveness.isUnused(inst)) {
5953 try reap(f, inst, &.{ty_op.operand});5788 try reap(f, inst, &.{ty_op.operand});
5954 return CValue.none;5789 return .none;
5955 }5790 }
59565791
5957 const operand = try f.resolveInst(ty_op.operand);5792 const operand = try f.resolveInst(ty_op.operand);
...@@ -5959,26 +5794,28 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5959,26 +5794,28 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
5959 const inst_ty = f.air.typeOfIndex(inst);5794 const inst_ty = f.air.typeOfIndex(inst);
5960 const writer = f.object.writer();5795 const writer = f.object.writer();
5961 const local = try f.allocLocal(inst, inst_ty);5796 const local = try f.allocLocal(inst, inst_ty);
5962 try f.writeCValue(writer, local, .Other);5797 const array_ty = f.air.typeOf(ty_op.operand).childType();
5963 const array_len = f.air.typeOf(ty_op.operand).elemType().arrayLen();
59645798
5965 try writer.writeAll(".ptr = ");5799 try f.writeCValueMember(writer, local, .{ .identifier = "ptr" });
5800 try writer.writeAll(" = ");
5801 // Unfortunately, C does not support any equivalent to
5802 // &(*(void *)p)[0], although LLVM does via GetElementPtr
5966 if (operand == .undef) {5803 if (operand == .undef) {
5967 // Unfortunately, C does not support any equivalent to
5968 // &(*(void *)p)[0], although LLVM does via GetElementPtr
5969 var buf: Type.SlicePtrFieldTypeBuffer = undefined;5804 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
5970 try f.writeCValue(writer, CValue{ .undef = inst_ty.slicePtrFieldType(&buf) }, .Initializer);5805 try f.writeCValue(writer, .{ .undef = inst_ty.slicePtrFieldType(&buf) }, .Initializer);
5971 } else {5806 } else if (array_ty.hasRuntimeBitsIgnoreComptime()) {
5972 try writer.writeAll("&(");5807 try writer.writeAll("&(");
5973 try f.writeCValueDeref(writer, operand);5808 try f.writeCValueDeref(writer, operand);
5974 try writer.print(")[{}]", .{try f.fmtIntLiteral(Type.usize, Value.zero)});5809 try writer.print(")[{}]", .{try f.fmtIntLiteral(Type.usize, Value.zero)});
5975 }5810 } else try f.writeCValue(writer, operand, .Initializer);
5811 try writer.writeAll("; ");
59765812
5813 const array_len = array_ty.arrayLen();
5977 var len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = array_len };5814 var len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = array_len };
5978 const len_val = Value.initPayload(&len_pl.base);5815 const len_val = Value.initPayload(&len_pl.base);
5979 try writer.writeAll("; ");5816 try f.writeCValueMember(writer, local, .{ .identifier = "len" });
5980 try f.writeCValue(writer, local, .Other);5817 try writer.print(" = {};\n", .{try f.fmtIntLiteral(Type.usize, len_val)});
5981 try writer.print(".len = {};\n", .{try f.fmtIntLiteral(Type.usize, len_val)});5818
5982 return local;5819 return local;
5983}5820}
59845821
...@@ -5987,7 +5824,7 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5987,7 +5824,7 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
59875824
5988 if (f.liveness.isUnused(inst)) {5825 if (f.liveness.isUnused(inst)) {
5989 try reap(f, inst, &.{ty_op.operand});5826 try reap(f, inst, &.{ty_op.operand});
5990 return CValue.none;5827 return .none;
5991 }5828 }
59925829
5993 const inst_ty = f.air.typeOfIndex(inst);5830 const inst_ty = f.air.typeOfIndex(inst);
...@@ -6035,7 +5872,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6035,7 +5872,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {
60355872
6036 if (f.liveness.isUnused(inst)) {5873 if (f.liveness.isUnused(inst)) {
6037 try reap(f, inst, &.{un_op});5874 try reap(f, inst, &.{un_op});
6038 return CValue.none;5875 return .none;
6039 }5876 }
60405877
6041 const operand = try f.resolveInst(un_op);5878 const operand = try f.resolveInst(un_op);
...@@ -6046,7 +5883,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6046,7 +5883,7 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {
6046 try f.writeCValue(writer, local, .Other);5883 try f.writeCValue(writer, local, .Other);
60475884
6048 try writer.writeAll(" = (");5885 try writer.writeAll(" = (");
6049 try f.renderTypecast(writer, inst_ty);5886 try f.renderType(writer, inst_ty);
6050 try writer.writeByte(')');5887 try writer.writeByte(')');
6051 try f.writeCValue(writer, operand, .Other);5888 try f.writeCValue(writer, operand, .Other);
6052 try writer.writeAll(";\n");5889 try writer.writeAll(";\n");
...@@ -6063,7 +5900,7 @@ fn airUnBuiltinCall(...@@ -6063,7 +5900,7 @@ fn airUnBuiltinCall(
60635900
6064 if (f.liveness.isUnused(inst)) {5901 if (f.liveness.isUnused(inst)) {
6065 try reap(f, inst, &.{ty_op.operand});5902 try reap(f, inst, &.{ty_op.operand});
6066 return CValue.none;5903 return .none;
6067 }5904 }
60685905
6069 const operand = try f.resolveInst(ty_op.operand);5906 const operand = try f.resolveInst(ty_op.operand);
...@@ -6095,7 +5932,7 @@ fn airBinBuiltinCall(...@@ -6095,7 +5932,7 @@ fn airBinBuiltinCall(
60955932
6096 if (f.liveness.isUnused(inst)) {5933 if (f.liveness.isUnused(inst)) {
6097 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });5934 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
6098 return CValue.none;5935 return .none;
6099 }5936 }
61005937
6101 const lhs = try f.resolveInst(bin_op.lhs);5938 const lhs = try f.resolveInst(bin_op.lhs);
...@@ -6168,7 +6005,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue...@@ -6168,7 +6005,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
6168 try writer.writeAll(";\n");6005 try writer.writeAll(";\n");
6169 try writer.writeAll("if (");6006 try writer.writeAll("if (");
6170 try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor});6007 try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor});
6171 try f.renderTypecast(writer, ptr_ty.childType());6008 try f.renderType(writer, ptr_ty.childType());
6172 try writer.writeByte(')');6009 try writer.writeByte(')');
6173 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");6010 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
6174 try writer.writeAll(" *)");6011 try writer.writeAll(" *)");
...@@ -6197,7 +6034,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue...@@ -6197,7 +6034,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
6197 try writer.writeAll(";\n");6034 try writer.writeAll(";\n");
6198 try f.writeCValue(writer, local, .Other);6035 try f.writeCValue(writer, local, .Other);
6199 try writer.print(".is_null = zig_cmpxchg_{s}((zig_atomic(", .{flavor});6036 try writer.print(".is_null = zig_cmpxchg_{s}((zig_atomic(", .{flavor});
6200 try f.renderTypecast(writer, ptr_ty.childType());6037 try f.renderType(writer, ptr_ty.childType());
6201 try writer.writeByte(')');6038 try writer.writeByte(')');
6202 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");6039 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
6203 try writer.writeAll(" *)");6040 try writer.writeAll(" *)");
...@@ -6217,8 +6054,8 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue...@@ -6217,8 +6054,8 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
6217 }6054 }
62186055
6219 if (f.liveness.isUnused(inst)) {6056 if (f.liveness.isUnused(inst)) {
6220 try freeLocal(f, inst, local.local, 0);6057 try freeLocal(f, inst, local.new_local, 0);
6221 return CValue.none;6058 return .none;
6222 }6059 }
62236060
6224 return local;6061 return local;
...@@ -6240,12 +6077,12 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6240,12 +6077,12 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
6240 switch (extra.op()) {6077 switch (extra.op()) {
6241 else => {6078 else => {
6242 try writer.writeAll("zig_atomic(");6079 try writer.writeAll("zig_atomic(");
6243 try f.renderTypecast(writer, ptr_ty.elemType());6080 try f.renderType(writer, ptr_ty.elemType());
6244 try writer.writeByte(')');6081 try writer.writeByte(')');
6245 },6082 },
6246 .Nand, .Min, .Max => {6083 .Nand, .Min, .Max => {
6247 // These are missing from stdatomic.h, so no atomic types for now.6084 // These are missing from stdatomic.h, so no atomic types for now.
6248 try f.renderTypecast(writer, ptr_ty.elemType());6085 try f.renderType(writer, ptr_ty.elemType());
6249 },6086 },
6250 }6087 }
6251 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");6088 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
...@@ -6260,8 +6097,8 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6260,8 +6097,8 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
6260 try writer.writeAll(");\n");6097 try writer.writeAll(");\n");
62616098
6262 if (f.liveness.isUnused(inst)) {6099 if (f.liveness.isUnused(inst)) {
6263 try freeLocal(f, inst, local.local, 0);6100 try freeLocal(f, inst, local.new_local, 0);
6264 return CValue.none;6101 return .none;
6265 }6102 }
62666103
6267 return local;6104 return local;
...@@ -6273,7 +6110,7 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6273,7 +6110,7 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
6273 try reap(f, inst, &.{atomic_load.ptr});6110 try reap(f, inst, &.{atomic_load.ptr});
6274 const ptr_ty = f.air.typeOf(atomic_load.ptr);6111 const ptr_ty = f.air.typeOf(atomic_load.ptr);
6275 if (!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst)) {6112 if (!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst)) {
6276 return CValue.none;6113 return .none;
6277 }6114 }
62786115
6279 const inst_ty = f.air.typeOfIndex(inst);6116 const inst_ty = f.air.typeOfIndex(inst);
...@@ -6282,7 +6119,7 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6282,7 +6119,7 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
6282 try f.writeCValue(writer, local, .Other);6119 try f.writeCValue(writer, local, .Other);
62836120
6284 try writer.writeAll(" = zig_atomic_load((zig_atomic(");6121 try writer.writeAll(" = zig_atomic_load((zig_atomic(");
6285 try f.renderTypecast(writer, ptr_ty.elemType());6122 try f.renderType(writer, ptr_ty.elemType());
6286 try writer.writeByte(')');6123 try writer.writeByte(')');
6287 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");6124 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
6288 try writer.writeAll(" *)");6125 try writer.writeAll(" *)");
...@@ -6305,7 +6142,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa...@@ -6305,7 +6142,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
6305 const writer = f.object.writer();6142 const writer = f.object.writer();
63066143
6307 try writer.writeAll("zig_atomic_store((zig_atomic(");6144 try writer.writeAll("zig_atomic_store((zig_atomic(");
6308 try f.renderTypecast(writer, ptr_ty.elemType());6145 try f.renderType(writer, ptr_ty.elemType());
6309 try writer.writeByte(')');6146 try writer.writeByte(')');
6310 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");6147 if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
6311 try writer.writeAll(" *)");6148 try writer.writeAll(" *)");
...@@ -6316,7 +6153,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa...@@ -6316,7 +6153,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
6316 try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType());6153 try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType());
6317 try writer.writeAll(");\n");6154 try writer.writeAll(");\n");
63186155
6319 return CValue.none;6156 return .none;
6320}6157}
63216158
6322fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {6159fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -6347,7 +6184,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6347,7 +6184,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
6347 try writer.writeAll(" += ");6184 try writer.writeAll(" += ");
6348 try f.object.dg.renderValue(writer, Type.usize, Value.one, .Other);6185 try f.object.dg.renderValue(writer, Type.usize, Value.one, .Other);
6349 try writer.writeAll(") ((");6186 try writer.writeAll(") ((");
6350 try f.renderTypecast(writer, u8_ptr_ty);6187 try f.renderType(writer, u8_ptr_ty);
6351 try writer.writeByte(')');6188 try writer.writeByte(')');
6352 try f.writeCValue(writer, dest_ptr, .FunctionArgument);6189 try f.writeCValue(writer, dest_ptr, .FunctionArgument);
6353 try writer.writeAll(")[");6190 try writer.writeAll(")[");
...@@ -6357,9 +6194,9 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6357,9 +6194,9 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
6357 try writer.writeAll(";\n");6194 try writer.writeAll(";\n");
63586195
6359 try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });6196 try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });
6360 try freeLocal(f, inst, index.local, 0);6197 try freeLocal(f, inst, index.new_local, 0);
63616198
6362 return CValue.none;6199 return .none;
6363 }6200 }
63646201
6365 try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });6202 try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });
...@@ -6371,7 +6208,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6371,7 +6208,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
6371 try f.writeCValue(writer, len, .FunctionArgument);6208 try f.writeCValue(writer, len, .FunctionArgument);
6372 try writer.writeAll(");\n");6209 try writer.writeAll(");\n");
63736210
6374 return CValue.none;6211 return .none;
6375}6212}
63766213
6377fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue {6214fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -6391,7 +6228,7 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6391,7 +6228,7 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue {
6391 try f.writeCValue(writer, len, .FunctionArgument);6228 try f.writeCValue(writer, len, .FunctionArgument);
6392 try writer.writeAll(");\n");6229 try writer.writeAll(");\n");
63936230
6394 return CValue.none;6231 return .none;
6395}6232}
63966233
6397fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {6234fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -6404,7 +6241,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6404,7 +6241,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
6404 const union_ty = f.air.typeOf(bin_op.lhs).childType();6241 const union_ty = f.air.typeOf(bin_op.lhs).childType();
6405 const target = f.object.dg.module.getTarget();6242 const target = f.object.dg.module.getTarget();
6406 const layout = union_ty.unionGetLayout(target);6243 const layout = union_ty.unionGetLayout(target);
6407 if (layout.tag_size == 0) return CValue.none;6244 if (layout.tag_size == 0) return .none;
64086245
6409 try writer.writeByte('(');6246 try writer.writeByte('(');
6410 try f.writeCValue(writer, union_ptr, .Other);6247 try f.writeCValue(writer, union_ptr, .Other);
...@@ -6412,7 +6249,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6412,7 +6249,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
6412 try f.writeCValue(writer, new_tag, .Other);6249 try f.writeCValue(writer, new_tag, .Other);
6413 try writer.writeAll(";\n");6250 try writer.writeAll(";\n");
64146251
6415 return CValue.none;6252 return .none;
6416}6253}
64176254
6418fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {6255fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -6420,7 +6257,7 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6420,7 +6257,7 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
64206257
6421 if (f.liveness.isUnused(inst)) {6258 if (f.liveness.isUnused(inst)) {
6422 try reap(f, inst, &.{ty_op.operand});6259 try reap(f, inst, &.{ty_op.operand});
6423 return CValue.none;6260 return .none;
6424 }6261 }
64256262
6426 const operand = try f.resolveInst(ty_op.operand);6263 const operand = try f.resolveInst(ty_op.operand);
...@@ -6430,7 +6267,7 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6430,7 +6267,7 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
64306267
6431 const target = f.object.dg.module.getTarget();6268 const target = f.object.dg.module.getTarget();
6432 const layout = un_ty.unionGetLayout(target);6269 const layout = un_ty.unionGetLayout(target);
6433 if (layout.tag_size == 0) return CValue.none;6270 if (layout.tag_size == 0) return .none;
64346271
6435 const inst_ty = f.air.typeOfIndex(inst);6272 const inst_ty = f.air.typeOfIndex(inst);
6436 const writer = f.object.writer();6273 const writer = f.object.writer();
...@@ -6448,7 +6285,7 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6448,7 +6285,7 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
64486285
6449 if (f.liveness.isUnused(inst)) {6286 if (f.liveness.isUnused(inst)) {
6450 try reap(f, inst, &.{un_op});6287 try reap(f, inst, &.{un_op});
6451 return CValue.none;6288 return .none;
6452 }6289 }
64536290
6454 const inst_ty = f.air.typeOfIndex(inst);6291 const inst_ty = f.air.typeOfIndex(inst);
...@@ -6459,7 +6296,9 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6459,7 +6296,9 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
6459 const writer = f.object.writer();6296 const writer = f.object.writer();
6460 const local = try f.allocLocal(inst, inst_ty);6297 const local = try f.allocLocal(inst, inst_ty);
6461 try f.writeCValue(writer, local, .Other);6298 try f.writeCValue(writer, local, .Other);
6462 try writer.print(" = {s}(", .{try f.object.dg.getTagNameFn(enum_ty)});6299 try writer.print(" = {s}(", .{
6300 try f.getLazyFnName(.{ .tag_name = enum_ty.getOwnerDecl() }, .{ .tag_name = enum_ty }),
6301 });
6463 try f.writeCValue(writer, operand, .Other);6302 try f.writeCValue(writer, operand, .Other);
6464 try writer.writeAll(");\n");6303 try writer.writeAll(");\n");
64656304
...@@ -6471,7 +6310,7 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6471,7 +6310,7 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
64716310
6472 if (f.liveness.isUnused(inst)) {6311 if (f.liveness.isUnused(inst)) {
6473 try reap(f, inst, &.{un_op});6312 try reap(f, inst, &.{un_op});
6474 return CValue.none;6313 return .none;
6475 }6314 }
64766315
6477 const writer = f.object.writer();6316 const writer = f.object.writer();
...@@ -6491,7 +6330,7 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6491,7 +6330,7 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
6491 const ty_op = f.air.instructions.items(.data)[inst].ty_op;6330 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
6492 if (f.liveness.isUnused(inst)) {6331 if (f.liveness.isUnused(inst)) {
6493 try reap(f, inst, &.{ty_op.operand});6332 try reap(f, inst, &.{ty_op.operand});
6494 return CValue.none;6333 return .none;
6495 }6334 }
64966335
6497 const inst_ty = f.air.typeOfIndex(inst);6336 const inst_ty = f.air.typeOfIndex(inst);
...@@ -6507,13 +6346,13 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6507,13 +6346,13 @@ fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
6507}6346}
65086347
6509fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue {6348fn airSelect(f: *Function, inst: Air.Inst.Index) !CValue {
6510 if (f.liveness.isUnused(inst)) return CValue.none;6349 if (f.liveness.isUnused(inst)) return .none;
65116350
6512 return f.fail("TODO: C backend: implement airSelect", .{});6351 return f.fail("TODO: C backend: implement airSelect", .{});
6513}6352}
65146353
6515fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {6354fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {
6516 if (f.liveness.isUnused(inst)) return CValue.none;6355 if (f.liveness.isUnused(inst)) return .none;
65176356
6518 return f.fail("TODO: C backend: implement airShuffle", .{});6357 return f.fail("TODO: C backend: implement airShuffle", .{});
6519}6358}
...@@ -6523,7 +6362,7 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6523,7 +6362,7 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
65236362
6524 if (f.liveness.isUnused(inst)) {6363 if (f.liveness.isUnused(inst)) {
6525 try reap(f, inst, &.{reduce.operand});6364 try reap(f, inst, &.{reduce.operand});
6526 return CValue.none;6365 return .none;
6527 }6366 }
65286367
6529 const target = f.object.dg.module.getTarget();6368 const target = f.object.dg.module.getTarget();
...@@ -6599,10 +6438,9 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6599,10 +6438,9 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
6599 //6438 //
6600 // Equivalent to:6439 // Equivalent to:
6601 // reduce: {6440 // reduce: {
6602 // var i: usize = 0;
6603 // var accum: T = init;6441 // var accum: T = init;
6604 // while (i < vec.len) : (i += 1) {6442 // for (vec) : (elem) {
6605 // accum = func(accum, vec[i]);6443 // accum = func(accum, elem);
6606 // }6444 // }
6607 // break :reduce accum;6445 // break :reduce accum;
6608 // }6446 // }
...@@ -6674,7 +6512,7 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6674,7 +6512,7 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
66746512
6675 try writer.writeAll(";\n");6513 try writer.writeAll(";\n");
66766514
6677 try freeLocal(f, inst, it.local, 0);6515 try freeLocal(f, inst, it.new_local, 0);
66786516
6679 return accum;6517 return accum;
6680}6518}
...@@ -6687,8 +6525,8 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6687,8 +6525,8 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6687 const gpa = f.object.dg.gpa;6525 const gpa = f.object.dg.gpa;
6688 const resolved_elements = try gpa.alloc(CValue, elements.len);6526 const resolved_elements = try gpa.alloc(CValue, elements.len);
6689 defer gpa.free(resolved_elements);6527 defer gpa.free(resolved_elements);
6690 for (elements, 0..) |element, i| {6528 for (resolved_elements, elements) |*resolved_element, element| {
6691 resolved_elements[i] = try f.resolveInst(element);6529 resolved_element.* = try f.resolveInst(element);
6692 }6530 }
6693 {6531 {
6694 var bt = iterateBigTomb(f, inst);6532 var bt = iterateBigTomb(f, inst);
...@@ -6697,7 +6535,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6697,7 +6535,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6697 }6535 }
6698 }6536 }
66996537
6700 if (f.liveness.isUnused(inst)) return CValue.none;6538 if (f.liveness.isUnused(inst)) return .none;
67016539
6702 const target = f.object.dg.module.getTarget();6540 const target = f.object.dg.module.getTarget();
67036541
...@@ -6723,50 +6561,51 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6723,50 +6561,51 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6723 .Auto, .Extern => {6561 .Auto, .Extern => {
6724 try f.writeCValue(writer, local, .Other);6562 try f.writeCValue(writer, local, .Other);
6725 try writer.writeAll(" = (");6563 try writer.writeAll(" = (");
6726 try f.renderTypecast(writer, inst_ty);6564 try f.renderType(writer, inst_ty);
6727 try writer.writeAll(")");6565 try writer.writeAll(")");
6728 try writer.writeByte('{');6566 try writer.writeByte('{');
6729 var empty = true;6567 var empty = true;
6730 for (elements, 0..) |element, index| {6568 for (elements, resolved_elements, 0..) |element, resolved_element, field_i| {
6731 if (inst_ty.structFieldValueComptime(index)) |_| continue;6569 if (inst_ty.structFieldValueComptime(field_i)) |_| continue;
67326570
6733 if (!empty) try writer.writeAll(", ");6571 if (!empty) try writer.writeAll(", ");
6734 if (!inst_ty.isTupleOrAnonStruct()) {6572
6735 try writer.print(".{ } = ", .{fmtIdent(inst_ty.structFieldName(index))});6573 const field_name: CValue = if (inst_ty.isSimpleTuple())
6736 }6574 .{ .field = field_i }
6575 else
6576 .{ .identifier = inst_ty.structFieldName(field_i) };
6577 try writer.writeByte('.');
6578 try f.object.dg.writeCValue(writer, field_name);
6579 try writer.writeAll(" = ");
67376580
6738 const element_ty = f.air.typeOf(element);6581 const element_ty = f.air.typeOf(element);
6739 try f.writeCValue(writer, switch (element_ty.zigTypeTag()) {6582 try f.writeCValue(writer, switch (element_ty.zigTypeTag()) {
6740 .Array => CValue{ .undef = element_ty },6583 .Array => .{ .undef = element_ty },
6741 else => resolved_elements[index],6584 else => resolved_element,
6742 }, .Initializer);6585 }, .Initializer);
6743 empty = false;6586 empty = false;
6744 }6587 }
6745 if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)});
6746 try writer.writeAll("};\n");6588 try writer.writeAll("};\n");
67476589
6748 var field_id: usize = 0;6590 for (elements, resolved_elements, 0..) |element, resolved_element, field_i| {
6749 for (elements, 0..) |element, index| {6591 if (inst_ty.structFieldValueComptime(field_i)) |_| continue;
6750 if (inst_ty.structFieldValueComptime(index)) |_| continue;
67516592
6752 const element_ty = f.air.typeOf(element);6593 const element_ty = f.air.typeOf(element);
6753 if (element_ty.zigTypeTag() != .Array) continue;6594 if (element_ty.zigTypeTag() != .Array) continue;
67546595
6755 const field_name = if (inst_ty.isTupleOrAnonStruct())6596 const field_name: CValue = if (inst_ty.isSimpleTuple())
6756 CValue{ .field = field_id }6597 .{ .field = field_i }
6757 else6598 else
6758 CValue{ .identifier = inst_ty.structFieldName(index) };6599 .{ .identifier = inst_ty.structFieldName(field_i) };
67596600
6760 try writer.writeAll(";\n");6601 try writer.writeAll(";\n");
6761 try writer.writeAll("memcpy(");6602 try writer.writeAll("memcpy(");
6762 try f.writeCValueMember(writer, local, field_name);6603 try f.writeCValueMember(writer, local, field_name);
6763 try writer.writeAll(", ");6604 try writer.writeAll(", ");
6764 try f.writeCValue(writer, resolved_elements[index], .FunctionArgument);6605 try f.writeCValue(writer, resolved_element, .FunctionArgument);
6765 try writer.writeAll(", sizeof(");6606 try writer.writeAll(", sizeof(");
6766 try f.renderTypecast(writer, element_ty);6607 try f.renderType(writer, element_ty);
6767 try writer.writeAll("));\n");6608 try writer.writeAll("));\n");
6768
6769 field_id += 1;
6770 }6609 }
6771 },6610 },
6772 .Packed => {6611 .Packed => {
...@@ -6784,7 +6623,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6784,7 +6623,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6784 const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);6623 const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base);
67856624
6786 var empty = true;6625 var empty = true;
6787 for (elements, 0..) |_, index| {6626 for (0..elements.len) |index| {
6788 const field_ty = inst_ty.structFieldType(index);6627 const field_ty = inst_ty.structFieldType(index);
6789 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;6628 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
67906629
...@@ -6810,11 +6649,11 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6810,11 +6649,11 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6810 try f.renderIntCast(writer, inst_ty, element, field_ty, .FunctionArgument);6649 try f.renderIntCast(writer, inst_ty, element, field_ty, .FunctionArgument);
6811 } else {6650 } else {
6812 try writer.writeByte('(');6651 try writer.writeByte('(');
6813 try f.renderTypecast(writer, inst_ty);6652 try f.renderType(writer, inst_ty);
6814 try writer.writeByte(')');6653 try writer.writeByte(')');
6815 if (field_ty.isPtrAtRuntime()) {6654 if (field_ty.isPtrAtRuntime()) {
6816 try writer.writeByte('(');6655 try writer.writeByte('(');
6817 try f.renderTypecast(writer, switch (int_info.signedness) {6656 try f.renderType(writer, switch (int_info.signedness) {
6818 .unsigned => Type.usize,6657 .unsigned => Type.usize,
6819 .signed => Type.isize,6658 .signed => Type.isize,
6820 });6659 });
...@@ -6833,13 +6672,6 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6833,13 +6672,6 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6833 empty = false;6672 empty = false;
6834 }6673 }
68356674
6836 if (empty) {
6837 try writer.writeByte('(');
6838 try f.renderTypecast(writer, inst_ty);
6839 try writer.writeByte(')');
6840 try f.writeCValue(writer, .{ .undef = inst_ty }, .Initializer);
6841 }
6842
6843 try writer.writeAll(";\n");6675 try writer.writeAll(";\n");
6844 },6676 },
6845 },6677 },
...@@ -6855,7 +6687,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6855,7 +6687,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
68556687
6856 if (f.liveness.isUnused(inst)) {6688 if (f.liveness.isUnused(inst)) {
6857 try reap(f, inst, &.{extra.init});6689 try reap(f, inst, &.{extra.init});
6858 return CValue.none;6690 return .none;
6859 }6691 }
68606692
6861 const union_ty = f.air.typeOfIndex(inst);6693 const union_ty = f.air.typeOfIndex(inst);
...@@ -6875,7 +6707,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6875,7 +6707,7 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
6875 return local;6707 return local;
6876 }6708 }
68776709
6878 if (union_ty.unionTagTypeSafety()) |tag_ty| {6710 const field: CValue = if (union_ty.unionTagTypeSafety()) |tag_ty| field: {
6879 const layout = union_ty.unionGetLayout(target);6711 const layout = union_ty.unionGetLayout(target);
6880 if (layout.tag_size != 0) {6712 if (layout.tag_size != 0) {
6881 const field_index = tag_ty.enumFieldIndex(field_name).?;6713 const field_index = tag_ty.enumFieldIndex(field_name).?;
...@@ -6892,18 +6724,13 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6892,18 +6724,13 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
6892 try f.writeCValue(writer, local, .Other);6724 try f.writeCValue(writer, local, .Other);
6893 try writer.print(".tag = {}; ", .{try f.fmtIntLiteral(tag_ty, int_val)});6725 try writer.print(".tag = {}; ", .{try f.fmtIntLiteral(tag_ty, int_val)});
6894 }6726 }
6895 try f.writeCValue(writer, local, .Other);6727 break :field .{ .payload_identifier = field_name };
6896 try writer.print(".payload.{ } = ", .{fmtIdent(field_name)});6728 } else .{ .identifier = field_name };
6897 try f.writeCValue(writer, payload, .Other);
6898 try writer.writeAll(";\n");
6899 return local;
6900 }
69016729
6902 try f.writeCValue(writer, local, .Other);6730 try f.writeCValueMember(writer, local, field);
6903 try writer.print(".{ } = ", .{fmtIdent(field_name)});6731 try writer.writeAll(" = ");
6904 try f.writeCValue(writer, payload, .Other);6732 try f.writeCValue(writer, payload, .Other);
6905 try writer.writeAll(";\n");6733 try writer.writeAll(";\n");
6906
6907 return local;6734 return local;
6908}6735}
69096736
...@@ -6914,7 +6741,7 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6914,7 +6741,7 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
6914 // The available prefetch intrinsics do not accept a cache argument; only6741 // The available prefetch intrinsics do not accept a cache argument; only
6915 // address, rw, and locality. So unless the cache is data, we do not lower6742 // address, rw, and locality. So unless the cache is data, we do not lower
6916 // this instruction.6743 // this instruction.
6917 .instruction => return CValue.none,6744 .instruction => return .none,
6918 }6745 }
6919 const ptr = try f.resolveInst(prefetch.ptr);6746 const ptr = try f.resolveInst(prefetch.ptr);
6920 try reap(f, inst, &.{prefetch.ptr});6747 try reap(f, inst, &.{prefetch.ptr});
...@@ -6924,11 +6751,11 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6924,11 +6751,11 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
6924 try writer.print(", {d}, {d});\n", .{6751 try writer.print(", {d}, {d});\n", .{
6925 @enumToInt(prefetch.rw), prefetch.locality,6752 @enumToInt(prefetch.rw), prefetch.locality,
6926 });6753 });
6927 return CValue.none;6754 return .none;
6928}6755}
69296756
6930fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue {6757fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue {
6931 if (f.liveness.isUnused(inst)) return CValue.none;6758 if (f.liveness.isUnused(inst)) return .none;
69326759
6933 const pl_op = f.air.instructions.items(.data)[inst].pl_op;6760 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
69346761
...@@ -6965,7 +6792,7 @@ fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6965,7 +6792,7 @@ fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {
6965 const un_op = f.air.instructions.items(.data)[inst].un_op;6792 const un_op = f.air.instructions.items(.data)[inst].un_op;
6966 if (f.liveness.isUnused(inst)) {6793 if (f.liveness.isUnused(inst)) {
6967 try reap(f, inst, &.{un_op});6794 try reap(f, inst, &.{un_op});
6968 return CValue.none;6795 return .none;
6969 }6796 }
69706797
6971 const operand = try f.resolveInst(un_op);6798 const operand = try f.resolveInst(un_op);
...@@ -6987,7 +6814,7 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal...@@ -6987,7 +6814,7 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal
6987 const un_op = f.air.instructions.items(.data)[inst].un_op;6814 const un_op = f.air.instructions.items(.data)[inst].un_op;
6988 if (f.liveness.isUnused(inst)) {6815 if (f.liveness.isUnused(inst)) {
6989 try reap(f, inst, &.{un_op});6816 try reap(f, inst, &.{un_op});
6990 return CValue.none;6817 return .none;
6991 }6818 }
6992 const operand = try f.resolveInst(un_op);6819 const operand = try f.resolveInst(un_op);
6993 try reap(f, inst, &.{un_op});6820 try reap(f, inst, &.{un_op});
...@@ -7009,7 +6836,7 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa...@@ -7009,7 +6836,7 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa
7009 const bin_op = f.air.instructions.items(.data)[inst].bin_op;6836 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
7010 if (f.liveness.isUnused(inst)) {6837 if (f.liveness.isUnused(inst)) {
7011 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });6838 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
7012 return CValue.none;6839 return .none;
7013 }6840 }
7014 const lhs = try f.resolveInst(bin_op.lhs);6841 const lhs = try f.resolveInst(bin_op.lhs);
7015 const rhs = try f.resolveInst(bin_op.rhs);6842 const rhs = try f.resolveInst(bin_op.rhs);
...@@ -7036,7 +6863,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7036,7 +6863,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
7036 const bin_op = f.air.extraData(Air.Bin, pl_op.payload).data;6863 const bin_op = f.air.extraData(Air.Bin, pl_op.payload).data;
7037 if (f.liveness.isUnused(inst)) {6864 if (f.liveness.isUnused(inst)) {
7038 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs, pl_op.operand });6865 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs, pl_op.operand });
7039 return CValue.none;6866 return .none;
7040 }6867 }
7041 const inst_ty = f.air.typeOfIndex(inst);6868 const inst_ty = f.air.typeOfIndex(inst);
7042 const mulend1 = try f.resolveInst(bin_op.lhs);6869 const mulend1 = try f.resolveInst(bin_op.lhs);
...@@ -7058,6 +6885,81 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7058,6 +6885,81 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
7058 return local;6885 return local;
7059}6886}
70606887
6888fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
6889 if (f.liveness.isUnused(inst)) return .none;
6890
6891 const inst_ty = f.air.typeOfIndex(inst);
6892 const fn_cty = try f.typeToCType(f.object.dg.decl.?.ty, .complete);
6893 const param_len = fn_cty.castTag(.varargs_function).?.data.param_types.len;
6894
6895 const writer = f.object.writer();
6896 const local = try f.allocLocal(inst, inst_ty);
6897 try writer.writeAll("va_start(*(va_list *)&");
6898 try f.writeCValue(writer, local, .Other);
6899 if (param_len > 0) {
6900 try writer.writeAll(", ");
6901 try f.writeCValue(writer, .{ .arg = param_len - 1 }, .FunctionArgument);
6902 }
6903 try writer.writeAll(");\n");
6904 return local;
6905}
6906
6907fn airCVaArg(f: *Function, inst: Air.Inst.Index) !CValue {
6908 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
6909 if (f.liveness.isUnused(inst)) {
6910 try reap(f, inst, &.{ty_op.operand});
6911 return .none;
6912 }
6913
6914 const inst_ty = f.air.typeOfIndex(inst);
6915 const va_list = try f.resolveInst(ty_op.operand);
6916 try reap(f, inst, &.{ty_op.operand});
6917
6918 const writer = f.object.writer();
6919 const local = try f.allocLocal(inst, inst_ty);
6920 try f.writeCValue(writer, local, .Other);
6921 try writer.writeAll(" = va_arg(*(va_list *)");
6922 try f.writeCValue(writer, va_list, .Other);
6923 try writer.writeAll(", ");
6924 try f.renderType(writer, f.air.getRefType(ty_op.ty));
6925 try writer.writeAll(");\n");
6926 return local;
6927}
6928
6929fn airCVaEnd(f: *Function, inst: Air.Inst.Index) !CValue {
6930 const un_op = f.air.instructions.items(.data)[inst].un_op;
6931
6932 const va_list = try f.resolveInst(un_op);
6933 try reap(f, inst, &.{un_op});
6934
6935 const writer = f.object.writer();
6936 try writer.writeAll("va_end(*(va_list *)");
6937 try f.writeCValue(writer, va_list, .Other);
6938 try writer.writeAll(");\n");
6939 return .none;
6940}
6941
6942fn airCVaCopy(f: *Function, inst: Air.Inst.Index) !CValue {
6943 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
6944 if (f.liveness.isUnused(inst)) {
6945 try reap(f, inst, &.{ty_op.operand});
6946 return .none;
6947 }
6948
6949 const inst_ty = f.air.typeOfIndex(inst);
6950 const va_list = try f.resolveInst(ty_op.operand);
6951 try reap(f, inst, &.{ty_op.operand});
6952
6953 const writer = f.object.writer();
6954 const local = try f.allocLocal(inst, inst_ty);
6955 try writer.writeAll("va_copy(*(va_list *)&");
6956 try f.writeCValue(writer, local, .Other);
6957 try writer.writeAll(", *(va_list *)");
6958 try f.writeCValue(writer, va_list, .Other);
6959 try writer.writeAll(");\n");
6960 return local;
6961}
6962
7061fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {6963fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {
7062 return switch (order) {6964 return switch (order) {
7063 // Note: unordered is actually even less atomic than relaxed6965 // Note: unordered is actually even less atomic than relaxed
...@@ -7243,8 +7145,9 @@ fn stringLiteral(child_stream: anytype) StringLiteral(@TypeOf(child_stream)) {...@@ -7243,8 +7145,9 @@ fn stringLiteral(child_stream: anytype) StringLiteral(@TypeOf(child_stream)) {
7243 return .{ .counting_writer = std.io.countingWriter(child_stream) };7145 return .{ .counting_writer = std.io.countingWriter(child_stream) };
7244}7146}
72457147
7148const FormatStringContext = struct { str: []const u8, sentinel: ?u8 };
7246fn formatStringLiteral(7149fn formatStringLiteral(
7247 str: []const u8,7150 data: FormatStringContext,
7248 comptime fmt: []const u8,7151 comptime fmt: []const u8,
7249 _: std.fmt.FormatOptions,7152 _: std.fmt.FormatOptions,
7250 writer: anytype,7153 writer: anytype,
...@@ -7253,13 +7156,13 @@ fn formatStringLiteral(...@@ -7253,13 +7156,13 @@ fn formatStringLiteral(
72537156
7254 var literal = stringLiteral(writer);7157 var literal = stringLiteral(writer);
7255 try literal.start();7158 try literal.start();
7256 for (str) |c|7159 for (data.str) |c| try literal.writeChar(c);
7257 try literal.writeChar(c);7160 if (data.sentinel) |sentinel| if (sentinel != 0) try literal.writeChar(sentinel);
7258 try literal.end();7161 try literal.end();
7259}7162}
72607163
7261fn fmtStringLiteral(str: []const u8) std.fmt.Formatter(formatStringLiteral) {7164fn fmtStringLiteral(str: []const u8, sentinel: ?u8) std.fmt.Formatter(formatStringLiteral) {
7262 return .{ .data = str };7165 return .{ .data = .{ .str = str, .sentinel = sentinel } };
7263}7166}
72647167
7265fn undefPattern(comptime IntType: type) IntType {7168fn undefPattern(comptime IntType: type) IntType {
...@@ -7344,7 +7247,7 @@ fn formatIntLiteral(...@@ -7344,7 +7247,7 @@ fn formatIntLiteral(
7344 use_twos_comp = true;7247 use_twos_comp = true;
7345 } else {7248 } else {
7346 // TODO: Use fmtIntLiteral for 0?7249 // TODO: Use fmtIntLiteral for 0?
7347 try writer.print("zig_sub_{c}{d}(zig_as_{c}{d}(0, 0), ", .{ signAbbrev(int_info.signedness), c_bits, signAbbrev(int_info.signedness), c_bits });7250 try writer.print("zig_sub_{c}{d}(zig_make_{c}{d}(0, 0), ", .{ signAbbrev(int_info.signedness), c_bits, signAbbrev(int_info.signedness), c_bits });
7348 }7251 }
7349 } else {7252 } else {
7350 try writer.writeByte('-');7253 try writer.writeByte('-');
...@@ -7354,11 +7257,16 @@ fn formatIntLiteral(...@@ -7354,11 +7257,16 @@ fn formatIntLiteral(
7354 switch (data.ty.tag()) {7257 switch (data.ty.tag()) {
7355 .c_short, .c_ushort, .c_int, .c_uint, .c_long, .c_ulong, .c_longlong, .c_ulonglong => {},7258 .c_short, .c_ushort, .c_int, .c_uint, .c_long, .c_ulong, .c_longlong, .c_ulonglong => {},
7356 else => {7259 else => {
7357 if (int_info.bits > 64 and data.location != null and data.location.? == .StaticInitializer) {7260 if (int_info.bits <= 64) {
7261 try writer.print("{s}INT{d}_C(", .{ switch (int_info.signedness) {
7262 .signed => "",
7263 .unsigned => "U",
7264 }, c_bits });
7265 } else if (data.location != null and data.location.? == .StaticInitializer) {
7358 // MSVC treats casting the struct initializer as not constant (C2099), so an alternate form is used in global initializers7266 // MSVC treats casting the struct initializer as not constant (C2099), so an alternate form is used in global initializers
7359 try writer.print("zig_as_constant_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits });7267 try writer.print("zig_make_constant_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits });
7360 } else {7268 } else {
7361 try writer.print("zig_as_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits });7269 try writer.print("zig_make_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits });
7362 }7270 }
7363 },7271 },
7364 }7272 }
...@@ -7467,17 +7375,20 @@ fn isByRef(ty: Type) bool {...@@ -7467,17 +7375,20 @@ fn isByRef(ty: Type) bool {
7467}7375}
74687376
7469const LowerFnRetTyBuffer = struct {7377const LowerFnRetTyBuffer = struct {
7378 names: [1][]const u8,
7470 types: [1]Type,7379 types: [1]Type,
7471 values: [1]Value,7380 values: [1]Value,
7472 payload: Type.Payload.Tuple,7381 payload: Type.Payload.AnonStruct,
7473};7382};
7474fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, target: std.Target) Type {7383fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, target: std.Target) Type {
7475 if (ret_ty.zigTypeTag() == .NoReturn) return Type.initTag(.noreturn);7384 if (ret_ty.zigTypeTag() == .NoReturn) return Type.initTag(.noreturn);
74767385
7477 if (lowersToArray(ret_ty, target)) {7386 if (lowersToArray(ret_ty, target)) {
7387 buffer.names = [1][]const u8{"array"};
7478 buffer.types = [1]Type{ret_ty};7388 buffer.types = [1]Type{ret_ty};
7479 buffer.values = [1]Value{Value.initTag(.unreachable_value)};7389 buffer.values = [1]Value{Value.initTag(.unreachable_value)};
7480 buffer.payload = .{ .data = .{7390 buffer.payload = .{ .data = .{
7391 .names = &buffer.names,
7481 .types = &buffer.types,7392 .types = &buffer.types,
7482 .values = &buffer.values,7393 .values = &buffer.values,
7483 } };7394 } };
...@@ -7533,7 +7444,7 @@ fn die(f: *Function, inst: Air.Inst.Index, ref: Air.Inst.Ref) !void {...@@ -7533,7 +7444,7 @@ fn die(f: *Function, inst: Air.Inst.Index, ref: Air.Inst.Ref) !void {
7533 if (f.air.instructions.items(.tag)[ref_inst] == .constant) return;7444 if (f.air.instructions.items(.tag)[ref_inst] == .constant) return;
7534 const c_value = (f.value_map.fetchRemove(ref) orelse return).value;7445 const c_value = (f.value_map.fetchRemove(ref) orelse return).value;
7535 const local_index = switch (c_value) {7446 const local_index = switch (c_value) {
7536 .local => |l| l,7447 .local, .new_local => |l| l,
7537 else => return,7448 else => return,
7538 };7449 };
7539 try freeLocal(f, inst, local_index, ref_inst);7450 try freeLocal(f, inst, local_index, ref_inst);
...@@ -7544,21 +7455,16 @@ fn freeLocal(f: *Function, inst: Air.Inst.Index, local_index: LocalIndex, ref_in...@@ -7544,21 +7455,16 @@ fn freeLocal(f: *Function, inst: Air.Inst.Index, local_index: LocalIndex, ref_in
7544 const local = &f.locals.items[local_index];7455 const local = &f.locals.items[local_index];
7545 log.debug("%{d}: freeing t{d} (operand %{d})", .{ inst, local_index, ref_inst });7456 log.debug("%{d}: freeing t{d} (operand %{d})", .{ inst, local_index, ref_inst });
7546 if (local.loop_depth < f.free_locals_clone_depth) return;7457 if (local.loop_depth < f.free_locals_clone_depth) return;
7547 const gop = try f.free_locals_stack.items[local.loop_depth].getOrPutContext(7458 const gop = try f.free_locals_stack.items[local.loop_depth].getOrPut(gpa, local.getType());
7548 gpa,
7549 local.ty,
7550 f.tyHashCtx(),
7551 );
7552 if (!gop.found_existing) gop.value_ptr.* = .{};7459 if (!gop.found_existing) gop.value_ptr.* = .{};
7553 if (std.debug.runtime_safety) {7460 if (std.debug.runtime_safety) {
7554 // If this trips, it means a local is being inserted into the
7555 // free_locals map while it already exists in the map, which is not
7556 // allowed.
7557 assert(mem.indexOfScalar(LocalIndex, gop.value_ptr.items, local_index) == null);
7558 // If this trips, an unfreeable allocation was attempted to be freed.7461 // If this trips, an unfreeable allocation was attempted to be freed.
7559 assert(!f.allocs.contains(local_index));7462 assert(!f.allocs.contains(local_index));
7560 }7463 }
7561 try gop.value_ptr.append(gpa, local_index);7464 // If this trips, it means a local is being inserted into the
7465 // free_locals map while it already exists in the map, which is not
7466 // allowed.
7467 try gop.value_ptr.putNoClobber(gpa, local_index, {});
7562}7468}
75637469
7564const BigTomb = struct {7470const BigTomb = struct {
...@@ -7607,14 +7513,36 @@ fn deinitFreeLocalsMap(gpa: mem.Allocator, map: *LocalsMap) void {...@@ -7607,14 +7513,36 @@ fn deinitFreeLocalsMap(gpa: mem.Allocator, map: *LocalsMap) void {
7607 map.deinit(gpa);7513 map.deinit(gpa);
7608}7514}
76097515
7610fn noticeBranchFrees(f: *Function, pre_locals_len: LocalIndex, inst: Air.Inst.Index) !void {7516fn noticeBranchFrees(
7611 for (f.locals.items[pre_locals_len..], 0..) |*local, local_offset| {7517 f: *Function,
7612 const local_index = pre_locals_len + @intCast(LocalIndex, local_offset);7518 pre_locals_len: LocalIndex,
7613 if (f.allocs.contains(local_index)) continue; // allocs are not freeable7519 pre_allocs_len: LocalIndex,
7520 inst: Air.Inst.Index,
7521) !void {
7522 const free_locals = f.getFreeLocals();
7523
7524 for (f.locals.items[pre_locals_len..], pre_locals_len..) |*local, local_i| {
7525 const local_index = @intCast(LocalIndex, local_i);
7526 if (f.allocs.contains(local_index)) {
7527 if (std.debug.runtime_safety) {
7528 // new allocs are no longer freeable, so make sure they aren't in the free list
7529 if (free_locals.getPtr(local.getType())) |locals_list| {
7530 assert(!locals_list.contains(local_index));
7531 }
7532 }
7533 continue;
7534 }
76147535
7615 // free more deeply nested locals from other branches at current depth7536 // free more deeply nested locals from other branches at current depth
7616 assert(local.loop_depth >= f.free_locals_stack.items.len - 1);7537 assert(local.loop_depth >= f.free_locals_stack.items.len - 1);
7617 local.loop_depth = @intCast(LoopDepth, f.free_locals_stack.items.len - 1);7538 local.loop_depth = @intCast(LoopDepth, f.free_locals_stack.items.len - 1);
7618 try freeLocal(f, inst, local_index, 0);7539 try freeLocal(f, inst, local_index, 0);
7619 }7540 }
7541
7542 for (f.allocs.keys()[pre_allocs_len..]) |local_i| {
7543 const local_index = @intCast(LocalIndex, local_i);
7544 const local = &f.locals.items[local_index];
7545 // new allocs are no longer freeable, so remove them from the free list
7546 if (free_locals.getPtr(local.getType())) |locals_list| _ = locals_list.swapRemove(local_index);
7547 }
7620}7548}
src/codegen/c/type.zig created+1896
...@@ -0,0 +1,1896 @@
1const std = @import("std");
2const cstr = std.cstr;
3const mem = std.mem;
4const Allocator = mem.Allocator;
5const assert = std.debug.assert;
6const autoHash = std.hash.autoHash;
7const Target = std.Target;
8
9const Module = @import("../../Module.zig");
10const Type = @import("../../type.zig").Type;
11
12pub const CType = extern union {
13 /// If the tag value is less than Tag.no_payload_count, then no pointer
14 /// dereference is needed.
15 tag_if_small_enough: Tag,
16 ptr_otherwise: *const Payload,
17
18 pub fn initTag(small_tag: Tag) CType {
19 assert(!small_tag.hasPayload());
20 return .{ .tag_if_small_enough = small_tag };
21 }
22
23 pub fn initPayload(pl: anytype) CType {
24 const T = @typeInfo(@TypeOf(pl)).Pointer.child;
25 return switch (pl.base.tag) {
26 inline else => |t| if (comptime t.hasPayload() and t.Type() == T) .{
27 .ptr_otherwise = &pl.base,
28 } else unreachable,
29 };
30 }
31
32 pub fn hasPayload(self: CType) bool {
33 return self.tag_if_small_enough.hasPayload();
34 }
35
36 pub fn tag(self: CType) Tag {
37 return if (self.hasPayload()) self.ptr_otherwise.tag else self.tag_if_small_enough;
38 }
39
40 pub fn cast(self: CType, comptime T: type) ?*const T {
41 if (!self.hasPayload()) return null;
42 const pl = self.ptr_otherwise;
43 return switch (pl.tag) {
44 inline else => |t| if (comptime t.hasPayload() and t.Type() == T)
45 @fieldParentPtr(T, "base", pl)
46 else
47 null,
48 };
49 }
50
51 pub fn castTag(self: CType, comptime t: Tag) ?*const t.Type() {
52 return if (self.tag() == t) @fieldParentPtr(t.Type(), "base", self.ptr_otherwise) else null;
53 }
54
55 pub const Tag = enum(usize) {
56 // The first section of this enum are tags that require no payload.
57 void,
58
59 // C basic types
60 char,
61
62 @"signed char",
63 short,
64 int,
65 long,
66 @"long long",
67
68 _Bool,
69 @"unsigned char",
70 @"unsigned short",
71 @"unsigned int",
72 @"unsigned long",
73 @"unsigned long long",
74
75 float,
76 double,
77 @"long double",
78
79 // C header types
80 // - stdbool.h
81 bool,
82 // - stddef.h
83 size_t,
84 ptrdiff_t,
85 // - stdint.h
86 uint8_t,
87 int8_t,
88 uint16_t,
89 int16_t,
90 uint32_t,
91 int32_t,
92 uint64_t,
93 int64_t,
94 uintptr_t,
95 intptr_t,
96
97 // zig.h types
98 zig_u128,
99 zig_i128,
100 zig_f16,
101 zig_f32,
102 zig_f64,
103 zig_f80,
104 zig_f128,
105 zig_c_longdouble, // Keep last_no_payload_tag updated!
106
107 // After this, the tag requires a payload.
108 pointer,
109 pointer_const,
110 pointer_volatile,
111 pointer_const_volatile,
112 array,
113 vector,
114 fwd_anon_struct,
115 fwd_anon_union,
116 fwd_struct,
117 fwd_union,
118 unnamed_struct,
119 unnamed_union,
120 packed_unnamed_struct,
121 packed_unnamed_union,
122 anon_struct,
123 anon_union,
124 @"struct",
125 @"union",
126 packed_struct,
127 packed_union,
128 function,
129 varargs_function,
130
131 pub const last_no_payload_tag = Tag.zig_c_longdouble;
132 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
133
134 pub fn hasPayload(self: Tag) bool {
135 return @enumToInt(self) >= no_payload_count;
136 }
137
138 pub fn toIndex(self: Tag) Index {
139 assert(!self.hasPayload());
140 return @intCast(Index, @enumToInt(self));
141 }
142
143 pub fn Type(comptime self: Tag) type {
144 return switch (self) {
145 .void,
146 .char,
147 .@"signed char",
148 .short,
149 .int,
150 .long,
151 .@"long long",
152 ._Bool,
153 .@"unsigned char",
154 .@"unsigned short",
155 .@"unsigned int",
156 .@"unsigned long",
157 .@"unsigned long long",
158 .float,
159 .double,
160 .@"long double",
161 .bool,
162 .size_t,
163 .ptrdiff_t,
164 .uint8_t,
165 .int8_t,
166 .uint16_t,
167 .int16_t,
168 .uint32_t,
169 .int32_t,
170 .uint64_t,
171 .int64_t,
172 .uintptr_t,
173 .intptr_t,
174 .zig_u128,
175 .zig_i128,
176 .zig_f16,
177 .zig_f32,
178 .zig_f64,
179 .zig_f80,
180 .zig_f128,
181 .zig_c_longdouble,
182 => @compileError("Type Tag " ++ @tagName(self) ++ " has no payload"),
183
184 .pointer,
185 .pointer_const,
186 .pointer_volatile,
187 .pointer_const_volatile,
188 => Payload.Child,
189
190 .array,
191 .vector,
192 => Payload.Sequence,
193
194 .fwd_anon_struct,
195 .fwd_anon_union,
196 => Payload.Fields,
197
198 .fwd_struct,
199 .fwd_union,
200 => Payload.FwdDecl,
201
202 .unnamed_struct,
203 .unnamed_union,
204 .packed_unnamed_struct,
205 .packed_unnamed_union,
206 => Payload.Unnamed,
207
208 .anon_struct,
209 .anon_union,
210 .@"struct",
211 .@"union",
212 .packed_struct,
213 .packed_union,
214 => Payload.Aggregate,
215
216 .function,
217 .varargs_function,
218 => Payload.Function,
219 };
220 }
221 };
222
223 pub const Payload = struct {
224 tag: Tag,
225
226 pub const Child = struct {
227 base: Payload,
228 data: Index,
229 };
230
231 pub const Sequence = struct {
232 base: Payload,
233 data: struct {
234 len: u64,
235 elem_type: Index,
236 },
237 };
238
239 pub const FwdDecl = struct {
240 base: Payload,
241 data: Module.Decl.Index,
242 };
243
244 pub const Fields = struct {
245 base: Payload,
246 data: Data,
247
248 pub const Data = []const Field;
249 pub const Field = struct {
250 name: [*:0]const u8,
251 type: Index,
252 alignas: AlignAs,
253 };
254 };
255
256 pub const Unnamed = struct {
257 base: Payload,
258 data: struct {
259 fields: Fields.Data,
260 owner_decl: Module.Decl.Index,
261 id: u32,
262 },
263 };
264
265 pub const Aggregate = struct {
266 base: Payload,
267 data: struct {
268 fields: Fields.Data,
269 fwd_decl: Index,
270 },
271 };
272
273 pub const Function = struct {
274 base: Payload,
275 data: struct {
276 return_type: Index,
277 param_types: []const Index,
278 },
279 };
280 };
281
282 pub const AlignAs = struct {
283 @"align": std.math.Log2Int(u32),
284 abi: std.math.Log2Int(u32),
285
286 pub fn init(alignment: u32, abi_alignment: u32) AlignAs {
287 const actual_align = if (alignment != 0) alignment else abi_alignment;
288 assert(std.math.isPowerOfTwo(actual_align));
289 assert(std.math.isPowerOfTwo(abi_alignment));
290 return .{
291 .@"align" = std.math.log2_int(u32, actual_align),
292 .abi = std.math.log2_int(u32, abi_alignment),
293 };
294 }
295 pub fn abiAlign(ty: Type, target: Target) AlignAs {
296 const abi_align = ty.abiAlignment(target);
297 return init(abi_align, abi_align);
298 }
299 pub fn fieldAlign(struct_ty: Type, field_i: usize, target: Target) AlignAs {
300 return init(
301 struct_ty.structFieldAlign(field_i, target),
302 struct_ty.structFieldType(field_i).abiAlignment(target),
303 );
304 }
305 pub fn unionPayloadAlign(union_ty: Type, target: Target) AlignAs {
306 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
307 const union_payload_align = union_obj.abiAlignment(target, false);
308 return init(union_payload_align, union_payload_align);
309 }
310
311 pub fn getAlign(self: AlignAs) u32 {
312 return @as(u32, 1) << self.@"align";
313 }
314 };
315
316 pub const Index = u32;
317 pub const Store = struct {
318 arena: std.heap.ArenaAllocator.State = .{},
319 set: Set = .{},
320
321 pub const Set = struct {
322 pub const Map = std.ArrayHashMapUnmanaged(CType, void, HashContext, true);
323 const HashContext = struct {
324 store: *const Set,
325
326 pub fn hash(self: @This(), cty: CType) Map.Hash {
327 return @truncate(Map.Hash, cty.hash(self.store.*));
328 }
329 pub fn eql(_: @This(), lhs: CType, rhs: CType, _: usize) bool {
330 return lhs.eql(rhs);
331 }
332 };
333
334 map: Map = .{},
335
336 pub fn indexToCType(self: Set, index: Index) CType {
337 if (index < Tag.no_payload_count) return initTag(@intToEnum(Tag, index));
338 return self.map.keys()[index - Tag.no_payload_count];
339 }
340
341 pub fn indexToHash(self: Set, index: Index) Map.Hash {
342 if (index < Tag.no_payload_count)
343 return (HashContext{ .store = &self }).hash(self.indexToCType(index));
344 return self.map.entries.items(.hash)[index - Tag.no_payload_count];
345 }
346
347 pub fn typeToIndex(self: Set, ty: Type, target: Target, kind: Kind) ?Index {
348 const lookup = Convert.Lookup{ .imm = .{ .set = &self, .target = target } };
349
350 var convert: Convert = undefined;
351 convert.initType(ty, kind, lookup) catch unreachable;
352
353 const t = convert.tag();
354 if (!t.hasPayload()) return t.toIndex();
355
356 return if (self.map.getIndexAdapted(
357 ty,
358 TypeAdapter32{ .kind = kind, .lookup = lookup, .convert = &convert },
359 )) |idx| @intCast(Index, Tag.no_payload_count + idx) else null;
360 }
361 };
362
363 pub const Promoted = struct {
364 arena: std.heap.ArenaAllocator,
365 set: Set,
366
367 pub fn gpa(self: *Promoted) Allocator {
368 return self.arena.child_allocator;
369 }
370
371 pub fn cTypeToIndex(self: *Promoted, cty: CType) Allocator.Error!Index {
372 const t = cty.tag();
373 if (@enumToInt(t) < Tag.no_payload_count) return @intCast(Index, @enumToInt(t));
374
375 const gop = try self.set.map.getOrPutContext(self.gpa(), cty, .{ .store = &self.set });
376 if (!gop.found_existing) gop.key_ptr.* = cty;
377 if (std.debug.runtime_safety) {
378 const key = &self.set.map.entries.items(.key)[gop.index];
379 assert(key == gop.key_ptr);
380 assert(cty.eql(key.*));
381 assert(cty.hash(self.set) == key.hash(self.set));
382 }
383 return @intCast(Index, Tag.no_payload_count + gop.index);
384 }
385
386 pub fn typeToIndex(
387 self: *Promoted,
388 ty: Type,
389 mod: *Module,
390 kind: Kind,
391 ) Allocator.Error!Index {
392 const lookup = Convert.Lookup{ .mut = .{ .promoted = self, .mod = mod } };
393
394 var convert: Convert = undefined;
395 try convert.initType(ty, kind, lookup);
396
397 const t = convert.tag();
398 if (!t.hasPayload()) return t.toIndex();
399
400 const gop = try self.set.map.getOrPutContextAdapted(
401 self.gpa(),
402 ty,
403 TypeAdapter32{ .kind = kind, .lookup = lookup.freeze(), .convert = &convert },
404 .{ .store = &self.set },
405 );
406 if (!gop.found_existing) {
407 errdefer _ = self.set.map.pop();
408 gop.key_ptr.* = try createFromConvert(self, ty, lookup.getTarget(), kind, convert);
409 }
410 if (std.debug.runtime_safety) {
411 const adapter = TypeAdapter64{
412 .kind = kind,
413 .lookup = lookup.freeze(),
414 .convert = &convert,
415 };
416 const cty = &self.set.map.entries.items(.key)[gop.index];
417 assert(cty == gop.key_ptr);
418 assert(adapter.eql(ty, cty.*));
419 assert(adapter.hash(ty) == cty.hash(self.set));
420 }
421 return @intCast(Index, Tag.no_payload_count + gop.index);
422 }
423 };
424
425 pub fn promote(self: Store, gpa: Allocator) Promoted {
426 return .{ .arena = self.arena.promote(gpa), .set = self.set };
427 }
428
429 pub fn demote(self: *Store, promoted: Promoted) void {
430 self.arena = promoted.arena.state;
431 self.set = promoted.set;
432 }
433
434 pub fn indexToCType(self: Store, index: Index) CType {
435 return self.set.indexToCType(index);
436 }
437
438 pub fn indexToHash(self: Store, index: Index) Set.Map.Hash {
439 return self.set.indexToHash(index);
440 }
441
442 pub fn cTypeToIndex(self: *Store, gpa: Allocator, cty: CType) !Index {
443 var promoted = self.promote(gpa);
444 defer self.demote(promoted);
445 return promoted.cTypeToIndex(cty);
446 }
447
448 pub fn typeToCType(self: *Store, gpa: Allocator, ty: Type, mod: *Module, kind: Kind) !CType {
449 const idx = try self.typeToIndex(gpa, ty, mod, kind);
450 return self.indexToCType(idx);
451 }
452
453 pub fn typeToIndex(self: *Store, gpa: Allocator, ty: Type, mod: *Module, kind: Kind) !Index {
454 var promoted = self.promote(gpa);
455 defer self.demote(promoted);
456 return promoted.typeToIndex(ty, mod, kind);
457 }
458
459 pub fn clearRetainingCapacity(self: *Store, gpa: Allocator) void {
460 var promoted = self.promote(gpa);
461 defer self.demote(promoted);
462 promoted.set.map.clearRetainingCapacity();
463 _ = promoted.arena.reset(.retain_capacity);
464 }
465
466 pub fn clearAndFree(self: *Store, gpa: Allocator) void {
467 var promoted = self.promote(gpa);
468 defer self.demote(promoted);
469 promoted.set.map.clearAndFree(gpa);
470 _ = promoted.arena.reset(.free_all);
471 }
472
473 pub fn shrinkRetainingCapacity(self: *Store, gpa: Allocator, new_len: usize) void {
474 self.set.map.shrinkRetainingCapacity(gpa, new_len);
475 }
476
477 pub fn shrinkAndFree(self: *Store, gpa: Allocator, new_len: usize) void {
478 self.set.map.shrinkAndFree(gpa, new_len);
479 }
480
481 pub fn count(self: Store) usize {
482 return self.set.map.count();
483 }
484
485 pub fn move(self: *Store) Store {
486 const moved = self.*;
487 self.* = .{};
488 return moved;
489 }
490
491 pub fn deinit(self: *Store, gpa: Allocator) void {
492 var promoted = self.promote(gpa);
493 promoted.set.map.deinit(gpa);
494 _ = promoted.arena.deinit();
495 self.* = undefined;
496 }
497 };
498
499 pub fn isPacked(self: CType) bool {
500 return switch (self.tag()) {
501 else => false,
502 .packed_unnamed_struct,
503 .packed_unnamed_union,
504 .packed_struct,
505 .packed_union,
506 => true,
507 };
508 }
509
510 pub fn fields(self: CType) Payload.Fields.Data {
511 return if (self.cast(Payload.Aggregate)) |pl|
512 pl.data.fields
513 else if (self.cast(Payload.Unnamed)) |pl|
514 pl.data.fields
515 else if (self.cast(Payload.Fields)) |pl|
516 pl.data
517 else
518 unreachable;
519 }
520
521 pub fn eql(lhs: CType, rhs: CType) bool {
522 return lhs.eqlContext(rhs, struct {
523 pub fn eqlIndex(_: @This(), lhs_idx: Index, rhs_idx: Index) bool {
524 return lhs_idx == rhs_idx;
525 }
526 }{});
527 }
528
529 pub fn eqlContext(lhs: CType, rhs: CType, ctx: anytype) bool {
530 // As a shortcut, if the small tags / addresses match, we're done.
531 if (lhs.tag_if_small_enough == rhs.tag_if_small_enough) return true;
532
533 const lhs_tag = lhs.tag();
534 const rhs_tag = rhs.tag();
535 if (lhs_tag != rhs_tag) return false;
536
537 return switch (lhs_tag) {
538 .void,
539 .char,
540 .@"signed char",
541 .short,
542 .int,
543 .long,
544 .@"long long",
545 ._Bool,
546 .@"unsigned char",
547 .@"unsigned short",
548 .@"unsigned int",
549 .@"unsigned long",
550 .@"unsigned long long",
551 .float,
552 .double,
553 .@"long double",
554 .bool,
555 .size_t,
556 .ptrdiff_t,
557 .uint8_t,
558 .int8_t,
559 .uint16_t,
560 .int16_t,
561 .uint32_t,
562 .int32_t,
563 .uint64_t,
564 .int64_t,
565 .uintptr_t,
566 .intptr_t,
567 .zig_u128,
568 .zig_i128,
569 .zig_f16,
570 .zig_f32,
571 .zig_f64,
572 .zig_f80,
573 .zig_f128,
574 .zig_c_longdouble,
575 => false,
576
577 .pointer,
578 .pointer_const,
579 .pointer_volatile,
580 .pointer_const_volatile,
581 => ctx.eqlIndex(lhs.cast(Payload.Child).?.data, rhs.cast(Payload.Child).?.data),
582
583 .array,
584 .vector,
585 => {
586 const lhs_data = lhs.cast(Payload.Sequence).?.data;
587 const rhs_data = rhs.cast(Payload.Sequence).?.data;
588 return lhs_data.len == rhs_data.len and
589 ctx.eqlIndex(lhs_data.elem_type, rhs_data.elem_type);
590 },
591
592 .fwd_anon_struct,
593 .fwd_anon_union,
594 => {
595 const lhs_data = lhs.cast(Payload.Fields).?.data;
596 const rhs_data = rhs.cast(Payload.Fields).?.data;
597 if (lhs_data.len != rhs_data.len) return false;
598 for (lhs_data, rhs_data) |lhs_field, rhs_field| {
599 if (!ctx.eqlIndex(lhs_field.type, rhs_field.type)) return false;
600 if (lhs_field.alignas.@"align" != rhs_field.alignas.@"align") return false;
601 if (cstr.cmp(lhs_field.name, rhs_field.name) != 0) return false;
602 }
603 return true;
604 },
605
606 .fwd_struct,
607 .fwd_union,
608 => lhs.cast(Payload.FwdDecl).?.data == rhs.cast(Payload.FwdDecl).?.data,
609
610 .unnamed_struct,
611 .unnamed_union,
612 .packed_unnamed_struct,
613 .packed_unnamed_union,
614 => {
615 const lhs_data = lhs.cast(Payload.Unnamed).?.data;
616 const rhs_data = rhs.cast(Payload.Unnamed).?.data;
617 return lhs_data.owner_decl == rhs_data.owner_decl and lhs_data.id == rhs_data.id;
618 },
619
620 .anon_struct,
621 .anon_union,
622 .@"struct",
623 .@"union",
624 .packed_struct,
625 .packed_union,
626 => ctx.eqlIndex(
627 lhs.cast(Payload.Aggregate).?.data.fwd_decl,
628 rhs.cast(Payload.Aggregate).?.data.fwd_decl,
629 ),
630
631 .function,
632 .varargs_function,
633 => {
634 const lhs_data = lhs.cast(Payload.Function).?.data;
635 const rhs_data = rhs.cast(Payload.Function).?.data;
636 if (lhs_data.param_types.len != rhs_data.param_types.len) return false;
637 if (!ctx.eqlIndex(lhs_data.return_type, rhs_data.return_type)) return false;
638 for (lhs_data.param_types, rhs_data.param_types) |lhs_param_idx, rhs_param_idx| {
639 if (!ctx.eqlIndex(lhs_param_idx, rhs_param_idx)) return false;
640 }
641 return true;
642 },
643 };
644 }
645
646 pub fn hash(self: CType, store: Store.Set) u64 {
647 var hasher = std.hash.Wyhash.init(0);
648 self.updateHasher(&hasher, store);
649 return hasher.final();
650 }
651
652 pub fn updateHasher(self: CType, hasher: anytype, store: Store.Set) void {
653 const t = self.tag();
654 autoHash(hasher, t);
655 switch (t) {
656 .void,
657 .char,
658 .@"signed char",
659 .short,
660 .int,
661 .long,
662 .@"long long",
663 ._Bool,
664 .@"unsigned char",
665 .@"unsigned short",
666 .@"unsigned int",
667 .@"unsigned long",
668 .@"unsigned long long",
669 .float,
670 .double,
671 .@"long double",
672 .bool,
673 .size_t,
674 .ptrdiff_t,
675 .uint8_t,
676 .int8_t,
677 .uint16_t,
678 .int16_t,
679 .uint32_t,
680 .int32_t,
681 .uint64_t,
682 .int64_t,
683 .uintptr_t,
684 .intptr_t,
685 .zig_u128,
686 .zig_i128,
687 .zig_f16,
688 .zig_f32,
689 .zig_f64,
690 .zig_f80,
691 .zig_f128,
692 .zig_c_longdouble,
693 => {},
694
695 .pointer,
696 .pointer_const,
697 .pointer_volatile,
698 .pointer_const_volatile,
699 => store.indexToCType(self.cast(Payload.Child).?.data).updateHasher(hasher, store),
700
701 .array,
702 .vector,
703 => {
704 const data = self.cast(Payload.Sequence).?.data;
705 autoHash(hasher, data.len);
706 store.indexToCType(data.elem_type).updateHasher(hasher, store);
707 },
708
709 .fwd_anon_struct,
710 .fwd_anon_union,
711 => for (self.cast(Payload.Fields).?.data) |field| {
712 store.indexToCType(field.type).updateHasher(hasher, store);
713 hasher.update(mem.span(field.name));
714 autoHash(hasher, field.alignas.@"align");
715 },
716
717 .fwd_struct,
718 .fwd_union,
719 => autoHash(hasher, self.cast(Payload.FwdDecl).?.data),
720
721 .unnamed_struct,
722 .unnamed_union,
723 .packed_unnamed_struct,
724 .packed_unnamed_union,
725 => {
726 const data = self.cast(Payload.Unnamed).?.data;
727 autoHash(hasher, data.owner_decl);
728 autoHash(hasher, data.id);
729 },
730
731 .anon_struct,
732 .anon_union,
733 .@"struct",
734 .@"union",
735 .packed_struct,
736 .packed_union,
737 => store.indexToCType(self.cast(Payload.Aggregate).?.data.fwd_decl)
738 .updateHasher(hasher, store),
739
740 .function,
741 .varargs_function,
742 => {
743 const data = self.cast(Payload.Function).?.data;
744 store.indexToCType(data.return_type).updateHasher(hasher, store);
745 for (data.param_types) |param_ty| {
746 store.indexToCType(param_ty).updateHasher(hasher, store);
747 }
748 },
749 }
750 }
751
752 pub const Kind = enum { forward, forward_parameter, complete, global, parameter, payload };
753
754 const Convert = struct {
755 storage: union {
756 none: void,
757 child: Payload.Child,
758 seq: Payload.Sequence,
759 fwd: Payload.FwdDecl,
760 anon: struct {
761 fields: [2]Payload.Fields.Field,
762 pl: union {
763 forward: Payload.Fields,
764 complete: Payload.Aggregate,
765 },
766 },
767 },
768 value: union(enum) {
769 tag: Tag,
770 cty: CType,
771 },
772
773 pub fn init(self: *@This(), t: Tag) void {
774 self.* = if (t.hasPayload()) .{
775 .storage = .{ .none = {} },
776 .value = .{ .tag = t },
777 } else .{
778 .storage = .{ .none = {} },
779 .value = .{ .cty = initTag(t) },
780 };
781 }
782
783 pub fn tag(self: @This()) Tag {
784 return switch (self.value) {
785 .tag => |t| t,
786 .cty => |c| c.tag(),
787 };
788 }
789
790 fn tagFromIntInfo(signedness: std.builtin.Signedness, bits: u16) Tag {
791 return switch (bits) {
792 0 => .void,
793 1...8 => switch (signedness) {
794 .unsigned => .uint8_t,
795 .signed => .int8_t,
796 },
797 9...16 => switch (signedness) {
798 .unsigned => .uint16_t,
799 .signed => .int16_t,
800 },
801 17...32 => switch (signedness) {
802 .unsigned => .uint32_t,
803 .signed => .int32_t,
804 },
805 33...64 => switch (signedness) {
806 .unsigned => .uint64_t,
807 .signed => .int64_t,
808 },
809 65...128 => switch (signedness) {
810 .unsigned => .zig_u128,
811 .signed => .zig_i128,
812 },
813 else => .array,
814 };
815 }
816
817 pub const Lookup = union(enum) {
818 fail: Target,
819 imm: struct {
820 set: *const Store.Set,
821 target: Target,
822 },
823 mut: struct {
824 promoted: *Store.Promoted,
825 mod: *Module,
826 },
827
828 pub fn isMutable(self: @This()) bool {
829 return switch (self) {
830 .fail, .imm => false,
831 .mut => true,
832 };
833 }
834
835 pub fn getTarget(self: @This()) Target {
836 return switch (self) {
837 .fail => |target| target,
838 .imm => |imm| imm.target,
839 .mut => |mut| mut.mod.getTarget(),
840 };
841 }
842
843 pub fn getSet(self: @This()) ?*const Store.Set {
844 return switch (self) {
845 .fail => null,
846 .imm => |imm| imm.set,
847 .mut => |mut| &mut.promoted.set,
848 };
849 }
850
851 pub fn typeToIndex(self: @This(), ty: Type, kind: Kind) !?Index {
852 return switch (self) {
853 .fail => null,
854 .imm => |imm| imm.set.typeToIndex(ty, imm.target, kind),
855 .mut => |mut| try mut.promoted.typeToIndex(ty, mut.mod, kind),
856 };
857 }
858
859 pub fn indexToCType(self: @This(), index: Index) ?CType {
860 return if (self.getSet()) |set| set.indexToCType(index) else null;
861 }
862
863 pub fn freeze(self: @This()) @This() {
864 return switch (self) {
865 .fail, .imm => self,
866 .mut => |mut| .{ .imm = .{ .set = &mut.promoted.set, .target = self.getTarget() } },
867 };
868 }
869 };
870
871 fn sortFields(self: *@This(), fields_len: usize) []Payload.Fields.Field {
872 const Field = Payload.Fields.Field;
873 const slice = self.storage.anon.fields[0..fields_len];
874 std.sort.sort(Field, slice, {}, struct {
875 fn before(_: void, lhs: Field, rhs: Field) bool {
876 return lhs.alignas.@"align" > rhs.alignas.@"align";
877 }
878 }.before);
879 return slice;
880 }
881
882 fn initAnon(self: *@This(), kind: Kind, fwd_idx: Index, fields_len: usize) void {
883 switch (kind) {
884 .forward, .forward_parameter => {
885 self.storage.anon.pl = .{ .forward = .{
886 .base = .{ .tag = .fwd_anon_struct },
887 .data = self.sortFields(fields_len),
888 } };
889 self.value = .{ .cty = initPayload(&self.storage.anon.pl.forward) };
890 },
891 .complete, .parameter, .global => {
892 self.storage.anon.pl = .{ .complete = .{
893 .base = .{ .tag = .anon_struct },
894 .data = .{
895 .fields = self.sortFields(fields_len),
896 .fwd_decl = fwd_idx,
897 },
898 } };
899 self.value = .{ .cty = initPayload(&self.storage.anon.pl.complete) };
900 },
901 .payload => unreachable,
902 }
903 }
904
905 fn initArrayParameter(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void {
906 if (switch (kind) {
907 .forward_parameter => @as(Index, undefined),
908 .parameter => try lookup.typeToIndex(ty, .forward_parameter),
909 .forward, .complete, .global, .payload => unreachable,
910 }) |fwd_idx| {
911 if (try lookup.typeToIndex(ty, switch (kind) {
912 .forward_parameter => .forward,
913 .parameter => .complete,
914 .forward, .complete, .global, .payload => unreachable,
915 })) |array_idx| {
916 self.storage = .{ .anon = undefined };
917 self.storage.anon.fields[0] = .{
918 .name = "array",
919 .type = array_idx,
920 .alignas = AlignAs.abiAlign(ty, lookup.getTarget()),
921 };
922 self.initAnon(kind, fwd_idx, 1);
923 } else self.init(switch (kind) {
924 .forward_parameter => .fwd_anon_struct,
925 .parameter => .anon_struct,
926 .forward, .complete, .global, .payload => unreachable,
927 });
928 } else self.init(.anon_struct);
929 }
930
931 pub fn initType(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void {
932 const target = lookup.getTarget();
933
934 self.* = undefined;
935 if (!ty.isFnOrHasRuntimeBitsIgnoreComptime())
936 self.init(.void)
937 else if (ty.isAbiInt()) switch (ty.tag()) {
938 .usize => self.init(.uintptr_t),
939 .isize => self.init(.intptr_t),
940 .c_short => self.init(.short),
941 .c_ushort => self.init(.@"unsigned short"),
942 .c_int => self.init(.int),
943 .c_uint => self.init(.@"unsigned int"),
944 .c_long => self.init(.long),
945 .c_ulong => self.init(.@"unsigned long"),
946 .c_longlong => self.init(.@"long long"),
947 .c_ulonglong => self.init(.@"unsigned long long"),
948 else => {
949 const info = ty.intInfo(target);
950 const t = tagFromIntInfo(info.signedness, info.bits);
951 switch (t) {
952 .void => unreachable,
953 else => self.init(t),
954 .array => switch (kind) {
955 .forward, .complete, .global => {
956 const abi_size = ty.abiSize(target);
957 const abi_align = ty.abiAlignment(target);
958 self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{
959 .len = @divExact(abi_size, abi_align),
960 .elem_type = tagFromIntInfo(
961 .unsigned,
962 @intCast(u16, abi_align * 8),
963 ).toIndex(),
964 } } };
965 self.value = .{ .cty = initPayload(&self.storage.seq) };
966 },
967 .forward_parameter,
968 .parameter,
969 => try self.initArrayParameter(ty, kind, lookup),
970 .payload => unreachable,
971 },
972 }
973 },
974 } else switch (ty.zigTypeTag()) {
975 .Frame => unreachable,
976 .AnyFrame => unreachable,
977
978 .Int,
979 .Enum,
980 .ErrorSet,
981 .Type,
982 .Void,
983 .NoReturn,
984 .ComptimeFloat,
985 .ComptimeInt,
986 .Undefined,
987 .Null,
988 .EnumLiteral,
989 => unreachable,
990
991 .Bool => self.init(.bool),
992
993 .Float => self.init(switch (ty.tag()) {
994 .f16 => .zig_f16,
995 .f32 => .zig_f32,
996 .f64 => .zig_f64,
997 .f80 => .zig_f80,
998 .f128 => .zig_f128,
999 .c_longdouble => .zig_c_longdouble,
1000 else => unreachable,
1001 }),
1002
1003 .Pointer => {
1004 const info = ty.ptrInfo().data;
1005 switch (info.size) {
1006 .Slice => {
1007 if (switch (kind) {
1008 .forward, .forward_parameter => @as(Index, undefined),
1009 .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward),
1010 .payload => unreachable,
1011 }) |fwd_idx| {
1012 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
1013 const ptr_ty = ty.slicePtrFieldType(&buf);
1014 if (try lookup.typeToIndex(ptr_ty, kind)) |ptr_idx| {
1015 self.storage = .{ .anon = undefined };
1016 self.storage.anon.fields[0] = .{
1017 .name = "ptr",
1018 .type = ptr_idx,
1019 .alignas = AlignAs.abiAlign(ptr_ty, target),
1020 };
1021 self.storage.anon.fields[1] = .{
1022 .name = "len",
1023 .type = Tag.uintptr_t.toIndex(),
1024 .alignas = AlignAs.abiAlign(Type.usize, target),
1025 };
1026 self.initAnon(kind, fwd_idx, 2);
1027 } else self.init(switch (kind) {
1028 .forward, .forward_parameter => .fwd_anon_struct,
1029 .complete, .parameter, .global => .anon_struct,
1030 .payload => unreachable,
1031 });
1032 } else self.init(.anon_struct);
1033 },
1034
1035 .One, .Many, .C => {
1036 const t: Tag = switch (info.@"volatile") {
1037 false => switch (info.mutable) {
1038 true => .pointer,
1039 false => .pointer_const,
1040 },
1041 true => switch (info.mutable) {
1042 true => .pointer_volatile,
1043 false => .pointer_const_volatile,
1044 },
1045 };
1046
1047 var host_int_pl = Type.Payload.Bits{
1048 .base = .{ .tag = .int_unsigned },
1049 .data = info.host_size * 8,
1050 };
1051 const pointee_ty = if (info.host_size > 0)
1052 Type.initPayload(&host_int_pl.base)
1053 else
1054 info.pointee_type;
1055
1056 if (if (info.size == .C and pointee_ty.tag() == .u8)
1057 Tag.char.toIndex()
1058 else
1059 try lookup.typeToIndex(pointee_ty, .forward)) |child_idx|
1060 {
1061 self.storage = .{ .child = .{
1062 .base = .{ .tag = t },
1063 .data = child_idx,
1064 } };
1065 self.value = .{ .cty = initPayload(&self.storage.child) };
1066 } else self.init(t);
1067 },
1068 }
1069 },
1070
1071 .Struct, .Union => |zig_ty_tag| if (ty.containerLayout() == .Packed) {
1072 if (ty.castTag(.@"struct")) |struct_obj| {
1073 try self.initType(struct_obj.data.backing_int_ty, kind, lookup);
1074 } else {
1075 var buf: Type.Payload.Bits = .{
1076 .base = .{ .tag = .int_unsigned },
1077 .data = @intCast(u16, ty.bitSize(target)),
1078 };
1079 try self.initType(Type.initPayload(&buf.base), kind, lookup);
1080 }
1081 } else if (ty.isTupleOrAnonStruct()) {
1082 if (lookup.isMutable()) {
1083 for (0..switch (zig_ty_tag) {
1084 .Struct => ty.structFieldCount(),
1085 .Union => ty.unionFields().count(),
1086 else => unreachable,
1087 }) |field_i| {
1088 const field_ty = ty.structFieldType(field_i);
1089 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or
1090 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
1091 _ = try lookup.typeToIndex(field_ty, switch (kind) {
1092 .forward, .forward_parameter => .forward,
1093 .complete, .parameter => .complete,
1094 .global => .global,
1095 .payload => unreachable,
1096 });
1097 }
1098 switch (kind) {
1099 .forward, .forward_parameter => {},
1100 .complete, .parameter, .global => _ = try lookup.typeToIndex(ty, .forward),
1101 .payload => unreachable,
1102 }
1103 }
1104 self.init(switch (kind) {
1105 .forward, .forward_parameter => switch (zig_ty_tag) {
1106 .Struct => .fwd_anon_struct,
1107 .Union => .fwd_anon_union,
1108 else => unreachable,
1109 },
1110 .complete, .parameter, .global => switch (zig_ty_tag) {
1111 .Struct => .anon_struct,
1112 .Union => .anon_union,
1113 else => unreachable,
1114 },
1115 .payload => unreachable,
1116 });
1117 } else {
1118 const tag_ty = ty.unionTagTypeSafety();
1119 const is_tagged_union_wrapper = kind != .payload and tag_ty != null;
1120 const is_struct = zig_ty_tag == .Struct or is_tagged_union_wrapper;
1121 switch (kind) {
1122 .forward, .forward_parameter => {
1123 self.storage = .{ .fwd = .{
1124 .base = .{ .tag = if (is_struct) .fwd_struct else .fwd_union },
1125 .data = ty.getOwnerDecl(),
1126 } };
1127 self.value = .{ .cty = initPayload(&self.storage.fwd) };
1128 },
1129 .complete, .parameter, .global, .payload => if (is_tagged_union_wrapper) {
1130 const fwd_idx = try lookup.typeToIndex(ty, .forward);
1131 const payload_idx = try lookup.typeToIndex(ty, .payload);
1132 const tag_idx = try lookup.typeToIndex(tag_ty.?, kind);
1133 if (fwd_idx != null and payload_idx != null and tag_idx != null) {
1134 self.storage = .{ .anon = undefined };
1135 var field_count: usize = 0;
1136 if (payload_idx != Tag.void.toIndex()) {
1137 self.storage.anon.fields[field_count] = .{
1138 .name = "payload",
1139 .type = payload_idx.?,
1140 .alignas = AlignAs.unionPayloadAlign(ty, target),
1141 };
1142 field_count += 1;
1143 }
1144 if (tag_idx != Tag.void.toIndex()) {
1145 self.storage.anon.fields[field_count] = .{
1146 .name = "tag",
1147 .type = tag_idx.?,
1148 .alignas = AlignAs.abiAlign(tag_ty.?, target),
1149 };
1150 field_count += 1;
1151 }
1152 self.storage.anon.pl = .{ .complete = .{
1153 .base = .{ .tag = .@"struct" },
1154 .data = .{
1155 .fields = self.sortFields(field_count),
1156 .fwd_decl = fwd_idx.?,
1157 },
1158 } };
1159 self.value = .{ .cty = initPayload(&self.storage.anon.pl.complete) };
1160 } else self.init(.@"struct");
1161 } else if (kind == .payload and ty.unionHasAllZeroBitFieldTypes()) {
1162 self.init(.void);
1163 } else {
1164 var is_packed = false;
1165 for (0..switch (zig_ty_tag) {
1166 .Struct => ty.structFieldCount(),
1167 .Union => ty.unionFields().count(),
1168 else => unreachable,
1169 }) |field_i| {
1170 const field_ty = ty.structFieldType(field_i);
1171 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
1172
1173 const field_align = AlignAs.fieldAlign(ty, field_i, target);
1174 if (field_align.@"align" < field_align.abi) {
1175 is_packed = true;
1176 if (!lookup.isMutable()) break;
1177 }
1178
1179 if (lookup.isMutable()) {
1180 _ = try lookup.typeToIndex(field_ty, switch (kind) {
1181 .forward, .forward_parameter => unreachable,
1182 .complete, .parameter, .payload => .complete,
1183 .global => .global,
1184 });
1185 }
1186 }
1187 switch (kind) {
1188 .forward, .forward_parameter => unreachable,
1189 .complete, .parameter, .global => {
1190 _ = try lookup.typeToIndex(ty, .forward);
1191 self.init(if (is_struct)
1192 if (is_packed) .packed_struct else .@"struct"
1193 else if (is_packed) .packed_union else .@"union");
1194 },
1195 .payload => self.init(if (is_packed)
1196 .packed_unnamed_union
1197 else
1198 .unnamed_union),
1199 }
1200 },
1201 }
1202 },
1203
1204 .Array, .Vector => |zig_ty_tag| {
1205 switch (kind) {
1206 .forward, .complete, .global => {
1207 const t: Tag = switch (zig_ty_tag) {
1208 .Array => .array,
1209 .Vector => .vector,
1210 else => unreachable,
1211 };
1212 if (try lookup.typeToIndex(ty.childType(), kind)) |child_idx| {
1213 self.storage = .{ .seq = .{ .base = .{ .tag = t }, .data = .{
1214 .len = ty.arrayLenIncludingSentinel(),
1215 .elem_type = child_idx,
1216 } } };
1217 self.value = .{ .cty = initPayload(&self.storage.seq) };
1218 } else self.init(t);
1219 },
1220 .forward_parameter, .parameter => try self.initArrayParameter(ty, kind, lookup),
1221 .payload => unreachable,
1222 }
1223 },
1224
1225 .Optional => {
1226 var buf: Type.Payload.ElemType = undefined;
1227 const payload_ty = ty.optionalChild(&buf);
1228 if (payload_ty.hasRuntimeBitsIgnoreComptime()) {
1229 if (ty.optionalReprIsPayload()) {
1230 try self.initType(payload_ty, kind, lookup);
1231 } else if (switch (kind) {
1232 .forward, .forward_parameter => @as(Index, undefined),
1233 .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward),
1234 .payload => unreachable,
1235 }) |fwd_idx| {
1236 if (try lookup.typeToIndex(payload_ty, switch (kind) {
1237 .forward, .forward_parameter => .forward,
1238 .complete, .parameter => .complete,
1239 .global => .global,
1240 .payload => unreachable,
1241 })) |payload_idx| {
1242 self.storage = .{ .anon = undefined };
1243 self.storage.anon.fields[0] = .{
1244 .name = "payload",
1245 .type = payload_idx,
1246 .alignas = AlignAs.abiAlign(payload_ty, target),
1247 };
1248 self.storage.anon.fields[1] = .{
1249 .name = "is_null",
1250 .type = Tag.bool.toIndex(),
1251 .alignas = AlignAs.abiAlign(Type.bool, target),
1252 };
1253 self.initAnon(kind, fwd_idx, 2);
1254 } else self.init(switch (kind) {
1255 .forward, .forward_parameter => .fwd_anon_struct,
1256 .complete, .parameter, .global => .anon_struct,
1257 .payload => unreachable,
1258 });
1259 } else self.init(.anon_struct);
1260 } else self.init(.bool);
1261 },
1262
1263 .ErrorUnion => {
1264 if (switch (kind) {
1265 .forward, .forward_parameter => @as(Index, undefined),
1266 .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward),
1267 .payload => unreachable,
1268 }) |fwd_idx| {
1269 const payload_ty = ty.errorUnionPayload();
1270 if (try lookup.typeToIndex(payload_ty, switch (kind) {
1271 .forward, .forward_parameter => .forward,
1272 .complete, .parameter => .complete,
1273 .global => .global,
1274 .payload => unreachable,
1275 })) |payload_idx| {
1276 const error_ty = ty.errorUnionSet();
1277 if (payload_idx == Tag.void.toIndex()) {
1278 try self.initType(error_ty, kind, lookup);
1279 } else if (try lookup.typeToIndex(error_ty, kind)) |error_idx| {
1280 self.storage = .{ .anon = undefined };
1281 self.storage.anon.fields[0] = .{
1282 .name = "payload",
1283 .type = payload_idx,
1284 .alignas = AlignAs.abiAlign(payload_ty, target),
1285 };
1286 self.storage.anon.fields[1] = .{
1287 .name = "error",
1288 .type = error_idx,
1289 .alignas = AlignAs.abiAlign(error_ty, target),
1290 };
1291 self.initAnon(kind, fwd_idx, 2);
1292 } else self.init(switch (kind) {
1293 .forward, .forward_parameter => .fwd_anon_struct,
1294 .complete, .parameter, .global => .anon_struct,
1295 .payload => unreachable,
1296 });
1297 } else self.init(switch (kind) {
1298 .forward, .forward_parameter => .fwd_anon_struct,
1299 .complete, .parameter, .global => .anon_struct,
1300 .payload => unreachable,
1301 });
1302 } else self.init(.anon_struct);
1303 },
1304
1305 .Opaque => switch (ty.tag()) {
1306 .anyopaque => self.init(.void),
1307 .@"opaque" => {
1308 self.storage = .{ .fwd = .{
1309 .base = .{ .tag = .fwd_struct },
1310 .data = ty.getOwnerDecl(),
1311 } };
1312 self.value = .{ .cty = initPayload(&self.storage.fwd) };
1313 },
1314 else => unreachable,
1315 },
1316
1317 .Fn => {
1318 const info = ty.fnInfo();
1319 if (!info.is_generic) {
1320 if (lookup.isMutable()) {
1321 const param_kind: Kind = switch (kind) {
1322 .forward, .forward_parameter => .forward_parameter,
1323 .complete, .parameter, .global => .parameter,
1324 .payload => unreachable,
1325 };
1326 _ = try lookup.typeToIndex(info.return_type, param_kind);
1327 for (info.param_types) |param_type| {
1328 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
1329 _ = try lookup.typeToIndex(param_type, param_kind);
1330 }
1331 }
1332 self.init(if (info.is_var_args) .varargs_function else .function);
1333 } else self.init(.void);
1334 },
1335 }
1336 }
1337 };
1338
1339 pub fn copy(self: CType, arena: Allocator) !CType {
1340 return self.copyContext(struct {
1341 arena: Allocator,
1342 pub fn copyIndex(_: @This(), idx: Index) Index {
1343 return idx;
1344 }
1345 }{ .arena = arena });
1346 }
1347
1348 fn copyFields(ctx: anytype, old_fields: Payload.Fields.Data) !Payload.Fields.Data {
1349 const new_fields = try ctx.arena.alloc(Payload.Fields.Field, old_fields.len);
1350 for (new_fields, old_fields) |*new_field, old_field| {
1351 new_field.name = try ctx.arena.dupeZ(u8, mem.span(old_field.name));
1352 new_field.type = ctx.copyIndex(old_field.type);
1353 new_field.alignas = old_field.alignas;
1354 }
1355 return new_fields;
1356 }
1357
1358 fn copyParams(ctx: anytype, old_param_types: []const Index) ![]const Index {
1359 const new_param_types = try ctx.arena.alloc(Index, old_param_types.len);
1360 for (new_param_types, old_param_types) |*new_param_type, old_param_type|
1361 new_param_type.* = ctx.copyIndex(old_param_type);
1362 return new_param_types;
1363 }
1364
1365 pub fn copyContext(self: CType, ctx: anytype) !CType {
1366 switch (self.tag()) {
1367 .void,
1368 .char,
1369 .@"signed char",
1370 .short,
1371 .int,
1372 .long,
1373 .@"long long",
1374 ._Bool,
1375 .@"unsigned char",
1376 .@"unsigned short",
1377 .@"unsigned int",
1378 .@"unsigned long",
1379 .@"unsigned long long",
1380 .float,
1381 .double,
1382 .@"long double",
1383 .bool,
1384 .size_t,
1385 .ptrdiff_t,
1386 .uint8_t,
1387 .int8_t,
1388 .uint16_t,
1389 .int16_t,
1390 .uint32_t,
1391 .int32_t,
1392 .uint64_t,
1393 .int64_t,
1394 .uintptr_t,
1395 .intptr_t,
1396 .zig_u128,
1397 .zig_i128,
1398 .zig_f16,
1399 .zig_f32,
1400 .zig_f64,
1401 .zig_f80,
1402 .zig_f128,
1403 .zig_c_longdouble,
1404 => return self,
1405
1406 .pointer,
1407 .pointer_const,
1408 .pointer_volatile,
1409 .pointer_const_volatile,
1410 => {
1411 const pl = self.cast(Payload.Child).?;
1412 const new_pl = try ctx.arena.create(Payload.Child);
1413 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = ctx.copyIndex(pl.data) };
1414 return initPayload(new_pl);
1415 },
1416
1417 .array,
1418 .vector,
1419 => {
1420 const pl = self.cast(Payload.Sequence).?;
1421 const new_pl = try ctx.arena.create(Payload.Sequence);
1422 new_pl.* = .{
1423 .base = .{ .tag = pl.base.tag },
1424 .data = .{ .len = pl.data.len, .elem_type = ctx.copyIndex(pl.data.elem_type) },
1425 };
1426 return initPayload(new_pl);
1427 },
1428
1429 .fwd_anon_struct,
1430 .fwd_anon_union,
1431 => {
1432 const pl = self.cast(Payload.Fields).?;
1433 const new_pl = try ctx.arena.create(Payload.Fields);
1434 new_pl.* = .{
1435 .base = .{ .tag = pl.base.tag },
1436 .data = try copyFields(ctx, pl.data),
1437 };
1438 return initPayload(new_pl);
1439 },
1440
1441 .fwd_struct,
1442 .fwd_union,
1443 => {
1444 const pl = self.cast(Payload.FwdDecl).?;
1445 const new_pl = try ctx.arena.create(Payload.FwdDecl);
1446 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = pl.data };
1447 return initPayload(new_pl);
1448 },
1449
1450 .unnamed_struct,
1451 .unnamed_union,
1452 .packed_unnamed_struct,
1453 .packed_unnamed_union,
1454 => {
1455 const pl = self.cast(Payload.Unnamed).?;
1456 const new_pl = try ctx.arena.create(Payload.Unnamed);
1457 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = .{
1458 .fields = try copyFields(ctx, pl.data.fields),
1459 .owner_decl = pl.data.owner_decl,
1460 .id = pl.data.id,
1461 } };
1462 return initPayload(new_pl);
1463 },
1464
1465 .anon_struct,
1466 .anon_union,
1467 .@"struct",
1468 .@"union",
1469 .packed_struct,
1470 .packed_union,
1471 => {
1472 const pl = self.cast(Payload.Aggregate).?;
1473 const new_pl = try ctx.arena.create(Payload.Aggregate);
1474 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = .{
1475 .fields = try copyFields(ctx, pl.data.fields),
1476 .fwd_decl = ctx.copyIndex(pl.data.fwd_decl),
1477 } };
1478 return initPayload(new_pl);
1479 },
1480
1481 .function,
1482 .varargs_function,
1483 => {
1484 const pl = self.cast(Payload.Function).?;
1485 const new_pl = try ctx.arena.create(Payload.Function);
1486 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = .{
1487 .return_type = ctx.copyIndex(pl.data.return_type),
1488 .param_types = try copyParams(ctx, pl.data.param_types),
1489 } };
1490 return initPayload(new_pl);
1491 },
1492 }
1493 }
1494
1495 fn createFromType(store: *Store.Promoted, ty: Type, target: Target, kind: Kind) !CType {
1496 var convert: Convert = undefined;
1497 try convert.initType(ty, kind, .{ .imm = .{ .set = &store.set, .target = target } });
1498 return createFromConvert(store, ty, target, kind, &convert);
1499 }
1500
1501 fn createFromConvert(
1502 store: *Store.Promoted,
1503 ty: Type,
1504 target: Target,
1505 kind: Kind,
1506 convert: Convert,
1507 ) !CType {
1508 const arena = store.arena.allocator();
1509 switch (convert.value) {
1510 .cty => |c| return c.copy(arena),
1511 .tag => |t| switch (t) {
1512 .fwd_anon_struct,
1513 .fwd_anon_union,
1514 .unnamed_struct,
1515 .unnamed_union,
1516 .packed_unnamed_struct,
1517 .packed_unnamed_union,
1518 .anon_struct,
1519 .anon_union,
1520 .@"struct",
1521 .@"union",
1522 .packed_struct,
1523 .packed_union,
1524 => {
1525 const zig_ty_tag = ty.zigTypeTag();
1526 const fields_len = switch (zig_ty_tag) {
1527 .Struct => ty.structFieldCount(),
1528 .Union => ty.unionFields().count(),
1529 else => unreachable,
1530 };
1531
1532 var c_fields_len: usize = 0;
1533 for (0..fields_len) |field_i| {
1534 const field_ty = ty.structFieldType(field_i);
1535 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or
1536 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
1537 c_fields_len += 1;
1538 }
1539
1540 const fields_pl = try arena.alloc(Payload.Fields.Field, c_fields_len);
1541 var c_field_i: usize = 0;
1542 for (0..fields_len) |field_i| {
1543 const field_ty = ty.structFieldType(field_i);
1544 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or
1545 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
1546
1547 defer c_field_i += 1;
1548 fields_pl[c_field_i] = .{
1549 .name = try if (ty.isSimpleTuple())
1550 std.fmt.allocPrintZ(arena, "f{}", .{field_i})
1551 else
1552 arena.dupeZ(u8, switch (zig_ty_tag) {
1553 .Struct => ty.structFieldName(field_i),
1554 .Union => ty.unionFields().keys()[field_i],
1555 else => unreachable,
1556 }),
1557 .type = store.set.typeToIndex(field_ty, target, switch (kind) {
1558 .forward, .forward_parameter => .forward,
1559 .complete, .parameter, .payload => .complete,
1560 .global => .global,
1561 }).?,
1562 .alignas = AlignAs.fieldAlign(ty, field_i, target),
1563 };
1564 }
1565
1566 switch (t) {
1567 .fwd_anon_struct,
1568 .fwd_anon_union,
1569 => {
1570 const anon_pl = try arena.create(Payload.Fields);
1571 anon_pl.* = .{ .base = .{ .tag = t }, .data = fields_pl };
1572 return initPayload(anon_pl);
1573 },
1574
1575 .unnamed_struct,
1576 .unnamed_union,
1577 .packed_unnamed_struct,
1578 .packed_unnamed_union,
1579 => {
1580 const unnamed_pl = try arena.create(Payload.Unnamed);
1581 unnamed_pl.* = .{ .base = .{ .tag = t }, .data = .{
1582 .fields = fields_pl,
1583 .owner_decl = ty.getOwnerDecl(),
1584 .id = if (ty.unionTagTypeSafety()) |_| 0 else unreachable,
1585 } };
1586 return initPayload(unnamed_pl);
1587 },
1588
1589 .anon_struct,
1590 .anon_union,
1591 .@"struct",
1592 .@"union",
1593 .packed_struct,
1594 .packed_union,
1595 => {
1596 const struct_pl = try arena.create(Payload.Aggregate);
1597 struct_pl.* = .{ .base = .{ .tag = t }, .data = .{
1598 .fields = fields_pl,
1599 .fwd_decl = store.set.typeToIndex(ty, target, .forward).?,
1600 } };
1601 return initPayload(struct_pl);
1602 },
1603
1604 else => unreachable,
1605 }
1606 },
1607
1608 .function,
1609 .varargs_function,
1610 => {
1611 const info = ty.fnInfo();
1612 assert(!info.is_generic);
1613 const param_kind: Kind = switch (kind) {
1614 .forward, .forward_parameter => .forward_parameter,
1615 .complete, .parameter, .global => .parameter,
1616 .payload => unreachable,
1617 };
1618
1619 var c_params_len: usize = 0;
1620 for (info.param_types) |param_type| {
1621 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
1622 c_params_len += 1;
1623 }
1624
1625 const params_pl = try arena.alloc(Index, c_params_len);
1626 var c_param_i: usize = 0;
1627 for (info.param_types) |param_type| {
1628 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
1629 params_pl[c_param_i] = store.set.typeToIndex(param_type, target, param_kind).?;
1630 c_param_i += 1;
1631 }
1632
1633 const fn_pl = try arena.create(Payload.Function);
1634 fn_pl.* = .{ .base = .{ .tag = t }, .data = .{
1635 .return_type = store.set.typeToIndex(info.return_type, target, param_kind).?,
1636 .param_types = params_pl,
1637 } };
1638 return initPayload(fn_pl);
1639 },
1640
1641 else => unreachable,
1642 },
1643 }
1644 }
1645
1646 pub const TypeAdapter64 = struct {
1647 kind: Kind,
1648 lookup: Convert.Lookup,
1649 convert: *const Convert,
1650
1651 fn eqlRecurse(self: @This(), ty: Type, cty: Index, kind: Kind) bool {
1652 assert(!self.lookup.isMutable());
1653
1654 var convert: Convert = undefined;
1655 convert.initType(ty, kind, self.lookup) catch unreachable;
1656
1657 const self_recurse = @This(){ .kind = kind, .lookup = self.lookup, .convert = &convert };
1658 return self_recurse.eql(ty, self.lookup.indexToCType(cty).?);
1659 }
1660
1661 pub fn eql(self: @This(), ty: Type, cty: CType) bool {
1662 switch (self.convert.value) {
1663 .cty => |c| return c.eql(cty),
1664 .tag => |t| {
1665 if (t != cty.tag()) return false;
1666
1667 const target = self.lookup.getTarget();
1668 switch (t) {
1669 .fwd_anon_struct,
1670 .fwd_anon_union,
1671 => {
1672 if (!ty.isTupleOrAnonStruct()) return false;
1673
1674 var name_buf: [
1675 std.fmt.count("f{}", .{std.math.maxInt(usize)})
1676 ]u8 = undefined;
1677 const c_fields = cty.cast(Payload.Fields).?.data;
1678
1679 const zig_ty_tag = ty.zigTypeTag();
1680 var c_field_i: usize = 0;
1681 for (0..switch (zig_ty_tag) {
1682 .Struct => ty.structFieldCount(),
1683 .Union => ty.unionFields().count(),
1684 else => unreachable,
1685 }) |field_i| {
1686 const field_ty = ty.structFieldType(field_i);
1687 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or
1688 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
1689
1690 defer c_field_i += 1;
1691 const c_field = &c_fields[c_field_i];
1692
1693 if (!self.eqlRecurse(field_ty, c_field.type, switch (self.kind) {
1694 .forward, .forward_parameter => .forward,
1695 .complete, .parameter => .complete,
1696 .global => .global,
1697 .payload => unreachable,
1698 }) or !mem.eql(
1699 u8,
1700 if (ty.isSimpleTuple())
1701 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
1702 else switch (zig_ty_tag) {
1703 .Struct => ty.structFieldName(field_i),
1704 .Union => ty.unionFields().keys()[field_i],
1705 else => unreachable,
1706 },
1707 mem.span(c_field.name),
1708 ) or AlignAs.fieldAlign(ty, field_i, target).@"align" !=
1709 c_field.alignas.@"align") return false;
1710 }
1711 return true;
1712 },
1713
1714 .unnamed_struct,
1715 .unnamed_union,
1716 .packed_unnamed_struct,
1717 .packed_unnamed_union,
1718 => switch (self.kind) {
1719 .forward, .forward_parameter, .complete, .parameter, .global => unreachable,
1720 .payload => if (ty.unionTagTypeSafety()) |_| {
1721 const data = cty.cast(Payload.Unnamed).?.data;
1722 return ty.getOwnerDecl() == data.owner_decl and data.id == 0;
1723 } else unreachable,
1724 },
1725
1726 .anon_struct,
1727 .anon_union,
1728 .@"struct",
1729 .@"union",
1730 .packed_struct,
1731 .packed_union,
1732 => return self.eqlRecurse(
1733 ty,
1734 cty.cast(Payload.Aggregate).?.data.fwd_decl,
1735 .forward,
1736 ),
1737
1738 .function,
1739 .varargs_function,
1740 => {
1741 if (ty.zigTypeTag() != .Fn) return false;
1742
1743 const info = ty.fnInfo();
1744 assert(!info.is_generic);
1745 const data = cty.cast(Payload.Function).?.data;
1746 const param_kind: Kind = switch (self.kind) {
1747 .forward, .forward_parameter => .forward_parameter,
1748 .complete, .parameter, .global => .parameter,
1749 .payload => unreachable,
1750 };
1751
1752 if (!self.eqlRecurse(info.return_type, data.return_type, param_kind))
1753 return false;
1754
1755 var c_param_i: usize = 0;
1756 for (info.param_types) |param_type| {
1757 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
1758
1759 if (c_param_i >= data.param_types.len) return false;
1760 const param_cty = data.param_types[c_param_i];
1761 c_param_i += 1;
1762
1763 if (!self.eqlRecurse(param_type, param_cty, param_kind))
1764 return false;
1765 }
1766 return c_param_i == data.param_types.len;
1767 },
1768
1769 else => unreachable,
1770 }
1771 },
1772 }
1773 }
1774
1775 pub fn hash(self: @This(), ty: Type) u64 {
1776 var hasher = std.hash.Wyhash.init(0);
1777 self.updateHasher(&hasher, ty);
1778 return hasher.final();
1779 }
1780
1781 fn updateHasherRecurse(self: @This(), hasher: anytype, ty: Type, kind: Kind) void {
1782 assert(!self.lookup.isMutable());
1783
1784 var convert: Convert = undefined;
1785 convert.initType(ty, kind, self.lookup) catch unreachable;
1786
1787 const self_recurse = @This(){ .kind = kind, .lookup = self.lookup, .convert = &convert };
1788 self_recurse.updateHasher(hasher, ty);
1789 }
1790
1791 pub fn updateHasher(self: @This(), hasher: anytype, ty: Type) void {
1792 switch (self.convert.value) {
1793 .cty => |c| return c.updateHasher(hasher, self.lookup.getSet().?.*),
1794 .tag => |t| {
1795 autoHash(hasher, t);
1796
1797 const target = self.lookup.getTarget();
1798 switch (t) {
1799 .fwd_anon_struct,
1800 .fwd_anon_union,
1801 => {
1802 var name_buf: [
1803 std.fmt.count("f{}", .{std.math.maxInt(usize)})
1804 ]u8 = undefined;
1805
1806 const zig_ty_tag = ty.zigTypeTag();
1807 for (0..switch (ty.zigTypeTag()) {
1808 .Struct => ty.structFieldCount(),
1809 .Union => ty.unionFields().count(),
1810 else => unreachable,
1811 }) |field_i| {
1812 const field_ty = ty.structFieldType(field_i);
1813 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i)) or
1814 !field_ty.hasRuntimeBitsIgnoreComptime()) continue;
1815
1816 self.updateHasherRecurse(hasher, field_ty, switch (self.kind) {
1817 .forward, .forward_parameter => .forward,
1818 .complete, .parameter => .complete,
1819 .global => .global,
1820 .payload => unreachable,
1821 });
1822 hasher.update(if (ty.isSimpleTuple())
1823 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
1824 else switch (zig_ty_tag) {
1825 .Struct => ty.structFieldName(field_i),
1826 .Union => ty.unionFields().keys()[field_i],
1827 else => unreachable,
1828 });
1829 autoHash(hasher, AlignAs.fieldAlign(ty, field_i, target).@"align");
1830 }
1831 },
1832
1833 .unnamed_struct,
1834 .unnamed_union,
1835 .packed_unnamed_struct,
1836 .packed_unnamed_union,
1837 => switch (self.kind) {
1838 .forward, .forward_parameter, .complete, .parameter, .global => unreachable,
1839 .payload => if (ty.unionTagTypeSafety()) |_| {
1840 autoHash(hasher, ty.getOwnerDecl());
1841 autoHash(hasher, @as(u32, 0));
1842 } else unreachable,
1843 },
1844
1845 .anon_struct,
1846 .anon_union,
1847 .@"struct",
1848 .@"union",
1849 .packed_struct,
1850 .packed_union,
1851 => self.updateHasherRecurse(hasher, ty, .forward),
1852
1853 .function,
1854 .varargs_function,
1855 => {
1856 const info = ty.fnInfo();
1857 assert(!info.is_generic);
1858 const param_kind: Kind = switch (self.kind) {
1859 .forward, .forward_parameter => .forward_parameter,
1860 .complete, .parameter, .global => .parameter,
1861 .payload => unreachable,
1862 };
1863
1864 self.updateHasherRecurse(hasher, info.return_type, param_kind);
1865 for (info.param_types) |param_type| {
1866 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
1867 self.updateHasherRecurse(hasher, param_type, param_kind);
1868 }
1869 },
1870
1871 else => unreachable,
1872 }
1873 },
1874 }
1875 }
1876 };
1877
1878 pub const TypeAdapter32 = struct {
1879 kind: Kind,
1880 lookup: Convert.Lookup,
1881 convert: *const Convert,
1882
1883 fn to64(self: @This()) TypeAdapter64 {
1884 return .{ .kind = self.kind, .lookup = self.lookup, .convert = self.convert };
1885 }
1886
1887 pub fn eql(self: @This(), ty: Type, cty: CType, cty_index: usize) bool {
1888 _ = cty_index;
1889 return self.to64().eql(ty, cty);
1890 }
1891
1892 pub fn hash(self: @This(), ty: Type) u32 {
1893 return @truncate(u32, self.to64().hash(ty));
1894 }
1895 };
1896};
src/codegen/llvm.zig+2-2
...@@ -6025,8 +6025,8 @@ pub const FuncGen = struct {...@@ -6025,8 +6025,8 @@ pub const FuncGen = struct {
6025 const field_ptr = try self.resolveInst(extra.field_ptr);6025 const field_ptr = try self.resolveInst(extra.field_ptr);
60266026
6027 const target = self.dg.module.getTarget();6027 const target = self.dg.module.getTarget();
6028 const struct_ty = self.air.getRefType(ty_pl.ty).childType();6028 const parent_ty = self.air.getRefType(ty_pl.ty).childType();
6029 const field_offset = struct_ty.structFieldOffset(extra.field_index, target);6029 const field_offset = parent_ty.structFieldOffset(extra.field_index, target);
60306030
6031 const res_ty = try self.dg.lowerType(self.air.getRefType(ty_pl.ty));6031 const res_ty = try self.dg.lowerType(self.air.getRefType(ty_pl.ty));
6032 if (field_offset == 0) {6032 if (field_offset == 0) {
src/link/C.zig+246-131
...@@ -22,27 +22,22 @@ base: link.File,...@@ -22,27 +22,22 @@ base: link.File,
22/// Instead, it tracks all declarations in this table, and iterates over it22/// Instead, it tracks all declarations in this table, and iterates over it
23/// in the flush function, stitching pre-rendered pieces of C code together.23/// in the flush function, stitching pre-rendered pieces of C code together.
24decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclBlock) = .{},24decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclBlock) = .{},
25/// Stores Type/Value data for `typedefs` to reference.
26/// Accumulates allocations and then there is a periodic garbage collection after flush().
27arena: std.heap.ArenaAllocator,
2825
29/// Per-declaration data.26/// Per-declaration data.
30const DeclBlock = struct {27const DeclBlock = struct {
31 code: std.ArrayListUnmanaged(u8) = .{},28 code: std.ArrayListUnmanaged(u8) = .{},
32 fwd_decl: std.ArrayListUnmanaged(u8) = .{},29 fwd_decl: std.ArrayListUnmanaged(u8) = .{},
33 /// Each Decl stores a mapping of Zig Types to corresponding C types, for every30 /// Each `Decl` stores a set of used `CType`s. In `flush()`, we iterate
34 /// Zig Type used by the Decl. In flush(), we iterate over each Decl31 /// over each `Decl` and generate the definition for each used `CType` once.
35 /// and emit the typedef code for all types, making sure to not emit the same thing twice.32 ctypes: codegen.CType.Store = .{},
36 /// Any arena memory the Type points to lives in the `arena` field of `C`.33 /// Key and Value storage use the ctype arena.
37 typedefs: codegen.TypedefMap.Unmanaged = .{},34 lazy_fns: codegen.LazyFnMap = .{},
3835
39 fn deinit(db: *DeclBlock, gpa: Allocator) void {36 fn deinit(db: *DeclBlock, gpa: Allocator) void {
40 db.code.deinit(gpa);37 db.lazy_fns.deinit(gpa);
38 db.ctypes.deinit(gpa);
41 db.fwd_decl.deinit(gpa);39 db.fwd_decl.deinit(gpa);
42 for (db.typedefs.values()) |typedef| {40 db.code.deinit(gpa);
43 gpa.free(typedef.rendered);
44 }
45 db.typedefs.deinit(gpa);
46 db.* = undefined;41 db.* = undefined;
47 }42 }
48};43};
...@@ -64,7 +59,6 @@ pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C...@@ -64,7 +59,6 @@ pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C
64 errdefer gpa.destroy(c_file);59 errdefer gpa.destroy(c_file);
6560
66 c_file.* = C{61 c_file.* = C{
67 .arena = std.heap.ArenaAllocator.init(gpa),
68 .base = .{62 .base = .{
69 .tag = .c,63 .tag = .c,
70 .options = options,64 .options = options,
...@@ -83,8 +77,6 @@ pub fn deinit(self: *C) void {...@@ -83,8 +77,6 @@ pub fn deinit(self: *C) void {
83 db.deinit(gpa);77 db.deinit(gpa);
84 }78 }
85 self.decl_table.deinit(gpa);79 self.decl_table.deinit(gpa);
86
87 self.arena.deinit();
88}80}
8981
90pub fn freeDecl(self: *C, decl_index: Module.Decl.Index) void {82pub fn freeDecl(self: *C, decl_index: Module.Decl.Index) void {
...@@ -99,124 +91,122 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes...@@ -99,124 +91,122 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes
99 const tracy = trace(@src());91 const tracy = trace(@src());
100 defer tracy.end();92 defer tracy.end();
10193
94 const gpa = self.base.allocator;
95
102 const decl_index = func.owner_decl;96 const decl_index = func.owner_decl;
103 const gop = try self.decl_table.getOrPut(self.base.allocator, decl_index);97 const gop = try self.decl_table.getOrPut(gpa, decl_index);
104 if (!gop.found_existing) {98 if (!gop.found_existing) {
105 gop.value_ptr.* = .{};99 gop.value_ptr.* = .{};
106 }100 }
101 const ctypes = &gop.value_ptr.ctypes;
102 const lazy_fns = &gop.value_ptr.lazy_fns;
107 const fwd_decl = &gop.value_ptr.fwd_decl;103 const fwd_decl = &gop.value_ptr.fwd_decl;
108 const typedefs = &gop.value_ptr.typedefs;
109 const code = &gop.value_ptr.code;104 const code = &gop.value_ptr.code;
105 ctypes.clearRetainingCapacity(gpa);
106 lazy_fns.clearRetainingCapacity();
110 fwd_decl.shrinkRetainingCapacity(0);107 fwd_decl.shrinkRetainingCapacity(0);
111 for (typedefs.values()) |typedef| {
112 module.gpa.free(typedef.rendered);
113 }
114 typedefs.clearRetainingCapacity();
115 code.shrinkRetainingCapacity(0);108 code.shrinkRetainingCapacity(0);
116109
117 var function: codegen.Function = .{110 var function: codegen.Function = .{
118 .value_map = codegen.CValueMap.init(module.gpa),111 .value_map = codegen.CValueMap.init(gpa),
119 .air = air,112 .air = air,
120 .liveness = liveness,113 .liveness = liveness,
121 .func = func,114 .func = func,
122 .object = .{115 .object = .{
123 .dg = .{116 .dg = .{
124 .gpa = module.gpa,117 .gpa = gpa,
125 .module = module,118 .module = module,
126 .error_msg = null,119 .error_msg = null,
127 .decl_index = decl_index,120 .decl_index = decl_index.toOptional(),
128 .decl = module.declPtr(decl_index),121 .decl = module.declPtr(decl_index),
129 .fwd_decl = fwd_decl.toManaged(module.gpa),122 .fwd_decl = fwd_decl.toManaged(gpa),
130 .typedefs = typedefs.promoteContext(module.gpa, .{ .mod = module }),123 .ctypes = ctypes.*,
131 .typedefs_arena = self.arena.allocator(),
132 },124 },
133 .code = code.toManaged(module.gpa),125 .code = code.toManaged(gpa),
134 .indent_writer = undefined, // set later so we can get a pointer to object.code126 .indent_writer = undefined, // set later so we can get a pointer to object.code
135 },127 },
136 .arena = std.heap.ArenaAllocator.init(module.gpa),128 .lazy_fns = lazy_fns.*,
129 .arena = std.heap.ArenaAllocator.init(gpa),
137 };130 };
138131
139 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };132 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
140 defer function.deinit(module.gpa);133 defer function.deinit();
141134
142 codegen.genFunc(&function) catch |err| switch (err) {135 codegen.genFunc(&function) catch |err| switch (err) {
143 error.AnalysisFail => {136 error.AnalysisFail => {
144 try module.failed_decls.put(module.gpa, decl_index, function.object.dg.error_msg.?);137 try module.failed_decls.put(gpa, decl_index, function.object.dg.error_msg.?);
145 return;138 return;
146 },139 },
147 else => |e| return e,140 else => |e| return e,
148 };141 };
149142
143 ctypes.* = function.object.dg.ctypes.move();
144 lazy_fns.* = function.lazy_fns.move();
150 fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();145 fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();
151 typedefs.* = function.object.dg.typedefs.unmanaged;
152 function.object.dg.typedefs.unmanaged = .{};
153 code.* = function.object.code.moveToUnmanaged();146 code.* = function.object.code.moveToUnmanaged();
154147
155 // Free excess allocated memory for this Decl.148 // Free excess allocated memory for this Decl.
156 fwd_decl.shrinkAndFree(module.gpa, fwd_decl.items.len);149 ctypes.shrinkAndFree(gpa, ctypes.count());
157 code.shrinkAndFree(module.gpa, code.items.len);150 lazy_fns.shrinkAndFree(gpa, lazy_fns.count());
151 fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);
152 code.shrinkAndFree(gpa, code.items.len);
158}153}
159154
160pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !void {155pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !void {
161 const tracy = trace(@src());156 const tracy = trace(@src());
162 defer tracy.end();157 defer tracy.end();
163158
164 const gop = try self.decl_table.getOrPut(self.base.allocator, decl_index);159 const gpa = self.base.allocator;
160
161 const gop = try self.decl_table.getOrPut(gpa, decl_index);
165 if (!gop.found_existing) {162 if (!gop.found_existing) {
166 gop.value_ptr.* = .{};163 gop.value_ptr.* = .{};
167 }164 }
165 const ctypes = &gop.value_ptr.ctypes;
168 const fwd_decl = &gop.value_ptr.fwd_decl;166 const fwd_decl = &gop.value_ptr.fwd_decl;
169 const typedefs = &gop.value_ptr.typedefs;
170 const code = &gop.value_ptr.code;167 const code = &gop.value_ptr.code;
168 ctypes.clearRetainingCapacity(gpa);
171 fwd_decl.shrinkRetainingCapacity(0);169 fwd_decl.shrinkRetainingCapacity(0);
172 for (typedefs.values()) |value| {
173 module.gpa.free(value.rendered);
174 }
175 typedefs.clearRetainingCapacity();
176 code.shrinkRetainingCapacity(0);170 code.shrinkRetainingCapacity(0);
177171
178 const decl = module.declPtr(decl_index);172 const decl = module.declPtr(decl_index);
179173
180 var object: codegen.Object = .{174 var object: codegen.Object = .{
181 .dg = .{175 .dg = .{
182 .gpa = module.gpa,176 .gpa = gpa,
183 .module = module,177 .module = module,
184 .error_msg = null,178 .error_msg = null,
185 .decl_index = decl_index,179 .decl_index = decl_index.toOptional(),
186 .decl = decl,180 .decl = decl,
187 .fwd_decl = fwd_decl.toManaged(module.gpa),181 .fwd_decl = fwd_decl.toManaged(gpa),
188 .typedefs = typedefs.promoteContext(module.gpa, .{ .mod = module }),182 .ctypes = ctypes.*,
189 .typedefs_arena = self.arena.allocator(),
190 },183 },
191 .code = code.toManaged(module.gpa),184 .code = code.toManaged(gpa),
192 .indent_writer = undefined, // set later so we can get a pointer to object.code185 .indent_writer = undefined, // set later so we can get a pointer to object.code
193 };186 };
194 object.indent_writer = .{ .underlying_writer = object.code.writer() };187 object.indent_writer = .{ .underlying_writer = object.code.writer() };
195 defer {188 defer {
196 object.code.deinit();189 object.code.deinit();
197 for (object.dg.typedefs.values()) |typedef| {190 object.dg.ctypes.deinit(object.dg.gpa);
198 module.gpa.free(typedef.rendered);
199 }
200 object.dg.typedefs.deinit();
201 object.dg.fwd_decl.deinit();191 object.dg.fwd_decl.deinit();
202 }192 }
203193
204 codegen.genDecl(&object) catch |err| switch (err) {194 codegen.genDecl(&object) catch |err| switch (err) {
205 error.AnalysisFail => {195 error.AnalysisFail => {
206 try module.failed_decls.put(module.gpa, decl_index, object.dg.error_msg.?);196 try module.failed_decls.put(gpa, decl_index, object.dg.error_msg.?);
207 return;197 return;
208 },198 },
209 else => |e| return e,199 else => |e| return e,
210 };200 };
211201
202 ctypes.* = object.dg.ctypes.move();
212 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();203 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
213 typedefs.* = object.dg.typedefs.unmanaged;
214 object.dg.typedefs.unmanaged = .{};
215 code.* = object.code.moveToUnmanaged();204 code.* = object.code.moveToUnmanaged();
216205
217 // Free excess allocated memory for this Decl.206 // Free excess allocated memory for this Decl.
218 fwd_decl.shrinkAndFree(module.gpa, fwd_decl.items.len);207 ctypes.shrinkAndFree(gpa, ctypes.count());
219 code.shrinkAndFree(module.gpa, code.items.len);208 fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);
209 code.shrinkAndFree(gpa, code.items.len);
220}210}
221211
222pub fn updateDeclLineNumber(self: *C, module: *Module, decl_index: Module.Decl.Index) !void {212pub fn updateDeclLineNumber(self: *C, module: *Module, decl_index: Module.Decl.Index) !void {
...@@ -246,7 +236,7 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -246,7 +236,7 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
246 sub_prog_node.activate();236 sub_prog_node.activate();
247 defer sub_prog_node.end();237 defer sub_prog_node.end();
248238
249 const gpa = comp.gpa;239 const gpa = self.base.allocator;
250 const module = self.base.options.module.?;240 const module = self.base.options.module.?;
251241
252 // This code path happens exclusively with -ofmt=c. The flush logic for242 // This code path happens exclusively with -ofmt=c. The flush logic for
...@@ -257,30 +247,28 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -257,30 +247,28 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
257247
258 const abi_define = abiDefine(comp);248 const abi_define = abiDefine(comp);
259249
260 // Covers defines, zig.h, typedef, and asm.250 // Covers defines, zig.h, ctypes, asm, lazy fwd.
261 var buf_count: usize = 2;251 try f.all_buffers.ensureUnusedCapacity(gpa, 5);
262 if (abi_define != null) buf_count += 1;
263 try f.all_buffers.ensureUnusedCapacity(gpa, buf_count);
264252
265 if (abi_define) |buf| f.appendBufAssumeCapacity(buf);253 if (abi_define) |buf| f.appendBufAssumeCapacity(buf);
266 f.appendBufAssumeCapacity(zig_h);254 f.appendBufAssumeCapacity(zig_h);
267255
268 const typedef_index = f.all_buffers.items.len;256 const ctypes_index = f.all_buffers.items.len;
269 f.all_buffers.items.len += 1;257 f.all_buffers.items.len += 1;
270258
271 {259 {
272 var asm_buf = f.asm_buf.toManaged(module.gpa);260 var asm_buf = f.asm_buf.toManaged(gpa);
273 defer asm_buf.deinit();261 defer f.asm_buf = asm_buf.moveToUnmanaged();
274262 try codegen.genGlobalAsm(module, asm_buf.writer());
275 try codegen.genGlobalAsm(module, &asm_buf);263 f.appendBufAssumeCapacity(asm_buf.items);
276
277 f.asm_buf = asm_buf.moveToUnmanaged();
278 f.appendBufAssumeCapacity(f.asm_buf.items);
279 }264 }
280265
281 try self.flushErrDecls(&f);266 const lazy_index = f.all_buffers.items.len;
267 f.all_buffers.items.len += 1;
268
269 try self.flushErrDecls(&f.lazy_db);
282270
283 // Typedefs, forward decls, and non-functions first.271 // `CType`s, forward decls, and non-functions first.
284 // Unlike other backends, the .c code we are emitting is order-dependent. Therefore272 // Unlike other backends, the .c code we are emitting is order-dependent. Therefore
285 // we must traverse the set of Decls that we are emitting according to their dependencies.273 // we must traverse the set of Decls that we are emitting according to their dependencies.
286 // Our strategy is to populate a set of remaining decls, pop Decls one by one,274 // Our strategy is to populate a set of remaining decls, pop Decls one by one,
...@@ -307,16 +295,33 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -307,16 +295,33 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
307 }295 }
308 }296 }
309297
310 f.all_buffers.items[typedef_index] = .{298 {
311 .iov_base = if (f.typedef_buf.items.len > 0) f.typedef_buf.items.ptr else "",299 // We need to flush lazy ctypes after flushing all decls but before flushing any decl ctypes.
312 .iov_len = f.typedef_buf.items.len,300 // This ensures that every lazy CType.Index exactly matches the global CType.Index.
301 assert(f.ctypes.count() == 0);
302 try self.flushCTypes(&f, .none, f.lazy_db.ctypes);
303
304 var it = self.decl_table.iterator();
305 while (it.next()) |entry|
306 try self.flushCTypes(&f, entry.key_ptr.toOptional(), entry.value_ptr.ctypes);
307 }
308
309 f.all_buffers.items[ctypes_index] = .{
310 .iov_base = if (f.ctypes_buf.items.len > 0) f.ctypes_buf.items.ptr else "",
311 .iov_len = f.ctypes_buf.items.len,
313 };312 };
314 f.file_size += f.typedef_buf.items.len;313 f.file_size += f.ctypes_buf.items.len;
314
315 f.all_buffers.items[lazy_index] = .{
316 .iov_base = if (f.lazy_db.fwd_decl.items.len > 0) f.lazy_db.fwd_decl.items.ptr else "",
317 .iov_len = f.lazy_db.fwd_decl.items.len,
318 };
319 f.file_size += f.lazy_db.fwd_decl.items.len;
315320
316 // Now the code.321 // Now the code.
317 try f.all_buffers.ensureUnusedCapacity(gpa, decl_values.len);322 try f.all_buffers.ensureUnusedCapacity(gpa, 1 + decl_values.len);
318 for (decl_values) |decl|323 f.appendBufAssumeCapacity(f.lazy_db.code.items);
319 f.appendBufAssumeCapacity(decl.code.items);324 for (decl_values) |decl| f.appendBufAssumeCapacity(decl.code.items);
320325
321 const file = self.base.file.?;326 const file = self.base.file.?;
322 try file.setEndPos(f.file_size);327 try file.setEndPos(f.file_size);
...@@ -324,22 +329,23 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)...@@ -324,22 +329,23 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node)
324}329}
325330
326const Flush = struct {331const Flush = struct {
327 err_decls: DeclBlock = .{},
328 remaining_decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void) = .{},332 remaining_decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void) = .{},
329 typedefs: Typedefs = .{},333
330 typedef_buf: std.ArrayListUnmanaged(u8) = .{},334 ctypes: codegen.CType.Store = .{},
335 ctypes_map: std.ArrayListUnmanaged(codegen.CType.Index) = .{},
336 ctypes_buf: std.ArrayListUnmanaged(u8) = .{},
337
338 lazy_db: DeclBlock = .{},
339 lazy_fns: LazyFns = .{},
340
331 asm_buf: std.ArrayListUnmanaged(u8) = .{},341 asm_buf: std.ArrayListUnmanaged(u8) = .{},
342
332 /// We collect a list of buffers to write, and write them all at once with pwritev 😎343 /// We collect a list of buffers to write, and write them all at once with pwritev 😎
333 all_buffers: std.ArrayListUnmanaged(std.os.iovec_const) = .{},344 all_buffers: std.ArrayListUnmanaged(std.os.iovec_const) = .{},
334 /// Keeps track of the total bytes of `all_buffers`.345 /// Keeps track of the total bytes of `all_buffers`.
335 file_size: u64 = 0,346 file_size: u64 = 0,
336347
337 const Typedefs = std.HashMapUnmanaged(348 const LazyFns = std.AutoHashMapUnmanaged(codegen.LazyFnKey, void);
338 Type,
339 void,
340 Type.HashContext64,
341 std.hash_map.default_max_load_percentage,
342 );
343349
344 fn appendBufAssumeCapacity(f: *Flush, buf: []const u8) void {350 fn appendBufAssumeCapacity(f: *Flush, buf: []const u8) void {
345 if (buf.len == 0) return;351 if (buf.len == 0) return;
...@@ -349,10 +355,13 @@ const Flush = struct {...@@ -349,10 +355,13 @@ const Flush = struct {
349355
350 fn deinit(f: *Flush, gpa: Allocator) void {356 fn deinit(f: *Flush, gpa: Allocator) void {
351 f.all_buffers.deinit(gpa);357 f.all_buffers.deinit(gpa);
352 f.typedef_buf.deinit(gpa);358 f.asm_buf.deinit(gpa);
353 f.typedefs.deinit(gpa);359 f.lazy_fns.deinit(gpa);
360 f.lazy_db.deinit(gpa);
361 f.ctypes_buf.deinit(gpa);
362 f.ctypes_map.deinit(gpa);
363 f.ctypes.deinit(gpa);
354 f.remaining_decls.deinit(gpa);364 f.remaining_decls.deinit(gpa);
355 f.err_decls.deinit(gpa);
356 }365 }
357};366};
358367
...@@ -360,53 +369,116 @@ const FlushDeclError = error{...@@ -360,53 +369,116 @@ const FlushDeclError = error{
360 OutOfMemory,369 OutOfMemory,
361};370};
362371
363fn flushTypedefs(self: *C, f: *Flush, typedefs: codegen.TypedefMap.Unmanaged) FlushDeclError!void {372fn flushCTypes(
364 if (typedefs.count() == 0) return;373 self: *C,
374 f: *Flush,
375 decl_index: Module.Decl.OptionalIndex,
376 decl_ctypes: codegen.CType.Store,
377) FlushDeclError!void {
365 const gpa = self.base.allocator;378 const gpa = self.base.allocator;
366 const module = self.base.options.module.?;379 const mod = self.base.options.module.?;
367380
368 try f.typedefs.ensureUnusedCapacityContext(gpa, @intCast(u32, typedefs.count()), .{381 const decl_ctypes_len = decl_ctypes.count();
369 .mod = module,382 f.ctypes_map.clearRetainingCapacity();
370 });383 try f.ctypes_map.ensureTotalCapacity(gpa, decl_ctypes_len);
371 var it = typedefs.iterator();384
372 while (it.next()) |new| {385 var global_ctypes = f.ctypes.promote(gpa);
373 const gop = f.typedefs.getOrPutAssumeCapacityContext(new.key_ptr.*, .{386 defer f.ctypes.demote(global_ctypes);
374 .mod = module,387
388 var ctypes_buf = f.ctypes_buf.toManaged(gpa);
389 defer f.ctypes_buf = ctypes_buf.moveToUnmanaged();
390 const writer = ctypes_buf.writer();
391
392 const slice = decl_ctypes.set.map.entries.slice();
393 for (slice.items(.key), 0..) |decl_cty, decl_i| {
394 const Context = struct {
395 arena: Allocator,
396 ctypes_map: []codegen.CType.Index,
397 cached_hash: codegen.CType.Store.Set.Map.Hash,
398 idx: codegen.CType.Index,
399
400 pub fn hash(ctx: @This(), _: codegen.CType) codegen.CType.Store.Set.Map.Hash {
401 return ctx.cached_hash;
402 }
403 pub fn eql(ctx: @This(), lhs: codegen.CType, rhs: codegen.CType, _: usize) bool {
404 return lhs.eqlContext(rhs, ctx);
405 }
406 pub fn eqlIndex(
407 ctx: @This(),
408 lhs_idx: codegen.CType.Index,
409 rhs_idx: codegen.CType.Index,
410 ) bool {
411 if (lhs_idx < codegen.CType.Tag.no_payload_count or
412 rhs_idx < codegen.CType.Tag.no_payload_count) return lhs_idx == rhs_idx;
413 const lhs_i = lhs_idx - codegen.CType.Tag.no_payload_count;
414 if (lhs_i >= ctx.ctypes_map.len) return false;
415 return ctx.ctypes_map[lhs_i] == rhs_idx;
416 }
417 pub fn copyIndex(ctx: @This(), idx: codegen.CType.Index) codegen.CType.Index {
418 if (idx < codegen.CType.Tag.no_payload_count) return idx;
419 return ctx.ctypes_map[idx - codegen.CType.Tag.no_payload_count];
420 }
421 };
422 const decl_idx = @intCast(codegen.CType.Index, codegen.CType.Tag.no_payload_count + decl_i);
423 const ctx = Context{
424 .arena = global_ctypes.arena.allocator(),
425 .ctypes_map = f.ctypes_map.items,
426 .cached_hash = decl_ctypes.indexToHash(decl_idx),
427 .idx = decl_idx,
428 };
429 const gop = try global_ctypes.set.map.getOrPutContextAdapted(gpa, decl_cty, ctx, .{
430 .store = &global_ctypes.set,
375 });431 });
432 const global_idx =
433 @intCast(codegen.CType.Index, codegen.CType.Tag.no_payload_count + gop.index);
434 f.ctypes_map.appendAssumeCapacity(global_idx);
376 if (!gop.found_existing) {435 if (!gop.found_existing) {
377 try f.typedef_buf.appendSlice(gpa, new.value_ptr.rendered);436 errdefer _ = global_ctypes.set.map.pop();
437 gop.key_ptr.* = try decl_cty.copyContext(ctx);
438 }
439 if (std.debug.runtime_safety) {
440 const global_cty = &global_ctypes.set.map.entries.items(.key)[gop.index];
441 assert(global_cty == gop.key_ptr);
442 assert(decl_cty.eqlContext(global_cty.*, ctx));
443 assert(decl_cty.hash(decl_ctypes.set) == global_cty.hash(global_ctypes.set));
378 }444 }
445 try codegen.genTypeDecl(
446 mod,
447 writer,
448 global_ctypes.set,
449 global_idx,
450 decl_index,
451 decl_ctypes.set,
452 decl_idx,
453 gop.found_existing,
454 );
379 }455 }
380}456}
381457
382fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void {458fn flushErrDecls(self: *C, db: *DeclBlock) FlushDeclError!void {
383 const module = self.base.options.module.?;459 const gpa = self.base.allocator;
384460
385 const fwd_decl = &f.err_decls.fwd_decl;461 const fwd_decl = &db.fwd_decl;
386 const typedefs = &f.err_decls.typedefs;462 const ctypes = &db.ctypes;
387 const code = &f.err_decls.code;463 const code = &db.code;
388464
389 var object = codegen.Object{465 var object = codegen.Object{
390 .dg = .{466 .dg = .{
391 .gpa = module.gpa,467 .gpa = gpa,
392 .module = module,468 .module = self.base.options.module.?,
393 .error_msg = null,469 .error_msg = null,
394 .decl_index = undefined,470 .decl_index = .none,
395 .decl = undefined,471 .decl = null,
396 .fwd_decl = fwd_decl.toManaged(module.gpa),472 .fwd_decl = fwd_decl.toManaged(gpa),
397 .typedefs = typedefs.promoteContext(module.gpa, .{ .mod = module }),473 .ctypes = ctypes.*,
398 .typedefs_arena = self.arena.allocator(),
399 },474 },
400 .code = code.toManaged(module.gpa),475 .code = code.toManaged(gpa),
401 .indent_writer = undefined, // set later so we can get a pointer to object.code476 .indent_writer = undefined, // set later so we can get a pointer to object.code
402 };477 };
403 object.indent_writer = .{ .underlying_writer = object.code.writer() };478 object.indent_writer = .{ .underlying_writer = object.code.writer() };
404 defer {479 defer {
405 object.code.deinit();480 object.code.deinit();
406 for (object.dg.typedefs.values()) |typedef| {481 object.dg.ctypes.deinit(gpa);
407 module.gpa.free(typedef.rendered);
408 }
409 object.dg.typedefs.deinit();
410 object.dg.fwd_decl.deinit();482 object.dg.fwd_decl.deinit();
411 }483 }
412484
...@@ -416,14 +488,58 @@ fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void {...@@ -416,14 +488,58 @@ fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void {
416 };488 };
417489
418 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();490 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
419 typedefs.* = object.dg.typedefs.unmanaged;491 ctypes.* = object.dg.ctypes.move();
420 object.dg.typedefs.unmanaged = .{};492 code.* = object.code.moveToUnmanaged();
493}
494
495fn flushLazyFn(self: *C, db: *DeclBlock, lazy_fn: codegen.LazyFnMap.Entry) FlushDeclError!void {
496 const gpa = self.base.allocator;
497
498 const fwd_decl = &db.fwd_decl;
499 const ctypes = &db.ctypes;
500 const code = &db.code;
501
502 var object = codegen.Object{
503 .dg = .{
504 .gpa = gpa,
505 .module = self.base.options.module.?,
506 .error_msg = null,
507 .decl_index = .none,
508 .decl = null,
509 .fwd_decl = fwd_decl.toManaged(gpa),
510 .ctypes = ctypes.*,
511 },
512 .code = code.toManaged(gpa),
513 .indent_writer = undefined, // set later so we can get a pointer to object.code
514 };
515 object.indent_writer = .{ .underlying_writer = object.code.writer() };
516 defer {
517 object.code.deinit();
518 object.dg.ctypes.deinit(gpa);
519 object.dg.fwd_decl.deinit();
520 }
521
522 codegen.genLazyFn(&object, lazy_fn) catch |err| switch (err) {
523 error.AnalysisFail => unreachable,
524 else => |e| return e,
525 };
526
527 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
528 ctypes.* = object.dg.ctypes.move();
421 code.* = object.code.moveToUnmanaged();529 code.* = object.code.moveToUnmanaged();
530}
422531
423 try self.flushTypedefs(f, typedefs.*);532fn flushLazyFns(self: *C, f: *Flush, lazy_fns: codegen.LazyFnMap) FlushDeclError!void {
424 try f.all_buffers.ensureUnusedCapacity(self.base.allocator, 1);533 const gpa = self.base.allocator;
425 f.appendBufAssumeCapacity(fwd_decl.items);534 try f.lazy_fns.ensureUnusedCapacity(gpa, @intCast(Flush.LazyFns.Size, lazy_fns.count()));
426 f.appendBufAssumeCapacity(code.items);535
536 var it = lazy_fns.iterator();
537 while (it.next()) |entry| {
538 const gop = f.lazy_fns.getOrPutAssumeCapacity(entry.key_ptr.*);
539 if (gop.found_existing) continue;
540 gop.value_ptr.* = {};
541 try self.flushLazyFn(&f.lazy_db, entry);
542 }
427}543}
428544
429/// Assumes `decl` was in the `remaining_decls` set, and has already been removed.545/// Assumes `decl` was in the `remaining_decls` set, and has already been removed.
...@@ -433,8 +549,8 @@ fn flushDecl(...@@ -433,8 +549,8 @@ fn flushDecl(
433 decl_index: Module.Decl.Index,549 decl_index: Module.Decl.Index,
434 export_names: std.StringHashMapUnmanaged(void),550 export_names: std.StringHashMapUnmanaged(void),
435) FlushDeclError!void {551) FlushDeclError!void {
436 const module = self.base.options.module.?;552 const gpa = self.base.allocator;
437 const decl = module.declPtr(decl_index);553 const decl = self.base.options.module.?.declPtr(decl_index);
438 // Before flushing any particular Decl we must ensure its554 // Before flushing any particular Decl we must ensure its
439 // dependencies are already flushed, so that the order in the .c555 // dependencies are already flushed, so that the order in the .c
440 // file comes out correctly.556 // file comes out correctly.
...@@ -445,10 +561,9 @@ fn flushDecl(...@@ -445,10 +561,9 @@ fn flushDecl(
445 }561 }
446562
447 const decl_block = self.decl_table.getPtr(decl_index).?;563 const decl_block = self.decl_table.getPtr(decl_index).?;
448 const gpa = self.base.allocator;
449564
450 try self.flushTypedefs(f, decl_block.typedefs);565 try self.flushLazyFns(f, decl_block.lazy_fns);
451 try f.all_buffers.ensureUnusedCapacity(gpa, 2);566 try f.all_buffers.ensureUnusedCapacity(gpa, 1);
452 if (!(decl.isExtern() and export_names.contains(mem.span(decl.name))))567 if (!(decl.isExtern() and export_names.contains(mem.span(decl.name))))
453 f.appendBufAssumeCapacity(decl_block.fwd_decl.items);568 f.appendBufAssumeCapacity(decl_block.fwd_decl.items);
454}569}
src/main.zig+140-81
...@@ -403,8 +403,11 @@ const usage_build_generic =...@@ -403,8 +403,11 @@ const usage_build_generic =
403 \\ ReleaseFast Optimizations on, safety off403 \\ ReleaseFast Optimizations on, safety off
404 \\ ReleaseSafe Optimizations on, safety on404 \\ ReleaseSafe Optimizations on, safety on
405 \\ ReleaseSmall Optimize for small binary, safety off405 \\ ReleaseSmall Optimize for small binary, safety off
406 \\ --pkg-begin [name] [path] Make pkg available to import and push current pkg406 \\ --mod [name]:[deps]:[src] Make a module available for dependency under the given name
407 \\ --pkg-end Pop current pkg407 \\ deps: [dep],[dep],...
408 \\ dep: [[import=]name]
409 \\ --deps [dep],[dep],... Set dependency names for the root package
410 \\ dep: [[import=]name]
408 \\ --main-pkg-path Set the directory of the root package411 \\ --main-pkg-path Set the directory of the root package
409 \\ -fPIC Force-enable Position Independent Code412 \\ -fPIC Force-enable Position Independent Code
410 \\ -fno-PIC Force-disable Position Independent Code413 \\ -fno-PIC Force-disable Position Independent Code
...@@ -858,15 +861,21 @@ fn buildOutputType(...@@ -858,15 +861,21 @@ fn buildOutputType(
858 var linker_export_symbol_names = std.ArrayList([]const u8).init(gpa);861 var linker_export_symbol_names = std.ArrayList([]const u8).init(gpa);
859 defer linker_export_symbol_names.deinit();862 defer linker_export_symbol_names.deinit();
860863
861 // This package only exists to clean up the code parsing --pkg-begin and864 // Contains every module specified via --mod. The dependencies are added
862 // --pkg-end flags. Use dummy values that are safe for the destroy call.865 // after argument parsing is completed. We use a StringArrayHashMap to make
863 var pkg_tree_root: Package = .{866 // error output consistent.
864 .root_src_directory = .{ .path = null, .handle = fs.cwd() },867 var modules = std.StringArrayHashMap(struct {
865 .root_src_path = &[0]u8{},868 mod: *Package,
866 .name = &[0]u8{},869 deps_str: []const u8, // still in CLI arg format
867 };870 }).init(gpa);
868 defer freePkgTree(gpa, &pkg_tree_root, false);871 defer {
869 var cur_pkg: *Package = &pkg_tree_root;872 var it = modules.iterator();
873 while (it.next()) |kv| kv.value_ptr.mod.destroy(gpa);
874 modules.deinit();
875 }
876
877 // The dependency string for the root package
878 var root_deps_str: ?[]const u8 = null;
870879
871 // before arg parsing, check for the NO_COLOR environment variable880 // before arg parsing, check for the NO_COLOR environment variable
872 // if it exists, default the color setting to .off881 // if it exists, default the color setting to .off
...@@ -943,34 +952,44 @@ fn buildOutputType(...@@ -943,34 +952,44 @@ fn buildOutputType(
943 } else {952 } else {
944 fatal("unexpected end-of-parameter mark: --", .{});953 fatal("unexpected end-of-parameter mark: --", .{});
945 }954 }
946 } else if (mem.eql(u8, arg, "--pkg-begin")) {955 } else if (mem.eql(u8, arg, "--mod")) {
947 const opt_pkg_name = args_iter.next();956 const info = args_iter.nextOrFatal();
948 const opt_pkg_path = args_iter.next();957 var info_it = mem.split(u8, info, ":");
949 if (opt_pkg_name == null or opt_pkg_path == null)958 const mod_name = info_it.next() orelse fatal("expected non-empty argument after {s}", .{arg});
950 fatal("Expected 2 arguments after {s}", .{arg});959 const deps_str = info_it.next() orelse fatal("expected 'name:deps:path' after {s}", .{arg});
951960 const root_src_orig = info_it.rest();
952 const pkg_name = opt_pkg_name.?;961 if (root_src_orig.len == 0) fatal("expected 'name:deps:path' after {s}", .{arg});
953 const pkg_path = try introspect.resolvePath(arena, opt_pkg_path.?);962 if (mod_name.len == 0) fatal("empty name for module at '{s}'", .{root_src_orig});
954963
955 const new_cur_pkg = Package.create(964 const root_src = try introspect.resolvePath(arena, root_src_orig);
956 gpa,965
957 pkg_name,966 for ([_][]const u8{ "std", "root", "builtin" }) |name| {
958 fs.path.dirname(pkg_path),967 if (mem.eql(u8, mod_name, name)) {
959 fs.path.basename(pkg_path),968 fatal("unable to add module '{s}' -> '{s}': conflicts with builtin module", .{ mod_name, root_src });
960 ) catch |err| {969 }
961 fatal("Failed to add package at path {s}: {s}", .{ pkg_path, @errorName(err) });970 }
962 };
963971
964 if (mem.eql(u8, pkg_name, "std") or mem.eql(u8, pkg_name, "root") or mem.eql(u8, pkg_name, "builtin")) {972 var mod_it = modules.iterator();
965 fatal("unable to add package '{s}' -> '{s}': conflicts with builtin package", .{ pkg_name, pkg_path });973 while (mod_it.next()) |kv| {
966 } else if (cur_pkg.table.get(pkg_name)) |prev| {974 if (std.mem.eql(u8, mod_name, kv.key_ptr.*)) {
967 fatal("unable to add package '{s}' -> '{s}': already exists as '{s}", .{ pkg_name, pkg_path, prev.root_src_path });975 fatal("unable to add module '{s}' -> '{s}': already exists as '{s}'", .{ mod_name, root_src, kv.value_ptr.mod.root_src_path });
976 }
977 }
978
979 try modules.ensureUnusedCapacity(1);
980 modules.put(mod_name, .{
981 .mod = try Package.create(
982 gpa,
983 fs.path.dirname(root_src),
984 fs.path.basename(root_src),
985 ),
986 .deps_str = deps_str,
987 }) catch unreachable;
988 } else if (mem.eql(u8, arg, "--deps")) {
989 if (root_deps_str != null) {
990 fatal("only one --deps argument is allowed", .{});
968 }991 }
969 try cur_pkg.addAndAdopt(gpa, new_cur_pkg);992 root_deps_str = args_iter.nextOrFatal();
970 cur_pkg = new_cur_pkg;
971 } else if (mem.eql(u8, arg, "--pkg-end")) {
972 cur_pkg = cur_pkg.parent orelse
973 fatal("encountered --pkg-end with no matching --pkg-begin", .{});
974 } else if (mem.eql(u8, arg, "--main-pkg-path")) {993 } else if (mem.eql(u8, arg, "--main-pkg-path")) {
975 main_pkg_path = args_iter.nextOrFatal();994 main_pkg_path = args_iter.nextOrFatal();
976 } else if (mem.eql(u8, arg, "-cflags")) {995 } else if (mem.eql(u8, arg, "-cflags")) {
...@@ -1955,12 +1974,15 @@ fn buildOutputType(...@@ -1955,12 +1974,15 @@ fn buildOutputType(
1955 linker_compress_debug_sections = std.meta.stringToEnum(link.CompressDebugSections, arg1) orelse {1974 linker_compress_debug_sections = std.meta.stringToEnum(link.CompressDebugSections, arg1) orelse {
1956 fatal("expected [none|zlib] after --compress-debug-sections, found '{s}'", .{arg1});1975 fatal("expected [none|zlib] after --compress-debug-sections, found '{s}'", .{arg1});
1957 };1976 };
1958 } else if (mem.eql(u8, arg, "-z")) {1977 } else if (mem.startsWith(u8, arg, "-z")) {
1959 i += 1;1978 var z_arg = arg[2..];
1960 if (i >= linker_args.items.len) {1979 if (z_arg.len == 0) {
1961 fatal("expected linker extension flag after '{s}'", .{arg});1980 i += 1;
1981 if (i >= linker_args.items.len) {
1982 fatal("expected linker extension flag after '{s}'", .{arg});
1983 }
1984 z_arg = linker_args.items[i];
1962 }1985 }
1963 const z_arg = linker_args.items[i];
1964 if (mem.eql(u8, z_arg, "nodelete")) {1986 if (mem.eql(u8, z_arg, "nodelete")) {
1965 linker_z_nodelete = true;1987 linker_z_nodelete = true;
1966 } else if (mem.eql(u8, z_arg, "notext")) {1988 } else if (mem.eql(u8, z_arg, "notext")) {
...@@ -2304,6 +2326,31 @@ fn buildOutputType(...@@ -2304,6 +2326,31 @@ fn buildOutputType(
2304 },2326 },
2305 }2327 }
23062328
2329 {
2330 // Resolve module dependencies
2331 var it = modules.iterator();
2332 while (it.next()) |kv| {
2333 const deps_str = kv.value_ptr.deps_str;
2334 var deps_it = ModuleDepIterator.init(deps_str);
2335 while (deps_it.next()) |dep| {
2336 if (dep.expose.len == 0) {
2337 fatal("module '{s}' depends on '{s}' with a blank name", .{ kv.key_ptr.*, dep.name });
2338 }
2339
2340 for ([_][]const u8{ "std", "root", "builtin" }) |name| {
2341 if (mem.eql(u8, dep.expose, name)) {
2342 fatal("unable to add module '{s}' under name '{s}': conflicts with builtin module", .{ dep.name, dep.expose });
2343 }
2344 }
2345
2346 const dep_mod = modules.get(dep.name) orelse
2347 fatal("module '{s}' depends on module '{s}' which does not exist", .{ kv.key_ptr.*, dep.name });
2348
2349 try kv.value_ptr.mod.add(gpa, dep.expose, dep_mod.mod);
2350 }
2351 }
2352 }
2353
2307 if (arg_mode == .build and optimize_mode == .ReleaseSmall and strip == null)2354 if (arg_mode == .build and optimize_mode == .ReleaseSmall and strip == null)
2308 strip = true;2355 strip = true;
23092356
...@@ -2883,14 +2930,14 @@ fn buildOutputType(...@@ -2883,14 +2930,14 @@ fn buildOutputType(
2883 if (main_pkg_path) |unresolved_main_pkg_path| {2930 if (main_pkg_path) |unresolved_main_pkg_path| {
2884 const p = try introspect.resolvePath(arena, unresolved_main_pkg_path);2931 const p = try introspect.resolvePath(arena, unresolved_main_pkg_path);
2885 if (p.len == 0) {2932 if (p.len == 0) {
2886 break :blk try Package.create(gpa, "root", null, src_path);2933 break :blk try Package.create(gpa, null, src_path);
2887 } else {2934 } else {
2888 const rel_src_path = try fs.path.relative(arena, p, src_path);2935 const rel_src_path = try fs.path.relative(arena, p, src_path);
2889 break :blk try Package.create(gpa, "root", p, rel_src_path);2936 break :blk try Package.create(gpa, p, rel_src_path);
2890 }2937 }
2891 } else {2938 } else {
2892 const root_src_dir_path = fs.path.dirname(src_path);2939 const root_src_dir_path = fs.path.dirname(src_path);
2893 break :blk Package.create(gpa, "root", root_src_dir_path, fs.path.basename(src_path)) catch |err| {2940 break :blk Package.create(gpa, root_src_dir_path, fs.path.basename(src_path)) catch |err| {
2894 if (root_src_dir_path) |p| {2941 if (root_src_dir_path) |p| {
2895 fatal("unable to open '{s}': {s}", .{ p, @errorName(err) });2942 fatal("unable to open '{s}': {s}", .{ p, @errorName(err) });
2896 } else {2943 } else {
...@@ -2901,23 +2948,24 @@ fn buildOutputType(...@@ -2901,23 +2948,24 @@ fn buildOutputType(
2901 } else null;2948 } else null;
2902 defer if (main_pkg) |p| p.destroy(gpa);2949 defer if (main_pkg) |p| p.destroy(gpa);
29032950
2904 // Transfer packages added with --pkg-begin/--pkg-end to the root package2951 // Transfer packages added with --deps to the root package
2905 if (main_pkg) |pkg| {2952 if (main_pkg) |mod| {
2906 var it = pkg_tree_root.table.valueIterator();2953 var it = ModuleDepIterator.init(root_deps_str orelse "");
2907 while (it.next()) |p| {2954 while (it.next()) |dep| {
2908 if (p.*.parent == &pkg_tree_root) {2955 if (dep.expose.len == 0) {
2909 p.*.parent = pkg;2956 fatal("root module depends on '{s}' with a blank name", .{dep.name});
2910 }2957 }
2911 }2958
2912 pkg.table = pkg_tree_root.table;2959 for ([_][]const u8{ "std", "root", "builtin" }) |name| {
2913 pkg_tree_root.table = .{};2960 if (mem.eql(u8, dep.expose, name)) {
2914 } else {2961 fatal("unable to add module '{s}' under name '{s}': conflicts with builtin module", .{ dep.name, dep.expose });
2915 // Remove any dangling pointers just in case.2962 }
2916 var it = pkg_tree_root.table.valueIterator();
2917 while (it.next()) |p| {
2918 if (p.*.parent == &pkg_tree_root) {
2919 p.*.parent = null;
2920 }2963 }
2964
2965 const dep_mod = modules.get(dep.name) orelse
2966 fatal("root module depends on module '{s}' which does not exist", .{dep.name});
2967
2968 try mod.add(gpa, dep.expose, dep_mod.mod);
2921 }2969 }
2922 }2970 }
29232971
...@@ -3397,6 +3445,32 @@ fn buildOutputType(...@@ -3397,6 +3445,32 @@ fn buildOutputType(
3397 return cleanExit();3445 return cleanExit();
3398}3446}
33993447
3448const ModuleDepIterator = struct {
3449 split: mem.SplitIterator(u8),
3450
3451 fn init(deps_str: []const u8) ModuleDepIterator {
3452 return .{ .split = mem.split(u8, deps_str, ",") };
3453 }
3454
3455 const Dependency = struct {
3456 expose: []const u8,
3457 name: []const u8,
3458 };
3459
3460 fn next(it: *ModuleDepIterator) ?Dependency {
3461 if (it.split.buffer.len == 0) return null; // don't return "" for the first iteration on ""
3462 const str = it.split.next() orelse return null;
3463 if (mem.indexOfScalar(u8, str, '=')) |i| {
3464 return .{
3465 .expose = str[0..i],
3466 .name = str[i + 1 ..],
3467 };
3468 } else {
3469 return .{ .expose = str, .name = str };
3470 }
3471 }
3472};
3473
3400fn parseCrossTargetOrReportFatalError(3474fn parseCrossTargetOrReportFatalError(
3401 allocator: Allocator,3475 allocator: Allocator,
3402 opts: std.zig.CrossTarget.ParseOptions,3476 opts: std.zig.CrossTarget.ParseOptions,
...@@ -3623,18 +3697,6 @@ fn updateModule(gpa: Allocator, comp: *Compilation, hook: AfterUpdateHook) !void...@@ -3623,18 +3697,6 @@ fn updateModule(gpa: Allocator, comp: *Compilation, hook: AfterUpdateHook) !void
3623 }3697 }
3624}3698}
36253699
3626fn freePkgTree(gpa: Allocator, pkg: *Package, free_parent: bool) void {
3627 {
3628 var it = pkg.table.valueIterator();
3629 while (it.next()) |value| {
3630 freePkgTree(gpa, value.*, true);
3631 }
3632 }
3633 if (free_parent) {
3634 pkg.destroy(gpa);
3635 }
3636}
3637
3638fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool) !void {3700fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool) !void {
3639 if (!build_options.have_llvm)3701 if (!build_options.have_llvm)
3640 fatal("cannot translate-c: compiler built without LLVM extensions", .{});3702 fatal("cannot translate-c: compiler built without LLVM extensions", .{});
...@@ -4138,7 +4200,6 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi...@@ -4138,7 +4200,6 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
4138 var main_pkg: Package = .{4200 var main_pkg: Package = .{
4139 .root_src_directory = zig_lib_directory,4201 .root_src_directory = zig_lib_directory,
4140 .root_src_path = "build_runner.zig",4202 .root_src_path = "build_runner.zig",
4141 .name = "root",
4142 };4203 };
41434204
4144 if (!build_options.omit_pkg_fetching_code) {4205 if (!build_options.omit_pkg_fetching_code) {
...@@ -4181,22 +4242,20 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi...@@ -4181,22 +4242,20 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
41814242
4182 const deps_pkg = try Package.createFilePkg(4243 const deps_pkg = try Package.createFilePkg(
4183 gpa,4244 gpa,
4184 "@dependencies",
4185 local_cache_directory,4245 local_cache_directory,
4186 "dependencies.zig",4246 "dependencies.zig",
4187 dependencies_source.items,4247 dependencies_source.items,
4188 );4248 );
41894249
4190 mem.swap(Package.Table, &main_pkg.table, &deps_pkg.table);4250 mem.swap(Package.Table, &main_pkg.table, &deps_pkg.table);
4191 try main_pkg.addAndAdopt(gpa, deps_pkg);4251 try main_pkg.add(gpa, "@dependencies", deps_pkg);
4192 }4252 }
41934253
4194 var build_pkg: Package = .{4254 var build_pkg: Package = .{
4195 .root_src_directory = build_directory,4255 .root_src_directory = build_directory,
4196 .root_src_path = build_zig_basename,4256 .root_src_path = build_zig_basename,
4197 .name = "@build",
4198 };4257 };
4199 try main_pkg.addAndAdopt(gpa, &build_pkg);4258 try main_pkg.add(gpa, "@build", &build_pkg);
42004259
4201 const comp = Compilation.create(gpa, .{4260 const comp = Compilation.create(gpa, .{
4202 .zig_lib_directory = zig_lib_directory,4261 .zig_lib_directory = zig_lib_directory,
...@@ -4431,7 +4490,7 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void...@@ -4431,7 +4490,7 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
4431 .root_decl = .none,4490 .root_decl = .none,
4432 };4491 };
44334492
4434 file.pkg = try Package.create(gpa, "root", null, file.sub_file_path);4493 file.pkg = try Package.create(gpa, null, file.sub_file_path);
4435 defer file.pkg.destroy(gpa);4494 defer file.pkg.destroy(gpa);
44364495
4437 file.zir = try AstGen.generate(gpa, file.tree);4496 file.zir = try AstGen.generate(gpa, file.tree);
...@@ -4642,7 +4701,7 @@ fn fmtPathFile(...@@ -4642,7 +4701,7 @@ fn fmtPathFile(
4642 .root_decl = .none,4701 .root_decl = .none,
4643 };4702 };
46444703
4645 file.pkg = try Package.create(fmt.gpa, "root", null, file.sub_file_path);4704 file.pkg = try Package.create(fmt.gpa, null, file.sub_file_path);
4646 defer file.pkg.destroy(fmt.gpa);4705 defer file.pkg.destroy(fmt.gpa);
46474706
4648 if (stat.size > max_src_size)4707 if (stat.size > max_src_size)
...@@ -5354,7 +5413,7 @@ pub fn cmdAstCheck(...@@ -5354,7 +5413,7 @@ pub fn cmdAstCheck(
5354 file.stat.size = source.len;5413 file.stat.size = source.len;
5355 }5414 }
53565415
5357 file.pkg = try Package.create(gpa, "root", null, file.sub_file_path);5416 file.pkg = try Package.create(gpa, null, file.sub_file_path);
5358 defer file.pkg.destroy(gpa);5417 defer file.pkg.destroy(gpa);
53595418
5360 file.tree = try Ast.parse(gpa, file.source, .zig);5419 file.tree = try Ast.parse(gpa, file.source, .zig);
...@@ -5473,7 +5532,7 @@ pub fn cmdChangelist(...@@ -5473,7 +5532,7 @@ pub fn cmdChangelist(
5473 .root_decl = .none,5532 .root_decl = .none,
5474 };5533 };
54755534
5476 file.pkg = try Package.create(gpa, "root", null, file.sub_file_path);5535 file.pkg = try Package.create(gpa, null, file.sub_file_path);
5477 defer file.pkg.destroy(gpa);5536 defer file.pkg.destroy(gpa);
54785537
5479 const source = try arena.allocSentinel(u8, @intCast(usize, stat.size), 0);5538 const source = try arena.allocSentinel(u8, @intCast(usize, stat.size), 0);
src/target.zig+1
...@@ -727,6 +727,7 @@ pub fn supportsFunctionAlignment(target: std.Target) bool {...@@ -727,6 +727,7 @@ pub fn supportsFunctionAlignment(target: std.Target) bool {
727pub fn supportsTailCall(target: std.Target, backend: std.builtin.CompilerBackend) bool {727pub fn supportsTailCall(target: std.Target, backend: std.builtin.CompilerBackend) bool {
728 switch (backend) {728 switch (backend) {
729 .stage1, .stage2_llvm => return @import("codegen/llvm.zig").supportsTailCall(target),729 .stage1, .stage2_llvm => return @import("codegen/llvm.zig").supportsTailCall(target),
730 .stage2_c => return true,
730 else => return false,731 else => return false,
731 }732 }
732}733}
src/test.zig+38-2
...@@ -583,6 +583,11 @@ pub const TestContext = struct {...@@ -583,6 +583,11 @@ pub const TestContext = struct {
583 path: []const u8,583 path: []const u8,
584 };584 };
585585
586 pub const DepModule = struct {
587 name: []const u8,
588 path: []const u8,
589 };
590
586 pub const Backend = enum {591 pub const Backend = enum {
587 stage1,592 stage1,
588 stage2,593 stage2,
...@@ -611,6 +616,7 @@ pub const TestContext = struct {...@@ -611,6 +616,7 @@ pub const TestContext = struct {
611 link_libc: bool = false,616 link_libc: bool = false,
612617
613 files: std.ArrayList(File),618 files: std.ArrayList(File),
619 deps: std.ArrayList(DepModule),
614620
615 result: anyerror!void = {},621 result: anyerror!void = {},
616622
...@@ -618,6 +624,13 @@ pub const TestContext = struct {...@@ -618,6 +624,13 @@ pub const TestContext = struct {
618 case.files.append(.{ .path = name, .src = src }) catch @panic("out of memory");624 case.files.append(.{ .path = name, .src = src }) catch @panic("out of memory");
619 }625 }
620626
627 pub fn addDepModule(case: *Case, name: []const u8, path: []const u8) void {
628 case.deps.append(.{
629 .name = name,
630 .path = path,
631 }) catch @panic("out of memory");
632 }
633
621 /// Adds a subcase in which the module is updated with `src`, and a C634 /// Adds a subcase in which the module is updated with `src`, and a C
622 /// header is generated.635 /// header is generated.
623 pub fn addHeader(self: *Case, src: [:0]const u8, result: [:0]const u8) void {636 pub fn addHeader(self: *Case, src: [:0]const u8, result: [:0]const u8) void {
...@@ -767,6 +780,7 @@ pub const TestContext = struct {...@@ -767,6 +780,7 @@ pub const TestContext = struct {
767 .updates = std.ArrayList(Update).init(ctx.cases.allocator),780 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
768 .output_mode = .Exe,781 .output_mode = .Exe,
769 .files = std.ArrayList(File).init(ctx.arena),782 .files = std.ArrayList(File).init(ctx.arena),
783 .deps = std.ArrayList(DepModule).init(ctx.arena),
770 }) catch @panic("out of memory");784 }) catch @panic("out of memory");
771 return &ctx.cases.items[ctx.cases.items.len - 1];785 return &ctx.cases.items[ctx.cases.items.len - 1];
772 }786 }
...@@ -787,6 +801,7 @@ pub const TestContext = struct {...@@ -787,6 +801,7 @@ pub const TestContext = struct {
787 .updates = std.ArrayList(Update).init(ctx.cases.allocator),801 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
788 .output_mode = .Exe,802 .output_mode = .Exe,
789 .files = std.ArrayList(File).init(ctx.arena),803 .files = std.ArrayList(File).init(ctx.arena),
804 .deps = std.ArrayList(DepModule).init(ctx.arena),
790 .link_libc = true,805 .link_libc = true,
791 }) catch @panic("out of memory");806 }) catch @panic("out of memory");
792 return &ctx.cases.items[ctx.cases.items.len - 1];807 return &ctx.cases.items[ctx.cases.items.len - 1];
...@@ -801,6 +816,7 @@ pub const TestContext = struct {...@@ -801,6 +816,7 @@ pub const TestContext = struct {
801 .updates = std.ArrayList(Update).init(ctx.cases.allocator),816 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
802 .output_mode = .Exe,817 .output_mode = .Exe,
803 .files = std.ArrayList(File).init(ctx.arena),818 .files = std.ArrayList(File).init(ctx.arena),
819 .deps = std.ArrayList(DepModule).init(ctx.arena),
804 .backend = .llvm,820 .backend = .llvm,
805 .link_libc = true,821 .link_libc = true,
806 }) catch @panic("out of memory");822 }) catch @panic("out of memory");
...@@ -818,6 +834,7 @@ pub const TestContext = struct {...@@ -818,6 +834,7 @@ pub const TestContext = struct {
818 .updates = std.ArrayList(Update).init(ctx.cases.allocator),834 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
819 .output_mode = .Obj,835 .output_mode = .Obj,
820 .files = std.ArrayList(File).init(ctx.arena),836 .files = std.ArrayList(File).init(ctx.arena),
837 .deps = std.ArrayList(DepModule).init(ctx.arena),
821 }) catch @panic("out of memory");838 }) catch @panic("out of memory");
822 return &ctx.cases.items[ctx.cases.items.len - 1];839 return &ctx.cases.items[ctx.cases.items.len - 1];
823 }840 }
...@@ -834,6 +851,7 @@ pub const TestContext = struct {...@@ -834,6 +851,7 @@ pub const TestContext = struct {
834 .output_mode = .Exe,851 .output_mode = .Exe,
835 .is_test = true,852 .is_test = true,
836 .files = std.ArrayList(File).init(ctx.arena),853 .files = std.ArrayList(File).init(ctx.arena),
854 .deps = std.ArrayList(DepModule).init(ctx.arena),
837 }) catch @panic("out of memory");855 }) catch @panic("out of memory");
838 return &ctx.cases.items[ctx.cases.items.len - 1];856 return &ctx.cases.items[ctx.cases.items.len - 1];
839 }857 }
...@@ -858,6 +876,7 @@ pub const TestContext = struct {...@@ -858,6 +876,7 @@ pub const TestContext = struct {
858 .updates = std.ArrayList(Update).init(ctx.cases.allocator),876 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
859 .output_mode = .Obj,877 .output_mode = .Obj,
860 .files = std.ArrayList(File).init(ctx.arena),878 .files = std.ArrayList(File).init(ctx.arena),
879 .deps = std.ArrayList(DepModule).init(ctx.arena),
861 }) catch @panic("out of memory");880 }) catch @panic("out of memory");
862 return &ctx.cases.items[ctx.cases.items.len - 1];881 return &ctx.cases.items[ctx.cases.items.len - 1];
863 }882 }
...@@ -1145,6 +1164,7 @@ pub const TestContext = struct {...@@ -1145,6 +1164,7 @@ pub const TestContext = struct {
1145 .output_mode = output_mode,1164 .output_mode = output_mode,
1146 .link_libc = backend == .llvm,1165 .link_libc = backend == .llvm,
1147 .files = std.ArrayList(TestContext.File).init(ctx.cases.allocator),1166 .files = std.ArrayList(TestContext.File).init(ctx.cases.allocator),
1167 .deps = std.ArrayList(DepModule).init(ctx.cases.allocator),
1148 });1168 });
1149 try cases.append(next);1169 try cases.append(next);
1150 }1170 }
...@@ -1497,9 +1517,25 @@ pub const TestContext = struct {...@@ -1497,9 +1517,25 @@ pub const TestContext = struct {
1497 var main_pkg: Package = .{1517 var main_pkg: Package = .{
1498 .root_src_directory = .{ .path = tmp_dir_path, .handle = tmp.dir },1518 .root_src_directory = .{ .path = tmp_dir_path, .handle = tmp.dir },
1499 .root_src_path = tmp_src_path,1519 .root_src_path = tmp_src_path,
1500 .name = "root",
1501 };1520 };
1502 defer main_pkg.table.deinit(allocator);1521 defer {
1522 var it = main_pkg.table.iterator();
1523 while (it.next()) |kv| {
1524 allocator.free(kv.key_ptr.*);
1525 kv.value_ptr.*.destroy(allocator);
1526 }
1527 main_pkg.table.deinit(allocator);
1528 }
1529
1530 for (case.deps.items) |dep| {
1531 var pkg = try Package.create(
1532 allocator,
1533 tmp_dir_path,
1534 dep.path,
1535 );
1536 errdefer pkg.destroy(allocator);
1537 try main_pkg.add(allocator, dep.name, pkg);
1538 }
15031539
1504 const bin_name = try std.zig.binNameAlloc(arena, .{1540 const bin_name = try std.zig.binNameAlloc(arena, .{
1505 .root_name = "test_case",1541 .root_name = "test_case",
src/value.zig+39-10
...@@ -1249,11 +1249,22 @@ pub const Value = extern union {...@@ -1249,11 +1249,22 @@ pub const Value = extern union {
1249 };1249 };
1250 }1250 }
12511251
1252 fn isDeclRef(val: Value) bool {
1253 var check = val;
1254 while (true) switch (check.tag()) {
1255 .variable, .decl_ref, .decl_ref_mut, .comptime_field_ptr => return true,
1256 .field_ptr => check = check.castTag(.field_ptr).?.data.container_ptr,
1257 .elem_ptr => check = check.castTag(.elem_ptr).?.data.array_ptr,
1258 .eu_payload_ptr, .opt_payload_ptr => check = check.cast(Value.Payload.PayloadPtr).?.data.container_ptr,
1259 else => return false,
1260 };
1261 }
1262
1252 /// Write a Value's contents to `buffer`.1263 /// Write a Value's contents to `buffer`.
1253 ///1264 ///
1254 /// Asserts that buffer.len >= ty.abiSize(). The buffer is allowed to extend past1265 /// Asserts that buffer.len >= ty.abiSize(). The buffer is allowed to extend past
1255 /// the end of the value in memory.1266 /// the end of the value in memory.
1256 pub fn writeToMemory(val: Value, ty: Type, mod: *Module, buffer: []u8) void {1267 pub fn writeToMemory(val: Value, ty: Type, mod: *Module, buffer: []u8) error{ReinterpretDeclRef}!void {
1257 const target = mod.getTarget();1268 const target = mod.getTarget();
1258 const endian = target.cpu.arch.endian();1269 const endian = target.cpu.arch.endian();
1259 if (val.isUndef()) {1270 if (val.isUndef()) {
...@@ -1309,7 +1320,7 @@ pub const Value = extern union {...@@ -1309,7 +1320,7 @@ pub const Value = extern union {
1309 var buf_off: usize = 0;1320 var buf_off: usize = 0;
1310 while (elem_i < len) : (elem_i += 1) {1321 while (elem_i < len) : (elem_i += 1) {
1311 const elem_val = val.elemValueBuffer(mod, elem_i, &elem_value_buf);1322 const elem_val = val.elemValueBuffer(mod, elem_i, &elem_value_buf);
1312 elem_val.writeToMemory(elem_ty, mod, buffer[buf_off..]);1323 try elem_val.writeToMemory(elem_ty, mod, buffer[buf_off..]);
1313 buf_off += elem_size;1324 buf_off += elem_size;
1314 }1325 }
1315 },1326 },
...@@ -1317,7 +1328,7 @@ pub const Value = extern union {...@@ -1317,7 +1328,7 @@ pub const Value = extern union {
1317 // We use byte_count instead of abi_size here, so that any padding bytes1328 // We use byte_count instead of abi_size here, so that any padding bytes
1318 // follow the data bytes, on both big- and little-endian systems.1329 // follow the data bytes, on both big- and little-endian systems.
1319 const byte_count = (@intCast(usize, ty.bitSize(target)) + 7) / 8;1330 const byte_count = (@intCast(usize, ty.bitSize(target)) + 7) / 8;
1320 writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);1331 return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);
1321 },1332 },
1322 .Struct => switch (ty.containerLayout()) {1333 .Struct => switch (ty.containerLayout()) {
1323 .Auto => unreachable, // Sema is supposed to have emitted a compile error already1334 .Auto => unreachable, // Sema is supposed to have emitted a compile error already
...@@ -1326,12 +1337,12 @@ pub const Value = extern union {...@@ -1326,12 +1337,12 @@ pub const Value = extern union {
1326 const field_vals = val.castTag(.aggregate).?.data;1337 const field_vals = val.castTag(.aggregate).?.data;
1327 for (fields, 0..) |field, i| {1338 for (fields, 0..) |field, i| {
1328 const off = @intCast(usize, ty.structFieldOffset(i, target));1339 const off = @intCast(usize, ty.structFieldOffset(i, target));
1329 writeToMemory(field_vals[i], field.ty, mod, buffer[off..]);1340 try writeToMemory(field_vals[i], field.ty, mod, buffer[off..]);
1330 }1341 }
1331 },1342 },
1332 .Packed => {1343 .Packed => {
1333 const byte_count = (@intCast(usize, ty.bitSize(target)) + 7) / 8;1344 const byte_count = (@intCast(usize, ty.bitSize(target)) + 7) / 8;
1334 writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);1345 return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);
1335 },1346 },
1336 },1347 },
1337 .ErrorSet => {1348 .ErrorSet => {
...@@ -1345,9 +1356,14 @@ pub const Value = extern union {...@@ -1345,9 +1356,14 @@ pub const Value = extern union {
1345 .Extern => @panic("TODO implement writeToMemory for extern unions"),1356 .Extern => @panic("TODO implement writeToMemory for extern unions"),
1346 .Packed => {1357 .Packed => {
1347 const byte_count = (@intCast(usize, ty.bitSize(target)) + 7) / 8;1358 const byte_count = (@intCast(usize, ty.bitSize(target)) + 7) / 8;
1348 writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);1359 return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0);
1349 },1360 },
1350 },1361 },
1362 .Pointer => {
1363 assert(!ty.isSlice()); // No well defined layout.
1364 if (val.isDeclRef()) return error.ReinterpretDeclRef;
1365 return val.writeToMemory(Type.usize, mod, buffer);
1366 },
1351 else => @panic("TODO implement writeToMemory for more types"),1367 else => @panic("TODO implement writeToMemory for more types"),
1352 }1368 }
1353 }1369 }
...@@ -1356,7 +1372,7 @@ pub const Value = extern union {...@@ -1356,7 +1372,7 @@ pub const Value = extern union {
1356 ///1372 ///
1357 /// Both the start and the end of the provided buffer must be tight, since1373 /// Both the start and the end of the provided buffer must be tight, since
1358 /// big-endian packed memory layouts start at the end of the buffer.1374 /// big-endian packed memory layouts start at the end of the buffer.
1359 pub fn writeToPackedMemory(val: Value, ty: Type, mod: *Module, buffer: []u8, bit_offset: usize) void {1375 pub fn writeToPackedMemory(val: Value, ty: Type, mod: *Module, buffer: []u8, bit_offset: usize) error{ReinterpretDeclRef}!void {
1360 const target = mod.getTarget();1376 const target = mod.getTarget();
1361 const endian = target.cpu.arch.endian();1377 const endian = target.cpu.arch.endian();
1362 if (val.isUndef()) {1378 if (val.isUndef()) {
...@@ -1420,7 +1436,7 @@ pub const Value = extern union {...@@ -1420,7 +1436,7 @@ pub const Value = extern union {
1420 // On big-endian systems, LLVM reverses the element order of vectors by default1436 // On big-endian systems, LLVM reverses the element order of vectors by default
1421 const tgt_elem_i = if (endian == .Big) len - elem_i - 1 else elem_i;1437 const tgt_elem_i = if (endian == .Big) len - elem_i - 1 else elem_i;
1422 const elem_val = val.elemValueBuffer(mod, tgt_elem_i, &elem_value_buf);1438 const elem_val = val.elemValueBuffer(mod, tgt_elem_i, &elem_value_buf);
1423 elem_val.writeToPackedMemory(elem_ty, mod, buffer, bit_offset + bits);1439 try elem_val.writeToPackedMemory(elem_ty, mod, buffer, bit_offset + bits);
1424 bits += elem_bit_size;1440 bits += elem_bit_size;
1425 }1441 }
1426 },1442 },
...@@ -1433,7 +1449,7 @@ pub const Value = extern union {...@@ -1433,7 +1449,7 @@ pub const Value = extern union {
1433 const field_vals = val.castTag(.aggregate).?.data;1449 const field_vals = val.castTag(.aggregate).?.data;
1434 for (fields, 0..) |field, i| {1450 for (fields, 0..) |field, i| {
1435 const field_bits = @intCast(u16, field.ty.bitSize(target));1451 const field_bits = @intCast(u16, field.ty.bitSize(target));
1436 field_vals[i].writeToPackedMemory(field.ty, mod, buffer, bit_offset + bits);1452 try field_vals[i].writeToPackedMemory(field.ty, mod, buffer, bit_offset + bits);
1437 bits += field_bits;1453 bits += field_bits;
1438 }1454 }
1439 },1455 },
...@@ -1446,9 +1462,14 @@ pub const Value = extern union {...@@ -1446,9 +1462,14 @@ pub const Value = extern union {
1446 const field_type = ty.unionFields().values()[field_index.?].ty;1462 const field_type = ty.unionFields().values()[field_index.?].ty;
1447 const field_val = val.fieldValue(field_type, field_index.?);1463 const field_val = val.fieldValue(field_type, field_index.?);
14481464
1449 field_val.writeToPackedMemory(field_type, mod, buffer, bit_offset);1465 return field_val.writeToPackedMemory(field_type, mod, buffer, bit_offset);
1450 },1466 },
1451 },1467 },
1468 .Pointer => {
1469 assert(!ty.isSlice()); // No well defined layout.
1470 if (val.isDeclRef()) return error.ReinterpretDeclRef;
1471 return val.writeToPackedMemory(Type.usize, mod, buffer, bit_offset);
1472 },
1452 else => @panic("TODO implement writeToPackedMemory for more types"),1473 else => @panic("TODO implement writeToPackedMemory for more types"),
1453 }1474 }
1454 }1475 }
...@@ -1553,6 +1574,10 @@ pub const Value = extern union {...@@ -1553,6 +1574,10 @@ pub const Value = extern union {
1553 };1574 };
1554 return Value.initPayload(&payload.base);1575 return Value.initPayload(&payload.base);
1555 },1576 },
1577 .Pointer => {
1578 assert(!ty.isSlice()); // No well defined layout.
1579 return readFromMemory(Type.usize, mod, buffer, arena);
1580 },
1556 else => @panic("TODO implement readFromMemory for more types"),1581 else => @panic("TODO implement readFromMemory for more types"),
1557 }1582 }
1558 }1583 }
...@@ -1640,6 +1665,10 @@ pub const Value = extern union {...@@ -1640,6 +1665,10 @@ pub const Value = extern union {
1640 return Tag.aggregate.create(arena, field_vals);1665 return Tag.aggregate.create(arena, field_vals);
1641 },1666 },
1642 },1667 },
1668 .Pointer => {
1669 assert(!ty.isSlice()); // No well defined layout.
1670 return readFromPackedMemory(Type.usize, mod, buffer, bit_offset, arena);
1671 },
1643 else => @panic("TODO implement readFromPackedMemory for more types"),1672 else => @panic("TODO implement readFromPackedMemory for more types"),
1644 }1673 }
1645 }1674 }
stage1/zig.h created+2486
...@@ -0,0 +1,2486 @@
1#undef linux
2
3#define __STDC_WANT_IEC_60559_TYPES_EXT__
4#include <float.h>
5#include <limits.h>
6#include <stddef.h>
7#include <stdint.h>
8
9#if _MSC_VER
10#include <intrin.h>
11#elif defined(__i386__) || defined(__x86_64__)
12#include <cpuid.h>
13#endif
14
15#if !defined(__cplusplus) && __STDC_VERSION__ <= 201710L
16#if __STDC_VERSION__ >= 199901L
17#include <stdbool.h>
18#else
19typedef char bool;
20#define false 0
21#define true 1
22#endif
23#endif
24
25#if defined(__has_builtin)
26#define zig_has_builtin(builtin) __has_builtin(__builtin_##builtin)
27#else
28#define zig_has_builtin(builtin) 0
29#endif
30
31#if defined(__has_attribute)
32#define zig_has_attribute(attribute) __has_attribute(attribute)
33#else
34#define zig_has_attribute(attribute) 0
35#endif
36
37#if __STDC_VERSION__ >= 201112L
38#define zig_threadlocal _Thread_local
39#elif defined(__GNUC__)
40#define zig_threadlocal __thread
41#elif _MSC_VER
42#define zig_threadlocal __declspec(thread)
43#else
44#define zig_threadlocal zig_threadlocal_unavailable
45#endif
46
47#if defined(__clang__)
48#define zig_clang
49#elif defined(__GNUC__)
50#define zig_gnuc
51#endif
52
53#if _MSC_VER
54#define zig_const_arr
55#define zig_callconv(c) __##c
56#else
57#define zig_const_arr static const
58#define zig_callconv(c) __attribute__((c))
59#endif
60
61#if zig_has_attribute(naked) || defined(zig_gnuc)
62#define zig_naked_decl __attribute__((naked))
63#define zig_naked __attribute__((naked))
64#elif defined(_MSC_VER)
65#define zig_naked_decl
66#define zig_naked __declspec(naked)
67#else
68#define zig_naked_decl zig_naked_unavailable
69#define zig_naked zig_naked_unavailable
70#endif
71
72#if zig_has_attribute(cold)
73#define zig_cold __attribute__((cold))
74#else
75#define zig_cold
76#endif
77
78#if __STDC_VERSION__ >= 199901L
79#define zig_restrict restrict
80#elif defined(__GNUC__)
81#define zig_restrict __restrict
82#else
83#define zig_restrict
84#endif
85
86#if __STDC_VERSION__ >= 201112L
87#define zig_align(alignment) _Alignas(alignment)
88#elif zig_has_attribute(aligned)
89#define zig_align(alignment) __attribute__((aligned(alignment)))
90#elif _MSC_VER
91#define zig_align(alignment) __declspec(align(alignment))
92#else
93#define zig_align zig_align_unavailable
94#endif
95
96#if zig_has_attribute(aligned)
97#define zig_under_align(alignment) __attribute__((aligned(alignment)))
98#elif _MSC_VER
99#define zig_under_align(alignment) zig_align(alignment)
100#else
101#define zig_align zig_align_unavailable
102#endif
103
104#if zig_has_attribute(aligned)
105#define zig_align_fn(alignment) __attribute__((aligned(alignment)))
106#elif _MSC_VER
107#define zig_align_fn(alignment)
108#else
109#define zig_align_fn zig_align_fn_unavailable
110#endif
111
112#if zig_has_attribute(packed)
113#define zig_packed(definition) __attribute__((packed)) definition
114#elif _MSC_VER
115#define zig_packed(definition) __pragma(pack(1)) definition __pragma(pack())
116#else
117#define zig_packed(definition) zig_packed_unavailable
118#endif
119
120#if zig_has_attribute(section)
121#define zig_linksection(name, def, ...) def __attribute__((section(name)))
122#elif _MSC_VER
123#define zig_linksection(name, def, ...) __pragma(section(name, __VA_ARGS__)) __declspec(allocate(name)) def
124#else
125#define zig_linksection(name, def, ...) zig_linksection_unavailable
126#endif
127
128#if zig_has_builtin(unreachable) || defined(zig_gnuc)
129#define zig_unreachable() __builtin_unreachable()
130#else
131#define zig_unreachable()
132#endif
133
134#if defined(__cplusplus)
135#define zig_extern extern "C"
136#else
137#define zig_extern extern
138#endif
139
140#if zig_has_attribute(alias)
141#define zig_export(sig, symbol, name) zig_extern sig __attribute__((alias(symbol)))
142#elif _MSC_VER
143#if _M_X64
144#define zig_export(sig, symbol, name) sig;\
145 __pragma(comment(linker, "/alternatename:" name "=" symbol ))
146#else /*_M_X64 */
147#define zig_export(sig, symbol, name) sig;\
148 __pragma(comment(linker, "/alternatename:_" name "=_" symbol ))
149#endif /*_M_X64 */
150#else
151#define zig_export(sig, symbol, name) __asm(name " = " symbol)
152#endif
153
154#if zig_has_builtin(debugtrap)
155#define zig_breakpoint() __builtin_debugtrap()
156#elif zig_has_builtin(trap) || defined(zig_gnuc)
157#define zig_breakpoint() __builtin_trap()
158#elif defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__)
159#define zig_breakpoint() __debugbreak()
160#elif defined(__i386__) || defined(__x86_64__)
161#define zig_breakpoint() __asm__ volatile("int $0x03");
162#else
163#define zig_breakpoint() raise(SIGTRAP)
164#endif
165
166#if zig_has_builtin(return_address) || defined(zig_gnuc)
167#define zig_return_address() __builtin_extract_return_addr(__builtin_return_address(0))
168#elif defined(_MSC_VER)
169#define zig_return_address() _ReturnAddress()
170#else
171#define zig_return_address() 0
172#endif
173
174#if zig_has_builtin(frame_address) || defined(zig_gnuc)
175#define zig_frame_address() __builtin_frame_address(0)
176#else
177#define zig_frame_address() 0
178#endif
179
180#if zig_has_builtin(prefetch) || defined(zig_gnuc)
181#define zig_prefetch(addr, rw, locality) __builtin_prefetch(addr, rw, locality)
182#else
183#define zig_prefetch(addr, rw, locality)
184#endif
185
186#if zig_has_builtin(memory_size) && zig_has_builtin(memory_grow)
187#define zig_wasm_memory_size(index) __builtin_wasm_memory_size(index)
188#define zig_wasm_memory_grow(index, delta) __builtin_wasm_memory_grow(index, delta)
189#else
190#define zig_wasm_memory_size(index) zig_unimplemented()
191#define zig_wasm_memory_grow(index, delta) zig_unimplemented()
192#endif
193
194#define zig_concat(lhs, rhs) lhs##rhs
195#define zig_expand_concat(lhs, rhs) zig_concat(lhs, rhs)
196
197#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
198#include <stdatomic.h>
199#define zig_atomic(type) _Atomic(type)
200#define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail)
201#define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) atomic_compare_exchange_weak_explicit (obj, &(expected), desired, succ, fail)
202#define zig_atomicrmw_xchg(obj, arg, order, type) atomic_exchange_explicit (obj, arg, order)
203#define zig_atomicrmw_add(obj, arg, order, type) atomic_fetch_add_explicit (obj, arg, order)
204#define zig_atomicrmw_sub(obj, arg, order, type) atomic_fetch_sub_explicit (obj, arg, order)
205#define zig_atomicrmw_or(obj, arg, order, type) atomic_fetch_or_explicit (obj, arg, order)
206#define zig_atomicrmw_xor(obj, arg, order, type) atomic_fetch_xor_explicit (obj, arg, order)
207#define zig_atomicrmw_and(obj, arg, order, type) atomic_fetch_and_explicit (obj, arg, order)
208#define zig_atomicrmw_nand(obj, arg, order, type) __atomic_fetch_nand (obj, arg, order)
209#define zig_atomicrmw_min(obj, arg, order, type) __atomic_fetch_min (obj, arg, order)
210#define zig_atomicrmw_max(obj, arg, order, type) __atomic_fetch_max (obj, arg, order)
211#define zig_atomic_store(obj, arg, order, type) atomic_store_explicit (obj, arg, order)
212#define zig_atomic_load(obj, order, type) atomic_load_explicit (obj, order)
213#define zig_fence(order) atomic_thread_fence(order)
214#elif defined(__GNUC__)
215#define memory_order_relaxed __ATOMIC_RELAXED
216#define memory_order_consume __ATOMIC_CONSUME
217#define memory_order_acquire __ATOMIC_ACQUIRE
218#define memory_order_release __ATOMIC_RELEASE
219#define memory_order_acq_rel __ATOMIC_ACQ_REL
220#define memory_order_seq_cst __ATOMIC_SEQ_CST
221#define zig_atomic(type) type
222#define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) __atomic_compare_exchange_n(obj, &(expected), desired, false, succ, fail)
223#define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) __atomic_compare_exchange_n(obj, &(expected), desired, true , succ, fail)
224#define zig_atomicrmw_xchg(obj, arg, order, type) __atomic_exchange_n(obj, arg, order)
225#define zig_atomicrmw_add(obj, arg, order, type) __atomic_fetch_add (obj, arg, order)
226#define zig_atomicrmw_sub(obj, arg, order, type) __atomic_fetch_sub (obj, arg, order)
227#define zig_atomicrmw_or(obj, arg, order, type) __atomic_fetch_or (obj, arg, order)
228#define zig_atomicrmw_xor(obj, arg, order, type) __atomic_fetch_xor (obj, arg, order)
229#define zig_atomicrmw_and(obj, arg, order, type) __atomic_fetch_and (obj, arg, order)
230#define zig_atomicrmw_nand(obj, arg, order, type) __atomic_fetch_nand(obj, arg, order)
231#define zig_atomicrmw_min(obj, arg, order, type) __atomic_fetch_min (obj, arg, order)
232#define zig_atomicrmw_max(obj, arg, order, type) __atomic_fetch_max (obj, arg, order)
233#define zig_atomic_store(obj, arg, order, type) __atomic_store_n (obj, arg, order)
234#define zig_atomic_load(obj, order, type) __atomic_load_n (obj, order)
235#define zig_fence(order) __atomic_thread_fence(order)
236#elif _MSC_VER && (_M_IX86 || _M_X64)
237#define memory_order_relaxed 0
238#define memory_order_consume 1
239#define memory_order_acquire 2
240#define memory_order_release 3
241#define memory_order_acq_rel 4
242#define memory_order_seq_cst 5
243#define zig_atomic(type) type
244#define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) zig_expand_concat(zig_msvc_cmpxchg_, type)(obj, &(expected), desired)
245#define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) zig_cmpxchg_strong(obj, expected, desired, succ, fail, type)
246#define zig_atomicrmw_xchg(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_xchg_, type)(obj, arg)
247#define zig_atomicrmw_add(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_add_, type)(obj, arg)
248#define zig_atomicrmw_sub(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_sub_, type)(obj, arg)
249#define zig_atomicrmw_or(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_or_, type)(obj, arg)
250#define zig_atomicrmw_xor(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_xor_, type)(obj, arg)
251#define zig_atomicrmw_and(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_and_, type)(obj, arg)
252#define zig_atomicrmw_nand(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_nand_, type)(obj, arg)
253#define zig_atomicrmw_min(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_min_, type)(obj, arg)
254#define zig_atomicrmw_max(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_max_, type)(obj, arg)
255#define zig_atomic_store(obj, arg, order, type) zig_expand_concat(zig_msvc_atomic_store_, type)(obj, arg)
256#define zig_atomic_load(obj, order, type) zig_expand_concat(zig_msvc_atomic_load_, type)(obj)
257#if _M_X64
258#define zig_fence(order) __faststorefence()
259#else
260#define zig_fence(order) zig_msvc_atomic_barrier()
261#endif
262
263// TODO: _MSC_VER && (_M_ARM || _M_ARM64)
264#else
265#define memory_order_relaxed 0
266#define memory_order_consume 1
267#define memory_order_acquire 2
268#define memory_order_release 3
269#define memory_order_acq_rel 4
270#define memory_order_seq_cst 5
271#define zig_atomic(type) type
272#define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) zig_unimplemented()
273#define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) zig_unimplemented()
274#define zig_atomicrmw_xchg(obj, arg, order, type) zig_unimplemented()
275#define zig_atomicrmw_add(obj, arg, order, type) zig_unimplemented()
276#define zig_atomicrmw_sub(obj, arg, order, type) zig_unimplemented()
277#define zig_atomicrmw_or(obj, arg, order, type) zig_unimplemented()
278#define zig_atomicrmw_xor(obj, arg, order, type) zig_unimplemented()
279#define zig_atomicrmw_and(obj, arg, order, type) zig_unimplemented()
280#define zig_atomicrmw_nand(obj, arg, order, type) zig_unimplemented()
281#define zig_atomicrmw_min(obj, arg, order, type) zig_unimplemented()
282#define zig_atomicrmw_max(obj, arg, order, type) zig_unimplemented()
283#define zig_atomic_store(obj, arg, order, type) zig_unimplemented()
284#define zig_atomic_load(obj, order, type) zig_unimplemented()
285#define zig_fence(order) zig_unimplemented()
286#endif
287
288#if __STDC_VERSION__ >= 201112L
289#define zig_noreturn _Noreturn void
290#elif zig_has_attribute(noreturn) || defined(zig_gnuc)
291#define zig_noreturn __attribute__((noreturn)) void
292#elif _MSC_VER
293#define zig_noreturn __declspec(noreturn) void
294#else
295#define zig_noreturn void
296#endif
297
298#define zig_bitSizeOf(T) (CHAR_BIT * sizeof(T))
299
300typedef uintptr_t zig_usize;
301typedef intptr_t zig_isize;
302typedef signed short int zig_c_short;
303typedef unsigned short int zig_c_ushort;
304typedef signed int zig_c_int;
305typedef unsigned int zig_c_uint;
306typedef signed long int zig_c_long;
307typedef unsigned long int zig_c_ulong;
308typedef signed long long int zig_c_longlong;
309typedef unsigned long long int zig_c_ulonglong;
310
311typedef uint8_t zig_u8;
312typedef int8_t zig_i8;
313typedef uint16_t zig_u16;
314typedef int16_t zig_i16;
315typedef uint32_t zig_u32;
316typedef int32_t zig_i32;
317typedef uint64_t zig_u64;
318typedef int64_t zig_i64;
319
320#define zig_as_u8(val) UINT8_C(val)
321#define zig_as_i8(val) INT8_C(val)
322#define zig_as_u16(val) UINT16_C(val)
323#define zig_as_i16(val) INT16_C(val)
324#define zig_as_u32(val) UINT32_C(val)
325#define zig_as_i32(val) INT32_C(val)
326#define zig_as_u64(val) UINT64_C(val)
327#define zig_as_i64(val) INT64_C(val)
328
329#define zig_minInt_u8 zig_as_u8(0)
330#define zig_maxInt_u8 UINT8_MAX
331#define zig_minInt_i8 INT8_MIN
332#define zig_maxInt_i8 INT8_MAX
333#define zig_minInt_u16 zig_as_u16(0)
334#define zig_maxInt_u16 UINT16_MAX
335#define zig_minInt_i16 INT16_MIN
336#define zig_maxInt_i16 INT16_MAX
337#define zig_minInt_u32 zig_as_u32(0)
338#define zig_maxInt_u32 UINT32_MAX
339#define zig_minInt_i32 INT32_MIN
340#define zig_maxInt_i32 INT32_MAX
341#define zig_minInt_u64 zig_as_u64(0)
342#define zig_maxInt_u64 UINT64_MAX
343#define zig_minInt_i64 INT64_MIN
344#define zig_maxInt_i64 INT64_MAX
345
346#define zig_compiler_rt_abbrev_u32 si
347#define zig_compiler_rt_abbrev_i32 si
348#define zig_compiler_rt_abbrev_u64 di
349#define zig_compiler_rt_abbrev_i64 di
350#define zig_compiler_rt_abbrev_u128 ti
351#define zig_compiler_rt_abbrev_i128 ti
352#define zig_compiler_rt_abbrev_f16 hf
353#define zig_compiler_rt_abbrev_f32 sf
354#define zig_compiler_rt_abbrev_f64 df
355#define zig_compiler_rt_abbrev_f80 xf
356#define zig_compiler_rt_abbrev_f128 tf
357
358zig_extern void *memcpy (void *zig_restrict, void const *zig_restrict, zig_usize);
359zig_extern void *memset (void *, int, zig_usize);
360
361/* ==================== 8/16/32/64-bit Integer Routines ===================== */
362
363#define zig_maxInt(Type, bits) zig_shr_##Type(zig_maxInt_##Type, (zig_bitSizeOf(zig_##Type) - bits))
364#define zig_expand_maxInt(Type, bits) zig_maxInt(Type, bits)
365#define zig_minInt(Type, bits) zig_not_##Type(zig_maxInt(Type, bits), bits)
366#define zig_expand_minInt(Type, bits) zig_minInt(Type, bits)
367
368#define zig_int_operator(Type, RhsType, operation, operator) \
369 static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##RhsType rhs) { \
370 return lhs operator rhs; \
371 }
372#define zig_int_basic_operator(Type, operation, operator) \
373 zig_int_operator(Type, Type, operation, operator)
374#define zig_int_shift_operator(Type, operation, operator) \
375 zig_int_operator(Type, u8, operation, operator)
376#define zig_int_helpers(w) \
377 zig_int_basic_operator(u##w, and, &) \
378 zig_int_basic_operator(i##w, and, &) \
379 zig_int_basic_operator(u##w, or, |) \
380 zig_int_basic_operator(i##w, or, |) \
381 zig_int_basic_operator(u##w, xor, ^) \
382 zig_int_basic_operator(i##w, xor, ^) \
383 zig_int_shift_operator(u##w, shl, <<) \
384 zig_int_shift_operator(i##w, shl, <<) \
385 zig_int_shift_operator(u##w, shr, >>) \
386\
387 static inline zig_i##w zig_shr_i##w(zig_i##w lhs, zig_u8 rhs) { \
388 zig_i##w sign_mask = lhs < zig_as_i##w(0) ? -zig_as_i##w(1) : zig_as_i##w(0); \
389 return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; \
390 } \
391\
392 static inline zig_u##w zig_not_u##w(zig_u##w val, zig_u8 bits) { \
393 return val ^ zig_maxInt(u##w, bits); \
394 } \
395\
396 static inline zig_i##w zig_not_i##w(zig_i##w val, zig_u8 bits) { \
397 (void)bits; \
398 return ~val; \
399 } \
400\
401 static inline zig_u##w zig_wrap_u##w(zig_u##w val, zig_u8 bits) { \
402 return val & zig_maxInt(u##w, bits); \
403 } \
404\
405 static inline zig_i##w zig_wrap_i##w(zig_i##w val, zig_u8 bits) { \
406 return (val & zig_as_u##w(1) << (bits - zig_as_u8(1))) != 0 \
407 ? val | zig_minInt(i##w, bits) : val & zig_maxInt(i##w, bits); \
408 } \
409\
410 zig_int_basic_operator(u##w, div_floor, /) \
411\
412 static inline zig_i##w zig_div_floor_i##w(zig_i##w lhs, zig_i##w rhs) { \
413 return lhs / rhs - (((lhs ^ rhs) & (lhs % rhs)) < zig_as_i##w(0)); \
414 } \
415\
416 zig_int_basic_operator(u##w, mod, %) \
417\
418 static inline zig_i##w zig_mod_i##w(zig_i##w lhs, zig_i##w rhs) { \
419 zig_i##w rem = lhs % rhs; \
420 return rem + (((lhs ^ rhs) & rem) < zig_as_i##w(0) ? rhs : zig_as_i##w(0)); \
421 } \
422\
423 static inline zig_u##w zig_shlw_u##w(zig_u##w lhs, zig_u8 rhs, zig_u8 bits) { \
424 return zig_wrap_u##w(zig_shl_u##w(lhs, rhs), bits); \
425 } \
426\
427 static inline zig_i##w zig_shlw_i##w(zig_i##w lhs, zig_u8 rhs, zig_u8 bits) { \
428 return zig_wrap_i##w((zig_i##w)zig_shl_u##w((zig_u##w)lhs, (zig_u##w)rhs), bits); \
429 } \
430\
431 static inline zig_u##w zig_addw_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \
432 return zig_wrap_u##w(lhs + rhs, bits); \
433 } \
434\
435 static inline zig_i##w zig_addw_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \
436 return zig_wrap_i##w((zig_i##w)((zig_u##w)lhs + (zig_u##w)rhs), bits); \
437 } \
438\
439 static inline zig_u##w zig_subw_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \
440 return zig_wrap_u##w(lhs - rhs, bits); \
441 } \
442\
443 static inline zig_i##w zig_subw_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \
444 return zig_wrap_i##w((zig_i##w)((zig_u##w)lhs - (zig_u##w)rhs), bits); \
445 } \
446\
447 static inline zig_u##w zig_mulw_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \
448 return zig_wrap_u##w(lhs * rhs, bits); \
449 } \
450\
451 static inline zig_i##w zig_mulw_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \
452 return zig_wrap_i##w((zig_i##w)((zig_u##w)lhs * (zig_u##w)rhs), bits); \
453 }
454zig_int_helpers(8)
455zig_int_helpers(16)
456zig_int_helpers(32)
457zig_int_helpers(64)
458
459static inline bool zig_addo_u32(zig_u32 *res, zig_u32 lhs, zig_u32 rhs, zig_u8 bits) {
460#if zig_has_builtin(add_overflow) || defined(zig_gnuc)
461 zig_u32 full_res;
462 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);
463 *res = zig_wrap_u32(full_res, bits);
464 return overflow || full_res < zig_minInt(u32, bits) || full_res > zig_maxInt(u32, bits);
465#else
466 *res = zig_addw_u32(lhs, rhs, bits);
467 return *res < lhs;
468#endif
469}
470
471static inline void zig_vaddo_u32(zig_u8 *ov, zig_u32 *res, int n,
472 const zig_u32 *lhs, const zig_u32 *rhs, zig_u8 bits)
473{
474 for (int i = 0; i < n; ++i) ov[i] = zig_addo_u32(&res[i], lhs[i], rhs[i], bits);
475}
476
477zig_extern zig_i32 __addosi4(zig_i32 lhs, zig_i32 rhs, zig_c_int *overflow);
478static inline bool zig_addo_i32(zig_i32 *res, zig_i32 lhs, zig_i32 rhs, zig_u8 bits) {
479#if zig_has_builtin(add_overflow) || defined(zig_gnuc)
480 zig_i32 full_res;
481 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);
482#else
483 zig_c_int overflow_int;
484 zig_i32 full_res = __addosi4(lhs, rhs, &overflow_int);
485 bool overflow = overflow_int != 0;
486#endif
487 *res = zig_wrap_i32(full_res, bits);
488 return overflow || full_res < zig_minInt(i32, bits) || full_res > zig_maxInt(i32, bits);
489}
490
491static inline void zig_vaddo_i32(zig_u8 *ov, zig_i32 *res, int n,
492 const zig_i32 *lhs, const zig_i32 *rhs, zig_u8 bits)
493{
494 for (int i = 0; i < n; ++i) ov[i] = zig_addo_i32(&res[i], lhs[i], rhs[i], bits);
495}
496
497static inline bool zig_addo_u64(zig_u64 *res, zig_u64 lhs, zig_u64 rhs, zig_u8 bits) {
498#if zig_has_builtin(add_overflow) || defined(zig_gnuc)
499 zig_u64 full_res;
500 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);
501 *res = zig_wrap_u64(full_res, bits);
502 return overflow || full_res < zig_minInt(u64, bits) || full_res > zig_maxInt(u64, bits);
503#else
504 *res = zig_addw_u64(lhs, rhs, bits);
505 return *res < lhs;
506#endif
507}
508
509static inline void zig_vaddo_u64(zig_u8 *ov, zig_u64 *res, int n,
510 const zig_u64 *lhs, const zig_u64 *rhs, zig_u8 bits)
511{
512 for (int i = 0; i < n; ++i) ov[i] = zig_addo_u64(&res[i], lhs[i], rhs[i], bits);
513}
514
515zig_extern zig_i64 __addodi4(zig_i64 lhs, zig_i64 rhs, zig_c_int *overflow);
516static inline bool zig_addo_i64(zig_i64 *res, zig_i64 lhs, zig_i64 rhs, zig_u8 bits) {
517#if zig_has_builtin(add_overflow) || defined(zig_gnuc)
518 zig_i64 full_res;
519 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);
520#else
521 zig_c_int overflow_int;
522 zig_i64 full_res = __addodi4(lhs, rhs, &overflow_int);
523 bool overflow = overflow_int != 0;
524#endif
525 *res = zig_wrap_i64(full_res, bits);
526 return overflow || full_res < zig_minInt(i64, bits) || full_res > zig_maxInt(i64, bits);
527}
528
529static inline void zig_vaddo_i64(zig_u8 *ov, zig_i64 *res, int n,
530 const zig_i64 *lhs, const zig_i64 *rhs, zig_u8 bits)
531{
532 for (int i = 0; i < n; ++i) ov[i] = zig_addo_i64(&res[i], lhs[i], rhs[i], bits);
533}
534
535static inline bool zig_addo_u8(zig_u8 *res, zig_u8 lhs, zig_u8 rhs, zig_u8 bits) {
536#if zig_has_builtin(add_overflow) || defined(zig_gnuc)
537 zig_u8 full_res;
538 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);
539 *res = zig_wrap_u8(full_res, bits);
540 return overflow || full_res < zig_minInt(u8, bits) || full_res > zig_maxInt(u8, bits);
541#else
542 zig_u32 full_res;
543 bool overflow = zig_addo_u32(&full_res, lhs, rhs, bits);
544 *res = (zig_u8)full_res;
545 return overflow;
546#endif
547}
548
549static inline void zig_vaddo_u8(zig_u8 *ov, zig_u8 *res, int n,
550 const zig_u8 *lhs, const zig_u8 *rhs, zig_u8 bits)
551{
552 for (int i = 0; i < n; ++i) ov[i] = zig_addo_u8(&res[i], lhs[i], rhs[i], bits);
553}
554
555static inline bool zig_addo_i8(zig_i8 *res, zig_i8 lhs, zig_i8 rhs, zig_u8 bits) {
556#if zig_has_builtin(add_overflow) || defined(zig_gnuc)
557 zig_i8 full_res;
558 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);
559 *res = zig_wrap_i8(full_res, bits);
560 return overflow || full_res < zig_minInt(i8, bits) || full_res > zig_maxInt(i8, bits);
561#else
562 zig_i32 full_res;
563 bool overflow = zig_addo_i32(&full_res, lhs, rhs, bits);
564 *res = (zig_i8)full_res;
565 return overflow;
566#endif
567}
568
569static inline void zig_vaddo_i8(zig_u8 *ov, zig_i8 *res, int n,
570 const zig_i8 *lhs, const zig_i8 *rhs, zig_u8 bits)
571{
572 for (int i = 0; i < n; ++i) ov[i] = zig_addo_i8(&res[i], lhs[i], rhs[i], bits);
573}
574
575static inline bool zig_addo_u16(zig_u16 *res, zig_u16 lhs, zig_u16 rhs, zig_u8 bits) {
576#if zig_has_builtin(add_overflow) || defined(zig_gnuc)
577 zig_u16 full_res;
578 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);
579 *res = zig_wrap_u16(full_res, bits);
580 return overflow || full_res < zig_minInt(u16, bits) || full_res > zig_maxInt(u16, bits);
581#else
582 zig_u32 full_res;
583 bool overflow = zig_addo_u32(&full_res, lhs, rhs, bits);
584 *res = (zig_u16)full_res;
585 return overflow;
586#endif
587}
588
589static inline void zig_vaddo_u16(zig_u8 *ov, zig_u16 *res, int n,
590 const zig_u16 *lhs, const zig_u16 *rhs, zig_u8 bits)
591{
592 for (int i = 0; i < n; ++i) ov[i] = zig_addo_u16(&res[i], lhs[i], rhs[i], bits);
593}
594
595static inline bool zig_addo_i16(zig_i16 *res, zig_i16 lhs, zig_i16 rhs, zig_u8 bits) {
596#if zig_has_builtin(add_overflow) || defined(zig_gnuc)
597 zig_i16 full_res;
598 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);
599 *res = zig_wrap_i16(full_res, bits);
600 return overflow || full_res < zig_minInt(i16, bits) || full_res > zig_maxInt(i16, bits);
601#else
602 zig_i32 full_res;
603 bool overflow = zig_addo_i32(&full_res, lhs, rhs, bits);
604 *res = (zig_i16)full_res;
605 return overflow;
606#endif
607}
608
609static inline void zig_vaddo_i16(zig_u8 *ov, zig_i16 *res, int n,
610 const zig_i16 *lhs, const zig_i16 *rhs, zig_u8 bits)
611{
612 for (int i = 0; i < n; ++i) ov[i] = zig_addo_i16(&res[i], lhs[i], rhs[i], bits);
613}
614
615static inline bool zig_subo_u32(zig_u32 *res, zig_u32 lhs, zig_u32 rhs, zig_u8 bits) {
616#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)
617 zig_u32 full_res;
618 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);
619 *res = zig_wrap_u32(full_res, bits);
620 return overflow || full_res < zig_minInt(u32, bits) || full_res > zig_maxInt(u32, bits);
621#else
622 *res = zig_subw_u32(lhs, rhs, bits);
623 return *res > lhs;
624#endif
625}
626
627static inline void zig_vsubo_u32(zig_u8 *ov, zig_u32 *res, int n,
628 const zig_u32 *lhs, const zig_u32 *rhs, zig_u8 bits)
629{
630 for (int i = 0; i < n; ++i) ov[i] = zig_subo_u32(&res[i], lhs[i], rhs[i], bits);
631}
632
633zig_extern zig_i32 __subosi4(zig_i32 lhs, zig_i32 rhs, zig_c_int *overflow);
634static inline bool zig_subo_i32(zig_i32 *res, zig_i32 lhs, zig_i32 rhs, zig_u8 bits) {
635#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)
636 zig_i32 full_res;
637 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);
638#else
639 zig_c_int overflow_int;
640 zig_i32 full_res = __subosi4(lhs, rhs, &overflow_int);
641 bool overflow = overflow_int != 0;
642#endif
643 *res = zig_wrap_i32(full_res, bits);
644 return overflow || full_res < zig_minInt(i32, bits) || full_res > zig_maxInt(i32, bits);
645}
646
647static inline void zig_vsubo_i32(zig_u8 *ov, zig_i32 *res, int n,
648 const zig_i32 *lhs, const zig_i32 *rhs, zig_u8 bits)
649{
650 for (int i = 0; i < n; ++i) ov[i] = zig_subo_i32(&res[i], lhs[i], rhs[i], bits);
651}
652
653static inline bool zig_subo_u64(zig_u64 *res, zig_u64 lhs, zig_u64 rhs, zig_u8 bits) {
654#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)
655 zig_u64 full_res;
656 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);
657 *res = zig_wrap_u64(full_res, bits);
658 return overflow || full_res < zig_minInt(u64, bits) || full_res > zig_maxInt(u64, bits);
659#else
660 *res = zig_subw_u64(lhs, rhs, bits);
661 return *res > lhs;
662#endif
663}
664
665static inline void zig_vsubo_u64(zig_u8 *ov, zig_u64 *res, int n,
666 const zig_u64 *lhs, const zig_u64 *rhs, zig_u8 bits)
667{
668 for (int i = 0; i < n; ++i) ov[i] = zig_subo_u64(&res[i], lhs[i], rhs[i], bits);
669}
670
671zig_extern zig_i64 __subodi4(zig_i64 lhs, zig_i64 rhs, zig_c_int *overflow);
672static inline bool zig_subo_i64(zig_i64 *res, zig_i64 lhs, zig_i64 rhs, zig_u8 bits) {
673#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)
674 zig_i64 full_res;
675 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);
676#else
677 zig_c_int overflow_int;
678 zig_i64 full_res = __subodi4(lhs, rhs, &overflow_int);
679 bool overflow = overflow_int != 0;
680#endif
681 *res = zig_wrap_i64(full_res, bits);
682 return overflow || full_res < zig_minInt(i64, bits) || full_res > zig_maxInt(i64, bits);
683}
684
685static inline void zig_vsubo_i64(zig_u8 *ov, zig_i64 *res, int n,
686 const zig_i64 *lhs, const zig_i64 *rhs, zig_u8 bits)
687{
688 for (int i = 0; i < n; ++i) ov[i] = zig_subo_i64(&res[i], lhs[i], rhs[i], bits);
689}
690
691static inline bool zig_subo_u8(zig_u8 *res, zig_u8 lhs, zig_u8 rhs, zig_u8 bits) {
692#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)
693 zig_u8 full_res;
694 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);
695 *res = zig_wrap_u8(full_res, bits);
696 return overflow || full_res < zig_minInt(u8, bits) || full_res > zig_maxInt(u8, bits);
697#else
698 zig_u32 full_res;
699 bool overflow = zig_subo_u32(&full_res, lhs, rhs, bits);
700 *res = (zig_u8)full_res;
701 return overflow;
702#endif
703}
704
705static inline void zig_vsubo_u8(zig_u8 *ov, zig_u8 *res, int n,
706 const zig_u8 *lhs, const zig_u8 *rhs, zig_u8 bits)
707{
708 for (int i = 0; i < n; ++i) ov[i] = zig_subo_u8(&res[i], lhs[i], rhs[i], bits);
709}
710
711static inline bool zig_subo_i8(zig_i8 *res, zig_i8 lhs, zig_i8 rhs, zig_u8 bits) {
712#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)
713 zig_i8 full_res;
714 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);
715 *res = zig_wrap_i8(full_res, bits);
716 return overflow || full_res < zig_minInt(i8, bits) || full_res > zig_maxInt(i8, bits);
717#else
718 zig_i32 full_res;
719 bool overflow = zig_subo_i32(&full_res, lhs, rhs, bits);
720 *res = (zig_i8)full_res;
721 return overflow;
722#endif
723}
724
725static inline void zig_vsubo_i8(zig_u8 *ov, zig_i8 *res, int n,
726 const zig_i8 *lhs, const zig_i8 *rhs, zig_u8 bits)
727{
728 for (int i = 0; i < n; ++i) ov[i] = zig_subo_i8(&res[i], lhs[i], rhs[i], bits);
729}
730
731
732static inline bool zig_subo_u16(zig_u16 *res, zig_u16 lhs, zig_u16 rhs, zig_u8 bits) {
733#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)
734 zig_u16 full_res;
735 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);
736 *res = zig_wrap_u16(full_res, bits);
737 return overflow || full_res < zig_minInt(u16, bits) || full_res > zig_maxInt(u16, bits);
738#else
739 zig_u32 full_res;
740 bool overflow = zig_subo_u32(&full_res, lhs, rhs, bits);
741 *res = (zig_u16)full_res;
742 return overflow;
743#endif
744}
745
746static inline void zig_vsubo_u16(zig_u8 *ov, zig_u16 *res, int n,
747 const zig_u16 *lhs, const zig_u16 *rhs, zig_u8 bits)
748{
749 for (int i = 0; i < n; ++i) ov[i] = zig_subo_u16(&res[i], lhs[i], rhs[i], bits);
750}
751
752
753static inline bool zig_subo_i16(zig_i16 *res, zig_i16 lhs, zig_i16 rhs, zig_u8 bits) {
754#if zig_has_builtin(sub_overflow) || defined(zig_gnuc)
755 zig_i16 full_res;
756 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);
757 *res = zig_wrap_i16(full_res, bits);
758 return overflow || full_res < zig_minInt(i16, bits) || full_res > zig_maxInt(i16, bits);
759#else
760 zig_i32 full_res;
761 bool overflow = zig_subo_i32(&full_res, lhs, rhs, bits);
762 *res = (zig_i16)full_res;
763 return overflow;
764#endif
765}
766
767static inline void zig_vsubo_i16(zig_u8 *ov, zig_i16 *res, int n,
768 const zig_i16 *lhs, const zig_i16 *rhs, zig_u8 bits)
769{
770 for (int i = 0; i < n; ++i) ov[i] = zig_subo_i16(&res[i], lhs[i], rhs[i], bits);
771}
772
773static inline bool zig_mulo_u32(zig_u32 *res, zig_u32 lhs, zig_u32 rhs, zig_u8 bits) {
774#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)
775 zig_u32 full_res;
776 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);
777 *res = zig_wrap_u32(full_res, bits);
778 return overflow || full_res < zig_minInt(u32, bits) || full_res > zig_maxInt(u32, bits);
779#else
780 *res = zig_mulw_u32(lhs, rhs, bits);
781 return rhs != zig_as_u32(0) && lhs > zig_maxInt(u32, bits) / rhs;
782#endif
783}
784
785static inline void zig_vmulo_u32(zig_u8 *ov, zig_u32 *res, int n,
786 const zig_u32 *lhs, const zig_u32 *rhs, zig_u8 bits)
787{
788 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_u32(&res[i], lhs[i], rhs[i], bits);
789}
790
791zig_extern zig_i32 __mulosi4(zig_i32 lhs, zig_i32 rhs, zig_c_int *overflow);
792static inline bool zig_mulo_i32(zig_i32 *res, zig_i32 lhs, zig_i32 rhs, zig_u8 bits) {
793#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)
794 zig_i32 full_res;
795 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);
796#else
797 zig_c_int overflow_int;
798 zig_i32 full_res = __mulosi4(lhs, rhs, &overflow_int);
799 bool overflow = overflow_int != 0;
800#endif
801 *res = zig_wrap_i32(full_res, bits);
802 return overflow || full_res < zig_minInt(i32, bits) || full_res > zig_maxInt(i32, bits);
803}
804
805static inline void zig_vmulo_i32(zig_u8 *ov, zig_i32 *res, int n,
806 const zig_i32 *lhs, const zig_i32 *rhs, zig_u8 bits)
807{
808 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_i32(&res[i], lhs[i], rhs[i], bits);
809}
810
811static inline bool zig_mulo_u64(zig_u64 *res, zig_u64 lhs, zig_u64 rhs, zig_u8 bits) {
812#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)
813 zig_u64 full_res;
814 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);
815 *res = zig_wrap_u64(full_res, bits);
816 return overflow || full_res < zig_minInt(u64, bits) || full_res > zig_maxInt(u64, bits);
817#else
818 *res = zig_mulw_u64(lhs, rhs, bits);
819 return rhs != zig_as_u64(0) && lhs > zig_maxInt(u64, bits) / rhs;
820#endif
821}
822
823static inline void zig_vmulo_u64(zig_u8 *ov, zig_u64 *res, int n,
824 const zig_u64 *lhs, const zig_u64 *rhs, zig_u8 bits)
825{
826 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_u64(&res[i], lhs[i], rhs[i], bits);
827}
828
829zig_extern zig_i64 __mulodi4(zig_i64 lhs, zig_i64 rhs, zig_c_int *overflow);
830static inline bool zig_mulo_i64(zig_i64 *res, zig_i64 lhs, zig_i64 rhs, zig_u8 bits) {
831#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)
832 zig_i64 full_res;
833 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);
834#else
835 zig_c_int overflow_int;
836 zig_i64 full_res = __mulodi4(lhs, rhs, &overflow_int);
837 bool overflow = overflow_int != 0;
838#endif
839 *res = zig_wrap_i64(full_res, bits);
840 return overflow || full_res < zig_minInt(i64, bits) || full_res > zig_maxInt(i64, bits);
841}
842
843static inline void zig_vmulo_i64(zig_u8 *ov, zig_i64 *res, int n,
844 const zig_i64 *lhs, const zig_i64 *rhs, zig_u8 bits)
845{
846 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_i64(&res[i], lhs[i], rhs[i], bits);
847}
848
849static inline bool zig_mulo_u8(zig_u8 *res, zig_u8 lhs, zig_u8 rhs, zig_u8 bits) {
850#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)
851 zig_u8 full_res;
852 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);
853 *res = zig_wrap_u8(full_res, bits);
854 return overflow || full_res < zig_minInt(u8, bits) || full_res > zig_maxInt(u8, bits);
855#else
856 zig_u32 full_res;
857 bool overflow = zig_mulo_u32(&full_res, lhs, rhs, bits);
858 *res = (zig_u8)full_res;
859 return overflow;
860#endif
861}
862
863static inline void zig_vmulo_u8(zig_u8 *ov, zig_u8 *res, int n,
864 const zig_u8 *lhs, const zig_u8 *rhs, zig_u8 bits)
865{
866 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_u8(&res[i], lhs[i], rhs[i], bits);
867}
868
869static inline bool zig_mulo_i8(zig_i8 *res, zig_i8 lhs, zig_i8 rhs, zig_u8 bits) {
870#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)
871 zig_i8 full_res;
872 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);
873 *res = zig_wrap_i8(full_res, bits);
874 return overflow || full_res < zig_minInt(i8, bits) || full_res > zig_maxInt(i8, bits);
875#else
876 zig_i32 full_res;
877 bool overflow = zig_mulo_i32(&full_res, lhs, rhs, bits);
878 *res = (zig_i8)full_res;
879 return overflow;
880#endif
881}
882
883static inline void zig_vmulo_i8(zig_u8 *ov, zig_i8 *res, int n,
884 const zig_i8 *lhs, const zig_i8 *rhs, zig_u8 bits)
885{
886 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_i8(&res[i], lhs[i], rhs[i], bits);
887}
888
889static inline bool zig_mulo_u16(zig_u16 *res, zig_u16 lhs, zig_u16 rhs, zig_u8 bits) {
890#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)
891 zig_u16 full_res;
892 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);
893 *res = zig_wrap_u16(full_res, bits);
894 return overflow || full_res < zig_minInt(u16, bits) || full_res > zig_maxInt(u16, bits);
895#else
896 zig_u32 full_res;
897 bool overflow = zig_mulo_u32(&full_res, lhs, rhs, bits);
898 *res = (zig_u16)full_res;
899 return overflow;
900#endif
901}
902
903static inline void zig_vmulo_u16(zig_u8 *ov, zig_u16 *res, int n,
904 const zig_u16 *lhs, const zig_u16 *rhs, zig_u8 bits)
905{
906 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_u16(&res[i], lhs[i], rhs[i], bits);
907}
908
909static inline bool zig_mulo_i16(zig_i16 *res, zig_i16 lhs, zig_i16 rhs, zig_u8 bits) {
910#if zig_has_builtin(mul_overflow) || defined(zig_gnuc)
911 zig_i16 full_res;
912 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);
913 *res = zig_wrap_i16(full_res, bits);
914 return overflow || full_res < zig_minInt(i16, bits) || full_res > zig_maxInt(i16, bits);
915#else
916 zig_i32 full_res;
917 bool overflow = zig_mulo_i32(&full_res, lhs, rhs, bits);
918 *res = (zig_i16)full_res;
919 return overflow;
920#endif
921}
922
923static inline void zig_vmulo_i16(zig_u8 *ov, zig_i16 *res, int n,
924 const zig_i16 *lhs, const zig_i16 *rhs, zig_u8 bits)
925{
926 for (int i = 0; i < n; ++i) ov[i] = zig_mulo_i16(&res[i], lhs[i], rhs[i], bits);
927}
928
929#define zig_int_builtins(w) \
930 static inline bool zig_shlo_u##w(zig_u##w *res, zig_u##w lhs, zig_u8 rhs, zig_u8 bits) { \
931 *res = zig_shlw_u##w(lhs, rhs, bits); \
932 return lhs > zig_maxInt(u##w, bits) >> rhs; \
933 } \
934\
935 static inline bool zig_shlo_i##w(zig_i##w *res, zig_i##w lhs, zig_u8 rhs, zig_u8 bits) { \
936 *res = zig_shlw_i##w(lhs, rhs, bits); \
937 zig_i##w mask = (zig_i##w)(zig_maxInt_u##w << (bits - rhs - 1)); \
938 return (lhs & mask) != zig_as_i##w(0) && (lhs & mask) != mask; \
939 } \
940\
941 static inline zig_u##w zig_shls_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \
942 zig_u##w res; \
943 if (rhs >= bits) return lhs != zig_as_u##w(0) ? zig_maxInt(u##w, bits) : lhs; \
944 return zig_shlo_u##w(&res, lhs, (zig_u8)rhs, bits) ? zig_maxInt(u##w, bits) : res; \
945 } \
946\
947 static inline zig_i##w zig_shls_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \
948 zig_i##w res; \
949 if ((zig_u##w)rhs < (zig_u##w)bits && !zig_shlo_i##w(&res, lhs, rhs, bits)) return res; \
950 return lhs < zig_as_i##w(0) ? zig_minInt(i##w, bits) : zig_maxInt(i##w, bits); \
951 } \
952\
953 static inline zig_u##w zig_adds_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \
954 zig_u##w res; \
955 return zig_addo_u##w(&res, lhs, rhs, bits) ? zig_maxInt(u##w, bits) : res; \
956 } \
957\
958 static inline zig_i##w zig_adds_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \
959 zig_i##w res; \
960 if (!zig_addo_i##w(&res, lhs, rhs, bits)) return res; \
961 return res >= zig_as_i##w(0) ? zig_minInt(i##w, bits) : zig_maxInt(i##w, bits); \
962 } \
963\
964 static inline zig_u##w zig_subs_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \
965 zig_u##w res; \
966 return zig_subo_u##w(&res, lhs, rhs, bits) ? zig_minInt(u##w, bits) : res; \
967 } \
968\
969 static inline zig_i##w zig_subs_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \
970 zig_i##w res; \
971 if (!zig_subo_i##w(&res, lhs, rhs, bits)) return res; \
972 return res >= zig_as_i##w(0) ? zig_minInt(i##w, bits) : zig_maxInt(i##w, bits); \
973 } \
974\
975 static inline zig_u##w zig_muls_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \
976 zig_u##w res; \
977 return zig_mulo_u##w(&res, lhs, rhs, bits) ? zig_maxInt(u##w, bits) : res; \
978 } \
979\
980 static inline zig_i##w zig_muls_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \
981 zig_i##w res; \
982 if (!zig_mulo_i##w(&res, lhs, rhs, bits)) return res; \
983 return (lhs ^ rhs) < zig_as_i##w(0) ? zig_minInt(i##w, bits) : zig_maxInt(i##w, bits); \
984 }
985zig_int_builtins(8)
986zig_int_builtins(16)
987zig_int_builtins(32)
988zig_int_builtins(64)
989
990#define zig_builtin8(name, val) __builtin_##name(val)
991typedef zig_c_uint zig_Builtin8;
992
993#define zig_builtin16(name, val) __builtin_##name(val)
994typedef zig_c_uint zig_Builtin16;
995
996#if INT_MIN <= INT32_MIN
997#define zig_builtin32(name, val) __builtin_##name(val)
998typedef zig_c_uint zig_Builtin32;
999#elif LONG_MIN <= INT32_MIN
1000#define zig_builtin32(name, val) __builtin_##name##l(val)
1001typedef zig_c_ulong zig_Builtin32;
1002#endif
1003
1004#if INT_MIN <= INT64_MIN
1005#define zig_builtin64(name, val) __builtin_##name(val)
1006typedef zig_c_uint zig_Builtin64;
1007#elif LONG_MIN <= INT64_MIN
1008#define zig_builtin64(name, val) __builtin_##name##l(val)
1009typedef zig_c_ulong zig_Builtin64;
1010#elif LLONG_MIN <= INT64_MIN
1011#define zig_builtin64(name, val) __builtin_##name##ll(val)
1012typedef zig_c_ulonglong zig_Builtin64;
1013#endif
1014
1015static inline zig_u8 zig_byte_swap_u8(zig_u8 val, zig_u8 bits) {
1016 return zig_wrap_u8(val >> (8 - bits), bits);
1017}
1018
1019static inline zig_i8 zig_byte_swap_i8(zig_i8 val, zig_u8 bits) {
1020 return zig_wrap_i8((zig_i8)zig_byte_swap_u8((zig_u8)val, bits), bits);
1021}
1022
1023static inline zig_u16 zig_byte_swap_u16(zig_u16 val, zig_u8 bits) {
1024 zig_u16 full_res;
1025#if zig_has_builtin(bswap16) || defined(zig_gnuc)
1026 full_res = __builtin_bswap16(val);
1027#else
1028 full_res = (zig_u16)zig_byte_swap_u8((zig_u8)(val >> 0), 8) << 8 |
1029 (zig_u16)zig_byte_swap_u8((zig_u8)(val >> 8), 8) >> 0;
1030#endif
1031 return zig_wrap_u16(full_res >> (16 - bits), bits);
1032}
1033
1034static inline zig_i16 zig_byte_swap_i16(zig_i16 val, zig_u8 bits) {
1035 return zig_wrap_i16((zig_i16)zig_byte_swap_u16((zig_u16)val, bits), bits);
1036}
1037
1038static inline zig_u32 zig_byte_swap_u32(zig_u32 val, zig_u8 bits) {
1039 zig_u32 full_res;
1040#if zig_has_builtin(bswap32) || defined(zig_gnuc)
1041 full_res = __builtin_bswap32(val);
1042#else
1043 full_res = (zig_u32)zig_byte_swap_u16((zig_u16)(val >> 0), 16) << 16 |
1044 (zig_u32)zig_byte_swap_u16((zig_u16)(val >> 16), 16) >> 0;
1045#endif
1046 return zig_wrap_u32(full_res >> (32 - bits), bits);
1047}
1048
1049static inline zig_i32 zig_byte_swap_i32(zig_i32 val, zig_u8 bits) {
1050 return zig_wrap_i32((zig_i32)zig_byte_swap_u32((zig_u32)val, bits), bits);
1051}
1052
1053static inline zig_u64 zig_byte_swap_u64(zig_u64 val, zig_u8 bits) {
1054 zig_u64 full_res;
1055#if zig_has_builtin(bswap64) || defined(zig_gnuc)
1056 full_res = __builtin_bswap64(val);
1057#else
1058 full_res = (zig_u64)zig_byte_swap_u32((zig_u32)(val >> 0), 32) << 32 |
1059 (zig_u64)zig_byte_swap_u32((zig_u32)(val >> 32), 32) >> 0;
1060#endif
1061 return zig_wrap_u64(full_res >> (64 - bits), bits);
1062}
1063
1064static inline zig_i64 zig_byte_swap_i64(zig_i64 val, zig_u8 bits) {
1065 return zig_wrap_i64((zig_i64)zig_byte_swap_u64((zig_u64)val, bits), bits);
1066}
1067
1068static inline zig_u8 zig_bit_reverse_u8(zig_u8 val, zig_u8 bits) {
1069 zig_u8 full_res;
1070#if zig_has_builtin(bitreverse8)
1071 full_res = __builtin_bitreverse8(val);
1072#else
1073 static zig_u8 const lut[0x10] = {
1074 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
1075 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf
1076 };
1077 full_res = lut[val >> 0 & 0xF] << 4 | lut[val >> 4 & 0xF] << 0;
1078#endif
1079 return zig_wrap_u8(full_res >> (8 - bits), bits);
1080}
1081
1082static inline zig_i8 zig_bit_reverse_i8(zig_i8 val, zig_u8 bits) {
1083 return zig_wrap_i8((zig_i8)zig_bit_reverse_u8((zig_u8)val, bits), bits);
1084}
1085
1086static inline zig_u16 zig_bit_reverse_u16(zig_u16 val, zig_u8 bits) {
1087 zig_u16 full_res;
1088#if zig_has_builtin(bitreverse16)
1089 full_res = __builtin_bitreverse16(val);
1090#else
1091 full_res = (zig_u16)zig_bit_reverse_u8((zig_u8)(val >> 0), 8) << 8 |
1092 (zig_u16)zig_bit_reverse_u8((zig_u8)(val >> 8), 8) >> 0;
1093#endif
1094 return zig_wrap_u16(full_res >> (16 - bits), bits);
1095}
1096
1097static inline zig_i16 zig_bit_reverse_i16(zig_i16 val, zig_u8 bits) {
1098 return zig_wrap_i16((zig_i16)zig_bit_reverse_u16((zig_u16)val, bits), bits);
1099}
1100
1101static inline zig_u32 zig_bit_reverse_u32(zig_u32 val, zig_u8 bits) {
1102 zig_u32 full_res;
1103#if zig_has_builtin(bitreverse32)
1104 full_res = __builtin_bitreverse32(val);
1105#else
1106 full_res = (zig_u32)zig_bit_reverse_u16((zig_u16)(val >> 0), 16) << 16 |
1107 (zig_u32)zig_bit_reverse_u16((zig_u16)(val >> 16), 16) >> 0;
1108#endif
1109 return zig_wrap_u32(full_res >> (32 - bits), bits);
1110}
1111
1112static inline zig_i32 zig_bit_reverse_i32(zig_i32 val, zig_u8 bits) {
1113 return zig_wrap_i32((zig_i32)zig_bit_reverse_u32((zig_u32)val, bits), bits);
1114}
1115
1116static inline zig_u64 zig_bit_reverse_u64(zig_u64 val, zig_u8 bits) {
1117 zig_u64 full_res;
1118#if zig_has_builtin(bitreverse64)
1119 full_res = __builtin_bitreverse64(val);
1120#else
1121 full_res = (zig_u64)zig_bit_reverse_u32((zig_u32)(val >> 0), 32) << 32 |
1122 (zig_u64)zig_bit_reverse_u32((zig_u32)(val >> 32), 32) >> 0;
1123#endif
1124 return zig_wrap_u64(full_res >> (64 - bits), bits);
1125}
1126
1127static inline zig_i64 zig_bit_reverse_i64(zig_i64 val, zig_u8 bits) {
1128 return zig_wrap_i64((zig_i64)zig_bit_reverse_u64((zig_u64)val, bits), bits);
1129}
1130
1131#define zig_builtin_popcount_common(w) \
1132 static inline zig_u8 zig_popcount_i##w(zig_i##w val, zig_u8 bits) { \
1133 return zig_popcount_u##w((zig_u##w)val, bits); \
1134 }
1135#if zig_has_builtin(popcount) || defined(zig_gnuc)
1136#define zig_builtin_popcount(w) \
1137 static inline zig_u8 zig_popcount_u##w(zig_u##w val, zig_u8 bits) { \
1138 (void)bits; \
1139 return zig_builtin##w(popcount, val); \
1140 } \
1141\
1142 zig_builtin_popcount_common(w)
1143#else
1144#define zig_builtin_popcount(w) \
1145 static inline zig_u8 zig_popcount_u##w(zig_u##w val, zig_u8 bits) { \
1146 (void)bits; \
1147 zig_u##w temp = val - ((val >> 1) & (zig_maxInt_u##w / 3)); \
1148 temp = (temp & (zig_maxInt_u##w / 5)) + ((temp >> 2) & (zig_maxInt_u##w / 5)); \
1149 temp = (temp + (temp >> 4)) & (zig_maxInt_u##w / 17); \
1150 return temp * (zig_maxInt_u##w / 255) >> (w - 8); \
1151 } \
1152\
1153 zig_builtin_popcount_common(w)
1154#endif
1155zig_builtin_popcount(8)
1156zig_builtin_popcount(16)
1157zig_builtin_popcount(32)
1158zig_builtin_popcount(64)
1159
1160#define zig_builtin_ctz_common(w) \
1161 static inline zig_u8 zig_ctz_i##w(zig_i##w val, zig_u8 bits) { \
1162 return zig_ctz_u##w((zig_u##w)val, bits); \
1163 }
1164#if zig_has_builtin(ctz) || defined(zig_gnuc)
1165#define zig_builtin_ctz(w) \
1166 static inline zig_u8 zig_ctz_u##w(zig_u##w val, zig_u8 bits) { \
1167 if (val == 0) return bits; \
1168 return zig_builtin##w(ctz, val); \
1169 } \
1170\
1171 zig_builtin_ctz_common(w)
1172#else
1173#define zig_builtin_ctz(w) \
1174 static inline zig_u8 zig_ctz_u##w(zig_u##w val, zig_u8 bits) { \
1175 return zig_popcount_u##w(zig_not_u##w(val, bits) & zig_subw_u##w(val, 1, bits), bits); \
1176 } \
1177\
1178 zig_builtin_ctz_common(w)
1179#endif
1180zig_builtin_ctz(8)
1181zig_builtin_ctz(16)
1182zig_builtin_ctz(32)
1183zig_builtin_ctz(64)
1184
1185#define zig_builtin_clz_common(w) \
1186 static inline zig_u8 zig_clz_i##w(zig_i##w val, zig_u8 bits) { \
1187 return zig_clz_u##w((zig_u##w)val, bits); \
1188 }
1189#if zig_has_builtin(clz) || defined(zig_gnuc)
1190#define zig_builtin_clz(w) \
1191 static inline zig_u8 zig_clz_u##w(zig_u##w val, zig_u8 bits) { \
1192 if (val == 0) return bits; \
1193 return zig_builtin##w(clz, val) - (zig_bitSizeOf(zig_Builtin##w) - bits); \
1194 } \
1195\
1196 zig_builtin_clz_common(w)
1197#else
1198#define zig_builtin_clz(w) \
1199 static inline zig_u8 zig_clz_u##w(zig_u##w val, zig_u8 bits) { \
1200 return zig_ctz_u##w(zig_bit_reverse_u##w(val, bits), bits); \
1201 } \
1202\
1203 zig_builtin_clz_common(w)
1204#endif
1205zig_builtin_clz(8)
1206zig_builtin_clz(16)
1207zig_builtin_clz(32)
1208zig_builtin_clz(64)
1209
1210/* ======================== 128-bit Integer Routines ======================== */
1211
1212#if !defined(zig_has_int128)
1213# if defined(__SIZEOF_INT128__)
1214# define zig_has_int128 1
1215# else
1216# define zig_has_int128 0
1217# endif
1218#endif
1219
1220#if zig_has_int128
1221
1222typedef unsigned __int128 zig_u128;
1223typedef signed __int128 zig_i128;
1224
1225#define zig_as_u128(hi, lo) ((zig_u128)(hi)<<64|(lo))
1226#define zig_as_i128(hi, lo) ((zig_i128)zig_as_u128(hi, lo))
1227#define zig_as_constant_u128(hi, lo) zig_as_u128(hi, lo)
1228#define zig_as_constant_i128(hi, lo) zig_as_i128(hi, lo)
1229#define zig_hi_u128(val) ((zig_u64)((val) >> 64))
1230#define zig_lo_u128(val) ((zig_u64)((val) >> 0))
1231#define zig_hi_i128(val) ((zig_i64)((val) >> 64))
1232#define zig_lo_i128(val) ((zig_u64)((val) >> 0))
1233#define zig_bitcast_u128(val) ((zig_u128)(val))
1234#define zig_bitcast_i128(val) ((zig_i128)(val))
1235#define zig_cmp_int128(Type) \
1236 static inline zig_i32 zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \
1237 return (lhs > rhs) - (lhs < rhs); \
1238 }
1239#define zig_bit_int128(Type, operation, operator) \
1240 static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \
1241 return lhs operator rhs; \
1242 }
1243
1244#else /* zig_has_int128 */
1245
1246#if __LITTLE_ENDIAN__ || _MSC_VER
1247typedef struct { zig_align(16) zig_u64 lo; zig_u64 hi; } zig_u128;
1248typedef struct { zig_align(16) zig_u64 lo; zig_i64 hi; } zig_i128;
1249#else
1250typedef struct { zig_align(16) zig_u64 hi; zig_u64 lo; } zig_u128;
1251typedef struct { zig_align(16) zig_i64 hi; zig_u64 lo; } zig_i128;
1252#endif
1253
1254#define zig_as_u128(hi, lo) ((zig_u128){ .h##i = (hi), .l##o = (lo) })
1255#define zig_as_i128(hi, lo) ((zig_i128){ .h##i = (hi), .l##o = (lo) })
1256
1257#if _MSC_VER
1258#define zig_as_constant_u128(hi, lo) { .h##i = (hi), .l##o = (lo) }
1259#define zig_as_constant_i128(hi, lo) { .h##i = (hi), .l##o = (lo) }
1260#else
1261#define zig_as_constant_u128(hi, lo) zig_as_u128(hi, lo)
1262#define zig_as_constant_i128(hi, lo) zig_as_i128(hi, lo)
1263#endif
1264#define zig_hi_u128(val) ((val).hi)
1265#define zig_lo_u128(val) ((val).lo)
1266#define zig_hi_i128(val) ((val).hi)
1267#define zig_lo_i128(val) ((val).lo)
1268#define zig_bitcast_u128(val) zig_as_u128((zig_u64)(val).hi, (val).lo)
1269#define zig_bitcast_i128(val) zig_as_i128((zig_i64)(val).hi, (val).lo)
1270#define zig_cmp_int128(Type) \
1271 static inline zig_i32 zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \
1272 return (lhs.hi == rhs.hi) \
1273 ? (lhs.lo > rhs.lo) - (lhs.lo < rhs.lo) \
1274 : (lhs.hi > rhs.hi) - (lhs.hi < rhs.hi); \
1275 }
1276#define zig_bit_int128(Type, operation, operator) \
1277 static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \
1278 return (zig_##Type){ .hi = lhs.hi operator rhs.hi, .lo = lhs.lo operator rhs.lo }; \
1279 }
1280
1281#endif /* zig_has_int128 */
1282
1283#define zig_minInt_u128 zig_as_u128(zig_minInt_u64, zig_minInt_u64)
1284#define zig_maxInt_u128 zig_as_u128(zig_maxInt_u64, zig_maxInt_u64)
1285#define zig_minInt_i128 zig_as_i128(zig_minInt_i64, zig_minInt_u64)
1286#define zig_maxInt_i128 zig_as_i128(zig_maxInt_i64, zig_maxInt_u64)
1287
1288zig_cmp_int128(u128)
1289zig_cmp_int128(i128)
1290
1291zig_bit_int128(u128, and, &)
1292zig_bit_int128(i128, and, &)
1293
1294zig_bit_int128(u128, or, |)
1295zig_bit_int128(i128, or, |)
1296
1297zig_bit_int128(u128, xor, ^)
1298zig_bit_int128(i128, xor, ^)
1299
1300static inline zig_u128 zig_shr_u128(zig_u128 lhs, zig_u8 rhs);
1301
1302#if zig_has_int128
1303
1304static inline zig_u128 zig_not_u128(zig_u128 val, zig_u8 bits) {
1305 return val ^ zig_maxInt(u128, bits);
1306}
1307
1308static inline zig_i128 zig_not_i128(zig_i128 val, zig_u8 bits) {
1309 (void)bits;
1310 return ~val;
1311}
1312
1313static inline zig_u128 zig_shr_u128(zig_u128 lhs, zig_u8 rhs) {
1314 return lhs >> rhs;
1315}
1316
1317static inline zig_u128 zig_shl_u128(zig_u128 lhs, zig_u8 rhs) {
1318 return lhs << rhs;
1319}
1320
1321static inline zig_i128 zig_shl_i128(zig_i128 lhs, zig_u8 rhs) {
1322 return lhs << rhs;
1323}
1324
1325static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) {
1326 return lhs + rhs;
1327}
1328
1329static inline zig_i128 zig_add_i128(zig_i128 lhs, zig_i128 rhs) {
1330 return lhs + rhs;
1331}
1332
1333static inline zig_u128 zig_sub_u128(zig_u128 lhs, zig_u128 rhs) {
1334 return lhs - rhs;
1335}
1336
1337static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) {
1338 return lhs - rhs;
1339}
1340
1341static inline zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs) {
1342 return lhs * rhs;
1343}
1344
1345static inline zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) {
1346 return lhs * rhs;
1347}
1348
1349static inline zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) {
1350 return lhs / rhs;
1351}
1352
1353static inline zig_i128 zig_div_trunc_i128(zig_i128 lhs, zig_i128 rhs) {
1354 return lhs / rhs;
1355}
1356
1357static inline zig_u128 zig_rem_u128(zig_u128 lhs, zig_u128 rhs) {
1358 return lhs % rhs;
1359}
1360
1361static inline zig_i128 zig_rem_i128(zig_i128 lhs, zig_i128 rhs) {
1362 return lhs % rhs;
1363}
1364
1365static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) {
1366 return zig_div_trunc_i128(lhs, rhs) - (((lhs ^ rhs) & zig_rem_i128(lhs, rhs)) < zig_as_i128(0, 0));
1367}
1368
1369static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) {
1370 zig_i128 rem = zig_rem_i128(lhs, rhs);
1371 return rem + (((lhs ^ rhs) & rem) < zig_as_i128(0, 0) ? rhs : zig_as_i128(0, 0));
1372}
1373
1374#else /* zig_has_int128 */
1375
1376static inline zig_u128 zig_not_u128(zig_u128 val, zig_u8 bits) {
1377 return (zig_u128){ .hi = zig_not_u64(val.hi, bits - zig_as_u8(64)), .lo = zig_not_u64(val.lo, zig_as_u8(64)) };
1378}
1379
1380static inline zig_i128 zig_not_i128(zig_i128 val, zig_u8 bits) {
1381 return (zig_i128){ .hi = zig_not_i64(val.hi, bits - zig_as_u8(64)), .lo = zig_not_u64(val.lo, zig_as_u8(64)) };
1382}
1383
1384static inline zig_u128 zig_shr_u128(zig_u128 lhs, zig_u8 rhs) {
1385 if (rhs == zig_as_u8(0)) return lhs;
1386 if (rhs >= zig_as_u8(64)) return (zig_u128){ .hi = zig_minInt_u64, .lo = lhs.hi >> (rhs - zig_as_u8(64)) };
1387 return (zig_u128){ .hi = lhs.hi >> rhs, .lo = lhs.hi << (zig_as_u8(64) - rhs) | lhs.lo >> rhs };
1388}
1389
1390static inline zig_u128 zig_shl_u128(zig_u128 lhs, zig_u8 rhs) {
1391 if (rhs == zig_as_u8(0)) return lhs;
1392 if (rhs >= zig_as_u8(64)) return (zig_u128){ .hi = lhs.lo << (rhs - zig_as_u8(64)), .lo = zig_minInt_u64 };
1393 return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs };
1394}
1395
1396static inline zig_i128 zig_shl_i128(zig_i128 lhs, zig_u8 rhs) {
1397 if (rhs == zig_as_u8(0)) return lhs;
1398 if (rhs >= zig_as_u8(64)) return (zig_i128){ .hi = lhs.lo << (rhs - zig_as_u8(64)), .lo = zig_minInt_u64 };
1399 return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs };
1400}
1401
1402static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) {
1403 zig_u128 res;
1404 res.hi = lhs.hi + rhs.hi + zig_addo_u64(&res.lo, lhs.lo, rhs.lo, 64);
1405 return res;
1406}
1407
1408static inline zig_i128 zig_add_i128(zig_i128 lhs, zig_i128 rhs) {
1409 zig_i128 res;
1410 res.hi = lhs.hi + rhs.hi + zig_addo_u64(&res.lo, lhs.lo, rhs.lo, 64);
1411 return res;
1412}
1413
1414static inline zig_u128 zig_sub_u128(zig_u128 lhs, zig_u128 rhs) {
1415 zig_u128 res;
1416 res.hi = lhs.hi - rhs.hi - zig_subo_u64(&res.lo, lhs.lo, rhs.lo, 64);
1417 return res;
1418}
1419
1420static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) {
1421 zig_i128 res;
1422 res.hi = lhs.hi - rhs.hi - zig_subo_u64(&res.lo, lhs.lo, rhs.lo, 64);
1423 return res;
1424}
1425
1426zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs);
1427static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs) {
1428 return zig_bitcast_u128(__multi3(zig_bitcast_i128(lhs), zig_bitcast_i128(rhs)));
1429}
1430
1431static zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) {
1432 return __multi3(lhs, rhs);
1433}
1434
1435zig_extern zig_u128 __udivti3(zig_u128 lhs, zig_u128 rhs);
1436static zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) {
1437 return __udivti3(lhs, rhs);
1438};
1439
1440zig_extern zig_i128 __divti3(zig_i128 lhs, zig_i128 rhs);
1441static zig_i128 zig_div_trunc_i128(zig_i128 lhs, zig_i128 rhs) {
1442 return __divti3(lhs, rhs);
1443};
1444
1445zig_extern zig_u128 __umodti3(zig_u128 lhs, zig_u128 rhs);
1446static zig_u128 zig_rem_u128(zig_u128 lhs, zig_u128 rhs) {
1447 return __umodti3(lhs, rhs);
1448}
1449
1450zig_extern zig_i128 __modti3(zig_i128 lhs, zig_i128 rhs);
1451static zig_i128 zig_rem_i128(zig_i128 lhs, zig_i128 rhs) {
1452 return __modti3(lhs, rhs);
1453}
1454
1455static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) {
1456 zig_i128 rem = zig_rem_i128(lhs, rhs);
1457 return zig_add_i128(rem, (((lhs.hi ^ rhs.hi) & rem.hi) < zig_as_i64(0) ? rhs : zig_as_i128(0, 0)));
1458}
1459
1460static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) {
1461 return zig_sub_i128(zig_div_trunc_i128(lhs, rhs), zig_as_i128(0, zig_cmp_i128(zig_and_i128(zig_xor_i128(lhs, rhs), zig_rem_i128(lhs, rhs)), zig_as_i128(0, 0)) < zig_as_i32(0)));
1462}
1463
1464#endif /* zig_has_int128 */
1465
1466#define zig_div_floor_u128 zig_div_trunc_u128
1467#define zig_mod_u128 zig_rem_u128
1468
1469static inline zig_u128 zig_nand_u128(zig_u128 lhs, zig_u128 rhs) {
1470 return zig_not_u128(zig_and_u128(lhs, rhs), 128);
1471}
1472
1473static inline zig_u128 zig_min_u128(zig_u128 lhs, zig_u128 rhs) {
1474 return zig_cmp_u128(lhs, rhs) < zig_as_i32(0) ? lhs : rhs;
1475}
1476
1477static inline zig_i128 zig_min_i128(zig_i128 lhs, zig_i128 rhs) {
1478 return zig_cmp_i128(lhs, rhs) < zig_as_i32(0) ? lhs : rhs;
1479}
1480
1481static inline zig_u128 zig_max_u128(zig_u128 lhs, zig_u128 rhs) {
1482 return zig_cmp_u128(lhs, rhs) > zig_as_i32(0) ? lhs : rhs;
1483}
1484
1485static inline zig_i128 zig_max_i128(zig_i128 lhs, zig_i128 rhs) {
1486 return zig_cmp_i128(lhs, rhs) > zig_as_i32(0) ? lhs : rhs;
1487}
1488
1489static inline zig_i128 zig_shr_i128(zig_i128 lhs, zig_u8 rhs) {
1490 zig_i128 sign_mask = zig_cmp_i128(lhs, zig_as_i128(0, 0)) < zig_as_i32(0) ? zig_sub_i128(zig_as_i128(0, 0), zig_as_i128(0, 1)) : zig_as_i128(0, 0);
1491 return zig_xor_i128(zig_bitcast_i128(zig_shr_u128(zig_bitcast_u128(zig_xor_i128(lhs, sign_mask)), rhs)), sign_mask);
1492}
1493
1494static inline zig_u128 zig_wrap_u128(zig_u128 val, zig_u8 bits) {
1495 return zig_and_u128(val, zig_maxInt(u128, bits));
1496}
1497
1498static inline zig_i128 zig_wrap_i128(zig_i128 val, zig_u8 bits) {
1499 return zig_as_i128(zig_wrap_i64(zig_hi_i128(val), bits - zig_as_u8(64)), zig_lo_i128(val));
1500}
1501
1502static inline zig_u128 zig_shlw_u128(zig_u128 lhs, zig_u8 rhs, zig_u8 bits) {
1503 return zig_wrap_u128(zig_shl_u128(lhs, rhs), bits);
1504}
1505
1506static inline zig_i128 zig_shlw_i128(zig_i128 lhs, zig_u8 rhs, zig_u8 bits) {
1507 return zig_wrap_i128(zig_bitcast_i128(zig_shl_u128(zig_bitcast_u128(lhs), rhs)), bits);
1508}
1509
1510static inline zig_u128 zig_addw_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1511 return zig_wrap_u128(zig_add_u128(lhs, rhs), bits);
1512}
1513
1514static inline zig_i128 zig_addw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1515 return zig_wrap_i128(zig_bitcast_i128(zig_add_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits);
1516}
1517
1518static inline zig_u128 zig_subw_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1519 return zig_wrap_u128(zig_sub_u128(lhs, rhs), bits);
1520}
1521
1522static inline zig_i128 zig_subw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1523 return zig_wrap_i128(zig_bitcast_i128(zig_sub_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits);
1524}
1525
1526static inline zig_u128 zig_mulw_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1527 return zig_wrap_u128(zig_mul_u128(lhs, rhs), bits);
1528}
1529
1530static inline zig_i128 zig_mulw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1531 return zig_wrap_i128(zig_bitcast_i128(zig_mul_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits);
1532}
1533
1534#if zig_has_int128
1535
1536static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1537#if zig_has_builtin(add_overflow)
1538 zig_u128 full_res;
1539 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);
1540 *res = zig_wrap_u128(full_res, bits);
1541 return overflow || full_res < zig_minInt(u128, bits) || full_res > zig_maxInt(u128, bits);
1542#else
1543 *res = zig_addw_u128(lhs, rhs, bits);
1544 return *res < lhs;
1545#endif
1546}
1547
1548zig_extern zig_i128 __addoti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow);
1549static inline bool zig_addo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1550#if zig_has_builtin(add_overflow)
1551 zig_i128 full_res;
1552 bool overflow = __builtin_add_overflow(lhs, rhs, &full_res);
1553#else
1554 zig_c_int overflow_int;
1555 zig_i128 full_res = __addoti4(lhs, rhs, &overflow_int);
1556 bool overflow = overflow_int != 0;
1557#endif
1558 *res = zig_wrap_i128(full_res, bits);
1559 return overflow || full_res < zig_minInt(i128, bits) || full_res > zig_maxInt(i128, bits);
1560}
1561
1562static inline bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1563#if zig_has_builtin(sub_overflow)
1564 zig_u128 full_res;
1565 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);
1566 *res = zig_wrap_u128(full_res, bits);
1567 return overflow || full_res < zig_minInt(u128, bits) || full_res > zig_maxInt(u128, bits);
1568#else
1569 *res = zig_subw_u128(lhs, rhs, bits);
1570 return *res > lhs;
1571#endif
1572}
1573
1574zig_extern zig_i128 __suboti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow);
1575static inline bool zig_subo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1576#if zig_has_builtin(sub_overflow)
1577 zig_i128 full_res;
1578 bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res);
1579#else
1580 zig_c_int overflow_int;
1581 zig_i128 full_res = __suboti4(lhs, rhs, &overflow_int);
1582 bool overflow = overflow_int != 0;
1583#endif
1584 *res = zig_wrap_i128(full_res, bits);
1585 return overflow || full_res < zig_minInt(i128, bits) || full_res > zig_maxInt(i128, bits);
1586}
1587
1588static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1589#if zig_has_builtin(mul_overflow)
1590 zig_u128 full_res;
1591 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);
1592 *res = zig_wrap_u128(full_res, bits);
1593 return overflow || full_res < zig_minInt(u128, bits) || full_res > zig_maxInt(u128, bits);
1594#else
1595 *res = zig_mulw_u128(lhs, rhs, bits);
1596 return rhs != zig_as_u128(0, 0) && lhs > zig_maxInt(u128, bits) / rhs;
1597#endif
1598}
1599
1600zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow);
1601static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1602#if zig_has_builtin(mul_overflow)
1603 zig_i128 full_res;
1604 bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res);
1605#else
1606 zig_c_int overflow_int;
1607 zig_i128 full_res = __muloti4(lhs, rhs, &overflow_int);
1608 bool overflow = overflow_int != 0;
1609#endif
1610 *res = zig_wrap_i128(full_res, bits);
1611 return overflow || full_res < zig_minInt(i128, bits) || full_res > zig_maxInt(i128, bits);
1612}
1613
1614#else /* zig_has_int128 */
1615
1616static inline bool zig_overflow_u128(bool overflow, zig_u128 full_res, zig_u8 bits) {
1617 return overflow ||
1618 zig_cmp_u128(full_res, zig_minInt(u128, bits)) < zig_as_i32(0) ||
1619 zig_cmp_u128(full_res, zig_maxInt(u128, bits)) > zig_as_i32(0);
1620}
1621
1622static inline bool zig_overflow_i128(bool overflow, zig_i128 full_res, zig_u8 bits) {
1623 return overflow ||
1624 zig_cmp_i128(full_res, zig_minInt(i128, bits)) < zig_as_i32(0) ||
1625 zig_cmp_i128(full_res, zig_maxInt(i128, bits)) > zig_as_i32(0);
1626}
1627
1628static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1629 zig_u128 full_res;
1630 bool overflow =
1631 zig_addo_u64(&full_res.hi, lhs.hi, rhs.hi, 64) |
1632 zig_addo_u64(&full_res.hi, full_res.hi, zig_addo_u64(&full_res.lo, lhs.lo, rhs.lo, 64), 64);
1633 *res = zig_wrap_u128(full_res, bits);
1634 return zig_overflow_u128(overflow, full_res, bits);
1635}
1636
1637zig_extern zig_i128 __addoti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow);
1638static inline bool zig_addo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1639 zig_c_int overflow_int;
1640 zig_i128 full_res = __addoti4(lhs, rhs, &overflow_int);
1641 *res = zig_wrap_i128(full_res, bits);
1642 return zig_overflow_i128(overflow_int, full_res, bits);
1643}
1644
1645static inline bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1646 zig_u128 full_res;
1647 bool overflow =
1648 zig_subo_u64(&full_res.hi, lhs.hi, rhs.hi, 64) |
1649 zig_subo_u64(&full_res.hi, full_res.hi, zig_subo_u64(&full_res.lo, lhs.lo, rhs.lo, 64), 64);
1650 *res = zig_wrap_u128(full_res, bits);
1651 return zig_overflow_u128(overflow, full_res, bits);
1652}
1653
1654zig_extern zig_i128 __suboti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow);
1655static inline bool zig_subo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1656 zig_c_int overflow_int;
1657 zig_i128 full_res = __suboti4(lhs, rhs, &overflow_int);
1658 *res = zig_wrap_i128(full_res, bits);
1659 return zig_overflow_i128(overflow_int, full_res, bits);
1660}
1661
1662static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1663 *res = zig_mulw_u128(lhs, rhs, bits);
1664 return zig_cmp_u128(*res, zig_as_u128(0, 0)) != zig_as_i32(0) &&
1665 zig_cmp_u128(lhs, zig_div_trunc_u128(zig_maxInt(u128, bits), rhs)) > zig_as_i32(0);
1666}
1667
1668zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow);
1669static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1670 zig_c_int overflow_int;
1671 zig_i128 full_res = __muloti4(lhs, rhs, &overflow_int);
1672 *res = zig_wrap_i128(full_res, bits);
1673 return zig_overflow_i128(overflow_int, full_res, bits);
1674}
1675
1676#endif /* zig_has_int128 */
1677
1678static inline bool zig_shlo_u128(zig_u128 *res, zig_u128 lhs, zig_u8 rhs, zig_u8 bits) {
1679 *res = zig_shlw_u128(lhs, rhs, bits);
1680 return zig_cmp_u128(lhs, zig_shr_u128(zig_maxInt(u128, bits), rhs)) > zig_as_i32(0);
1681}
1682
1683static inline bool zig_shlo_i128(zig_i128 *res, zig_i128 lhs, zig_u8 rhs, zig_u8 bits) {
1684 *res = zig_shlw_i128(lhs, rhs, bits);
1685 zig_i128 mask = zig_bitcast_i128(zig_shl_u128(zig_maxInt_u128, bits - rhs - zig_as_u8(1)));
1686 return zig_cmp_i128(zig_and_i128(lhs, mask), zig_as_i128(0, 0)) != zig_as_i32(0) &&
1687 zig_cmp_i128(zig_and_i128(lhs, mask), mask) != zig_as_i32(0);
1688}
1689
1690static inline zig_u128 zig_shls_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1691 zig_u128 res;
1692 if (zig_cmp_u128(rhs, zig_as_u128(0, bits)) >= zig_as_i32(0))
1693 return zig_cmp_u128(lhs, zig_as_u128(0, 0)) != zig_as_i32(0) ? zig_maxInt(u128, bits) : lhs;
1694
1695#if zig_has_int128
1696 return zig_shlo_u128(&res, lhs, (zig_u8)rhs, bits) ? zig_maxInt(u128, bits) : res;
1697#else
1698 return zig_shlo_u128(&res, lhs, (zig_u8)rhs.lo, bits) ? zig_maxInt(u128, bits) : res;
1699#endif
1700}
1701
1702static inline zig_i128 zig_shls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1703 zig_i128 res;
1704 if (zig_cmp_u128(zig_bitcast_u128(rhs), zig_as_u128(0, bits)) < zig_as_i32(0) && !zig_shlo_i128(&res, lhs, zig_lo_i128(rhs), bits)) return res;
1705 return zig_cmp_i128(lhs, zig_as_i128(0, 0)) < zig_as_i32(0) ? zig_minInt(i128, bits) : zig_maxInt(i128, bits);
1706}
1707
1708static inline zig_u128 zig_adds_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1709 zig_u128 res;
1710 return zig_addo_u128(&res, lhs, rhs, bits) ? zig_maxInt(u128, bits) : res;
1711}
1712
1713static inline zig_i128 zig_adds_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1714 zig_i128 res;
1715 if (!zig_addo_i128(&res, lhs, rhs, bits)) return res;
1716 return zig_cmp_i128(res, zig_as_i128(0, 0)) >= zig_as_i32(0) ? zig_minInt(i128, bits) : zig_maxInt(i128, bits);
1717}
1718
1719static inline zig_u128 zig_subs_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1720 zig_u128 res;
1721 return zig_subo_u128(&res, lhs, rhs, bits) ? zig_minInt(u128, bits) : res;
1722}
1723
1724static inline zig_i128 zig_subs_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1725 zig_i128 res;
1726 if (!zig_subo_i128(&res, lhs, rhs, bits)) return res;
1727 return zig_cmp_i128(res, zig_as_i128(0, 0)) >= zig_as_i32(0) ? zig_minInt(i128, bits) : zig_maxInt(i128, bits);
1728}
1729
1730static inline zig_u128 zig_muls_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) {
1731 zig_u128 res;
1732 return zig_mulo_u128(&res, lhs, rhs, bits) ? zig_maxInt(u128, bits) : res;
1733}
1734
1735static inline zig_i128 zig_muls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
1736 zig_i128 res;
1737 if (!zig_mulo_i128(&res, lhs, rhs, bits)) return res;
1738 return zig_cmp_i128(zig_xor_i128(lhs, rhs), zig_as_i128(0, 0)) < zig_as_i32(0) ? zig_minInt(i128, bits) : zig_maxInt(i128, bits);
1739}
1740
1741static inline zig_u8 zig_clz_u128(zig_u128 val, zig_u8 bits) {
1742 if (bits <= zig_as_u8(64)) return zig_clz_u64(zig_lo_u128(val), bits);
1743 if (zig_hi_u128(val) != 0) return zig_clz_u64(zig_hi_u128(val), bits - zig_as_u8(64));
1744 return zig_clz_u64(zig_lo_u128(val), zig_as_u8(64)) + (bits - zig_as_u8(64));
1745}
1746
1747static inline zig_u8 zig_clz_i128(zig_i128 val, zig_u8 bits) {
1748 return zig_clz_u128(zig_bitcast_u128(val), bits);
1749}
1750
1751static inline zig_u8 zig_ctz_u128(zig_u128 val, zig_u8 bits) {
1752 if (zig_lo_u128(val) != 0) return zig_ctz_u64(zig_lo_u128(val), zig_as_u8(64));
1753 return zig_ctz_u64(zig_hi_u128(val), bits - zig_as_u8(64)) + zig_as_u8(64);
1754}
1755
1756static inline zig_u8 zig_ctz_i128(zig_i128 val, zig_u8 bits) {
1757 return zig_ctz_u128(zig_bitcast_u128(val), bits);
1758}
1759
1760static inline zig_u8 zig_popcount_u128(zig_u128 val, zig_u8 bits) {
1761 return zig_popcount_u64(zig_hi_u128(val), bits - zig_as_u8(64)) +
1762 zig_popcount_u64(zig_lo_u128(val), zig_as_u8(64));
1763}
1764
1765static inline zig_u8 zig_popcount_i128(zig_i128 val, zig_u8 bits) {
1766 return zig_popcount_u128(zig_bitcast_u128(val), bits);
1767}
1768
1769static inline zig_u128 zig_byte_swap_u128(zig_u128 val, zig_u8 bits) {
1770 zig_u128 full_res;
1771#if zig_has_builtin(bswap128)
1772 full_res = __builtin_bswap128(val);
1773#else
1774 full_res = zig_as_u128(zig_byte_swap_u64(zig_lo_u128(val), zig_as_u8(64)),
1775 zig_byte_swap_u64(zig_hi_u128(val), zig_as_u8(64)));
1776#endif
1777 return zig_shr_u128(full_res, zig_as_u8(128) - bits);
1778}
1779
1780static inline zig_i128 zig_byte_swap_i128(zig_i128 val, zig_u8 bits) {
1781 return zig_bitcast_i128(zig_byte_swap_u128(zig_bitcast_u128(val), bits));
1782}
1783
1784static inline zig_u128 zig_bit_reverse_u128(zig_u128 val, zig_u8 bits) {
1785 return zig_shr_u128(zig_as_u128(zig_bit_reverse_u64(zig_lo_u128(val), zig_as_u8(64)),
1786 zig_bit_reverse_u64(zig_hi_u128(val), zig_as_u8(64))),
1787 zig_as_u8(128) - bits);
1788}
1789
1790static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, zig_u8 bits) {
1791 return zig_bitcast_i128(zig_bit_reverse_u128(zig_bitcast_u128(val), bits));
1792}
1793
1794/* ========================= Floating Point Support ========================= */
1795
1796#if _MSC_VER
1797#define zig_msvc_flt_inf ((double)(1e+300 * 1e+300))
1798#define zig_msvc_flt_inff ((float)(1e+300 * 1e+300))
1799#define zig_msvc_flt_infl ((long double)(1e+300 * 1e+300))
1800#define zig_msvc_flt_nan ((double)(zig_msvc_flt_inf * 0.f))
1801#define zig_msvc_flt_nanf ((float)(zig_msvc_flt_inf * 0.f))
1802#define zig_msvc_flt_nanl ((long double)(zig_msvc_flt_inf * 0.f))
1803#define __builtin_nan(str) nan(str)
1804#define __builtin_nanf(str) nanf(str)
1805#define __builtin_nanl(str) nanl(str)
1806#define __builtin_inf() zig_msvc_flt_inf
1807#define __builtin_inff() zig_msvc_flt_inff
1808#define __builtin_infl() zig_msvc_flt_infl
1809#endif
1810
1811#if (zig_has_builtin(nan) && zig_has_builtin(nans) && zig_has_builtin(inf)) || defined(zig_gnuc)
1812#define zig_has_float_builtins 1
1813#define zig_as_special_f16(sign, name, arg, repr) sign zig_as_f16(__builtin_##name, )(arg)
1814#define zig_as_special_f32(sign, name, arg, repr) sign zig_as_f32(__builtin_##name, )(arg)
1815#define zig_as_special_f64(sign, name, arg, repr) sign zig_as_f64(__builtin_##name, )(arg)
1816#define zig_as_special_f80(sign, name, arg, repr) sign zig_as_f80(__builtin_##name, )(arg)
1817#define zig_as_special_f128(sign, name, arg, repr) sign zig_as_f128(__builtin_##name, )(arg)
1818#define zig_as_special_c_longdouble(sign, name, arg, repr) sign zig_as_c_longdouble(__builtin_##name, )(arg)
1819#else
1820#define zig_has_float_builtins 0
1821#define zig_as_special_f16(sign, name, arg, repr) zig_float_from_repr_f16(repr)
1822#define zig_as_special_f32(sign, name, arg, repr) zig_float_from_repr_f32(repr)
1823#define zig_as_special_f64(sign, name, arg, repr) zig_float_from_repr_f64(repr)
1824#define zig_as_special_f80(sign, name, arg, repr) zig_float_from_repr_f80(repr)
1825#define zig_as_special_f128(sign, name, arg, repr) zig_float_from_repr_f128(repr)
1826#define zig_as_special_c_longdouble(sign, name, arg, repr) zig_float_from_repr_c_longdouble(repr)
1827#endif
1828
1829#define zig_has_f16 1
1830#define zig_bitSizeOf_f16 16
1831#define zig_libc_name_f16(name) __##name##h
1832#define zig_as_special_constant_f16(sign, name, arg, repr) zig_as_special_f16(sign, name, arg, repr)
1833#if FLT_MANT_DIG == 11
1834typedef float zig_f16;
1835#define zig_as_f16(fp, repr) fp##f
1836#elif DBL_MANT_DIG == 11
1837typedef double zig_f16;
1838#define zig_as_f16(fp, repr) fp
1839#elif LDBL_MANT_DIG == 11
1840#define zig_bitSizeOf_c_longdouble 16
1841typedef long double zig_f16;
1842#define zig_as_f16(fp, repr) fp##l
1843#elif FLT16_MANT_DIG == 11 && (zig_has_builtin(inff16) || defined(zig_gnuc))
1844typedef _Float16 zig_f16;
1845#define zig_as_f16(fp, repr) fp##f16
1846#elif defined(__SIZEOF_FP16__)
1847typedef __fp16 zig_f16;
1848#define zig_as_f16(fp, repr) fp##f16
1849#else
1850#undef zig_has_f16
1851#define zig_has_f16 0
1852#define zig_repr_f16 i16
1853typedef zig_i16 zig_f16;
1854#define zig_as_f16(fp, repr) repr
1855#undef zig_as_special_f16
1856#define zig_as_special_f16(sign, name, arg, repr) repr
1857#undef zig_as_special_constant_f16
1858#define zig_as_special_constant_f16(sign, name, arg, repr) repr
1859#endif
1860
1861#define zig_has_f32 1
1862#define zig_bitSizeOf_f32 32
1863#define zig_libc_name_f32(name) name##f
1864#if _MSC_VER
1865#define zig_as_special_constant_f32(sign, name, arg, repr) sign zig_as_f32(zig_msvc_flt_##name, )
1866#else
1867#define zig_as_special_constant_f32(sign, name, arg, repr) zig_as_special_f32(sign, name, arg, repr)
1868#endif
1869#if FLT_MANT_DIG == 24
1870typedef float zig_f32;
1871#define zig_as_f32(fp, repr) fp##f
1872#elif DBL_MANT_DIG == 24
1873typedef double zig_f32;
1874#define zig_as_f32(fp, repr) fp
1875#elif LDBL_MANT_DIG == 24
1876#define zig_bitSizeOf_c_longdouble 32
1877typedef long double zig_f32;
1878#define zig_as_f32(fp, repr) fp##l
1879#elif FLT32_MANT_DIG == 24
1880typedef _Float32 zig_f32;
1881#define zig_as_f32(fp, repr) fp##f32
1882#else
1883#undef zig_has_f32
1884#define zig_has_f32 0
1885#define zig_repr_f32 i32
1886typedef zig_i32 zig_f32;
1887#define zig_as_f32(fp, repr) repr
1888#undef zig_as_special_f32
1889#define zig_as_special_f32(sign, name, arg, repr) repr
1890#undef zig_as_special_constant_f32
1891#define zig_as_special_constant_f32(sign, name, arg, repr) repr
1892#endif
1893
1894#define zig_has_f64 1
1895#define zig_bitSizeOf_f64 64
1896#define zig_libc_name_f64(name) name
1897#if _MSC_VER
1898#ifdef ZIG_TARGET_ABI_MSVC
1899#define zig_bitSizeOf_c_longdouble 64
1900#endif
1901#define zig_as_special_constant_f64(sign, name, arg, repr) sign zig_as_f64(zig_msvc_flt_##name, )
1902#else /* _MSC_VER */
1903#define zig_as_special_constant_f64(sign, name, arg, repr) zig_as_special_f64(sign, name, arg, repr)
1904#endif /* _MSC_VER */
1905#if FLT_MANT_DIG == 53
1906typedef float zig_f64;
1907#define zig_as_f64(fp, repr) fp##f
1908#elif DBL_MANT_DIG == 53
1909typedef double zig_f64;
1910#define zig_as_f64(fp, repr) fp
1911#elif LDBL_MANT_DIG == 53
1912#define zig_bitSizeOf_c_longdouble 64
1913typedef long double zig_f64;
1914#define zig_as_f64(fp, repr) fp##l
1915#elif FLT64_MANT_DIG == 53
1916typedef _Float64 zig_f64;
1917#define zig_as_f64(fp, repr) fp##f64
1918#elif FLT32X_MANT_DIG == 53
1919typedef _Float32x zig_f64;
1920#define zig_as_f64(fp, repr) fp##f32x
1921#else
1922#undef zig_has_f64
1923#define zig_has_f64 0
1924#define zig_repr_f64 i64
1925typedef zig_i64 zig_f64;
1926#define zig_as_f64(fp, repr) repr
1927#undef zig_as_special_f64
1928#define zig_as_special_f64(sign, name, arg, repr) repr
1929#undef zig_as_special_constant_f64
1930#define zig_as_special_constant_f64(sign, name, arg, repr) repr
1931#endif
1932
1933#define zig_has_f80 1
1934#define zig_bitSizeOf_f80 80
1935#define zig_libc_name_f80(name) __##name##x
1936#define zig_as_special_constant_f80(sign, name, arg, repr) zig_as_special_f80(sign, name, arg, repr)
1937#if FLT_MANT_DIG == 64
1938typedef float zig_f80;
1939#define zig_as_f80(fp, repr) fp##f
1940#elif DBL_MANT_DIG == 64
1941typedef double zig_f80;
1942#define zig_as_f80(fp, repr) fp
1943#elif LDBL_MANT_DIG == 64
1944#define zig_bitSizeOf_c_longdouble 80
1945typedef long double zig_f80;
1946#define zig_as_f80(fp, repr) fp##l
1947#elif FLT80_MANT_DIG == 64
1948typedef _Float80 zig_f80;
1949#define zig_as_f80(fp, repr) fp##f80
1950#elif FLT64X_MANT_DIG == 64
1951typedef _Float64x zig_f80;
1952#define zig_as_f80(fp, repr) fp##f64x
1953#elif defined(__SIZEOF_FLOAT80__)
1954typedef __float80 zig_f80;
1955#define zig_as_f80(fp, repr) fp##l
1956#else
1957#undef zig_has_f80
1958#define zig_has_f80 0
1959#define zig_repr_f80 i128
1960typedef zig_i128 zig_f80;
1961#define zig_as_f80(fp, repr) repr
1962#undef zig_as_special_f80
1963#define zig_as_special_f80(sign, name, arg, repr) repr
1964#undef zig_as_special_constant_f80
1965#define zig_as_special_constant_f80(sign, name, arg, repr) repr
1966#endif
1967
1968#define zig_has_f128 1
1969#define zig_bitSizeOf_f128 128
1970#define zig_libc_name_f128(name) name##q
1971#define zig_as_special_constant_f128(sign, name, arg, repr) zig_as_special_f128(sign, name, arg, repr)
1972#if FLT_MANT_DIG == 113
1973typedef float zig_f128;
1974#define zig_as_f128(fp, repr) fp##f
1975#elif DBL_MANT_DIG == 113
1976typedef double zig_f128;
1977#define zig_as_f128(fp, repr) fp
1978#elif LDBL_MANT_DIG == 113
1979#define zig_bitSizeOf_c_longdouble 128
1980typedef long double zig_f128;
1981#define zig_as_f128(fp, repr) fp##l
1982#elif FLT128_MANT_DIG == 113
1983typedef _Float128 zig_f128;
1984#define zig_as_f128(fp, repr) fp##f128
1985#elif FLT64X_MANT_DIG == 113
1986typedef _Float64x zig_f128;
1987#define zig_as_f128(fp, repr) fp##f64x
1988#elif defined(__SIZEOF_FLOAT128__)
1989typedef __float128 zig_f128;
1990#define zig_as_f128(fp, repr) fp##q
1991#undef zig_as_special_f128
1992#define zig_as_special_f128(sign, name, arg, repr) sign __builtin_##name##f128(arg)
1993#else
1994#undef zig_has_f128
1995#define zig_has_f128 0
1996#define zig_repr_f128 i128
1997typedef zig_i128 zig_f128;
1998#define zig_as_f128(fp, repr) repr
1999#undef zig_as_special_f128
2000#define zig_as_special_f128(sign, name, arg, repr) repr
2001#undef zig_as_special_constant_f128
2002#define zig_as_special_constant_f128(sign, name, arg, repr) repr
2003#endif
2004
2005#define zig_has_c_longdouble 1
2006
2007#ifdef ZIG_TARGET_ABI_MSVC
2008#define zig_libc_name_c_longdouble(name) name
2009#else
2010#define zig_libc_name_c_longdouble(name) name##l
2011#endif
2012
2013#define zig_as_special_constant_c_longdouble(sign, name, arg, repr) zig_as_special_c_longdouble(sign, name, arg, repr)
2014#ifdef zig_bitSizeOf_c_longdouble
2015
2016#ifdef ZIG_TARGET_ABI_MSVC
2017typedef double zig_c_longdouble;
2018#undef zig_bitSizeOf_c_longdouble
2019#define zig_bitSizeOf_c_longdouble 64
2020#define zig_as_c_longdouble(fp, repr) fp
2021#else
2022typedef long double zig_c_longdouble;
2023#define zig_as_c_longdouble(fp, repr) fp##l
2024#endif
2025
2026#else /* zig_bitSizeOf_c_longdouble */
2027
2028#undef zig_has_c_longdouble
2029#define zig_has_c_longdouble 0
2030#define zig_bitSizeOf_c_longdouble 80
2031#define zig_compiler_rt_abbrev_c_longdouble zig_compiler_rt_abbrev_f80
2032#define zig_repr_c_longdouble i128
2033typedef zig_i128 zig_c_longdouble;
2034#define zig_as_c_longdouble(fp, repr) repr
2035#undef zig_as_special_c_longdouble
2036#define zig_as_special_c_longdouble(sign, name, arg, repr) repr
2037#undef zig_as_special_constant_c_longdouble
2038#define zig_as_special_constant_c_longdouble(sign, name, arg, repr) repr
2039
2040#endif /* zig_bitSizeOf_c_longdouble */
2041
2042#if !zig_has_float_builtins
2043#define zig_float_from_repr(Type, ReprType) \
2044 static inline zig_##Type zig_float_from_repr_##Type(zig_##ReprType repr) { \
2045 return *((zig_##Type*)&repr); \
2046 }
2047
2048zig_float_from_repr(f16, u16)
2049zig_float_from_repr(f32, u32)
2050zig_float_from_repr(f64, u64)
2051zig_float_from_repr(f80, u128)
2052zig_float_from_repr(f128, u128)
2053#if zig_bitSizeOf_c_longdouble == 80
2054zig_float_from_repr(c_longdouble, u128)
2055#else
2056#define zig_expand_float_from_repr(Type, ReprType) zig_float_from_repr(Type, ReprType)
2057zig_expand_float_from_repr(c_longdouble, zig_expand_concat(u, zig_bitSizeOf_c_longdouble))
2058#endif
2059#endif
2060
2061#define zig_cast_f16 (zig_f16)
2062#define zig_cast_f32 (zig_f32)
2063#define zig_cast_f64 (zig_f64)
2064
2065#if _MSC_VER && !zig_has_f128
2066#define zig_cast_f80
2067#define zig_cast_c_longdouble
2068#define zig_cast_f128
2069#else
2070#define zig_cast_f80 (zig_f80)
2071#define zig_cast_c_longdouble (zig_c_longdouble)
2072#define zig_cast_f128 (zig_f128)
2073#endif
2074
2075#define zig_convert_builtin(ResType, operation, ArgType, version) \
2076 zig_extern zig_##ResType zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \
2077 zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(zig_##ArgType);
2078zig_convert_builtin(f16, trunc, f32, 2)
2079zig_convert_builtin(f16, trunc, f64, 2)
2080zig_convert_builtin(f16, trunc, f80, 2)
2081zig_convert_builtin(f16, trunc, f128, 2)
2082zig_convert_builtin(f32, extend, f16, 2)
2083zig_convert_builtin(f32, trunc, f64, 2)
2084zig_convert_builtin(f32, trunc, f80, 2)
2085zig_convert_builtin(f32, trunc, f128, 2)
2086zig_convert_builtin(f64, extend, f16, 2)
2087zig_convert_builtin(f64, extend, f32, 2)
2088zig_convert_builtin(f64, trunc, f80, 2)
2089zig_convert_builtin(f64, trunc, f128, 2)
2090zig_convert_builtin(f80, extend, f16, 2)
2091zig_convert_builtin(f80, extend, f32, 2)
2092zig_convert_builtin(f80, extend, f64, 2)
2093zig_convert_builtin(f80, trunc, f128, 2)
2094zig_convert_builtin(f128, extend, f16, 2)
2095zig_convert_builtin(f128, extend, f32, 2)
2096zig_convert_builtin(f128, extend, f64, 2)
2097zig_convert_builtin(f128, extend, f80, 2)
2098
2099#define zig_float_negate_builtin_0(Type) \
2100 static inline zig_##Type zig_neg_##Type(zig_##Type arg) { \
2101 return zig_expand_concat(zig_xor_, zig_repr_##Type)(arg, zig_expand_minInt(zig_repr_##Type, zig_bitSizeOf_##Type)); \
2102 }
2103#define zig_float_negate_builtin_1(Type) \
2104 static inline zig_##Type zig_neg_##Type(zig_##Type arg) { \
2105 return -arg; \
2106 }
2107
2108#define zig_float_less_builtin_0(Type, operation) \
2109 zig_extern zig_i32 zig_expand_concat(zig_expand_concat(__##operation, \
2110 zig_compiler_rt_abbrev_##Type), 2)(zig_##Type, zig_##Type); \
2111 static inline zig_i32 zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \
2112 return zig_expand_concat(zig_expand_concat(__##operation, zig_compiler_rt_abbrev_##Type), 2)(lhs, rhs); \
2113 }
2114#define zig_float_less_builtin_1(Type, operation) \
2115 static inline zig_i32 zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \
2116 return (!(lhs <= rhs) - (lhs < rhs)); \
2117 }
2118
2119#define zig_float_greater_builtin_0(Type, operation) \
2120 zig_float_less_builtin_0(Type, operation)
2121#define zig_float_greater_builtin_1(Type, operation) \
2122 static inline zig_i32 zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \
2123 return ((lhs > rhs) - !(lhs >= rhs)); \
2124 }
2125
2126#define zig_float_binary_builtin_0(Type, operation, operator) \
2127 zig_extern zig_##Type zig_expand_concat(zig_expand_concat(__##operation, \
2128 zig_compiler_rt_abbrev_##Type), 3)(zig_##Type, zig_##Type); \
2129 static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \
2130 return zig_expand_concat(zig_expand_concat(__##operation, zig_compiler_rt_abbrev_##Type), 3)(lhs, rhs); \
2131 }
2132#define zig_float_binary_builtin_1(Type, operation, operator) \
2133 static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \
2134 return lhs operator rhs; \
2135 }
2136
2137#define zig_float_builtins(Type) \
2138 zig_convert_builtin(i32, fix, Type, ) \
2139 zig_convert_builtin(u32, fixuns, Type, ) \
2140 zig_convert_builtin(i64, fix, Type, ) \
2141 zig_convert_builtin(u64, fixuns, Type, ) \
2142 zig_convert_builtin(i128, fix, Type, ) \
2143 zig_convert_builtin(u128, fixuns, Type, ) \
2144 zig_convert_builtin(Type, float, i32, ) \
2145 zig_convert_builtin(Type, floatun, u32, ) \
2146 zig_convert_builtin(Type, float, i64, ) \
2147 zig_convert_builtin(Type, floatun, u64, ) \
2148 zig_convert_builtin(Type, float, i128, ) \
2149 zig_convert_builtin(Type, floatun, u128, ) \
2150 zig_expand_concat(zig_float_negate_builtin_, zig_has_##Type)(Type) \
2151 zig_expand_concat(zig_float_less_builtin_, zig_has_##Type)(Type, cmp) \
2152 zig_expand_concat(zig_float_less_builtin_, zig_has_##Type)(Type, ne) \
2153 zig_expand_concat(zig_float_less_builtin_, zig_has_##Type)(Type, eq) \
2154 zig_expand_concat(zig_float_less_builtin_, zig_has_##Type)(Type, lt) \
2155 zig_expand_concat(zig_float_less_builtin_, zig_has_##Type)(Type, le) \
2156 zig_expand_concat(zig_float_greater_builtin_, zig_has_##Type)(Type, gt) \
2157 zig_expand_concat(zig_float_greater_builtin_, zig_has_##Type)(Type, ge) \
2158 zig_expand_concat(zig_float_binary_builtin_, zig_has_##Type)(Type, add, +) \
2159 zig_expand_concat(zig_float_binary_builtin_, zig_has_##Type)(Type, sub, -) \
2160 zig_expand_concat(zig_float_binary_builtin_, zig_has_##Type)(Type, mul, *) \
2161 zig_expand_concat(zig_float_binary_builtin_, zig_has_##Type)(Type, div, /) \
2162 zig_extern zig_##Type zig_libc_name_##Type(sqrt)(zig_##Type); \
2163 zig_extern zig_##Type zig_libc_name_##Type(sin)(zig_##Type); \
2164 zig_extern zig_##Type zig_libc_name_##Type(cos)(zig_##Type); \
2165 zig_extern zig_##Type zig_libc_name_##Type(tan)(zig_##Type); \
2166 zig_extern zig_##Type zig_libc_name_##Type(exp)(zig_##Type); \
2167 zig_extern zig_##Type zig_libc_name_##Type(exp2)(zig_##Type); \
2168 zig_extern zig_##Type zig_libc_name_##Type(log)(zig_##Type); \
2169 zig_extern zig_##Type zig_libc_name_##Type(log2)(zig_##Type); \
2170 zig_extern zig_##Type zig_libc_name_##Type(log10)(zig_##Type); \
2171 zig_extern zig_##Type zig_libc_name_##Type(fabs)(zig_##Type); \
2172 zig_extern zig_##Type zig_libc_name_##Type(floor)(zig_##Type); \
2173 zig_extern zig_##Type zig_libc_name_##Type(ceil)(zig_##Type); \
2174 zig_extern zig_##Type zig_libc_name_##Type(round)(zig_##Type); \
2175 zig_extern zig_##Type zig_libc_name_##Type(trunc)(zig_##Type); \
2176 zig_extern zig_##Type zig_libc_name_##Type(fmod)(zig_##Type, zig_##Type); \
2177 zig_extern zig_##Type zig_libc_name_##Type(fmin)(zig_##Type, zig_##Type); \
2178 zig_extern zig_##Type zig_libc_name_##Type(fmax)(zig_##Type, zig_##Type); \
2179 zig_extern zig_##Type zig_libc_name_##Type(fma)(zig_##Type, zig_##Type, zig_##Type); \
2180\
2181 static inline zig_##Type zig_div_trunc_##Type(zig_##Type lhs, zig_##Type rhs) { \
2182 return zig_libc_name_##Type(trunc)(zig_div_##Type(lhs, rhs)); \
2183 } \
2184\
2185 static inline zig_##Type zig_div_floor_##Type(zig_##Type lhs, zig_##Type rhs) { \
2186 return zig_libc_name_##Type(floor)(zig_div_##Type(lhs, rhs)); \
2187 } \
2188\
2189 static inline zig_##Type zig_mod_##Type(zig_##Type lhs, zig_##Type rhs) { \
2190 return zig_sub_##Type(lhs, zig_mul_##Type(zig_div_floor_##Type(lhs, rhs), rhs)); \
2191 }
2192zig_float_builtins(f16)
2193zig_float_builtins(f32)
2194zig_float_builtins(f64)
2195zig_float_builtins(f80)
2196zig_float_builtins(f128)
2197zig_float_builtins(c_longdouble)
2198
2199#if _MSC_VER && (_M_IX86 || _M_X64)
2200
2201// TODO: zig_msvc_atomic_load should load 32 bit without interlocked on x86, and load 64 bit without interlocked on x64
2202
2203#define zig_msvc_atomics(Type, suffix) \
2204 static inline bool zig_msvc_cmpxchg_##Type(zig_##Type volatile* obj, zig_##Type* expected, zig_##Type desired) { \
2205 zig_##Type comparand = *expected; \
2206 zig_##Type initial = _InterlockedCompareExchange##suffix(obj, desired, comparand); \
2207 bool exchanged = initial == comparand; \
2208 if (!exchanged) { \
2209 *expected = initial; \
2210 } \
2211 return exchanged; \
2212 } \
2213 static inline zig_##Type zig_msvc_atomicrmw_xchg_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2214 return _InterlockedExchange##suffix(obj, value); \
2215 } \
2216 static inline zig_##Type zig_msvc_atomicrmw_add_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2217 return _InterlockedExchangeAdd##suffix(obj, value); \
2218 } \
2219 static inline zig_##Type zig_msvc_atomicrmw_sub_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2220 bool success = false; \
2221 zig_##Type new; \
2222 zig_##Type prev; \
2223 while (!success) { \
2224 prev = *obj; \
2225 new = prev - value; \
2226 success = zig_msvc_cmpxchg_##Type(obj, &prev, new); \
2227 } \
2228 return prev; \
2229 } \
2230 static inline zig_##Type zig_msvc_atomicrmw_or_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2231 return _InterlockedOr##suffix(obj, value); \
2232 } \
2233 static inline zig_##Type zig_msvc_atomicrmw_xor_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2234 return _InterlockedXor##suffix(obj, value); \
2235 } \
2236 static inline zig_##Type zig_msvc_atomicrmw_and_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2237 return _InterlockedAnd##suffix(obj, value); \
2238 } \
2239 static inline zig_##Type zig_msvc_atomicrmw_nand_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2240 bool success = false; \
2241 zig_##Type new; \
2242 zig_##Type prev; \
2243 while (!success) { \
2244 prev = *obj; \
2245 new = ~(prev & value); \
2246 success = zig_msvc_cmpxchg_##Type(obj, &prev, new); \
2247 } \
2248 return prev; \
2249 } \
2250 static inline zig_##Type zig_msvc_atomicrmw_min_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2251 bool success = false; \
2252 zig_##Type new; \
2253 zig_##Type prev; \
2254 while (!success) { \
2255 prev = *obj; \
2256 new = value < prev ? value : prev; \
2257 success = zig_msvc_cmpxchg_##Type(obj, &prev, new); \
2258 } \
2259 return prev; \
2260 } \
2261 static inline zig_##Type zig_msvc_atomicrmw_max_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2262 bool success = false; \
2263 zig_##Type new; \
2264 zig_##Type prev; \
2265 while (!success) { \
2266 prev = *obj; \
2267 new = value > prev ? value : prev; \
2268 success = zig_msvc_cmpxchg_##Type(obj, &prev, new); \
2269 } \
2270 return prev; \
2271 } \
2272 static inline void zig_msvc_atomic_store_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2273 _InterlockedExchange##suffix(obj, value); \
2274 } \
2275 static inline zig_##Type zig_msvc_atomic_load_##Type(zig_##Type volatile* obj) { \
2276 return _InterlockedOr##suffix(obj, 0); \
2277 }
2278
2279zig_msvc_atomics(u8, 8)
2280zig_msvc_atomics(i8, 8)
2281zig_msvc_atomics(u16, 16)
2282zig_msvc_atomics(i16, 16)
2283zig_msvc_atomics(u32, )
2284zig_msvc_atomics(i32, )
2285
2286#if _M_X64
2287zig_msvc_atomics(u64, 64)
2288zig_msvc_atomics(i64, 64)
2289#endif
2290
2291#define zig_msvc_flt_atomics(Type, ReprType, suffix) \
2292 static inline bool zig_msvc_cmpxchg_##Type(zig_##Type volatile* obj, zig_##Type* expected, zig_##Type desired) { \
2293 zig_##ReprType comparand = *((zig_##ReprType*)expected); \
2294 zig_##ReprType initial = _InterlockedCompareExchange##suffix((zig_##ReprType volatile*)obj, *((zig_##ReprType*)&desired), comparand); \
2295 bool exchanged = initial == comparand; \
2296 if (!exchanged) { \
2297 *expected = *((zig_##Type*)&initial); \
2298 } \
2299 return exchanged; \
2300 } \
2301 static inline zig_##Type zig_msvc_atomicrmw_xchg_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2302 zig_##ReprType initial = _InterlockedExchange##suffix((zig_##ReprType volatile*)obj, *((zig_##ReprType*)&value)); \
2303 return *((zig_##Type*)&initial); \
2304 } \
2305 static inline zig_##Type zig_msvc_atomicrmw_add_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2306 bool success = false; \
2307 zig_##ReprType new; \
2308 zig_##Type prev; \
2309 while (!success) { \
2310 prev = *obj; \
2311 new = prev + value; \
2312 success = zig_msvc_cmpxchg_##Type(obj, &prev, *((zig_##ReprType*)&new)); \
2313 } \
2314 return prev; \
2315 } \
2316 static inline zig_##Type zig_msvc_atomicrmw_sub_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2317 bool success = false; \
2318 zig_##ReprType new; \
2319 zig_##Type prev; \
2320 while (!success) { \
2321 prev = *obj; \
2322 new = prev - value; \
2323 success = zig_msvc_cmpxchg_##Type(obj, &prev, *((zig_##ReprType*)&new)); \
2324 } \
2325 return prev; \
2326 }
2327
2328zig_msvc_flt_atomics(f32, u32, )
2329#if _M_X64
2330zig_msvc_flt_atomics(f64, u64, 64)
2331#endif
2332
2333#if _M_IX86
2334static inline void zig_msvc_atomic_barrier() {
2335 zig_i32 barrier;
2336 __asm {
2337 xchg barrier, eax
2338 }
2339}
2340
2341static inline void* zig_msvc_atomicrmw_xchg_p32(void** obj, zig_u32* arg) {
2342 return _InterlockedExchangePointer(obj, arg);
2343}
2344
2345static inline void zig_msvc_atomic_store_p32(void** obj, zig_u32* arg) {
2346 _InterlockedExchangePointer(obj, arg);
2347}
2348
2349static inline void* zig_msvc_atomic_load_p32(void** obj) {
2350 return (void*)_InterlockedOr((void*)obj, 0);
2351}
2352
2353static inline bool zig_msvc_cmpxchg_p32(void** obj, void** expected, void* desired) {
2354 void* comparand = *expected;
2355 void* initial = _InterlockedCompareExchangePointer(obj, desired, comparand);
2356 bool exchanged = initial == comparand;
2357 if (!exchanged) {
2358 *expected = initial;
2359 }
2360 return exchanged;
2361}
2362#else /* _M_IX86 */
2363static inline void* zig_msvc_atomicrmw_xchg_p64(void** obj, zig_u64* arg) {
2364 return _InterlockedExchangePointer(obj, arg);
2365}
2366
2367static inline void zig_msvc_atomic_store_p64(void** obj, zig_u64* arg) {
2368 _InterlockedExchangePointer(obj, arg);
2369}
2370
2371static inline void* zig_msvc_atomic_load_p64(void** obj) {
2372 return (void*)_InterlockedOr64((void*)obj, 0);
2373}
2374
2375static inline bool zig_msvc_cmpxchg_p64(void** obj, void** expected, void* desired) {
2376 void* comparand = *expected;
2377 void* initial = _InterlockedCompareExchangePointer(obj, desired, comparand);
2378 bool exchanged = initial == comparand;
2379 if (!exchanged) {
2380 *expected = initial;
2381 }
2382 return exchanged;
2383}
2384
2385static inline bool zig_msvc_cmpxchg_u128(zig_u128 volatile* obj, zig_u128* expected, zig_u128 desired) {
2386 return _InterlockedCompareExchange128((zig_i64 volatile*)obj, desired.hi, desired.lo, (zig_i64*)expected);
2387}
2388
2389static inline bool zig_msvc_cmpxchg_i128(zig_i128 volatile* obj, zig_i128* expected, zig_i128 desired) {
2390 return _InterlockedCompareExchange128((zig_i64 volatile*)obj, desired.hi, desired.lo, (zig_u64*)expected);
2391}
2392
2393#define zig_msvc_atomics_128xchg(Type) \
2394 static inline zig_##Type zig_msvc_atomicrmw_xchg_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2395 bool success = false; \
2396 zig_##Type prev; \
2397 while (!success) { \
2398 prev = *obj; \
2399 success = zig_msvc_cmpxchg_##Type(obj, &prev, value); \
2400 } \
2401 return prev; \
2402 }
2403
2404zig_msvc_atomics_128xchg(u128)
2405zig_msvc_atomics_128xchg(i128)
2406
2407#define zig_msvc_atomics_128op(Type, operation) \
2408 static inline zig_##Type zig_msvc_atomicrmw_##operation##_##Type(zig_##Type volatile* obj, zig_##Type value) { \
2409 bool success = false; \
2410 zig_##Type new; \
2411 zig_##Type prev; \
2412 while (!success) { \
2413 prev = *obj; \
2414 new = zig_##operation##_##Type(prev, value); \
2415 success = zig_msvc_cmpxchg_##Type(obj, &prev, new); \
2416 } \
2417 return prev; \
2418 }
2419
2420zig_msvc_atomics_128op(u128, add)
2421zig_msvc_atomics_128op(u128, sub)
2422zig_msvc_atomics_128op(u128, or)
2423zig_msvc_atomics_128op(u128, xor)
2424zig_msvc_atomics_128op(u128, and)
2425zig_msvc_atomics_128op(u128, nand)
2426zig_msvc_atomics_128op(u128, min)
2427zig_msvc_atomics_128op(u128, max)
2428#endif /* _M_IX86 */
2429
2430#endif /* _MSC_VER && (_M_IX86 || _M_X64) */
2431
2432/* ========================= Special Case Intrinsics ========================= */
2433
2434#if (_MSC_VER && _M_X64) || defined(__x86_64__)
2435
2436static inline void* zig_x86_64_windows_teb(void) {
2437#if _MSC_VER
2438 return (void*)__readgsqword(0x30);
2439#else
2440 void* teb;
2441 __asm volatile(" movq %%gs:0x30, %[ptr]": [ptr]"=r"(teb)::);
2442 return teb;
2443#endif
2444}
2445
2446#elif (_MSC_VER && _M_IX86) || defined(__i386__) || defined(__X86__)
2447
2448static inline void* zig_x86_windows_teb(void) {
2449#if _MSC_VER
2450 return (void*)__readfsdword(0x18);
2451#else
2452 void* teb;
2453 __asm volatile(" movl %%fs:0x18, %[ptr]": [ptr]"=r"(teb)::);
2454 return teb;
2455#endif
2456}
2457
2458#endif
2459
2460#if (_MSC_VER && (_M_IX86 || _M_X64)) || defined(__i386__) || defined(__x86_64__)
2461
2462static inline void zig_x86_cpuid(zig_u32 leaf_id, zig_u32 subid, zig_u32* eax, zig_u32* ebx, zig_u32* ecx, zig_u32* edx) {
2463 zig_u32 cpu_info[4];
2464#if _MSC_VER
2465 __cpuidex(cpu_info, leaf_id, subid);
2466#else
2467 __cpuid_count(leaf_id, subid, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]);
2468#endif
2469 *eax = cpu_info[0];
2470 *ebx = cpu_info[1];
2471 *ecx = cpu_info[2];
2472 *edx = cpu_info[3];
2473}
2474
2475static inline zig_u32 zig_x86_get_xcr0(void) {
2476#if _MSC_VER
2477 return (zig_u32)_xgetbv(0);
2478#else
2479 zig_u32 eax;
2480 zig_u32 edx;
2481 __asm__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0));
2482 return eax;
2483#endif
2484}
2485
2486#endif
stage1/zig1.wasm
Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ
test/behavior/align.zig+5-1
...@@ -551,7 +551,11 @@ test "align(N) on functions" {...@@ -551,7 +551,11 @@ test "align(N) on functions" {
551 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO551 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
552 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO552 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
553 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO553 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
554 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO this is not supported on MSVC554
555 // This is not supported on MSVC
556 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) {
557 return error.SkipZigTest;
558 }
555559
556 // function alignment is a compile error on wasm32/wasm64560 // function alignment is a compile error on wasm32/wasm64
557 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;561 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
test/behavior/asm.zig+13-5
...@@ -7,6 +7,7 @@ const is_x86_64_linux = builtin.cpu.arch == .x86_64 and builtin.os.tag == .linux...@@ -7,6 +7,7 @@ const is_x86_64_linux = builtin.cpu.arch == .x86_64 and builtin.os.tag == .linux
7comptime {7comptime {
8 if (builtin.zig_backend != .stage2_arm and8 if (builtin.zig_backend != .stage2_arm and
9 builtin.zig_backend != .stage2_aarch64 and9 builtin.zig_backend != .stage2_aarch64 and
10 !(builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) and // MSVC doesn't support inline assembly
10 is_x86_64_linux)11 is_x86_64_linux)
11 {12 {
12 asm (13 asm (
...@@ -23,7 +24,8 @@ test "module level assembly" {...@@ -23,7 +24,8 @@ test "module level assembly" {
23 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
24 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO25 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
25 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO26 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
26 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO27
28 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
2729
28 if (is_x86_64_linux) {30 if (is_x86_64_linux) {
29 try expect(this_is_my_alias() == 1234);31 try expect(this_is_my_alias() == 1234);
...@@ -36,7 +38,8 @@ test "output constraint modifiers" {...@@ -36,7 +38,8 @@ test "output constraint modifiers" {
36 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO38 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
37 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO39 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
38 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO40 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
39 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO41
42 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
4043
41 // This is only testing compilation.44 // This is only testing compilation.
42 var a: u32 = 3;45 var a: u32 = 3;
...@@ -58,7 +61,8 @@ test "alternative constraints" {...@@ -58,7 +61,8 @@ test "alternative constraints" {
58 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO61 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
59 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO62 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
60 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO63 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
61 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO64
65 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
6266
63 // Make sure we allow commas as a separator for alternative constraints.67 // Make sure we allow commas as a separator for alternative constraints.
64 var a: u32 = 3;68 var a: u32 = 3;
...@@ -75,7 +79,8 @@ test "sized integer/float in asm input" {...@@ -75,7 +79,8 @@ test "sized integer/float in asm input" {
75 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO79 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO80 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO81 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
78 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO82
83 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
7984
80 asm volatile (""85 asm volatile (""
81 :86 :
...@@ -125,7 +130,8 @@ test "struct/array/union types as input values" {...@@ -125,7 +130,8 @@ test "struct/array/union types as input values" {
125 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO130 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
126 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO131 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
127 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO132 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
128 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO133
134 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
129135
130 asm volatile (""136 asm volatile (""
131 :137 :
...@@ -151,6 +157,8 @@ test "asm modifiers (AArch64)" {...@@ -151,6 +157,8 @@ test "asm modifiers (AArch64)" {
151 if (builtin.target.cpu.arch != .aarch64) return error.SkipZigTest;157 if (builtin.target.cpu.arch != .aarch64) return error.SkipZigTest;
152 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO158 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
153159
160 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
161
154 var x: u32 = 15;162 var x: u32 = 15;
155 const double = asm ("add %[ret:w], %[in:w], %[in:w]"163 const double = asm ("add %[ret:w], %[in:w], %[in:w]"
156 : [ret] "=r" (-> u32),164 : [ret] "=r" (-> u32),
test/behavior/basic.zig+15
...@@ -387,6 +387,7 @@ fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA {...@@ -387,6 +387,7 @@ fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA {
387}387}
388388
389test "take address of parameter" {389test "take address of parameter" {
390 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
390 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;391 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
391 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;392 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
392 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO393 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1143,3 +1144,17 @@ test "orelse coercion as function argument" {...@@ -1143,3 +1144,17 @@ test "orelse coercion as function argument" {
1143 var foo = Container.init(optional orelse .{});1144 var foo = Container.init(optional orelse .{});
1144 try expect(foo.a.?.start == -1);1145 try expect(foo.a.?.start == -1);
1145}1146}
1147
1148test "runtime-known globals initialized with undefined" {
1149 const S = struct {
1150 var array: [10]u32 = [_]u32{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
1151 var vp: [*]u32 = undefined;
1152 var s: []u32 = undefined;
1153 };
1154
1155 S.vp = &S.array;
1156 S.s = S.vp[0..5];
1157
1158 try expect(S.s[0] == 1);
1159 try expect(S.s[4] == 5);
1160}
test/behavior/cast.zig+9
...@@ -1568,3 +1568,12 @@ test "@volatileCast without a result location" {...@@ -1568,3 +1568,12 @@ test "@volatileCast without a result location" {
1568 try expect(@TypeOf(z) == *i32);1568 try expect(@TypeOf(z) == *i32);
1569 try expect(z.* == 1234);1569 try expect(z.* == 1234);
1570}1570}
1571
1572test "coercion from single-item pointer to @as to slice" {
1573 var x: u32 = 1;
1574
1575 // Why the following line gets a compile error?
1576 const t: []u32 = @as(*[1]u32, &x);
1577
1578 try expect(t[0] == 1);
1579}
test/behavior/const_slice_child.zig+1
...@@ -9,6 +9,7 @@ var argv: [*]const [*]const u8 = undefined;...@@ -9,6 +9,7 @@ var argv: [*]const [*]const u8 = undefined;
9test "const slice child" {9test "const slice child" {
10 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO13 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1314
14 const strs = [_][*]const u8{ "one", "two", "three" };15 const strs = [_][*]const u8{ "one", "two", "three" };
test/behavior/eval.zig+1
...@@ -1338,6 +1338,7 @@ test "lazy sizeof is resolved in division" {...@@ -1338,6 +1338,7 @@ test "lazy sizeof is resolved in division" {
13381338
1339test "lazy value is resolved as slice operand" {1339test "lazy value is resolved as slice operand" {
1340 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1340 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1341 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1342 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13421343
1343 const A = struct { a: u32 };1344 const A = struct { a: u32 };
test/behavior/field_parent_ptr.zig+78
...@@ -44,3 +44,81 @@ fn testParentFieldPtrFirst(a: *const bool) !void {...@@ -44,3 +44,81 @@ fn testParentFieldPtrFirst(a: *const bool) !void {
44 try expect(base == &foo);44 try expect(base == &foo);
45 try expect(&base.a == a);45 try expect(&base.a == a);
46}46}
47
48test "@fieldParentPtr untagged union" {
49 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
50 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
52
53 try testFieldParentPtrUnion(&bar.c);
54 comptime try testFieldParentPtrUnion(&bar.c);
55}
56
57const Bar = union(enum) {
58 a: bool,
59 b: f32,
60 c: i32,
61 d: i32,
62};
63
64const bar = Bar{ .c = 42 };
65
66fn testFieldParentPtrUnion(c: *const i32) !void {
67 try expect(c == &bar.c);
68
69 const base = @fieldParentPtr(Bar, "c", c);
70 try expect(base == &bar);
71 try expect(&base.c == c);
72}
73
74test "@fieldParentPtr tagged union" {
75 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
76 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
78
79 try testFieldParentPtrTaggedUnion(&bar_tagged.c);
80 comptime try testFieldParentPtrTaggedUnion(&bar_tagged.c);
81}
82
83const BarTagged = union(enum) {
84 a: bool,
85 b: f32,
86 c: i32,
87 d: i32,
88};
89
90const bar_tagged = BarTagged{ .c = 42 };
91
92fn testFieldParentPtrTaggedUnion(c: *const i32) !void {
93 try expect(c == &bar_tagged.c);
94
95 const base = @fieldParentPtr(BarTagged, "c", c);
96 try expect(base == &bar_tagged);
97 try expect(&base.c == c);
98}
99
100test "@fieldParentPtr extern union" {
101 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
103 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
104
105 try testFieldParentPtrExternUnion(&bar_extern.c);
106 comptime try testFieldParentPtrExternUnion(&bar_extern.c);
107}
108
109const BarExtern = extern union {
110 a: bool,
111 b: f32,
112 c: i32,
113 d: i32,
114};
115
116const bar_extern = BarExtern{ .c = 42 };
117
118fn testFieldParentPtrExternUnion(c: *const i32) !void {
119 try expect(c == &bar_extern.c);
120
121 const base = @fieldParentPtr(BarExtern, "c", c);
122 try expect(base == &bar_extern);
123 try expect(&base.c == c);
124}
test/behavior/int_comparison_elision.zig-1
...@@ -13,7 +13,6 @@ test "int comparison elision" {...@@ -13,7 +13,6 @@ test "int comparison elision" {
1313
14 // TODO: support int types > 128 bits wide in other backends14 // TODO: support int types > 128 bits wide in other backends
15 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO15 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
16 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
17 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO16 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO17 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO18 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/lower_strlit_to_vector.zig-1
...@@ -7,7 +7,6 @@ test "strlit to vector" {...@@ -7,7 +7,6 @@ test "strlit to vector" {
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1110
12 const strlit = "0123456789abcdef0123456789ABCDEF";11 const strlit = "0123456789abcdef0123456789ABCDEF";
13 const vec_from_strlit: @Vector(32, u8) = strlit.*;12 const vec_from_strlit: @Vector(32, u8) = strlit.*;
test/behavior/math.zig-1
...@@ -1463,7 +1463,6 @@ test "vector integer addition" {...@@ -1463,7 +1463,6 @@ test "vector integer addition" {
1463 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1463 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1464 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1464 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1465 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1465 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1466 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1467 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1466 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14681467
1469 const S = struct {1468 const S = struct {
test/behavior/packed-struct.zig-1
...@@ -603,7 +603,6 @@ test "packed struct initialized in bitcast" {...@@ -603,7 +603,6 @@ test "packed struct initialized in bitcast" {
603test "pointer to container level packed struct field" {603test "pointer to container level packed struct field" {
604 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;604 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
605 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;605 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
606 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
607 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;606 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
608 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;607 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
609608
test/behavior/pointers.zig-1
...@@ -507,7 +507,6 @@ test "ptrCast comptime known slice to C pointer" {...@@ -507,7 +507,6 @@ test "ptrCast comptime known slice to C pointer" {
507}507}
508508
509test "ptrToInt on a generic function" {509test "ptrToInt on a generic function" {
510 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
511 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO510 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
512 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO511 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
513 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO512 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
test/behavior/struct.zig+35-1
...@@ -1330,7 +1330,6 @@ test "struct field init value is size of the struct" {...@@ -1330,7 +1330,6 @@ test "struct field init value is size of the struct" {
1330}1330}
13311331
1332test "under-aligned struct field" {1332test "under-aligned struct field" {
1333 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1334 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1333 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1335 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1334 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1336 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1335 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
...@@ -1578,3 +1577,38 @@ test "directly initiating tuple like struct" {...@@ -1578,3 +1577,38 @@ test "directly initiating tuple like struct" {
1578 const a = struct { u8 }{8};1577 const a = struct { u8 }{8};
1579 try expect(a[0] == 8);1578 try expect(a[0] == 8);
1580}1579}
1580
1581test "instantiate struct with comptime field" {
1582 {
1583 var things = struct {
1584 comptime foo: i8 = 1,
1585 }{};
1586
1587 comptime std.debug.assert(things.foo == 1);
1588 }
1589
1590 {
1591 const T = struct {
1592 comptime foo: i8 = 1,
1593 };
1594 var things = T{};
1595
1596 comptime std.debug.assert(things.foo == 1);
1597 }
1598
1599 {
1600 var things: struct {
1601 comptime foo: i8 = 1,
1602 } = .{};
1603
1604 comptime std.debug.assert(things.foo == 1);
1605 }
1606
1607 {
1608 var things: struct {
1609 comptime foo: i8 = 1,
1610 } = undefined; // Segmentation fault at address 0x0
1611
1612 comptime std.debug.assert(things.foo == 1);
1613 }
1614}
test/behavior/type_info.zig+6
...@@ -603,3 +603,9 @@ test "@typeInfo decls ignore dependency loops" {...@@ -603,3 +603,9 @@ test "@typeInfo decls ignore dependency loops" {
603 };603 };
604 _ = S.foo;604 _ = S.foo;
605}605}
606
607test "type info of tuple of string literal default value" {
608 const struct_field = @typeInfo(@TypeOf(.{"hi"})).Struct.fields[0];
609 const value = @ptrCast(*align(1) const *const [2:0]u8, struct_field.default_value.?).*;
610 comptime std.debug.assert(value[0] == 'h');
611}
test/behavior/var_args.zig+16-8
...@@ -96,10 +96,9 @@ fn doNothingWithFirstArg(args: anytype) void {...@@ -96,10 +96,9 @@ fn doNothingWithFirstArg(args: anytype) void {
96test "simple variadic function" {96test "simple variadic function" {
97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO98 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
100 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO99 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
101 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO100 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
102 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos and builtin.zig_backend == .stage2_llvm) {101 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos) {
103 // https://github.com/ziglang/zig/issues/14096102 // https://github.com/ziglang/zig/issues/14096
104 return error.SkipZigTest;103 return error.SkipZigTest;
105 }104 }
...@@ -112,6 +111,12 @@ test "simple variadic function" {...@@ -112,6 +111,12 @@ test "simple variadic function" {
112 return @cVaArg(&ap, c_int);111 return @cVaArg(&ap, c_int);
113 }112 }
114113
114 fn compatible(_: c_int, ...) callconv(.C) c_int {
115 var ap = @cVaStart();
116 defer @cVaEnd(&ap);
117 return @cVaArg(&ap, c_int);
118 }
119
115 fn add(count: c_int, ...) callconv(.C) c_int {120 fn add(count: c_int, ...) callconv(.C) c_int {
116 var ap = @cVaStart();121 var ap = @cVaStart();
117 defer @cVaEnd(&ap);122 defer @cVaEnd(&ap);
...@@ -124,8 +129,13 @@ test "simple variadic function" {...@@ -124,8 +129,13 @@ test "simple variadic function" {
124 }129 }
125 };130 };
126131
127 try std.testing.expectEqual(@as(c_int, 0), S.simple(@as(c_int, 0)));132 if (builtin.zig_backend != .stage2_c) {
128 try std.testing.expectEqual(@as(c_int, 1024), S.simple(@as(c_int, 1024)));133 // pre C23 doesn't support varargs without a preceding runtime arg.
134 try std.testing.expectEqual(@as(c_int, 0), S.simple(@as(c_int, 0)));
135 try std.testing.expectEqual(@as(c_int, 1024), S.simple(@as(c_int, 1024)));
136 }
137 try std.testing.expectEqual(@as(c_int, 0), S.compatible(undefined, @as(c_int, 0)));
138 try std.testing.expectEqual(@as(c_int, 1024), S.compatible(undefined, @as(c_int, 1024)));
129 try std.testing.expectEqual(@as(c_int, 0), S.add(0));139 try std.testing.expectEqual(@as(c_int, 0), S.add(0));
130 try std.testing.expectEqual(@as(c_int, 1), S.add(1, @as(c_int, 1)));140 try std.testing.expectEqual(@as(c_int, 1), S.add(1, @as(c_int, 1)));
131 try std.testing.expectEqual(@as(c_int, 3), S.add(2, @as(c_int, 1), @as(c_int, 2)));141 try std.testing.expectEqual(@as(c_int, 3), S.add(2, @as(c_int, 1), @as(c_int, 2)));
...@@ -134,10 +144,9 @@ test "simple variadic function" {...@@ -134,10 +144,9 @@ test "simple variadic function" {
134test "variadic functions" {144test "variadic functions" {
135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO145 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
136 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO146 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
137 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
138 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO147 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
139 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO148 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
140 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos and builtin.zig_backend == .stage2_llvm) {149 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos) {
141 // https://github.com/ziglang/zig/issues/14096150 // https://github.com/ziglang/zig/issues/14096
142 return error.SkipZigTest;151 return error.SkipZigTest;
143 }152 }
...@@ -178,10 +187,9 @@ test "variadic functions" {...@@ -178,10 +187,9 @@ test "variadic functions" {
178test "copy VaList" {187test "copy VaList" {
179 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
180 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO189 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
181 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
182 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO190 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
183 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO191 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
184 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos and builtin.zig_backend == .stage2_llvm) {192 if (builtin.cpu.arch == .aarch64 and builtin.os.tag != .macos) {
185 // https://github.com/ziglang/zig/issues/14096193 // https://github.com/ziglang/zig/issues/14096
186 return error.SkipZigTest;194 return error.SkipZigTest;
187 }195 }
test/behavior/vector.zig+2-5
...@@ -75,7 +75,6 @@ test "vector int operators" {...@@ -75,7 +75,6 @@ test "vector int operators" {
75 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO75 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO77 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
78 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
79 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO78 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8079
81 const S = struct {80 const S = struct {
...@@ -178,7 +177,6 @@ test "tuple to vector" {...@@ -178,7 +177,6 @@ test "tuple to vector" {
178 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO177 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
179 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO178 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
180 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO179 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
181 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
182 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO180 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
183181
184 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) {182 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) {
...@@ -943,7 +941,6 @@ test "multiplication-assignment operator with an array operand" {...@@ -943,7 +941,6 @@ test "multiplication-assignment operator with an array operand" {
943 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO941 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
944 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO942 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
945 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO943 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
946 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
947 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO944 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
948945
949 const S = struct {946 const S = struct {
...@@ -1247,10 +1244,10 @@ test "array operands to shuffle are coerced to vectors" {...@@ -1247,10 +1244,10 @@ test "array operands to shuffle are coerced to vectors" {
1247test "load packed vector element" {1244test "load packed vector element" {
1248 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1245 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1249 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1246 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1250 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1251 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1247 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1252 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1248 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1253 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1249 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1250 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
12541251
1255 var x: @Vector(2, u15) = .{ 1, 4 };1252 var x: @Vector(2, u15) = .{ 1, 4 };
1256 try expect((&x[0]).* == 1);1253 try expect((&x[0]).* == 1);
...@@ -1260,10 +1257,10 @@ test "load packed vector element" {...@@ -1260,10 +1257,10 @@ test "load packed vector element" {
1260test "store packed vector element" {1257test "store packed vector element" {
1261 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1258 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1262 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1259 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1263 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1264 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1260 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1265 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1261 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1266 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1262 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1263 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
12671264
1268 var v = @Vector(4, u1){ 1, 1, 1, 1 };1265 var v = @Vector(4, u1){ 1, 1, 1, 1 };
1269 try expectEqual(@Vector(4, u1){ 1, 1, 1, 1 }, v);1266 try expectEqual(@Vector(4, u1){ 1, 1, 1, 1 }, v);
test/cases/compile_errors/bitCast_same_size_but_bit_count_mismatch.zig+1-1
...@@ -7,4 +7,4 @@ export fn entry(byte: u8) void {...@@ -7,4 +7,4 @@ export fn entry(byte: u8) void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:29: error: @bitCast size mismatch: destination type 'u7' has 7 bits but source type 'u8' has 8 bits10// :2:16: error: @bitCast size mismatch: destination type 'u7' has 7 bits but source type 'u8' has 8 bits
test/cases/compile_errors/bitCast_with_different_sizes_inside_an_expression.zig+1-1
...@@ -7,4 +7,4 @@ export fn entry() void {...@@ -7,4 +7,4 @@ export fn entry() void {
7// backend=stage27// backend=stage2
8// target=native8// target=native
9//9//
10// :2:29: error: @bitCast size mismatch: destination type 'u8' has 8 bits but source type 'f32' has 32 bits10// :2:16: error: @bitCast size mismatch: destination type 'u8' has 8 bits but source type 'f32' has 32 bits
test/cases/compile_errors/error_set_membership.zig created+31
...@@ -0,0 +1,31 @@
1const std = @import("std");
2
3const Error = error{InvalidCharacter};
4
5const Direction = enum { upside_down };
6
7const Barrrr = union(enum) {
8 float: f64,
9 direction: Direction,
10};
11
12fn fooey(bar: std.meta.Tag(Barrrr), args: []const []const u8) !Barrrr {
13 return switch (bar) {
14 .float => .{ .float = try std.fmt.parseFloat(f64, args[0]) },
15 .direction => if (std.mem.eql(u8, args[0], "upside_down"))
16 Barrrr{ .direction = .upside_down }
17 else
18 error.InvalidDirection,
19 };
20}
21
22pub fn main() Error!void {
23 std.debug.print("{}", .{try fooey(.direction, &[_][]const u8{ "one", "two", "three" })});
24}
25
26// error
27// backend=llvm
28// target=native
29//
30// :23:29: error: expected type 'error{InvalidCharacter}', found '@typeInfo(@typeInfo(@TypeOf(tmp.fooey)).Fn.return_type.?).ErrorUnion.error_set'
31// :23:29: note: 'error.InvalidDirection' not a member of destination error set
test/cases/compile_errors/fieldParentPtr-non_struct.zig+1-1
...@@ -7,4 +7,4 @@ export fn foo(a: *i32) *Foo {...@@ -7,4 +7,4 @@ export fn foo(a: *i32) *Foo {
7// backend=llvm7// backend=llvm
8// target=native8// target=native
9//9//
10// :3:28: error: expected struct type, found 'i32'10// :3:28: error: expected struct or union type, found 'i32'
test/compile_errors.zig+22
...@@ -288,4 +288,26 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -288,4 +288,26 @@ pub fn addCases(ctx: *TestContext) !void {
288 //, &[_][]const u8{288 //, &[_][]const u8{
289 // "tmp.zig:4:1: error: unable to inline function",289 // "tmp.zig:4:1: error: unable to inline function",
290 //});290 //});
291
292 {
293 const case = ctx.obj("file in multiple modules", .{});
294 case.backend = .stage2;
295
296 case.addSourceFile("foo.zig",
297 \\const dummy = 0;
298 );
299
300 case.addDepModule("foo", "foo.zig");
301
302 case.addError(
303 \\comptime {
304 \\ _ = @import("foo");
305 \\ _ = @import("foo.zig");
306 \\}
307 , &[_][]const u8{
308 ":1:1: error: file exists in multiple modules",
309 ":1:1: note: root of module root.foo",
310 ":3:17: note: imported from module root",
311 });
312 }
291}313}
test/link/macho/dead_strip_dylibs/build.zig+1-1
...@@ -29,7 +29,7 @@ pub fn build(b: *std.Build) void {...@@ -29,7 +29,7 @@ pub fn build(b: *std.Build) void {
29 exe.dead_strip_dylibs = true;29 exe.dead_strip_dylibs = true;
3030
31 const run_cmd = exe.run();31 const run_cmd = exe.run();
32 run_cmd.expected_exit_code = @bitCast(u8, @as(i8, -2)); // should fail32 run_cmd.expected_term = .{ .Exited = @bitCast(u8, @as(i8, -2)) }; // should fail
33 test_step.dependOn(&run_cmd.step);33 test_step.dependOn(&run_cmd.step);
34 }34 }
35}35}
test/src/compare_output.zig+1-1
...@@ -168,7 +168,7 @@ pub const CompareOutputContext = struct {...@@ -168,7 +168,7 @@ pub const CompareOutputContext = struct {
168 run.addArgs(case.cli_args);168 run.addArgs(case.cli_args);
169 run.stderr_action = .ignore;169 run.stderr_action = .ignore;
170 run.stdout_action = .ignore;170 run.stdout_action = .ignore;
171 run.expected_exit_code = 126;171 run.expected_term = .{ .Exited = 126 };
172172
173 self.step.dependOn(&run.step);173 self.step.dependOn(&run.step);
174 },174 },
test/stage2/cbe.zig+6-6
...@@ -959,7 +959,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -959,7 +959,7 @@ pub fn addCases(ctx: *TestContext) !void {
959 \\ _ = a;959 \\ _ = a;
960 \\}960 \\}
961 ,961 ,
962 \\zig_extern void start(zig_u8 const a0);962 \\zig_extern void start(uint8_t const a0);
963 \\963 \\
964 );964 );
965 ctx.h("header with multiple param function", linux_x64,965 ctx.h("header with multiple param function", linux_x64,
...@@ -967,19 +967,19 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -967,19 +967,19 @@ pub fn addCases(ctx: *TestContext) !void {
967 \\ _ = a; _ = b; _ = c;967 \\ _ = a; _ = b; _ = c;
968 \\}968 \\}
969 ,969 ,
970 \\zig_extern void start(zig_u8 const a0, zig_u8 const a1, zig_u8 const a2);970 \\zig_extern void start(uint8_t const a0, uint8_t const a1, uint8_t const a2);
971 \\971 \\
972 );972 );
973 ctx.h("header with u32 param function", linux_x64,973 ctx.h("header with u32 param function", linux_x64,
974 \\export fn start(a: u32) void{ _ = a; }974 \\export fn start(a: u32) void{ _ = a; }
975 ,975 ,
976 \\zig_extern void start(zig_u32 const a0);976 \\zig_extern void start(uint32_t const a0);
977 \\977 \\
978 );978 );
979 ctx.h("header with usize param function", linux_x64,979 ctx.h("header with usize param function", linux_x64,
980 \\export fn start(a: usize) void{ _ = a; }980 \\export fn start(a: usize) void{ _ = a; }
981 ,981 ,
982 \\zig_extern void start(zig_usize const a0);982 \\zig_extern void start(uintptr_t const a0);
983 \\983 \\
984 );984 );
985 ctx.h("header with bool param function", linux_x64,985 ctx.h("header with bool param function", linux_x64,
...@@ -993,7 +993,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -993,7 +993,7 @@ pub fn addCases(ctx: *TestContext) !void {
993 \\ unreachable;993 \\ unreachable;
994 \\}994 \\}
995 ,995 ,
996 \\zig_extern zig_noreturn start(void);996 \\zig_extern zig_noreturn void start(void);
997 \\997 \\
998 );998 );
999 ctx.h("header with multiple functions", linux_x64,999 ctx.h("header with multiple functions", linux_x64,
...@@ -1009,7 +1009,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1009,7 +1009,7 @@ pub fn addCases(ctx: *TestContext) !void {
1009 ctx.h("header with multiple includes", linux_x64,1009 ctx.h("header with multiple includes", linux_x64,
1010 \\export fn start(a: u32, b: usize) void{ _ = a; _ = b; }1010 \\export fn start(a: u32, b: usize) void{ _ = a; _ = b; }
1011 ,1011 ,
1012 \\zig_extern void start(zig_u32 const a0, zig_usize const a1);1012 \\zig_extern void start(uint32_t const a0, uintptr_t const a1);
1013 \\1013 \\
1014 );1014 );
1015}1015}
test/stage2/nvptx.zig+1
...@@ -97,6 +97,7 @@ pub fn addPtx(...@@ -97,6 +97,7 @@ pub fn addPtx(
97 .updates = std.ArrayList(TestContext.Update).init(ctx.cases.allocator),97 .updates = std.ArrayList(TestContext.Update).init(ctx.cases.allocator),
98 .output_mode = .Obj,98 .output_mode = .Obj,
99 .files = std.ArrayList(TestContext.File).init(ctx.cases.allocator),99 .files = std.ArrayList(TestContext.File).init(ctx.cases.allocator),
100 .deps = std.ArrayList(TestContext.DepModule).init(ctx.cases.allocator),
100 .link_libc = false,101 .link_libc = false,
101 .backend = .llvm,102 .backend = .llvm,
102 // Bug in Debug mode103 // Bug in Debug mode
test/standalone.zig+9
...@@ -84,6 +84,9 @@ pub fn addCases(cases: *tests.StandaloneContext) void {...@@ -84,6 +84,9 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
84 cases.addBuildFile("test/standalone/pie/build.zig", .{});84 cases.addBuildFile("test/standalone/pie/build.zig", .{});
85 }85 }
86 cases.addBuildFile("test/standalone/issue_12706/build.zig", .{});86 cases.addBuildFile("test/standalone/issue_12706/build.zig", .{});
87 if (std.os.have_sigpipe_support) {
88 cases.addBuildFile("test/standalone/sigpipe/build.zig", .{});
89 }
8790
88 // Ensure the development tools are buildable. Alphabetically sorted.91 // Ensure the development tools are buildable. Alphabetically sorted.
89 // No need to build `tools/spirv/grammar.zig`.92 // No need to build `tools/spirv/grammar.zig`.
...@@ -104,4 +107,10 @@ pub fn addCases(cases: *tests.StandaloneContext) void {...@@ -104,4 +107,10 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
104 cases.addBuildFile("test/standalone/emit_asm_and_bin/build.zig", .{});107 cases.addBuildFile("test/standalone/emit_asm_and_bin/build.zig", .{});
105 cases.addBuildFile("test/standalone/issue_12588/build.zig", .{});108 cases.addBuildFile("test/standalone/issue_12588/build.zig", .{});
106 cases.addBuildFile("test/standalone/embed_generated_file/build.zig", .{});109 cases.addBuildFile("test/standalone/embed_generated_file/build.zig", .{});
110
111 cases.addBuildFile("test/standalone/dep_diamond/build.zig", .{});
112 cases.addBuildFile("test/standalone/dep_triangle/build.zig", .{});
113 cases.addBuildFile("test/standalone/dep_recursive/build.zig", .{});
114 cases.addBuildFile("test/standalone/dep_mutually_recursive/build.zig", .{});
115 cases.addBuildFile("test/standalone/dep_shared_builtin/build.zig", .{});
107}116}
test/standalone/dep_diamond/bar.zig created+1
...@@ -0,0 +1 @@
1pub const shared = @import("shared");
test/standalone/dep_diamond/build.zig created+28
...@@ -0,0 +1,28 @@
1const std = @import("std");
2
3pub fn build(b: *std.Build) void {
4 const optimize = b.standardOptimizeOption(.{});
5
6 const shared = b.createModule(.{
7 .source_file = .{ .path = "shared.zig" },
8 });
9
10 const exe = b.addExecutable(.{
11 .name = "test",
12 .root_source_file = .{ .path = "test.zig" },
13 .optimize = optimize,
14 });
15 exe.addAnonymousModule("foo", .{
16 .source_file = .{ .path = "foo.zig" },
17 .dependencies = &.{.{ .name = "shared", .module = shared }},
18 });
19 exe.addAnonymousModule("bar", .{
20 .source_file = .{ .path = "bar.zig" },
21 .dependencies = &.{.{ .name = "shared", .module = shared }},
22 });
23
24 const run = exe.run();
25
26 const test_step = b.step("test", "Test it");
27 test_step.dependOn(&run.step);
28}
test/standalone/dep_diamond/foo.zig created+1
...@@ -0,0 +1 @@
1pub const shared = @import("shared");
test/standalone/dep_diamond/shared.zig created+1
...@@ -0,0 +1 @@
1// (empty)
test/standalone/dep_diamond/test.zig created+7
...@@ -0,0 +1,7 @@
1const foo = @import("foo");
2const bar = @import("bar");
3const assert = @import("std").debug.assert;
4
5pub fn main() void {
6 assert(foo.shared == bar.shared);
7}
test/standalone/dep_mutually_recursive/bar.zig created+6
...@@ -0,0 +1,6 @@
1const assert = @import("std").debug.assert;
2pub const foo = @import("foo");
3
4comptime {
5 assert(foo.bar == @This());
6}
test/standalone/dep_mutually_recursive/build.zig created+26
...@@ -0,0 +1,26 @@
1const std = @import("std");
2
3pub fn build(b: *std.Build) void {
4 const optimize = b.standardOptimizeOption(.{});
5
6 const foo = b.createModule(.{
7 .source_file = .{ .path = "foo.zig" },
8 });
9 const bar = b.createModule(.{
10 .source_file = .{ .path = "bar.zig" },
11 });
12 foo.dependencies.put("bar", bar) catch @panic("OOM");
13 bar.dependencies.put("foo", foo) catch @panic("OOM");
14
15 const exe = b.addExecutable(.{
16 .name = "test",
17 .root_source_file = .{ .path = "test.zig" },
18 .optimize = optimize,
19 });
20 exe.addModule("foo", foo);
21
22 const run = exe.run();
23
24 const test_step = b.step("test", "Test it");
25 test_step.dependOn(&run.step);
26}
test/standalone/dep_mutually_recursive/foo.zig created+6
...@@ -0,0 +1,6 @@
1const assert = @import("std").debug.assert;
2pub const bar = @import("bar");
3
4comptime {
5 assert(bar.foo == @This());
6}
test/standalone/dep_mutually_recursive/test.zig created+7
...@@ -0,0 +1,7 @@
1const foo = @import("foo");
2const assert = @import("std").debug.assert;
3
4pub fn main() void {
5 assert(foo == foo.bar.foo);
6 assert(foo == foo.bar.foo.bar.foo);
7}
test/standalone/dep_recursive/build.zig created+22
...@@ -0,0 +1,22 @@
1const std = @import("std");
2
3pub fn build(b: *std.Build) void {
4 const optimize = b.standardOptimizeOption(.{});
5
6 const foo = b.createModule(.{
7 .source_file = .{ .path = "foo.zig" },
8 });
9 foo.dependencies.put("foo", foo) catch @panic("OOM");
10
11 const exe = b.addExecutable(.{
12 .name = "test",
13 .root_source_file = .{ .path = "test.zig" },
14 .optimize = optimize,
15 });
16 exe.addModule("foo", foo);
17
18 const run = exe.run();
19
20 const test_step = b.step("test", "Test it");
21 test_step.dependOn(&run.step);
22}
test/standalone/dep_recursive/foo.zig created+6
...@@ -0,0 +1,6 @@
1const assert = @import("std").debug.assert;
2pub const foo = @import("foo");
3
4comptime {
5 assert(foo == @This());
6}
test/standalone/dep_recursive/test.zig created+8
...@@ -0,0 +1,8 @@
1const foo = @import("foo");
2const shared = @import("shared");
3const assert = @import("std").debug.assert;
4
5pub fn main() void {
6 assert(foo == foo.foo);
7 assert(foo == foo.foo.foo);
8}
test/standalone/dep_shared_builtin/build.zig created+19
...@@ -0,0 +1,19 @@
1const std = @import("std");
2
3pub fn build(b: *std.Build) void {
4 const optimize = b.standardOptimizeOption(.{});
5
6 const exe = b.addExecutable(.{
7 .name = "test",
8 .root_source_file = .{ .path = "test.zig" },
9 .optimize = optimize,
10 });
11 exe.addAnonymousModule("foo", .{
12 .source_file = .{ .path = "foo.zig" },
13 });
14
15 const run = exe.run();
16
17 const test_step = b.step("test", "Test it");
18 test_step.dependOn(&run.step);
19}
test/standalone/dep_shared_builtin/foo.zig created+3
...@@ -0,0 +1,3 @@
1pub const std = @import("std");
2pub const builtin = @import("builtin");
3pub const root = @import("root");
test/standalone/dep_shared_builtin/test.zig created+11
...@@ -0,0 +1,11 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const root = @import("root");
4const foo = @import("foo");
5
6pub fn main() void {
7 std.debug.assert(root == @This());
8 std.debug.assert(std == foo.std);
9 std.debug.assert(builtin == foo.builtin);
10 std.debug.assert(root == foo.root);
11}
test/standalone/dep_triangle/build.zig created+25
...@@ -0,0 +1,25 @@
1const std = @import("std");
2
3pub fn build(b: *std.Build) void {
4 const optimize = b.standardOptimizeOption(.{});
5
6 const shared = b.createModule(.{
7 .source_file = .{ .path = "shared.zig" },
8 });
9
10 const exe = b.addExecutable(.{
11 .name = "test",
12 .root_source_file = .{ .path = "test.zig" },
13 .optimize = optimize,
14 });
15 exe.addAnonymousModule("foo", .{
16 .source_file = .{ .path = "foo.zig" },
17 .dependencies = &.{.{ .name = "shared", .module = shared }},
18 });
19 exe.addModule("shared", shared);
20
21 const run = exe.run();
22
23 const test_step = b.step("test", "Test it");
24 test_step.dependOn(&run.step);
25}
test/standalone/dep_triangle/foo.zig created+1
...@@ -0,0 +1 @@
1pub const shared = @import("shared");
test/standalone/dep_triangle/shared.zig created+1
...@@ -0,0 +1 @@
1// (empty)
test/standalone/dep_triangle/test.zig created+7
...@@ -0,0 +1,7 @@
1const foo = @import("foo");
2const shared = @import("shared");
3const assert = @import("std").debug.assert;
4
5pub fn main() void {
6 assert(foo.shared == shared);
7}
test/standalone/install_raw_hex/build.zig+10-5
...@@ -3,6 +3,9 @@ const std = @import("std");...@@ -3,6 +3,9 @@ const std = @import("std");
3const CheckFileStep = std.Build.CheckFileStep;3const CheckFileStep = std.Build.CheckFileStep;
44
5pub fn build(b: *std.Build) void {5pub fn build(b: *std.Build) void {
6 const test_step = b.step("test", "Test the program");
7 b.default_step.dependOn(test_step);
8
6 const target = .{9 const target = .{
7 .cpu_arch = .thumb,10 .cpu_arch = .thumb,
8 .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m4 },11 .cpu_model = .{ .explicit = &std.Target.arm.cpu.cortex_m4 },
...@@ -19,12 +22,14 @@ pub fn build(b: *std.Build) void {...@@ -19,12 +22,14 @@ pub fn build(b: *std.Build) void {
19 .optimize = optimize,22 .optimize = optimize,
20 });23 });
2124
22 const test_step = b.step("test", "Test the program");25 const hex_step = elf.addObjCopy(.{
23 b.default_step.dependOn(test_step);26 .basename = "hello.hex",
2427 });
25 const hex_step = b.addInstallRaw(elf, "hello.hex", .{});
26 test_step.dependOn(&hex_step.step);28 test_step.dependOn(&hex_step.step);
2729
28 const explicit_format_hex_step = b.addInstallRaw(elf, "hello.foo", .{ .format = .hex });30 const explicit_format_hex_step = elf.addObjCopy(.{
31 .basename = "hello.foo",
32 .format = .hex,
33 });
29 test_step.dependOn(&explicit_format_hex_step.step);34 test_step.dependOn(&explicit_format_hex_step.step);
30}35}
test/standalone/sigpipe/breakpipe.zig created+21
...@@ -0,0 +1,21 @@
1const std = @import("std");
2const build_options = @import("build_options");
3
4pub const std_options = if (build_options.keep_sigpipe) struct {
5 pub const keep_sigpipe = true;
6} else struct {
7 // intentionally not setting keep_sigpipe to ensure the default behavior is equivalent to false
8};
9
10pub fn main() !void {
11 const pipe = try std.os.pipe();
12 std.os.close(pipe[0]);
13 _ = std.os.write(pipe[1], "a") catch |err| switch (err) {
14 error.BrokenPipe => {
15 try std.io.getStdOut().writer().writeAll("BrokenPipe\n");
16 std.os.exit(123);
17 },
18 else => |e| return e,
19 };
20 unreachable;
21}
test/standalone/sigpipe/build.zig created+35
...@@ -0,0 +1,35 @@
1const std = @import("std");
2const os = std.os;
3
4pub fn build(b: *std.build.Builder) !void {
5 const test_step = b.step("test", "Run the tests");
6
7 // This test runs "breakpipe" as a child process and that process
8 // depends on inheriting a SIGPIPE disposition of "default".
9 {
10 const act = os.Sigaction{
11 .handler = .{ .handler = os.SIG.DFL },
12 .mask = os.empty_sigset,
13 .flags = 0,
14 };
15 try os.sigaction(os.SIG.PIPE, &act, null);
16 }
17
18 for ([_]bool{ false, true }) |keep_sigpipe| {
19 const options = b.addOptions();
20 options.addOption(bool, "keep_sigpipe", keep_sigpipe);
21 const exe = b.addExecutable(.{
22 .name = "breakpipe",
23 .root_source_file = .{ .path = "breakpipe.zig" },
24 });
25 exe.addOptions("build_options", options);
26 const run = exe.run();
27 if (keep_sigpipe) {
28 run.expected_term = .{ .Signal = std.os.SIG.PIPE };
29 } else {
30 run.stdout_action = .{ .expect_exact = "BrokenPipe\n" };
31 run.expected_term = .{ .Exited = 123 };
32 }
33 test_step.dependOn(&run.step);
34 }
35}
test/tests.zig+8-8
...@@ -58,14 +58,14 @@ const test_targets = blk: {...@@ -58,14 +58,14 @@ const test_targets = blk: {
58 .link_libc = true,58 .link_libc = true,
59 .backend = .stage2_c,59 .backend = .stage2_c,
60 },60 },
61 //.{61 .{
62 // .target = .{62 .target = .{
63 // .cpu_arch = .x86_64,63 .cpu_arch = .x86_64,
64 // .os_tag = .linux,64 .os_tag = .linux,
65 // .abi = .none,65 .abi = .none,
66 // },66 },
67 // .backend = .stage2_x86_64,67 .backend = .stage2_x86_64,
68 //},68 },
69 .{69 .{
70 .target = .{70 .target = .{
71 .cpu_arch = .aarch64,71 .cpu_arch = .aarch64,