authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-01-16 12:26:04-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-01-16 12:26:04-05:00
logb897e98d30b7e471cdabf6b8f0baab44998265cd
tree642a2e9b0eb824c9cae69bfd29a72c11eb4b7101
parenteb3726c502e92ec4a3689732a76479c6d561cff5
parentee9ab15679ee04a40bdc582779faf43fb10836ce

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


61 files changed, 3197 insertions(+), 344 deletions(-)

CMakeLists.txt+5
...@@ -364,6 +364,11 @@ set(ZIG_STD_FILES...@@ -364,6 +364,11 @@ set(ZIG_STD_FILES
364 "c/index.zig"364 "c/index.zig"
365 "c/linux.zig"365 "c/linux.zig"
366 "c/windows.zig"366 "c/windows.zig"
367 "crypto/index.zig"
368 "crypto/md5.zig"
369 "crypto/sha1.zig"
370 "crypto/sha2.zig"
371 "crypto/blake2.zig"
367 "cstr.zig"372 "cstr.zig"
368 "debug/failing_allocator.zig"373 "debug/failing_allocator.zig"
369 "debug/index.zig"374 "debug/index.zig"
README.md+5-2
...@@ -54,7 +54,7 @@ that counts as "freestanding" for the purposes of this table....@@ -54,7 +54,7 @@ that counts as "freestanding" for the purposes of this table.
5454
55| | freestanding | linux | macosx | windows | other |55| | freestanding | linux | macosx | windows | other |
56|-------------|--------------|---------|---------|---------|---------|56|-------------|--------------|---------|---------|---------|---------|
57|i386 | OK | planned | OK | OK | planned |57|i386 | OK | planned | OK | planned | planned |
58|x86_64 | OK | OK | OK | OK | planned |58|x86_64 | OK | OK | OK | OK | planned |
59|arm | OK | planned | planned | N/A | planned |59|arm | OK | planned | planned | N/A | planned |
60|aarch64 | OK | planned | planned | planned | planned |60|aarch64 | OK | planned | planned | planned | planned |
...@@ -125,17 +125,20 @@ libc. Create demo games using Zig....@@ -125,17 +125,20 @@ libc. Create demo games using Zig.
125125
126##### POSIX126##### POSIX
127127
128 * gcc >= 5.0.0 or clang >= 3.6.0
129 * cmake >= 2.8.5128 * cmake >= 2.8.5
129 * gcc >= 5.0.0 or clang >= 3.6.0
130 * LLVM, Clang, LLD libraries == 6.x, compiled with the same gcc or clang version above130 * LLVM, Clang, LLD libraries == 6.x, compiled with the same gcc or clang version above
131131
132##### Windows132##### Windows
133133
134 * cmake >= 2.8.5
134 * Microsoft Visual Studio 2015135 * Microsoft Visual Studio 2015
135 * LLVM, Clang, LLD libraries == 6.x, compiled with the same MSVC version above136 * LLVM, Clang, LLD libraries == 6.x, compiled with the same MSVC version above
136137
137#### Instructions138#### Instructions
138139
140##### POSIX
141
139If you have gcc or clang installed, you can find out what `ZIG_LIBC_LIB_DIR`,142If you have gcc or clang installed, you can find out what `ZIG_LIBC_LIB_DIR`,
140`ZIG_LIBC_STATIC_LIB_DIR`, and `ZIG_LIBC_INCLUDE_DIR` should be set to143`ZIG_LIBC_STATIC_LIB_DIR`, and `ZIG_LIBC_INCLUDE_DIR` should be set to
141(example below).144(example below).
build.zig+6-6
...@@ -10,7 +10,7 @@ const ArrayList = std.ArrayList;...@@ -10,7 +10,7 @@ const ArrayList = std.ArrayList;
10const Buffer = std.Buffer;10const Buffer = std.Buffer;
11const io = std.io;11const io = std.io;
1212
13pub fn build(b: &Builder) {13pub fn build(b: &Builder) -> %void {
14 const mode = b.standardReleaseOptions();14 const mode = b.standardReleaseOptions();
1515
16 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");16 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
...@@ -36,7 +36,7 @@ pub fn build(b: &Builder) {...@@ -36,7 +36,7 @@ pub fn build(b: &Builder) {
36 const test_step = b.step("test", "Run all the tests");36 const test_step = b.step("test", "Run all the tests");
3737
38 // find the stage0 build artifacts because we're going to re-use config.h and zig_cpp library38 // find the stage0 build artifacts because we're going to re-use config.h and zig_cpp library
39 const build_info = b.exec([][]const u8{b.zig_exe, "BUILD_INFO"});39 const build_info = try b.exec([][]const u8{b.zig_exe, "BUILD_INFO"});
40 var index: usize = 0;40 var index: usize = 0;
41 const cmake_binary_dir = nextValue(&index, build_info);41 const cmake_binary_dir = nextValue(&index, build_info);
42 const cxx_compiler = nextValue(&index, build_info);42 const cxx_compiler = nextValue(&index, build_info);
...@@ -68,7 +68,7 @@ pub fn build(b: &Builder) {...@@ -68,7 +68,7 @@ pub fn build(b: &Builder) {
68 dependOnLib(exe, llvm);68 dependOnLib(exe, llvm);
6969
70 if (exe.target.getOs() == builtin.Os.linux) {70 if (exe.target.getOs() == builtin.Os.linux) {
71 const libstdcxx_path_padded = b.exec([][]const u8{cxx_compiler, "-print-file-name=libstdc++.a"});71 const libstdcxx_path_padded = try b.exec([][]const u8{cxx_compiler, "-print-file-name=libstdc++.a"});
72 const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\r\n").next();72 const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\r\n").next();
73 exe.addObjectFile(libstdcxx_path);73 exe.addObjectFile(libstdcxx_path);
7474
...@@ -155,9 +155,9 @@ const LibraryDep = struct {...@@ -155,9 +155,9 @@ const LibraryDep = struct {
155};155};
156156
157fn findLLVM(b: &Builder, llvm_config_exe: []const u8) -> %LibraryDep {157fn findLLVM(b: &Builder, llvm_config_exe: []const u8) -> %LibraryDep {
158 const libs_output = b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"});158 const libs_output = try b.exec([][]const u8{llvm_config_exe, "--libs", "--system-libs"});
159 const includes_output = b.exec([][]const u8{llvm_config_exe, "--includedir"});159 const includes_output = try b.exec([][]const u8{llvm_config_exe, "--includedir"});
160 const libdir_output = b.exec([][]const u8{llvm_config_exe, "--libdir"});160 const libdir_output = try b.exec([][]const u8{llvm_config_exe, "--libdir"});
161161
162 var result = LibraryDep {162 var result = LibraryDep {
163 .libs = ArrayList([]const u8).init(b.allocator),163 .libs = ArrayList([]const u8).init(b.allocator),
doc/langref.html.in+8
...@@ -142,6 +142,7 @@...@@ -142,6 +142,7 @@
142 <li><a href="#builtin-TagType">@TagType</a></li>142 <li><a href="#builtin-TagType">@TagType</a></li>
143 <li><a href="#builtin-EnumTagType">@EnumTagType</a></li>143 <li><a href="#builtin-EnumTagType">@EnumTagType</a></li>
144 <li><a href="#builtin-errorName">@errorName</a></li>144 <li><a href="#builtin-errorName">@errorName</a></li>
145 <li><a href="#builtin-errorReturnTrace">@errorReturnTrace</a></li>
145 <li><a href="#builtin-fence">@fence</a></li>146 <li><a href="#builtin-fence">@fence</a></li>
146 <li><a href="#builtin-fieldParentPtr">@fieldParentPtr</a></li>147 <li><a href="#builtin-fieldParentPtr">@fieldParentPtr</a></li>
147 <li><a href="#builtin-frameAddress">@frameAddress</a></li>148 <li><a href="#builtin-frameAddress">@frameAddress</a></li>
...@@ -4412,6 +4413,13 @@ test.zig:6:2: error: found compile log statement...@@ -4412,6 +4413,13 @@ test.zig:6:2: error: found compile log statement
4412 or all calls have a compile-time known value for <code>err</code>, then no4413 or all calls have a compile-time known value for <code>err</code>, then no
4413 error name table will be generated.4414 error name table will be generated.
4414 </p>4415 </p>
4416 <h3 id="builtin-errorReturnTrace">@errorReturnTrace</h3>
4417 <pre><code class="zig">@errorReturnTrace() -&gt; ?&amp;builtin.StackTrace</code></pre>
4418 <p>
4419 If the binary is built with error return tracing, and this function is invoked in a
4420 function that calls a function with an error or error union return type, returns a
4421 stack trace object. Otherwise returns `null`.
4422 </p>
4415 <h3 id="builtin-fence">@fence</h3>4423 <h3 id="builtin-fence">@fence</h3>
4416 <pre><code class="zig">@fence(order: AtomicOrder)</code></pre>4424 <pre><code class="zig">@fence(order: AtomicOrder)</code></pre>
4417 <p>4425 <p>
example/mix_o_files/build.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const Builder = @import("std").build.Builder;1const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) {3pub fn build(b: &Builder) -> %void {
4 const obj = b.addObject("base64", "base64.zig");4 const obj = b.addObject("base64", "base64.zig");
55
6 const exe = b.addCExecutable("test");6 const exe = b.addCExecutable("test");
example/shared_library/build.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const Builder = @import("std").build.Builder;1const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) {3pub fn build(b: &Builder) -> %void {
4 const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));4 const lib = b.addSharedLibrary("mathtest", "mathtest.zig", b.version(1, 0, 0));
55
6 const exe = b.addCExecutable("test");6 const exe = b.addCExecutable("test");
src-self-hosted/parser.zig-6
...@@ -1146,12 +1146,6 @@ fn testCanonical(source: []const u8) {...@@ -1146,12 +1146,6 @@ fn testCanonical(source: []const u8) {
1146}1146}
11471147
1148test "zig fmt" {1148test "zig fmt" {
1149 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
1150 // TODO get this test passing
1151 // https://github.com/zig-lang/zig/issues/537
1152 return;
1153 }
1154
1155 testCanonical(1149 testCanonical(
1156 \\extern fn puts(s: &const u8) -> c_int;1150 \\extern fn puts(s: &const u8) -> c_int;
1157 \\1151 \\
src/all_types.hpp+13
...@@ -1205,6 +1205,7 @@ struct FnTableEntry {...@@ -1205,6 +1205,7 @@ struct FnTableEntry {
1205 uint32_t alignstack_value;1205 uint32_t alignstack_value;
12061206
1207 ZigList<FnExport> export_list;1207 ZigList<FnExport> export_list;
1208 bool calls_errorable_function;
1208};1209};
12091210
1210uint32_t fn_table_entry_hash(FnTableEntry*);1211uint32_t fn_table_entry_hash(FnTableEntry*);
...@@ -1273,6 +1274,7 @@ enum BuiltinFnId {...@@ -1273,6 +1274,7 @@ enum BuiltinFnId {
1273 BuiltinFnIdSetAlignStack,1274 BuiltinFnIdSetAlignStack,
1274 BuiltinFnIdArgType,1275 BuiltinFnIdArgType,
1275 BuiltinFnIdExport,1276 BuiltinFnIdExport,
1277 BuiltinFnIdErrorReturnTrace,
1276};1278};
12771279
1278struct BuiltinFnEntry {1280struct BuiltinFnEntry {
...@@ -1498,6 +1500,7 @@ struct CodeGen {...@@ -1498,6 +1500,7 @@ struct CodeGen {
1498 Buf triple_str;1500 Buf triple_str;
1499 BuildMode build_mode;1501 BuildMode build_mode;
1500 bool is_test_build;1502 bool is_test_build;
1503 bool have_err_ret_tracing;
1501 uint32_t target_os_index;1504 uint32_t target_os_index;
1502 uint32_t target_arch_index;1505 uint32_t target_arch_index;
1503 uint32_t target_environ_index;1506 uint32_t target_environ_index;
...@@ -1530,6 +1533,7 @@ struct CodeGen {...@@ -1530,6 +1533,7 @@ struct CodeGen {
1530 FnTableEntry *panic_fn;1533 FnTableEntry *panic_fn;
1531 LLVMValueRef cur_ret_ptr;1534 LLVMValueRef cur_ret_ptr;
1532 LLVMValueRef cur_fn_val;1535 LLVMValueRef cur_fn_val;
1536 LLVMValueRef cur_err_ret_trace_val;
1533 bool c_want_stdint;1537 bool c_want_stdint;
1534 bool c_want_stdbool;1538 bool c_want_stdbool;
1535 AstNode *root_export_decl;1539 AstNode *root_export_decl;
...@@ -1572,6 +1576,8 @@ struct CodeGen {...@@ -1572,6 +1576,8 @@ struct CodeGen {
1572 size_t largest_err_name_len;1576 size_t largest_err_name_len;
1573 LLVMValueRef safety_crash_err_fn;1577 LLVMValueRef safety_crash_err_fn;
15741578
1579 LLVMValueRef return_err_fn;
1580
1575 IrInstruction *invalid_instruction;1581 IrInstruction *invalid_instruction;
1576 ConstExprValue const_void_val;1582 ConstExprValue const_void_val;
15771583
...@@ -1595,6 +1601,8 @@ struct CodeGen {...@@ -1595,6 +1601,8 @@ struct CodeGen {
1595 ZigList<AstNode *> tld_ref_source_node_stack;1601 ZigList<AstNode *> tld_ref_source_node_stack;
15961602
1597 TypeTableEntry *align_amt_type;1603 TypeTableEntry *align_amt_type;
1604 TypeTableEntry *stack_trace_type;
1605 TypeTableEntry *ptr_to_stack_trace_type;
1598};1606};
15991607
1600enum VarLinkage {1608enum VarLinkage {
...@@ -1896,6 +1904,7 @@ enum IrInstructionId {...@@ -1896,6 +1904,7 @@ enum IrInstructionId {
1896 IrInstructionIdSetAlignStack,1904 IrInstructionIdSetAlignStack,
1897 IrInstructionIdArgType,1905 IrInstructionIdArgType,
1898 IrInstructionIdExport,1906 IrInstructionIdExport,
1907 IrInstructionIdErrorReturnTrace,
1899};1908};
19001909
1901struct IrInstruction {1910struct IrInstruction {
...@@ -2717,6 +2726,10 @@ struct IrInstructionExport {...@@ -2717,6 +2726,10 @@ struct IrInstructionExport {
2717 IrInstruction *target;2726 IrInstruction *target;
2718};2727};
27192728
2729struct IrInstructionErrorReturnTrace {
2730 IrInstruction base;
2731};
2732
2720static const size_t slice_ptr_index = 0;2733static const size_t slice_ptr_index = 0;
2721static const size_t slice_len_index = 1;2734static const size_t slice_len_index = 1;
27222735
src/analyze.cpp+48-12
...@@ -869,6 +869,16 @@ static const char *calling_convention_fn_type_str(CallingConvention cc) {...@@ -869,6 +869,16 @@ static const char *calling_convention_fn_type_str(CallingConvention cc) {
869 zig_unreachable();869 zig_unreachable();
870}870}
871871
872TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g) {
873 if (g->stack_trace_type == nullptr) {
874 ConstExprValue *stack_trace_type_val = get_builtin_value(g, "StackTrace");
875 assert(stack_trace_type_val->type->id == TypeTableEntryIdMetaType);
876 g->stack_trace_type = stack_trace_type_val->data.x_type;
877 g->ptr_to_stack_trace_type = get_pointer_to_type(g, g->stack_trace_type, false);
878 }
879 return g->ptr_to_stack_trace_type;
880}
881
872TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {882TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
873 auto table_entry = g->fn_type_table.maybe_get(fn_type_id);883 auto table_entry = g->fn_type_table.maybe_get(fn_type_id);
874 if (table_entry) {884 if (table_entry) {
...@@ -915,10 +925,16 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -915,10 +925,16 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
915 if (!skip_debug_info) {925 if (!skip_debug_info) {
916 bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) &&926 bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) &&
917 handle_is_ptr(fn_type_id->return_type);927 handle_is_ptr(fn_type_id->return_type);
928 bool prefix_arg_error_return_trace = g->have_err_ret_tracing &&
929 (fn_type_id->return_type->id == TypeTableEntryIdErrorUnion ||
930 fn_type_id->return_type->id == TypeTableEntryIdPureError);
918 // +1 for maybe making the first argument the return value931 // +1 for maybe making the first argument the return value
919 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + fn_type_id->param_count);932 // +1 for maybe last argument the error return trace
920 // +1 because 0 is the return type and +1 for maybe making first arg ret val933 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(2 + fn_type_id->param_count);
921 ZigLLVMDIType **param_di_types = allocate<ZigLLVMDIType*>(2 + fn_type_id->param_count);934 // +1 because 0 is the return type and
935 // +1 for maybe making first arg ret val and
936 // +1 for maybe last argument the error return trace
937 ZigLLVMDIType **param_di_types = allocate<ZigLLVMDIType*>(3 + fn_type_id->param_count);
922 param_di_types[0] = fn_type_id->return_type->di_type;938 param_di_types[0] = fn_type_id->return_type->di_type;
923 size_t gen_param_index = 0;939 size_t gen_param_index = 0;
924 TypeTableEntry *gen_return_type;940 TypeTableEntry *gen_return_type;
...@@ -936,6 +952,14 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -936,6 +952,14 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
936 }952 }
937 fn_type->data.fn.gen_return_type = gen_return_type;953 fn_type->data.fn.gen_return_type = gen_return_type;
938954
955 if (prefix_arg_error_return_trace) {
956 TypeTableEntry *gen_type = get_ptr_to_stack_trace_type(g);
957 gen_param_types[gen_param_index] = gen_type->type_ref;
958 gen_param_index += 1;
959 // after the gen_param_index += 1 because 0 is the return type
960 param_di_types[gen_param_index] = gen_type->di_type;
961 }
962
939 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);963 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);
940 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {964 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
941 FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i];965 FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i];
...@@ -1168,6 +1192,9 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -1168,6 +1192,9 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
1168 }1192 }
11691193
1170 TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type);1194 TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type);
1195 if (type_is_invalid(type_entry)) {
1196 return g->builtin_types.entry_invalid;
1197 }
1171 if (fn_type_id.cc != CallingConventionUnspecified) {1198 if (fn_type_id.cc != CallingConventionUnspecified) {
1172 type_ensure_zero_bits_known(g, type_entry);1199 type_ensure_zero_bits_known(g, type_entry);
1173 if (!type_has_bits(type_entry)) {1200 if (!type_has_bits(type_entry)) {
...@@ -2204,6 +2231,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {...@@ -2204,6 +2231,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
2204 // is a pointer to this very struct, or a function pointer with parameters that2231 // is a pointer to this very struct, or a function pointer with parameters that
2205 // reference such a type.2232 // reference such a type.
2206 union_type->data.unionation.zero_bits_known = true;2233 union_type->data.unionation.zero_bits_known = true;
2234 union_type->data.unionation.zero_bits_loop_flag = false;
2207 if (union_type->data.unionation.abi_alignment == 0) {2235 if (union_type->data.unionation.abi_alignment == 0) {
2208 if (union_type->data.unionation.layout == ContainerLayoutPacked) {2236 if (union_type->data.unionation.layout == ContainerLayoutPacked) {
2209 union_type->data.unionation.abi_alignment = 1;2237 union_type->data.unionation.abi_alignment = 1;
...@@ -2558,7 +2586,7 @@ static bool scope_is_root_decls(Scope *scope) {...@@ -2558,7 +2586,7 @@ static bool scope_is_root_decls(Scope *scope) {
25582586
2559static void wrong_panic_prototype(CodeGen *g, AstNode *proto_node, TypeTableEntry *fn_type) {2587static void wrong_panic_prototype(CodeGen *g, AstNode *proto_node, TypeTableEntry *fn_type) {
2560 add_node_error(g, proto_node,2588 add_node_error(g, proto_node,
2561 buf_sprintf("expected 'fn([]const u8) -> unreachable', found '%s'",2589 buf_sprintf("expected 'fn([]const u8, ?&builtin.StackTrace) -> unreachable', found '%s'",
2562 buf_ptr(&fn_type->name)));2590 buf_ptr(&fn_type->name)));
2563}2591}
25642592
...@@ -2567,7 +2595,7 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {...@@ -2567,7 +2595,7 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {
2567 assert(proto_node->type == NodeTypeFnProto);2595 assert(proto_node->type == NodeTypeFnProto);
2568 TypeTableEntry *fn_type = panic_fn->type_entry;2596 TypeTableEntry *fn_type = panic_fn->type_entry;
2569 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;2597 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
2570 if (fn_type_id->param_count != 1) {2598 if (fn_type_id->param_count != 2) {
2571 return wrong_panic_prototype(g, proto_node, fn_type);2599 return wrong_panic_prototype(g, proto_node, fn_type);
2572 }2600 }
2573 TypeTableEntry *const_u8_ptr = get_pointer_to_type(g, g->builtin_types.entry_u8, true);2601 TypeTableEntry *const_u8_ptr = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
...@@ -2576,6 +2604,11 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {...@@ -2576,6 +2604,11 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) {
2576 return wrong_panic_prototype(g, proto_node, fn_type);2604 return wrong_panic_prototype(g, proto_node, fn_type);
2577 }2605 }
25782606
2607 TypeTableEntry *nullable_ptr_to_stack_trace_type = get_maybe_type(g, get_ptr_to_stack_trace_type(g));
2608 if (fn_type_id->param_info[1].type != nullable_ptr_to_stack_trace_type) {
2609 return wrong_panic_prototype(g, proto_node, fn_type);
2610 }
2611
2579 TypeTableEntry *actual_return_type = fn_type_id->return_type;2612 TypeTableEntry *actual_return_type = fn_type_id->return_type;
2580 if (actual_return_type != g->builtin_types.entry_unreachable) {2613 if (actual_return_type != g->builtin_types.entry_unreachable) {
2581 return wrong_panic_prototype(g, proto_node, fn_type);2614 return wrong_panic_prototype(g, proto_node, fn_type);
...@@ -2680,13 +2713,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {...@@ -2680,13 +2713,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
2680 {2713 {
2681 if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) {2714 if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) {
2682 g->main_fn = fn_table_entry;2715 g->main_fn = fn_table_entry;
2683 TypeTableEntry *err_void = get_error_type(g, g->builtin_types.entry_void);
2684 TypeTableEntry *actual_return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type;
2685 if (actual_return_type != err_void) {
2686 add_node_error(g, fn_proto->return_type,
2687 buf_sprintf("expected return type of main to be '%%void', instead is '%s'",
2688 buf_ptr(&actual_return_type->name)));
2689 }
2690 } else if ((import->package == g->panic_package || g->have_pub_panic) &&2716 } else if ((import->package == g->panic_package || g->have_pub_panic) &&
2691 buf_eql_str(&fn_table_entry->symbol_name, "panic"))2717 buf_eql_str(&fn_table_entry->symbol_name, "panic"))
2692 {2718 {
...@@ -5527,3 +5553,13 @@ bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b) {...@@ -5527,3 +5553,13 @@ bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b) {
5527 return a == b;5553 return a == b;
5528}5554}
55295555
5556ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) {
5557 Tld *tld = codegen->compile_var_import->decls_scope->decl_table.get(buf_create_from_str(name));
5558 resolve_top_level_decl(codegen, tld, false, nullptr);
5559 assert(tld->id == TldIdVar);
5560 TldVar *tld_var = (TldVar *)tld;
5561 ConstExprValue *var_value = tld_var->var->value;
5562 assert(var_value != nullptr);
5563 return var_value;
5564}
5565
src/analyze.hpp+5
...@@ -185,4 +185,9 @@ PackageTableEntry *new_anonymous_package(void);...@@ -185,4 +185,9 @@ PackageTableEntry *new_anonymous_package(void);
185Buf *const_value_to_buffer(ConstExprValue *const_val);185Buf *const_value_to_buffer(ConstExprValue *const_val);
186void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage, bool ccc);186void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage, bool ccc);
187187
188
189ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);
190TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g);
191
192
188#endif193#endif
src/bigint.cpp+440-10
...@@ -12,6 +12,9 @@...@@ -12,6 +12,9 @@
12#include "os.hpp"12#include "os.hpp"
13#include "softfloat.hpp"13#include "softfloat.hpp"
1414
15#include <limits>
16#include <algorithm>
17
15static void bigint_normalize(BigInt *dest) {18static void bigint_normalize(BigInt *dest) {
16 const uint64_t *digits = bigint_ptr(dest);19 const uint64_t *digits = bigint_ptr(dest);
1720
...@@ -539,7 +542,7 @@ void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) {...@@ -539,7 +542,7 @@ void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) {
539 dest->data.digits[i] = x;542 dest->data.digits[i] = x;
540 i += 1;543 i += 1;
541544
542 if (!found_digit)545 if (!found_digit || i >= bigger_op->digit_count)
543 break;546 break;
544 }547 }
545 assert(overflow == 0);548 assert(overflow == 0);
...@@ -670,19 +673,417 @@ void bigint_mul_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t...@@ -670,19 +673,417 @@ void bigint_mul_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t
670 bigint_truncate(dest, &unwrapped, bit_count, is_signed);673 bigint_truncate(dest, &unwrapped, bit_count, is_signed);
671}674}
672675
676enum ZeroBehavior {
677 /// \brief The returned value is undefined.
678 ZB_Undefined,
679 /// \brief The returned value is numeric_limits<T>::max()
680 ZB_Max,
681 /// \brief The returned value is numeric_limits<T>::digits
682 ZB_Width
683};
684
685template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
686 static std::size_t count(T Val, ZeroBehavior) {
687 if (!Val)
688 return std::numeric_limits<T>::digits;
689
690 // Bisection method.
691 std::size_t ZeroBits = 0;
692 for (T Shift = std::numeric_limits<T>::digits >> 1; Shift; Shift >>= 1) {
693 T Tmp = Val >> Shift;
694 if (Tmp)
695 Val = Tmp;
696 else
697 ZeroBits |= Shift;
698 }
699 return ZeroBits;
700 }
701};
702
703#if __GNUC__ >= 4 || defined(_MSC_VER)
704template <typename T> struct LeadingZerosCounter<T, 4> {
705 static std::size_t count(T Val, ZeroBehavior ZB) {
706 if (ZB != ZB_Undefined && Val == 0)
707 return 32;
708
709#if defined(_MSC_VER)
710 unsigned long Index;
711 _BitScanReverse(&Index, Val);
712 return Index ^ 31;
713#else
714 return __builtin_clz(Val);
715#endif
716 }
717};
718
719#if !defined(_MSC_VER) || defined(_M_X64)
720template <typename T> struct LeadingZerosCounter<T, 8> {
721 static std::size_t count(T Val, ZeroBehavior ZB) {
722 if (ZB != ZB_Undefined && Val == 0)
723 return 64;
724
725#if defined(_MSC_VER)
726 unsigned long Index;
727 _BitScanReverse64(&Index, Val);
728 return Index ^ 63;
729#else
730 return __builtin_clzll(Val);
731#endif
732 }
733};
734#endif
735#endif
736
737/// \brief Count number of 0's from the most significant bit to the least
738/// stopping at the first 1.
739///
740/// Only unsigned integral types are allowed.
741///
742/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
743/// valid arguments.
744template <typename T>
745std::size_t countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
746 static_assert(std::numeric_limits<T>::is_integer &&
747 !std::numeric_limits<T>::is_signed,
748 "Only unsigned integral types are allowed.");
749 return LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB);
750}
751
752/// Make a 64-bit integer from a high / low pair of 32-bit integers.
753constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) {
754 return ((uint64_t)High << 32) | (uint64_t)Low;
755}
756
757/// Return the high 32 bits of a 64 bit value.
758constexpr inline uint32_t Hi_32(uint64_t Value) {
759 return static_cast<uint32_t>(Value >> 32);
760}
761
762/// Return the low 32 bits of a 64 bit value.
763constexpr inline uint32_t Lo_32(uint64_t Value) {
764 return static_cast<uint32_t>(Value);
765}
766
767/// Implementation of Knuth's Algorithm D (Division of nonnegative integers)
768/// from "Art of Computer Programming, Volume 2", section 4.3.1, p. 272. The
769/// variables here have the same names as in the algorithm. Comments explain
770/// the algorithm and any deviation from it.
771static void KnuthDiv(uint32_t *u, uint32_t *v, uint32_t *q, uint32_t* r,
772 unsigned m, unsigned n)
773{
774 assert(u && "Must provide dividend");
775 assert(v && "Must provide divisor");
776 assert(q && "Must provide quotient");
777 assert(u != v && u != q && v != q && "Must use different memory");
778 assert(n>1 && "n must be > 1");
779
780 // b denotes the base of the number system. In our case b is 2^32.
781 const uint64_t b = uint64_t(1) << 32;
782
783 // D1. [Normalize.] Set d = b / (v[n-1] + 1) and multiply all the digits of
784 // u and v by d. Note that we have taken Knuth's advice here to use a power
785 // of 2 value for d such that d * v[n-1] >= b/2 (b is the base). A power of
786 // 2 allows us to shift instead of multiply and it is easy to determine the
787 // shift amount from the leading zeros. We are basically normalizing the u
788 // and v so that its high bits are shifted to the top of v's range without
789 // overflow. Note that this can require an extra word in u so that u must
790 // be of length m+n+1.
791 unsigned shift = countLeadingZeros(v[n-1]);
792 uint32_t v_carry = 0;
793 uint32_t u_carry = 0;
794 if (shift) {
795 for (unsigned i = 0; i < m+n; ++i) {
796 uint32_t u_tmp = u[i] >> (32 - shift);
797 u[i] = (u[i] << shift) | u_carry;
798 u_carry = u_tmp;
799 }
800 for (unsigned i = 0; i < n; ++i) {
801 uint32_t v_tmp = v[i] >> (32 - shift);
802 v[i] = (v[i] << shift) | v_carry;
803 v_carry = v_tmp;
804 }
805 }
806 u[m+n] = u_carry;
807
808 // D2. [Initialize j.] Set j to m. This is the loop counter over the places.
809 int j = m;
810 do {
811 // D3. [Calculate q'.].
812 // Set qp = (u[j+n]*b + u[j+n-1]) / v[n-1]. (qp=qprime=q')
813 // Set rp = (u[j+n]*b + u[j+n-1]) % v[n-1]. (rp=rprime=r')
814 // Now test if qp == b or qp*v[n-2] > b*rp + u[j+n-2]; if so, decrease
815 // qp by 1, increase rp by v[n-1], and repeat this test if rp < b. The test
816 // on v[n-2] determines at high speed most of the cases in which the trial
817 // value qp is one too large, and it eliminates all cases where qp is two
818 // too large.
819 uint64_t dividend = Make_64(u[j+n], u[j+n-1]);
820 uint64_t qp = dividend / v[n-1];
821 uint64_t rp = dividend % v[n-1];
822 if (qp == b || qp*v[n-2] > b*rp + u[j+n-2]) {
823 qp--;
824 rp += v[n-1];
825 if (rp < b && (qp == b || qp*v[n-2] > b*rp + u[j+n-2]))
826 qp--;
827 }
828
829 // D4. [Multiply and subtract.] Replace (u[j+n]u[j+n-1]...u[j]) with
830 // (u[j+n]u[j+n-1]..u[j]) - qp * (v[n-1]...v[1]v[0]). This computation
831 // consists of a simple multiplication by a one-place number, combined with
832 // a subtraction.
833 // The digits (u[j+n]...u[j]) should be kept positive; if the result of
834 // this step is actually negative, (u[j+n]...u[j]) should be left as the
835 // true value plus b**(n+1), namely as the b's complement of
836 // the true value, and a "borrow" to the left should be remembered.
837 int64_t borrow = 0;
838 for (unsigned i = 0; i < n; ++i) {
839 uint64_t p = uint64_t(qp) * uint64_t(v[i]);
840 int64_t subres = int64_t(u[j+i]) - borrow - Lo_32(p);
841 u[j+i] = Lo_32(subres);
842 borrow = Hi_32(p) - Hi_32(subres);
843 }
844 bool isNeg = u[j+n] < borrow;
845 u[j+n] -= Lo_32(borrow);
846
847 // D5. [Test remainder.] Set q[j] = qp. If the result of step D4 was
848 // negative, go to step D6; otherwise go on to step D7.
849 q[j] = Lo_32(qp);
850 if (isNeg) {
851 // D6. [Add back]. The probability that this step is necessary is very
852 // small, on the order of only 2/b. Make sure that test data accounts for
853 // this possibility. Decrease q[j] by 1
854 q[j]--;
855 // and add (0v[n-1]...v[1]v[0]) to (u[j+n]u[j+n-1]...u[j+1]u[j]).
856 // A carry will occur to the left of u[j+n], and it should be ignored
857 // since it cancels with the borrow that occurred in D4.
858 bool carry = false;
859 for (unsigned i = 0; i < n; i++) {
860 uint32_t limit = std::min(u[j+i],v[i]);
861 u[j+i] += v[i] + carry;
862 carry = u[j+i] < limit || (carry && u[j+i] == limit);
863 }
864 u[j+n] += carry;
865 }
866
867 // D7. [Loop on j.] Decrease j by one. Now if j >= 0, go back to D3.
868 } while (--j >= 0);
869
870 // D8. [Unnormalize]. Now q[...] is the desired quotient, and the desired
871 // remainder may be obtained by dividing u[...] by d. If r is non-null we
872 // compute the remainder (urem uses this).
873 if (r) {
874 // The value d is expressed by the "shift" value above since we avoided
875 // multiplication by d by using a shift left. So, all we have to do is
876 // shift right here.
877 if (shift) {
878 uint32_t carry = 0;
879 for (int i = n-1; i >= 0; i--) {
880 r[i] = (u[i] >> shift) | carry;
881 carry = u[i] << (32 - shift);
882 }
883 } else {
884 for (int i = n-1; i >= 0; i--) {
885 r[i] = u[i];
886 }
887 }
888 }
889}
890
891// Implementation ported from LLVM/lib/Support/APInt.cpp
892static void bigint_unsigned_division(const BigInt *op1, const BigInt *op2, BigInt *Quotient, BigInt *Remainder) {
893 Cmp cmp = bigint_cmp(op1, op2);
894 if (cmp == CmpLT) {
895 if (Quotient != nullptr) {
896 bigint_init_unsigned(Quotient, 0);
897 }
898 if (Remainder != nullptr) {
899 bigint_init_bigint(Remainder, op1);
900 }
901 return;
902 }
903 if (cmp == CmpEQ) {
904 if (Quotient != nullptr) {
905 bigint_init_unsigned(Quotient, 1);
906 }
907 if (Remainder != nullptr) {
908 bigint_init_unsigned(Remainder, 0);
909 }
910 return;
911 }
912
913 const uint64_t *LHS = bigint_ptr(op1);
914 const uint64_t *RHS = bigint_ptr(op2);
915 unsigned lhsWords = op1->digit_count;
916 unsigned rhsWords = op2->digit_count;
917
918 // First, compose the values into an array of 32-bit words instead of
919 // 64-bit words. This is a necessity of both the "short division" algorithm
920 // and the Knuth "classical algorithm" which requires there to be native
921 // operations for +, -, and * on an m bit value with an m*2 bit result. We
922 // can't use 64-bit operands here because we don't have native results of
923 // 128-bits. Furthermore, casting the 64-bit values to 32-bit values won't
924 // work on large-endian machines.
925 unsigned n = rhsWords * 2;
926 unsigned m = (lhsWords * 2) - n;
927
928 // Allocate space for the temporary values we need either on the stack, if
929 // it will fit, or on the heap if it won't.
930 uint32_t SPACE[128];
931 uint32_t *U = nullptr;
932 uint32_t *V = nullptr;
933 uint32_t *Q = nullptr;
934 uint32_t *R = nullptr;
935 if ((Remainder?4:3)*n+2*m+1 <= 128) {
936 U = &SPACE[0];
937 V = &SPACE[m+n+1];
938 Q = &SPACE[(m+n+1) + n];
939 if (Remainder)
940 R = &SPACE[(m+n+1) + n + (m+n)];
941 } else {
942 U = new uint32_t[m + n + 1];
943 V = new uint32_t[n];
944 Q = new uint32_t[m+n];
945 if (Remainder)
946 R = new uint32_t[n];
947 }
948
949 // Initialize the dividend
950 memset(U, 0, (m+n+1)*sizeof(uint32_t));
951 for (unsigned i = 0; i < lhsWords; ++i) {
952 uint64_t tmp = LHS[i];
953 U[i * 2] = Lo_32(tmp);
954 U[i * 2 + 1] = Hi_32(tmp);
955 }
956 U[m+n] = 0; // this extra word is for "spill" in the Knuth algorithm.
957
958 // Initialize the divisor
959 memset(V, 0, (n)*sizeof(uint32_t));
960 for (unsigned i = 0; i < rhsWords; ++i) {
961 uint64_t tmp = RHS[i];
962 V[i * 2] = Lo_32(tmp);
963 V[i * 2 + 1] = Hi_32(tmp);
964 }
965
966 // initialize the quotient and remainder
967 memset(Q, 0, (m+n) * sizeof(uint32_t));
968 if (Remainder)
969 memset(R, 0, n * sizeof(uint32_t));
970
971 // Now, adjust m and n for the Knuth division. n is the number of words in
972 // the divisor. m is the number of words by which the dividend exceeds the
973 // divisor (i.e. m+n is the length of the dividend). These sizes must not
974 // contain any zero words or the Knuth algorithm fails.
975 for (unsigned i = n; i > 0 && V[i-1] == 0; i--) {
976 n--;
977 m++;
978 }
979 for (unsigned i = m+n; i > 0 && U[i-1] == 0; i--)
980 m--;
981
982 // If we're left with only a single word for the divisor, Knuth doesn't work
983 // so we implement the short division algorithm here. This is much simpler
984 // and faster because we are certain that we can divide a 64-bit quantity
985 // by a 32-bit quantity at hardware speed and short division is simply a
986 // series of such operations. This is just like doing short division but we
987 // are using base 2^32 instead of base 10.
988 assert(n != 0 && "Divide by zero?");
989 if (n == 1) {
990 uint32_t divisor = V[0];
991 uint32_t remainder = 0;
992 for (int i = m; i >= 0; i--) {
993 uint64_t partial_dividend = Make_64(remainder, U[i]);
994 if (partial_dividend == 0) {
995 Q[i] = 0;
996 remainder = 0;
997 } else if (partial_dividend < divisor) {
998 Q[i] = 0;
999 remainder = Lo_32(partial_dividend);
1000 } else if (partial_dividend == divisor) {
1001 Q[i] = 1;
1002 remainder = 0;
1003 } else {
1004 Q[i] = Lo_32(partial_dividend / divisor);
1005 remainder = Lo_32(partial_dividend - (Q[i] * divisor));
1006 }
1007 }
1008 if (R)
1009 R[0] = remainder;
1010 } else {
1011 // Now we're ready to invoke the Knuth classical divide algorithm. In this
1012 // case n > 1.
1013 KnuthDiv(U, V, Q, R, m, n);
1014 }
1015
1016 // If the caller wants the quotient
1017 if (Quotient) {
1018 Quotient->is_negative = false;
1019 Quotient->digit_count = lhsWords;
1020 if (lhsWords == 1) {
1021 Quotient->data.digit = Make_64(Q[1], Q[0]);
1022 } else {
1023 Quotient->data.digits = allocate<uint64_t>(lhsWords);
1024 for (size_t i = 0; i < lhsWords; i += 1) {
1025 Quotient->data.digits[i] = Make_64(Q[i*2+1], Q[i*2]);
1026 }
1027 }
1028 }
1029
1030 // If the caller wants the remainder
1031 if (Remainder) {
1032 Remainder->is_negative = false;
1033 Remainder->digit_count = rhsWords;
1034 if (rhsWords == 1) {
1035 Remainder->data.digit = Make_64(R[1], R[0]);
1036 } else {
1037 Remainder->data.digits = allocate<uint64_t>(rhsWords);
1038 for (size_t i = 0; i < rhsWords; i += 1) {
1039 Remainder->data.digits[i] = Make_64(R[i*2+1], R[i*2]);
1040 }
1041 }
1042 }
1043}
1044
673void bigint_div_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2) {1045void bigint_div_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2) {
674 assert(op2->digit_count != 0); // division by zero1046 assert(op2->digit_count != 0); // division by zero
675 if (op1->digit_count == 0) {1047 if (op1->digit_count == 0) {
676 bigint_init_unsigned(dest, 0);1048 bigint_init_unsigned(dest, 0);
677 return;1049 return;
678 }1050 }
679 if (op1->digit_count != 1 || op2->digit_count != 1) {
680 zig_panic("TODO bigint div_trunc with >1 digits");
681 }
682 const uint64_t *op1_digits = bigint_ptr(op1);1051 const uint64_t *op1_digits = bigint_ptr(op1);
683 const uint64_t *op2_digits = bigint_ptr(op2);1052 const uint64_t *op2_digits = bigint_ptr(op2);
684 dest->data.digit = op1_digits[0] / op2_digits[0];1053 if (op1->digit_count == 1 && op2->digit_count == 1) {
685 dest->digit_count = 1;1054 dest->data.digit = op1_digits[0] / op2_digits[0];
1055 dest->digit_count = 1;
1056 dest->is_negative = op1->is_negative != op2->is_negative;
1057 bigint_normalize(dest);
1058 return;
1059 }
1060 if (op2->digit_count == 1 && op2_digits[0] == 1) {
1061 // X / 1 == X
1062 bigint_init_bigint(dest, op1);
1063 dest->is_negative = op1->is_negative != op2->is_negative;
1064 bigint_normalize(dest);
1065 return;
1066 }
1067
1068 const BigInt *op1_positive;
1069 BigInt op1_positive_data;
1070 if (op1->is_negative) {
1071 bigint_negate(&op1_positive_data, op1);
1072 op1_positive = &op1_positive_data;
1073 } else {
1074 op1_positive = op1;
1075 }
1076
1077 const BigInt *op2_positive;
1078 BigInt op2_positive_data;
1079 if (op2->is_negative) {
1080 bigint_negate(&op2_positive_data, op2);
1081 op2_positive = &op2_positive_data;
1082 } else {
1083 op2_positive = op2;
1084 }
1085
1086 bigint_unsigned_division(op1_positive, op2_positive, dest, nullptr);
686 dest->is_negative = op1->is_negative != op2->is_negative;1087 dest->is_negative = op1->is_negative != op2->is_negative;
687 bigint_normalize(dest);1088 bigint_normalize(dest);
688}1089}
...@@ -714,6 +1115,14 @@ void bigint_rem(BigInt *dest, const BigInt *op1, const BigInt *op2) {...@@ -714,6 +1115,14 @@ void bigint_rem(BigInt *dest, const BigInt *op1, const BigInt *op2) {
714 }1115 }
715 const uint64_t *op1_digits = bigint_ptr(op1);1116 const uint64_t *op1_digits = bigint_ptr(op1);
716 const uint64_t *op2_digits = bigint_ptr(op2);1117 const uint64_t *op2_digits = bigint_ptr(op2);
1118
1119 if (op1->digit_count == 1 && op2->digit_count == 1) {
1120 dest->data.digit = op1_digits[0] % op2_digits[0];
1121 dest->digit_count = 1;
1122 dest->is_negative = op1->is_negative;
1123 bigint_normalize(dest);
1124 return;
1125 }
717 if (op2->digit_count == 2 && op2_digits[0] == 0 && op2_digits[1] == 1) {1126 if (op2->digit_count == 2 && op2_digits[0] == 0 && op2_digits[1] == 1) {
718 // special case this divisor1127 // special case this divisor
719 bigint_init_unsigned(dest, op1_digits[0]);1128 bigint_init_unsigned(dest, op1_digits[0]);
...@@ -721,11 +1130,32 @@ void bigint_rem(BigInt *dest, const BigInt *op1, const BigInt *op2) {...@@ -721,11 +1130,32 @@ void bigint_rem(BigInt *dest, const BigInt *op1, const BigInt *op2) {
721 bigint_normalize(dest);1130 bigint_normalize(dest);
722 return;1131 return;
723 }1132 }
724 if (op1->digit_count != 1 || op2->digit_count != 1) {1133
725 zig_panic("TODO bigint rem with >1 digits");1134 if (op2->digit_count == 1 && op2_digits[0] == 1) {
1135 // X % 1 == 0
1136 bigint_init_unsigned(dest, 0);
1137 return;
726 }1138 }
727 dest->data.digit = op1_digits[0] % op2_digits[0];1139
728 dest->digit_count = 1;1140 const BigInt *op1_positive;
1141 BigInt op1_positive_data;
1142 if (op1->is_negative) {
1143 bigint_negate(&op1_positive_data, op1);
1144 op1_positive = &op1_positive_data;
1145 } else {
1146 op1_positive = op1;
1147 }
1148
1149 const BigInt *op2_positive;
1150 BigInt op2_positive_data;
1151 if (op2->is_negative) {
1152 bigint_negate(&op2_positive_data, op2);
1153 op2_positive = &op2_positive_data;
1154 } else {
1155 op2_positive = op2;
1156 }
1157
1158 bigint_unsigned_division(op1_positive, op2_positive, nullptr, dest);
729 dest->is_negative = op1->is_negative;1159 dest->is_negative = op1->is_negative;
730 bigint_normalize(dest);1160 bigint_normalize(dest);
731}1161}
src/codegen.cpp+231-16
...@@ -404,6 +404,19 @@ static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) {...@@ -404,6 +404,19 @@ static LLVMLinkage to_llvm_linkage(GlobalLinkageId id) {
404 zig_unreachable();404 zig_unreachable();
405}405}
406406
407static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_entry) {
408 if (!g->have_err_ret_tracing) {
409 return UINT32_MAX;
410 }
411 TypeTableEntry *fn_type = fn_table_entry->type_entry;
412 TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;
413 if (return_type->id != TypeTableEntryIdErrorUnion && return_type->id != TypeTableEntryIdPureError) {
414 return UINT32_MAX;
415 }
416 bool first_arg_ret = type_has_bits(return_type) && handle_is_ptr(return_type);
417 return first_arg_ret ? 1 : 0;
418}
419
407static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {420static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
408 if (fn_table_entry->llvm_value)421 if (fn_table_entry->llvm_value)
409 return fn_table_entry->llvm_value;422 return fn_table_entry->llvm_value;
...@@ -483,7 +496,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {...@@ -483,7 +496,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
483 LLVMSetUnnamedAddr(fn_table_entry->llvm_value, true);496 LLVMSetUnnamedAddr(fn_table_entry->llvm_value, true);
484 }497 }
485498
486 if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdUnreachable) {499 TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;
500 if (return_type->id == TypeTableEntryIdUnreachable) {
487 addLLVMFnAttr(fn_table_entry->llvm_value, "noreturn");501 addLLVMFnAttr(fn_table_entry->llvm_value, "noreturn");
488 }502 }
489503
...@@ -520,13 +534,11 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {...@@ -520,13 +534,11 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
520 // use the ABI alignment, which is fine.534 // use the ABI alignment, which is fine.
521 }535 }
522536
523 if (!type_has_bits(fn_type->data.fn.fn_type_id.return_type)) {537 if (!type_has_bits(return_type)) {
524 // nothing to do538 // nothing to do
525 } else if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdPointer ||539 } else if (return_type->id == TypeTableEntryIdPointer || return_type->id == TypeTableEntryIdFn) {
526 fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdFn)
527 {
528 addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");540 addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");
529 } else if (handle_is_ptr(fn_type->data.fn.fn_type_id.return_type) &&541 } else if (handle_is_ptr(return_type) &&
530 calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc))542 calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc))
531 {543 {
532 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");544 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
...@@ -563,6 +575,11 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {...@@ -563,6 +575,11 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
563 }575 }
564 }576 }
565577
578 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
579 if (err_ret_trace_arg_index != UINT32_MAX) {
580 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)err_ret_trace_arg_index, "nonnull");
581 }
582
566 return fn_table_entry->llvm_value;583 return fn_table_entry->llvm_value;
567}584}
568585
...@@ -864,16 +881,25 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {...@@ -864,16 +881,25 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
864 return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(str_type->type_ref, 0));881 return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(str_type->type_ref, 0));
865}882}
866883
867static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) {884static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace_arg) {
868 assert(g->panic_fn != nullptr);885 assert(g->panic_fn != nullptr);
869 LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);886 LLVMValueRef fn_val = fn_llvm_value(g, g->panic_fn);
870 LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc);887 LLVMCallConv llvm_cc = get_llvm_cc(g, g->panic_fn->type_entry->data.fn.fn_type_id.cc);
871 ZigLLVMBuildCall(g->builder, fn_val, &msg_arg, 1, llvm_cc, ZigLLVM_FnInlineAuto, "");888 if (stack_trace_arg == nullptr) {
889 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
890 stack_trace_arg = LLVMConstNull(ptr_to_stack_trace_type->type_ref);
891 }
892 LLVMValueRef args[] = {
893 msg_arg,
894 stack_trace_arg,
895 };
896 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, ZigLLVM_FnInlineAuto, "");
897 LLVMSetTailCall(call_instruction, true);
872 LLVMBuildUnreachable(g->builder);898 LLVMBuildUnreachable(g->builder);
873}899}
874900
875static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) {901static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) {
876 gen_panic(g, get_panic_msg_ptr_val(g, msg_id));902 gen_panic(g, get_panic_msg_ptr_val(g, msg_id), nullptr);
877}903}
878904
879static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {905static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {
...@@ -895,6 +921,87 @@ static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {...@@ -895,6 +921,87 @@ static LLVMValueRef get_memcpy_fn_val(CodeGen *g) {
895 return g->memcpy_fn_val;921 return g->memcpy_fn_val;
896}922}
897923
924static LLVMValueRef get_return_err_fn(CodeGen *g) {
925 if (g->return_err_fn != nullptr)
926 return g->return_err_fn;
927
928 assert(g->err_tag_type != nullptr);
929
930 LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
931
932 LLVMTypeRef arg_types[] = {
933 // error return trace pointer
934 get_ptr_to_stack_trace_type(g)->type_ref,
935 // return address
936 ptr_u8,
937 };
938 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
939
940 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_return_error"), false);
941 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
942 addLLVMFnAttr(fn_val, "cold");
943 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
944 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
945 addLLVMFnAttr(fn_val, "nounwind");
946 add_uwtable_attr(g, fn_val);
947 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
948 addLLVMArgAttr(fn_val, (unsigned)1, "nonnull");
949 if (g->build_mode == BuildModeDebug) {
950 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
951 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
952 }
953
954 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
955 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
956 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
957 LLVMPositionBuilderAtEnd(g->builder, entry_block);
958 ZigLLVMClearCurrentDebugLocation(g->builder);
959
960 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;
961
962 // stack_trace.instruction_addresses[stack_trace.index % stack_trace.instruction_addresses.len] = return_address;
963
964 LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);
965 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
966 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)index_field_index, "");
967 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
968 LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)addresses_field_index, "");
969
970 TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
971 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
972 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)ptr_field_index, "");
973 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
974 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, "");
975
976 LLVMValueRef len_value = gen_load_untyped(g, len_field_ptr, 0, false, "");
977 LLVMValueRef index_val = gen_load_untyped(g, index_field_ptr, 0, false, "");
978 LLVMValueRef modded_val = LLVMBuildURem(g->builder, index_val, len_value, "");
979 LLVMValueRef address_indices[] = {
980 modded_val,
981 };
982
983 LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");
984 LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, ptr_value, address_indices, 1, "");
985
986 LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, LLVMGetParam(fn_val, 1), usize_type_ref, "");
987
988 LLVMValueRef address_value = LLVMBuildPtrToInt(g->builder, return_address, usize_type_ref, "");
989 gen_store_untyped(g, address_value, address_slot, 0, false);
990
991 // stack_trace.index += 1;
992 LLVMValueRef index_plus_one_val = LLVMBuildAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), "");
993 gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false);
994
995 // return;
996 LLVMBuildRetVoid(g->builder);
997
998 LLVMPositionBuilderAtEnd(g->builder, prev_block);
999 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
1000
1001 g->return_err_fn = fn_val;
1002 return fn_val;
1003}
1004
898static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {1005static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
899 if (g->safety_crash_err_fn != nullptr)1006 if (g->safety_crash_err_fn != nullptr)
900 return g->safety_crash_err_fn;1007 return g->safety_crash_err_fn;
...@@ -953,7 +1060,11 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -953,7 +1060,11 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
953 LLVMValueRef offset_buf_ptr = LLVMConstInBoundsGEP(global_array, offset_ptr_indices, 2);1060 LLVMValueRef offset_buf_ptr = LLVMConstInBoundsGEP(global_array, offset_ptr_indices, 2);
9541061
955 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_fail_unwrap"), false);1062 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_fail_unwrap"), false);
956 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), &g->err_tag_type->type_ref, 1, false);1063 LLVMTypeRef arg_types[] = {
1064 g->ptr_to_stack_trace_type->type_ref,
1065 g->err_tag_type->type_ref,
1066 };
1067 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
957 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);1068 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
958 addLLVMFnAttr(fn_val, "noreturn");1069 addLLVMFnAttr(fn_val, "noreturn");
959 addLLVMFnAttr(fn_val, "cold");1070 addLLVMFnAttr(fn_val, "cold");
...@@ -975,7 +1086,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -975,7 +1086,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
975 LLVMPositionBuilderAtEnd(g->builder, entry_block);1086 LLVMPositionBuilderAtEnd(g->builder, entry_block);
976 ZigLLVMClearCurrentDebugLocation(g->builder);1087 ZigLLVMClearCurrentDebugLocation(g->builder);
9771088
978 LLVMValueRef err_val = LLVMGetParam(fn_val, 0);1089 LLVMValueRef err_val = LLVMGetParam(fn_val, 1);
9791090
980 LLVMValueRef err_table_indices[] = {1091 LLVMValueRef err_table_indices[] = {
981 LLVMConstNull(g->builtin_types.entry_usize->type_ref),1092 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
...@@ -1005,7 +1116,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -1005,7 +1116,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
1005 LLVMValueRef global_slice_len_field_ptr = LLVMBuildStructGEP(g->builder, global_slice, slice_len_index, "");1116 LLVMValueRef global_slice_len_field_ptr = LLVMBuildStructGEP(g->builder, global_slice, slice_len_index, "");
1006 gen_store(g, full_buf_len, global_slice_len_field_ptr, u8_ptr_type);1117 gen_store(g, full_buf_len, global_slice_len_field_ptr, u8_ptr_type);
10071118
1008 gen_panic(g, global_slice);1119 gen_panic(g, global_slice, LLVMGetParam(fn_val, 0));
10091120
1010 LLVMPositionBuilderAtEnd(g->builder, prev_block);1121 LLVMPositionBuilderAtEnd(g->builder, prev_block);
1011 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);1122 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
...@@ -1016,8 +1127,18 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {...@@ -1016,8 +1127,18 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
10161127
1017static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {1128static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) {
1018 LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g);1129 LLVMValueRef safety_crash_err_fn = get_safety_crash_err_fn(g);
1019 ZigLLVMBuildCall(g->builder, safety_crash_err_fn, &err_val, 1, get_llvm_cc(g, CallingConventionUnspecified),1130 LLVMValueRef err_ret_trace_val = g->cur_err_ret_trace_val;
1131 if (err_ret_trace_val == nullptr) {
1132 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
1133 err_ret_trace_val = LLVMConstNull(ptr_to_stack_trace_type->type_ref);
1134 }
1135 LLVMValueRef args[] = {
1136 err_ret_trace_val,
1137 err_val,
1138 };
1139 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 2, get_llvm_cc(g, CallingConventionUnspecified),
1020 ZigLLVM_FnInlineAuto, "");1140 ZigLLVM_FnInlineAuto, "");
1141 LLVMSetTailCall(call_instruction, true);
1021 LLVMBuildUnreachable(g->builder);1142 LLVMBuildUnreachable(g->builder);
1022}1143}
10231144
...@@ -1296,6 +1417,35 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {...@@ -1296,6 +1417,35 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
1296static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {1417static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
1297 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);1418 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
1298 TypeTableEntry *return_type = return_instruction->value->value.type;1419 TypeTableEntry *return_type = return_instruction->value->value.type;
1420
1421 if (g->have_err_ret_tracing) {
1422 bool is_err_return = false;
1423 if (return_type->id == TypeTableEntryIdErrorUnion) {
1424 if (return_instruction->value->value.special == ConstValSpecialStatic) {
1425 is_err_return = return_instruction->value->value.data.x_err_union.err != nullptr;
1426 } else if (return_instruction->value->value.special == ConstValSpecialRuntime) {
1427 is_err_return = return_instruction->value->value.data.rh_error_union == RuntimeHintErrorUnionError;
1428 // TODO: emit a branch to check if the return value is an error
1429 }
1430 } else if (return_type->id == TypeTableEntryIdPureError) {
1431 is_err_return = true;
1432 }
1433 if (is_err_return) {
1434 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "ReturnError");
1435 LLVMValueRef block_address = LLVMBlockAddress(g->cur_fn_val, return_block);
1436
1437 LLVMValueRef return_err_fn = get_return_err_fn(g);
1438 LLVMValueRef args[] = {
1439 g->cur_err_ret_trace_val,
1440 block_address,
1441 };
1442 LLVMBuildBr(g->builder, return_block);
1443 LLVMPositionBuilderAtEnd(g->builder, return_block);
1444 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 2,
1445 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
1446 LLVMSetTailCall(call_instruction, true);
1447 }
1448 }
1299 if (handle_is_ptr(return_type)) {1449 if (handle_is_ptr(return_type)) {
1300 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {1450 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {
1301 assert(g->cur_ret_ptr);1451 assert(g->cur_ret_ptr);
...@@ -2330,7 +2480,8 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -2330,7 +2480,8 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
2330 TypeTableEntry *src_return_type = fn_type_id->return_type;2480 TypeTableEntry *src_return_type = fn_type_id->return_type;
2331 bool ret_has_bits = type_has_bits(src_return_type);2481 bool ret_has_bits = type_has_bits(src_return_type);
2332 bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type);2482 bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type);
2333 size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0);2483 bool prefix_arg_err_ret_stack = g->have_err_ret_tracing && (src_return_type->id == TypeTableEntryIdErrorUnion || src_return_type->id == TypeTableEntryIdPureError);
2484 size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0);
2334 bool is_var_args = fn_type_id->is_var_args;2485 bool is_var_args = fn_type_id->is_var_args;
2335 LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);2486 LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
2336 size_t gen_param_index = 0;2487 size_t gen_param_index = 0;
...@@ -2338,6 +2489,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -2338,6 +2489,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
2338 gen_param_values[gen_param_index] = instruction->tmp_ptr;2489 gen_param_values[gen_param_index] = instruction->tmp_ptr;
2339 gen_param_index += 1;2490 gen_param_index += 1;
2340 }2491 }
2492 if (prefix_arg_err_ret_stack) {
2493 gen_param_values[gen_param_index] = g->cur_err_ret_trace_val;
2494 gen_param_index += 1;
2495 }
2341 for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) {2496 for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) {
2342 IrInstruction *param_instruction = instruction->args[call_i];2497 IrInstruction *param_instruction = instruction->args[call_i];
2343 TypeTableEntry *param_type = param_instruction->value.type;2498 TypeTableEntry *param_type = param_instruction->value.type;
...@@ -2881,6 +3036,16 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I...@@ -2881,6 +3036,16 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
2881 return target_val;3036 return target_val;
2882}3037}
28833038
3039static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *executable,
3040 IrInstructionErrorReturnTrace *instruction)
3041{
3042 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
3043 if (g->cur_err_ret_trace_val == nullptr) {
3044 return LLVMConstNull(ptr_to_stack_trace_type->type_ref);
3045 }
3046 return g->cur_err_ret_trace_val;
3047}
3048
2884static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {3049static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) {
2885 switch (atomic_order) {3050 switch (atomic_order) {
2886 case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;3051 case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered;
...@@ -3474,7 +3639,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec...@@ -3474,7 +3639,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec
3474}3639}
34753640
3476static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) {3641static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) {
3477 gen_panic(g, ir_llvm_value(g, instruction->msg));3642 gen_panic(g, ir_llvm_value(g, instruction->msg), nullptr);
3478 return nullptr;3643 return nullptr;
3479}3644}
34803645
...@@ -3654,6 +3819,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -3654,6 +3819,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
3654 return ir_render_field_parent_ptr(g, executable, (IrInstructionFieldParentPtr *)instruction);3819 return ir_render_field_parent_ptr(g, executable, (IrInstructionFieldParentPtr *)instruction);
3655 case IrInstructionIdAlignCast:3820 case IrInstructionIdAlignCast:
3656 return ir_render_align_cast(g, executable, (IrInstructionAlignCast *)instruction);3821 return ir_render_align_cast(g, executable, (IrInstructionAlignCast *)instruction);
3822 case IrInstructionIdErrorReturnTrace:
3823 return ir_render_error_return_trace(g, executable, (IrInstructionErrorReturnTrace *)instruction);
3657 }3824 }
3658 zig_unreachable();3825 zig_unreachable();
3659}3826}
...@@ -4493,7 +4660,8 @@ static void do_code_gen(CodeGen *g) {...@@ -4493,7 +4660,8 @@ static void do_code_gen(CodeGen *g) {
4493 LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);4660 LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);
4494 g->cur_fn = fn_table_entry;4661 g->cur_fn = fn_table_entry;
4495 g->cur_fn_val = fn;4662 g->cur_fn_val = fn;
4496 if (handle_is_ptr(fn_table_entry->type_entry->data.fn.fn_type_id.return_type)) {4663 TypeTableEntry *return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type;
4664 if (handle_is_ptr(return_type)) {
4497 g->cur_ret_ptr = LLVMGetParam(fn, 0);4665 g->cur_ret_ptr = LLVMGetParam(fn, 0);
4498 } else {4666 } else {
4499 g->cur_ret_ptr = nullptr;4667 g->cur_ret_ptr = nullptr;
...@@ -4502,6 +4670,42 @@ static void do_code_gen(CodeGen *g) {...@@ -4502,6 +4670,42 @@ static void do_code_gen(CodeGen *g) {
4502 build_all_basic_blocks(g, fn_table_entry);4670 build_all_basic_blocks(g, fn_table_entry);
4503 clear_debug_source_node(g);4671 clear_debug_source_node(g);
45044672
4673 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
4674 if (err_ret_trace_arg_index != UINT32_MAX) {
4675 g->cur_err_ret_trace_val = LLVMGetParam(fn, err_ret_trace_arg_index);
4676 } else if (g->have_err_ret_tracing && fn_table_entry->calls_errorable_function) {
4677 // TODO call graph analysis to find out what this number needs to be for every function
4678 static const size_t stack_trace_ptr_count = 30;
4679
4680 TypeTableEntry *usize = g->builtin_types.entry_usize;
4681 TypeTableEntry *array_type = get_array_type(g, usize, stack_trace_ptr_count);
4682 LLVMValueRef err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses",
4683 get_abi_alignment(g, array_type));
4684 g->cur_err_ret_trace_val = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type));
4685 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
4686 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)index_field_index, "");
4687 gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false);
4688
4689 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
4690 LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val, (unsigned)addresses_field_index, "");
4691
4692 TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
4693 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
4694 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)ptr_field_index, "");
4695 LLVMValueRef zero = LLVMConstNull(usize->type_ref);
4696 LLVMValueRef indices[] = {zero, zero};
4697 LLVMValueRef err_ret_array_val_elem0_ptr = LLVMBuildInBoundsGEP(g->builder, err_ret_array_val,
4698 indices, 2, "");
4699 gen_store(g, err_ret_array_val_elem0_ptr, ptr_field_ptr,
4700 get_pointer_to_type(g, get_pointer_to_type(g, usize, false), false));
4701
4702 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
4703 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, "");
4704 gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
4705 } else {
4706 g->cur_err_ret_trace_val = nullptr;
4707 }
4708
4505 // allocate temporary stack data4709 // allocate temporary stack data
4506 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_list.length; alloca_i += 1) {4710 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_list.length; alloca_i += 1) {
4507 IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i);4711 IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i);
...@@ -5064,6 +5268,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -5064,6 +5268,7 @@ static void define_builtin_fns(CodeGen *g) {
5064 create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1);5268 create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1);
5065 create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2);5269 create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2);
5066 create_builtin_fn(g, BuiltinFnIdExport, "export", 3);5270 create_builtin_fn(g, BuiltinFnIdExport, "export", 3);
5271 create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0);
5067}5272}
50685273
5069static const char *bool_to_str(bool b) {5274static const char *bool_to_str(bool b) {
...@@ -5088,6 +5293,12 @@ static void define_builtin_compile_vars(CodeGen *g) {...@@ -5088,6 +5293,12 @@ static void define_builtin_compile_vars(CodeGen *g) {
5088 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);5293 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
5089 Buf *contents = buf_alloc();5294 Buf *contents = buf_alloc();
50905295
5296 buf_append_str(contents,
5297 "pub const StackTrace = struct {\n"
5298 " index: usize,\n"
5299 " instruction_addresses: []usize,\n"
5300 "};\n\n");
5301
5091 const char *cur_os = nullptr;5302 const char *cur_os = nullptr;
5092 {5303 {
5093 buf_appendf(contents, "pub const Os = enum {\n");5304 buf_appendf(contents, "pub const Os = enum {\n");
...@@ -5233,6 +5444,7 @@ static void define_builtin_compile_vars(CodeGen *g) {...@@ -5233,6 +5444,7 @@ static void define_builtin_compile_vars(CodeGen *g) {
5233 buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt);5444 buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt);
5234 buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode));5445 buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode));
5235 buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->libc_link_lib != nullptr));5446 buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->libc_link_lib != nullptr));
5447 buf_appendf(contents, "pub const have_error_return_tracing = %s;\n", bool_to_str(g->have_err_ret_tracing));
52365448
5237 buf_appendf(contents, "pub const __zig_test_fn_slice = {}; // overwritten later\n");5449 buf_appendf(contents, "pub const __zig_test_fn_slice = {}; // overwritten later\n");
52385450
...@@ -5251,6 +5463,7 @@ static void define_builtin_compile_vars(CodeGen *g) {...@@ -5251,6 +5463,7 @@ static void define_builtin_compile_vars(CodeGen *g) {
5251 g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);5463 g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
5252 g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);5464 g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package);
5253 g->compile_var_import = add_source_file(g, g->compile_var_package, abs_full_path, contents);5465 g->compile_var_import = add_source_file(g, g->compile_var_package, abs_full_path, contents);
5466 scan_import(g, g->compile_var_import);
5254}5467}
52555468
5256static void init(CodeGen *g) {5469static void init(CodeGen *g) {
...@@ -5359,6 +5572,8 @@ static void init(CodeGen *g) {...@@ -5359,6 +5572,8 @@ static void init(CodeGen *g) {
5359 }5572 }
5360 }5573 }
53615574
5575 g->have_err_ret_tracing = g->build_mode != BuildModeFastRelease;
5576
5362 define_builtin_fns(g);5577 define_builtin_fns(g);
5363 define_builtin_compile_vars(g);5578 define_builtin_compile_vars(g);
5364}5579}
src/ir.cpp+49-12
...@@ -572,6 +572,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArgType *) {...@@ -572,6 +572,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionArgType *) {
572 return IrInstructionIdArgType;572 return IrInstructionIdArgType;
573}573}
574574
575static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorReturnTrace *) {
576 return IrInstructionIdErrorReturnTrace;
577}
578
575template<typename T>579template<typename T>
576static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {580static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
577 T *special_instruction = allocate<T>(1);581 T *special_instruction = allocate<T>(1);
...@@ -2305,6 +2309,12 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s...@@ -2305,6 +2309,12 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s
2305 return &instruction->base;2309 return &instruction->base;
2306}2310}
23072311
2312static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node) {
2313 IrInstructionErrorReturnTrace *instruction = ir_build_instruction<IrInstructionErrorReturnTrace>(irb, scope, source_node);
2314
2315 return &instruction->base;
2316}
2317
2308static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {2318static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
2309 results[ReturnKindUnconditional] = 0;2319 results[ReturnKindUnconditional] = 0;
2310 results[ReturnKindError] = 0;2320 results[ReturnKindError] = 0;
...@@ -3731,6 +3741,10 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -3731,6 +3741,10 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
37313741
3732 return ir_build_export(irb, scope, node, arg0_value, arg1_value, arg2_value);3742 return ir_build_export(irb, scope, node, arg0_value, arg1_value, arg2_value);
3733 }3743 }
3744 case BuiltinFnIdErrorReturnTrace:
3745 {
3746 return ir_build_error_return_trace(irb, scope, node);
3747 }
3734 }3748 }
3735 zig_unreachable();3749 zig_unreachable();
3736}3750}
...@@ -8230,16 +8244,6 @@ static bool ir_resolve_comptime(IrAnalyze *ira, IrInstruction *value, bool *out)...@@ -8230,16 +8244,6 @@ static bool ir_resolve_comptime(IrAnalyze *ira, IrInstruction *value, bool *out)
8230 return ir_resolve_bool(ira, value, out);8244 return ir_resolve_bool(ira, value, out);
8231}8245}
82328246
8233static ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) {
8234 Tld *tld = codegen->compile_var_import->decls_scope->decl_table.get(buf_create_from_str(name));
8235 resolve_top_level_decl(codegen, tld, false, nullptr);
8236 assert(tld->id == TldIdVar);
8237 TldVar *tld_var = (TldVar *)tld;
8238 ConstExprValue *var_value = tld_var->var->value;
8239 assert(var_value != nullptr);
8240 return var_value;
8241}
8242
8243static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, AtomicOrder *out) {8247static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, AtomicOrder *out) {
8244 if (type_is_invalid(value->value.type))8248 if (type_is_invalid(value->value.type))
8245 return false;8249 return false;
...@@ -9578,6 +9582,24 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi...@@ -9578,6 +9582,24 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
9578 return ira->codegen->builtin_types.entry_void;9582 return ira->codegen->builtin_types.entry_void;
9579}9583}
95809584
9585static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
9586 IrInstructionErrorReturnTrace *instruction)
9587{
9588 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
9589 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
9590 TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);
9591 if (fn_entry == nullptr || !fn_entry->calls_errorable_function || !ira->codegen->have_err_ret_tracing) {
9592 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
9593 out_val->data.x_maybe = nullptr;
9594 return nullable_type;
9595 }
9596
9597 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
9598 instruction->base.source_node);
9599 ir_link_new_instruction(new_instruction, &instruction->base);
9600 return nullable_type;
9601}
9602
9581static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,9603static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,
9582 IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)9604 IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i)
9583{9605{
...@@ -9836,7 +9858,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -9836,7 +9858,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
98369858
9837 if (fn_proto_node->data.fn_proto.is_var_args) {9859 if (fn_proto_node->data.fn_proto.is_var_args) {
9838 ir_add_error(ira, &call_instruction->base,9860 ir_add_error(ira, &call_instruction->base,
9839 buf_sprintf("compiler bug: unable to call var args function at compile time. https://github.com/andrewrk/zig/issues/313"));9861 buf_sprintf("compiler bug: unable to call var args function at compile time. https://github.com/zig-lang/zig/issues/313"));
9840 return ira->codegen->builtin_types.entry_invalid;9862 return ira->codegen->builtin_types.entry_invalid;
9841 }9863 }
98429864
...@@ -10053,9 +10075,21 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -10053,9 +10075,21 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
10053 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;10075 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
10054 ir_add_alloca(ira, new_call_instruction, return_type);10076 ir_add_alloca(ira, new_call_instruction, return_type);
1005510077
10078 if (return_type->id == TypeTableEntryIdPureError || return_type->id == TypeTableEntryIdErrorUnion) {
10079 parent_fn_entry->calls_errorable_function = true;
10080 }
10081
10056 return ir_finish_anal(ira, return_type);10082 return ir_finish_anal(ira, return_type);
10057 }10083 }
1005810084
10085 FnTableEntry *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);
10086 assert(fn_type_id->return_type != nullptr);
10087 assert(parent_fn_entry != nullptr);
10088 if (fn_type_id->return_type->id == TypeTableEntryIdPureError || fn_type_id->return_type->id == TypeTableEntryIdErrorUnion) {
10089 parent_fn_entry->calls_errorable_function = true;
10090 }
10091
10092
10059 IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count);10093 IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count);
10060 size_t next_arg_index = 0;10094 size_t next_arg_index = 0;
10061 if (first_arg_ptr) {10095 if (first_arg_ptr) {
...@@ -13977,7 +14011,7 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc...@@ -13977,7 +14011,7 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc
13977 return ira->codegen->builtin_types.entry_invalid;14011 return ira->codegen->builtin_types.entry_invalid;
13978 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);14012 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
1397914013
13980 ensure_complete_type(ira->codegen, type_entry);14014 type_ensure_zero_bits_known(ira->codegen, type_entry);
13981 if (type_is_invalid(type_entry))14015 if (type_is_invalid(type_entry))
13982 return ira->codegen->builtin_types.entry_invalid;14016 return ira->codegen->builtin_types.entry_invalid;
1398314017
...@@ -15322,6 +15356,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -15322,6 +15356,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
15322 return ir_analyze_instruction_tag_type(ira, (IrInstructionTagType *)instruction);15356 return ir_analyze_instruction_tag_type(ira, (IrInstructionTagType *)instruction);
15323 case IrInstructionIdExport:15357 case IrInstructionIdExport:
15324 return ir_analyze_instruction_export(ira, (IrInstructionExport *)instruction);15358 return ir_analyze_instruction_export(ira, (IrInstructionExport *)instruction);
15359 case IrInstructionIdErrorReturnTrace:
15360 return ir_analyze_instruction_error_return_trace(ira, (IrInstructionErrorReturnTrace *)instruction);
15325 }15361 }
15326 zig_unreachable();15362 zig_unreachable();
15327}15363}
...@@ -15505,6 +15541,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -15505,6 +15541,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
15505 case IrInstructionIdOpaqueType:15541 case IrInstructionIdOpaqueType:
15506 case IrInstructionIdArgType:15542 case IrInstructionIdArgType:
15507 case IrInstructionIdTagType:15543 case IrInstructionIdTagType:
15544 case IrInstructionIdErrorReturnTrace:
15508 return false;15545 return false;
15509 case IrInstructionIdAsm:15546 case IrInstructionIdAsm:
15510 {15547 {
src/ir_print.cpp+7
...@@ -996,6 +996,10 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) {...@@ -996,6 +996,10 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) {
996 }996 }
997}997}
998998
999static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) {
1000 fprintf(irp->f, "@errorReturnTrace()");
1001}
1002
9991003
1000static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1004static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1001 ir_print_prefix(irp, instruction);1005 ir_print_prefix(irp, instruction);
...@@ -1308,6 +1312,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1308,6 +1312,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1308 case IrInstructionIdExport:1312 case IrInstructionIdExport:
1309 ir_print_export(irp, (IrInstructionExport *)instruction);1313 ir_print_export(irp, (IrInstructionExport *)instruction);
1310 break;1314 break;
1315 case IrInstructionIdErrorReturnTrace:
1316 ir_print_error_return_trace(irp, (IrInstructionErrorReturnTrace *)instruction);
1317 break;
1311 }1318 }
1312 fprintf(irp->f, "\n");1319 fprintf(irp->f, "\n");
1313}1320}
src/translate_c.cpp+83-7
...@@ -1964,6 +1964,8 @@ static int trans_local_declaration(Context *c, TransScope *scope, const DeclStmt...@@ -1964,6 +1964,8 @@ static int trans_local_declaration(Context *c, TransScope *scope, const DeclStmt
1964 if (init_node == nullptr)1964 if (init_node == nullptr)
1965 return ErrorUnexpected;1965 return ErrorUnexpected;
19661966
1967 } else {
1968 init_node = trans_create_node(c, NodeTypeUndefinedLiteral);
1967 }1969 }
1968 AstNode *type_node = trans_qual_type(c, qual_type, stmt->getLocStart());1970 AstNode *type_node = trans_qual_type(c, qual_type, stmt->getLocStart());
1969 if (type_node == nullptr)1971 if (type_node == nullptr)
...@@ -2224,12 +2226,6 @@ static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt *...@@ -2224,12 +2226,6 @@ static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt *
2224 // if (c) t else e2226 // if (c) t else e
2225 AstNode *if_node = trans_create_node(c, NodeTypeIfBoolExpr);2227 AstNode *if_node = trans_create_node(c, NodeTypeIfBoolExpr);
22262228
2227 // TODO: condition != 0
2228 AstNode *condition_node = trans_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue);
2229 if (condition_node == nullptr)
2230 return nullptr;
2231 if_node->data.if_bool_expr.condition = condition_node;
2232
2233 TransScope *then_scope = trans_stmt(c, scope, stmt->getThen(), &if_node->data.if_bool_expr.then_block);2229 TransScope *then_scope = trans_stmt(c, scope, stmt->getThen(), &if_node->data.if_bool_expr.then_block);
2234 if (then_scope == nullptr)2230 if (then_scope == nullptr)
2235 return nullptr;2231 return nullptr;
...@@ -2240,7 +2236,87 @@ static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt *...@@ -2240,7 +2236,87 @@ static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt *
2240 return nullptr;2236 return nullptr;
2241 }2237 }
22422238
2243 return if_node;2239 AstNode *condition_node = trans_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue);
2240 if (condition_node == nullptr)
2241 return nullptr;
2242
2243 switch (condition_node->type) {
2244 case NodeTypeBinOpExpr:
2245 switch (condition_node->data.bin_op_expr.bin_op) {
2246 case BinOpTypeBoolOr:
2247 case BinOpTypeBoolAnd:
2248 case BinOpTypeCmpEq:
2249 case BinOpTypeCmpNotEq:
2250 case BinOpTypeCmpLessThan:
2251 case BinOpTypeCmpGreaterThan:
2252 case BinOpTypeCmpLessOrEq:
2253 case BinOpTypeCmpGreaterOrEq:
2254 if_node->data.if_bool_expr.condition = condition_node;
2255 return if_node;
2256 default:
2257 goto convert_to_bitcast;
2258 }
2259
2260 case NodeTypePrefixOpExpr:
2261 switch (condition_node->data.prefix_op_expr.prefix_op) {
2262 case PrefixOpBoolNot:
2263 if_node->data.if_bool_expr.condition = condition_node;
2264 return if_node;
2265 default:
2266 goto convert_to_bitcast;
2267 }
2268
2269 case NodeTypeBoolLiteral:
2270 if_node->data.if_bool_expr.condition = condition_node;
2271 return if_node;
2272
2273 default: {
2274 // In Zig, float, int and pointer does not work in if statements.
2275 // To make it work, we bitcast any value we get to an int of the right size
2276 // and comp it to 0
2277 // TODO: This doesn't work for pointers, as they become nullable on
2278 // translate
2279 // c: if (cond) { }
2280 // zig: {
2281 // zig: const _tmp = cond;
2282 // zig: if (@bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0) { }
2283 // zig: }
2284 convert_to_bitcast:
2285 TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
2286
2287 // const _tmp = cond;
2288 // TODO: avoid name collisions with generated variable names
2289 Buf* tmp_var_name = buf_create_from_str("_tmp");
2290 AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, condition_node);
2291 child_scope->node->data.block.statements.append(tmp_var_decl);
2292
2293 // @sizeOf(@typeOf(_tmp)) * 8
2294 AstNode *typeof_tmp = trans_create_node_builtin_fn_call_str(c, "typeOf");
2295 typeof_tmp->data.fn_call_expr.params.append(trans_create_node_symbol(c, tmp_var_name));
2296 AstNode *sizeof_tmp = trans_create_node_builtin_fn_call_str(c, "sizeOf");
2297 sizeof_tmp->data.fn_call_expr.params.append(typeof_tmp);
2298 AstNode *sizeof_tmp_in_bits = trans_create_node_bin_op(
2299 c, sizeof_tmp, BinOpTypeMult,
2300 trans_create_node_unsigned_negative(c, 8, false));
2301
2302 // @IntType(false, @sizeOf(@typeOf(_tmp)) * 8)
2303 AstNode *int_type = trans_create_node_builtin_fn_call_str(c, "IntType");
2304 int_type->data.fn_call_expr.params.append(trans_create_node_bool(c, false));
2305 int_type->data.fn_call_expr.params.append(sizeof_tmp_in_bits);
2306
2307 // @bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp)
2308 AstNode *bit_cast = trans_create_node_builtin_fn_call_str(c, "bitCast");
2309 bit_cast->data.fn_call_expr.params.append(int_type);
2310 bit_cast->data.fn_call_expr.params.append(trans_create_node_symbol(c, tmp_var_name));
2311
2312 // if (@bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0) { }
2313 AstNode *not_eql_zero = trans_create_node_bin_op(c, bit_cast, BinOpTypeCmpNotEq, trans_create_node_unsigned_negative(c, 0, false));
2314 if_node->data.if_bool_expr.condition = not_eql_zero;
2315 child_scope->node->data.block.statements.append(if_node);
2316
2317 return child_scope->node;
2318 }
2319 }
2244}2320}
22452321
2246static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *scope, const CallExpr *stmt) {2322static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *scope, const CallExpr *stmt) {
std/build.zig+4-6
...@@ -247,11 +247,11 @@ pub const Builder = struct {...@@ -247,11 +247,11 @@ pub const Builder = struct {
247 defer wanted_steps.deinit();247 defer wanted_steps.deinit();
248248
249 if (step_names.len == 0) {249 if (step_names.len == 0) {
250 wanted_steps.append(&self.default_step) catch unreachable;250 try wanted_steps.append(&self.default_step);
251 } else {251 } else {
252 for (step_names) |step_name| {252 for (step_names) |step_name| {
253 const s = try self.getTopLevelStepByName(step_name);253 const s = try self.getTopLevelStepByName(step_name);
254 wanted_steps.append(s) catch unreachable;254 try wanted_steps.append(s);
255 }255 }
256 }256 }
257257
...@@ -721,11 +721,9 @@ pub const Builder = struct {...@@ -721,11 +721,9 @@ pub const Builder = struct {
721 return error.FileNotFound;721 return error.FileNotFound;
722 }722 }
723723
724 pub fn exec(self: &Builder, argv: []const []const u8) -> []u8 {724 pub fn exec(self: &Builder, argv: []const []const u8) -> %[]u8 {
725 const max_output_size = 100 * 1024;725 const max_output_size = 100 * 1024;
726 const result = os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size) catch |err| {726 const result = try os.ChildProcess.exec(self.allocator, argv, null, null, max_output_size);
727 std.debug.panic("Unable to spawn {}: {}", argv[0], @errorName(err));
728 };
729 switch (result.term) {727 switch (result.term) {
730 os.ChildProcess.Term.Exited => |code| {728 os.ChildProcess.Term.Exited => |code| {
731 if (code != 0) {729 if (code != 0) {
std/crypto/blake2.zig created+445
...@@ -0,0 +1,445 @@
1const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");
3const endian = @import("../endian.zig");
4const debug = @import("../debug/index.zig");
5const builtin = @import("builtin");
6const htest = @import("test.zig");
7
8const RoundParam = struct {
9 a: usize, b: usize, c: usize, d: usize, x: usize, y: usize,
10};
11
12fn Rp(a: usize, b: usize, c: usize, d: usize, x: usize, y: usize) -> RoundParam {
13 return RoundParam { .a = a, .b = b, .c = c, .d = d, .x = x, .y = y, };
14}
15
16/////////////////////
17// Blake2s
18
19pub const Blake2s224 = Blake2s(224);
20pub const Blake2s256 = Blake2s(256);
21
22fn Blake2s(comptime out_len: usize) -> type { return struct {
23 const Self = this;
24
25 const iv = [8]u32 {
26 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
27 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
28 };
29
30 const sigma = [10][16]u8 {
31 []const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
32 []const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
33 []const u8 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
34 []const u8 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
35 []const u8 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
36 []const u8 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
37 []const u8 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
38 []const u8 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
39 []const u8 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
40 []const u8 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
41 };
42
43 h: [8]u32,
44 t: u64,
45 // Streaming cache
46 buf: [64]u8,
47 buf_len: u8,
48
49 pub fn init() -> Self {
50 debug.assert(8 <= out_len and out_len <= 512);
51
52 var s: Self = undefined;
53 s.reset();
54 return s;
55 }
56
57 pub fn reset(d: &Self) {
58 mem.copy(u32, d.h[0..], iv[0..]);
59
60 // No key plus default parameters
61 d.h[0] ^= 0x01010000 ^ u32(out_len >> 3);
62 d.t = 0;
63 d.buf_len = 0;
64 }
65
66 pub fn hash(b: []const u8, out: []u8) {
67 var d = Self.init();
68 d.update(b);
69 d.final(out);
70 }
71
72 pub fn update(d: &Self, b: []const u8) {
73 var off: usize = 0;
74
75 // Partial buffer exists from previous update. Copy into buffer then hash.
76 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
77 off += 64 - d.buf_len;
78 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
79 d.t += 64;
80 d.round(d.buf[0..], false);
81 d.buf_len = 0;
82 }
83
84 // Full middle blocks.
85 while (off + 64 < b.len) : (off += 64) {
86 d.t += 64;
87 d.round(b[off..off + 64], false);
88 }
89
90 // Copy any remainder for next pass.
91 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
92 d.buf_len += u8(b[off..].len);
93 }
94
95 pub fn final(d: &Self, out: []u8) {
96 debug.assert(out.len >= out_len / 8);
97
98 mem.set(u8, d.buf[d.buf_len..], 0);
99 d.t += d.buf_len;
100 d.round(d.buf[0..], true);
101
102 const rr = d.h[0 .. out_len / 32];
103
104 for (rr) |s, j| {
105 mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Little);
106 }
107 }
108
109 fn round(d: &Self, b: []const u8, last: bool) {
110 debug.assert(b.len == 64);
111
112 var m: [16]u32 = undefined;
113 var v: [16]u32 = undefined;
114
115 for (m) |*r, i| {
116 *r = mem.readIntLE(u32, b[4*i .. 4*i + 4]);
117 }
118
119 var k: usize = 0;
120 while (k < 8) : (k += 1) {
121 v[k] = d.h[k];
122 v[k+8] = iv[k];
123 }
124
125 v[12] ^= @truncate(u32, d.t);
126 v[13] ^= u32(d.t >> 32);
127 if (last) v[14] = ~v[14];
128
129 const rounds = comptime []RoundParam {
130 Rp(0, 4, 8, 12, 0, 1),
131 Rp(1, 5, 9, 13, 2, 3),
132 Rp(2, 6, 10, 14, 4, 5),
133 Rp(3, 7, 11, 15, 6, 7),
134 Rp(0, 5, 10, 15, 8, 9),
135 Rp(1, 6, 11, 12, 10, 11),
136 Rp(2, 7, 8, 13, 12, 13),
137 Rp(3, 4, 9, 14, 14, 15),
138 };
139
140 comptime var j: usize = 0;
141 inline while (j < 10) : (j += 1) {
142 inline for (rounds) |r| {
143 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
144 v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(16));
145 v[r.c] = v[r.c] +% v[r.d];
146 v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(12));
147 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
148 v[r.d] = math.rotr(u32, v[r.d] ^ v[r.a], usize(8));
149 v[r.c] = v[r.c] +% v[r.d];
150 v[r.b] = math.rotr(u32, v[r.b] ^ v[r.c], usize(7));
151 }
152 }
153
154 for (d.h) |*r, i| {
155 *r ^= v[i] ^ v[i + 8];
156 }
157 }
158};}
159
160test "blake2s224 single" {
161 const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4";
162 htest.assertEqualHash(Blake2s224, h1, "");
163
164 const h2 = "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55";
165 htest.assertEqualHash(Blake2s224, h2, "abc");
166
167 const h3 = "e4e5cb6c7cae41982b397bf7b7d2d9d1949823ae78435326e8db4912";
168 htest.assertEqualHash(Blake2s224, h3, "The quick brown fox jumps over the lazy dog");
169}
170
171test "blake2s224 streaming" {
172 var h = Blake2s224.init();
173 var out: [28]u8 = undefined;
174
175 const h1 = "1fa1291e65248b37b3433475b2a0dd63d54a11ecc4e3e034e7bc1ef4";
176
177 h.final(out[0..]);
178 htest.assertEqual(h1, out[0..]);
179
180 const h2 = "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55";
181
182 h.reset();
183 h.update("abc");
184 h.final(out[0..]);
185 htest.assertEqual(h2, out[0..]);
186
187 h.reset();
188 h.update("a");
189 h.update("b");
190 h.update("c");
191 h.final(out[0..]);
192 htest.assertEqual(h2, out[0..]);
193}
194
195test "blake2s256 single" {
196 const h1 = "69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9";
197 htest.assertEqualHash(Blake2s256, h1, "");
198
199 const h2 = "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982";
200 htest.assertEqualHash(Blake2s256, h2, "abc");
201
202 const h3 = "606beeec743ccbeff6cbcdf5d5302aa855c256c29b88c8ed331ea1a6bf3c8812";
203 htest.assertEqualHash(Blake2s256, h3, "The quick brown fox jumps over the lazy dog");
204}
205
206test "blake2s256 streaming" {
207 var h = Blake2s256.init();
208 var out: [32]u8 = undefined;
209
210 const h1 = "69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9";
211
212 h.final(out[0..]);
213 htest.assertEqual(h1, out[0..]);
214
215 const h2 = "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982";
216
217 h.reset();
218 h.update("abc");
219 h.final(out[0..]);
220 htest.assertEqual(h2, out[0..]);
221
222 h.reset();
223 h.update("a");
224 h.update("b");
225 h.update("c");
226 h.final(out[0..]);
227 htest.assertEqual(h2, out[0..]);
228}
229
230
231/////////////////////
232// Blake2b
233
234pub const Blake2b384 = Blake2b(384);
235pub const Blake2b512 = Blake2b(512);
236
237fn Blake2b(comptime out_len: usize) -> type { return struct {
238 const Self = this;
239
240 const iv = [8]u64 {
241 0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
242 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
243 0x510e527fade682d1, 0x9b05688c2b3e6c1f,
244 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
245 };
246
247 const sigma = [12][16]u8 {
248 []const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
249 []const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
250 []const u8 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
251 []const u8 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
252 []const u8 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
253 []const u8 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
254 []const u8 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
255 []const u8 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
256 []const u8 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
257 []const u8 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 },
258 []const u8 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
259 []const u8 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
260 };
261
262 h: [8]u64,
263 t: u128,
264 // Streaming cache
265 buf: [128]u8,
266 buf_len: u8,
267
268 pub fn init() -> Self {
269 debug.assert(8 <= out_len and out_len <= 512);
270
271 var s: Self = undefined;
272 s.reset();
273 return s;
274 }
275
276 pub fn reset(d: &Self) {
277 mem.copy(u64, d.h[0..], iv[0..]);
278
279 // No key plus default parameters
280 d.h[0] ^= 0x01010000 ^ (out_len >> 3);
281 d.t = 0;
282 d.buf_len = 0;
283 }
284
285 pub fn hash(b: []const u8, out: []u8) {
286 var d = Self.init();
287 d.update(b);
288 d.final(out);
289 }
290
291 pub fn update(d: &Self, b: []const u8) {
292 var off: usize = 0;
293
294 // Partial buffer exists from previous update. Copy into buffer then hash.
295 if (d.buf_len != 0 and d.buf_len + b.len > 128) {
296 off += 128 - d.buf_len;
297 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
298 d.t += 128;
299 d.round(d.buf[0..], false);
300 d.buf_len = 0;
301 }
302
303 // Full middle blocks.
304 while (off + 128 < b.len) : (off += 128) {
305 d.t += 128;
306 d.round(b[off..off + 128], false);
307 }
308
309 // Copy any remainder for next pass.
310 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
311 d.buf_len += u8(b[off..].len);
312 }
313
314 pub fn final(d: &Self, out: []u8) {
315 mem.set(u8, d.buf[d.buf_len..], 0);
316 d.t += d.buf_len;
317 d.round(d.buf[0..], true);
318
319 const rr = d.h[0 .. out_len / 64];
320
321 for (rr) |s, j| {
322 mem.writeInt(out[8*j .. 8*j + 8], s, builtin.Endian.Little);
323 }
324 }
325
326 fn round(d: &Self, b: []const u8, last: bool) {
327 debug.assert(b.len == 128);
328
329 var m: [16]u64 = undefined;
330 var v: [16]u64 = undefined;
331
332 for (m) |*r, i| {
333 *r = mem.readIntLE(u64, b[8*i .. 8*i + 8]);
334 }
335
336 var k: usize = 0;
337 while (k < 8) : (k += 1) {
338 v[k] = d.h[k];
339 v[k+8] = iv[k];
340 }
341
342 v[12] ^= @truncate(u64, d.t);
343 v[13] ^= u64(d.t >> 64);
344 if (last) v[14] = ~v[14];
345
346 const rounds = comptime []RoundParam {
347 Rp(0, 4, 8, 12, 0, 1),
348 Rp(1, 5, 9, 13, 2, 3),
349 Rp(2, 6, 10, 14, 4, 5),
350 Rp(3, 7, 11, 15, 6, 7),
351 Rp(0, 5, 10, 15, 8, 9),
352 Rp(1, 6, 11, 12, 10, 11),
353 Rp(2, 7, 8, 13, 12, 13),
354 Rp(3, 4, 9, 14, 14, 15),
355 };
356
357 comptime var j: usize = 0;
358 inline while (j < 12) : (j += 1) {
359 inline for (rounds) |r| {
360 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.x]];
361 v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(32));
362 v[r.c] = v[r.c] +% v[r.d];
363 v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(24));
364 v[r.a] = v[r.a] +% v[r.b] +% m[sigma[j][r.y]];
365 v[r.d] = math.rotr(u64, v[r.d] ^ v[r.a], usize(16));
366 v[r.c] = v[r.c] +% v[r.d];
367 v[r.b] = math.rotr(u64, v[r.b] ^ v[r.c], usize(63));
368 }
369 }
370
371 for (d.h) |*r, i| {
372 *r ^= v[i] ^ v[i + 8];
373 }
374 }
375};}
376
377test "blake2b384 single" {
378 const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100";
379 htest.assertEqualHash(Blake2b384, h1, "");
380
381 const h2 = "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4";
382 htest.assertEqualHash(Blake2b384, h2, "abc");
383
384 const h3 = "b7c81b228b6bd912930e8f0b5387989691c1cee1e65aade4da3b86a3c9f678fc8018f6ed9e2906720c8d2a3aeda9c03d";
385 htest.assertEqualHash(Blake2b384, h3, "The quick brown fox jumps over the lazy dog");
386}
387
388test "blake2b384 streaming" {
389 var h = Blake2b384.init();
390 var out: [48]u8 = undefined;
391
392 const h1 = "b32811423377f52d7862286ee1a72ee540524380fda1724a6f25d7978c6fd3244a6caf0498812673c5e05ef583825100";
393
394 h.final(out[0..]);
395 htest.assertEqual(h1, out[0..]);
396
397 const h2 = "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4";
398
399 h.reset();
400 h.update("abc");
401 h.final(out[0..]);
402 htest.assertEqual(h2, out[0..]);
403
404 h.reset();
405 h.update("a");
406 h.update("b");
407 h.update("c");
408 h.final(out[0..]);
409 htest.assertEqual(h2, out[0..]);
410}
411
412test "blake2b512 single" {
413 const h1 = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce";
414 htest.assertEqualHash(Blake2b512, h1, "");
415
416 const h2 = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923";
417 htest.assertEqualHash(Blake2b512, h2, "abc");
418
419 const h3 = "a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918";
420 htest.assertEqualHash(Blake2b512, h3, "The quick brown fox jumps over the lazy dog");
421}
422
423test "blake2b512 streaming" {
424 var h = Blake2b512.init();
425 var out: [64]u8 = undefined;
426
427 const h1 = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce";
428
429 h.final(out[0..]);
430 htest.assertEqual(h1, out[0..]);
431
432 const h2 = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923";
433
434 h.reset();
435 h.update("abc");
436 h.final(out[0..]);
437 htest.assertEqual(h2, out[0..]);
438
439 h.reset();
440 h.update("a");
441 h.update("b");
442 h.update("c");
443 h.final(out[0..]);
444 htest.assertEqual(h2, out[0..]);
445}
std/crypto/index.zig created+21
...@@ -0,0 +1,21 @@
1pub const Md5 = @import("sha1.zig").Md5;
2pub const Sha1 = @import("md5.zig").Sha1;
3
4const sha2 = @import("sha2.zig");
5pub const Sha224 = sha2.Sha224;
6pub const Sha256 = sha2.Sha256;
7pub const Sha384 = sha2.Sha384;
8pub const Sha512 = sha2.Sha512;
9
10const blake2 = @import("blake2.zig");
11pub const Blake2s224 = blake2.Blake2s224;
12pub const Blake2s256 = blake2.Blake2s256;
13pub const Blake2b384 = blake2.Blake2b384;
14pub const Blake2b512 = blake2.Blake2b512;
15
16test "crypto" {
17 _ = @import("md5.zig");
18 _ = @import("sha1.zig");
19 _ = @import("sha2.zig");
20 _ = @import("blake2.zig");
21}
std/crypto/md5.zig created+260
...@@ -0,0 +1,260 @@
1const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");
3const endian = @import("../endian.zig");
4const builtin = @import("builtin");
5const debug = @import("../debug/index.zig");
6const fmt = @import("../fmt/index.zig");
7
8const RoundParam = struct {
9 a: usize, b: usize, c: usize, d: usize,
10 k: usize, s: u32, t: u32
11};
12
13fn Rp(a: usize, b: usize, c: usize, d: usize, k: usize, s: u32, t: u32) -> RoundParam {
14 return RoundParam { .a = a, .b = b, .c = c, .d = d, .k = k, .s = s, .t = t };
15}
16
17/// const hash1 = Md5.hash("my input");
18///
19/// const hasher = Md5.init();
20/// hasher.update("my ");
21/// hasher.update("input");
22/// const hash2 = hasher.final();
23pub const Md5 = struct {
24 const Self = this;
25
26 s: [4]u32,
27 // Streaming Cache
28 buf: [64]u8,
29 buf_len: u8,
30 total_len: u64,
31
32 pub fn init() -> Self {
33 var d: Self = undefined;
34 d.reset();
35 return d;
36 }
37
38 pub fn reset(d: &Self) {
39 d.s[0] = 0x67452301;
40 d.s[1] = 0xEFCDAB89;
41 d.s[2] = 0x98BADCFE;
42 d.s[3] = 0x10325476;
43 d.buf_len = 0;
44 d.total_len = 0;
45 }
46
47 pub fn hash(b: []const u8, out: []u8) {
48 var d = Md5.init();
49 d.update(b);
50 d.final(out);
51 }
52
53 pub fn update(d: &Self, b: []const u8) {
54 var off: usize = 0;
55
56 // Partial buffer exists from previous update. Copy into buffer then hash.
57 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
58 off += 64 - d.buf_len;
59 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
60
61 d.round(d.buf[0..]);
62 d.buf_len = 0;
63 }
64
65 // Full middle blocks.
66 while (off + 64 < b.len) : (off += 64) {
67 d.round(b[off..off + 64]);
68 }
69
70 // Copy any remainder for next pass.
71 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
72 d.buf_len += u8(b[off..].len);
73
74 // Md5 uses the bottom 64-bits for length padding
75 d.total_len +%= b.len;
76 }
77
78 pub fn final(d: &Self, out: []u8) {
79 debug.assert(out.len >= 16);
80
81 // The buffer here will never be completely full.
82 mem.set(u8, d.buf[d.buf_len..], 0);
83
84 // Append padding bits.
85 d.buf[d.buf_len] = 0x80;
86 d.buf_len += 1;
87
88 // > 448 mod 512 so need to add an extra round to wrap around.
89 if (64 - d.buf_len < 8) {
90 d.round(d.buf[0..]);
91 mem.set(u8, d.buf[0..], 0);
92 }
93
94 // Append message length.
95 var i: usize = 1;
96 var len = d.total_len >> 5;
97 d.buf[56] = u8(d.total_len & 0x1f) << 3;
98 while (i < 8) : (i += 1) {
99 d.buf[56 + i] = u8(len & 0xff);
100 len >>= 8;
101 }
102
103 d.round(d.buf[0..]);
104
105 for (d.s) |s, j| {
106 mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Little);
107 }
108 }
109
110 fn round(d: &Self, b: []const u8) {
111 debug.assert(b.len == 64);
112
113 var s: [16]u32 = undefined;
114
115 // ERROR: cannot unroll this at comptime
116 var i: usize = 0;
117 while (i < 16) : (i += 1) {
118 // NOTE: Performing or's separately improves perf by ~10%
119 s[i] = 0;
120 s[i] |= u32(b[i*4+0]);
121 s[i] |= u32(b[i*4+1]) << 8;
122 s[i] |= u32(b[i*4+2]) << 16;
123 s[i] |= u32(b[i*4+3]) << 24;
124 }
125
126 var v: [4]u32 = []u32 {
127 d.s[0], d.s[1], d.s[2], d.s[3],
128 };
129
130 const round0 = comptime []RoundParam {
131 Rp(0, 1, 2, 3, 0, 7, 0xD76AA478),
132 Rp(3, 0, 1, 2, 1, 12, 0xE8C7B756),
133 Rp(2, 3, 0, 1, 2, 17, 0x242070DB),
134 Rp(1, 2, 3, 0, 3, 22, 0xC1BDCEEE),
135 Rp(0, 1, 2, 3, 4, 7, 0xF57C0FAF),
136 Rp(3, 0, 1, 2, 5, 12, 0x4787C62A),
137 Rp(2, 3, 0, 1, 6, 17, 0xA8304613),
138 Rp(1, 2, 3, 0, 7, 22, 0xFD469501),
139 Rp(0, 1, 2, 3, 8, 7, 0x698098D8),
140 Rp(3, 0, 1, 2, 9, 12, 0x8B44F7AF),
141 Rp(2, 3, 0, 1, 10, 17, 0xFFFF5BB1),
142 Rp(1, 2, 3, 0, 11, 22, 0x895CD7BE),
143 Rp(0, 1, 2, 3, 12, 7, 0x6B901122),
144 Rp(3, 0, 1, 2, 13, 12, 0xFD987193),
145 Rp(2, 3, 0, 1, 14, 17, 0xA679438E),
146 Rp(1, 2, 3, 0, 15, 22, 0x49B40821),
147 };
148 inline for (round0) |r| {
149 v[r.a] = v[r.a] +% (v[r.d] ^ (v[r.b] & (v[r.c] ^ v[r.d]))) +% r.t +% s[r.k];
150 v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
151 }
152
153 const round1 = comptime []RoundParam {
154 Rp(0, 1, 2, 3, 1, 5, 0xF61E2562),
155 Rp(3, 0, 1, 2, 6, 9, 0xC040B340),
156 Rp(2, 3, 0, 1, 11, 14, 0x265E5A51),
157 Rp(1, 2, 3, 0, 0, 20, 0xE9B6C7AA),
158 Rp(0, 1, 2, 3, 5, 5, 0xD62F105D),
159 Rp(3, 0, 1, 2, 10, 9, 0x02441453),
160 Rp(2, 3, 0, 1, 15, 14, 0xD8A1E681),
161 Rp(1, 2, 3, 0, 4, 20, 0xE7D3FBC8),
162 Rp(0, 1, 2, 3, 9, 5, 0x21E1CDE6),
163 Rp(3, 0, 1, 2, 14, 9, 0xC33707D6),
164 Rp(2, 3, 0, 1, 3, 14, 0xF4D50D87),
165 Rp(1, 2, 3, 0, 8, 20, 0x455A14ED),
166 Rp(0, 1, 2, 3, 13, 5, 0xA9E3E905),
167 Rp(3, 0, 1, 2, 2, 9, 0xFCEFA3F8),
168 Rp(2, 3, 0, 1, 7, 14, 0x676F02D9),
169 Rp(1, 2, 3, 0, 12, 20, 0x8D2A4C8A),
170 };
171 inline for (round1) |r| {
172 v[r.a] = v[r.a] +% (v[r.c] ^ (v[r.d] & (v[r.b] ^ v[r.c]))) +% r.t +% s[r.k];
173 v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
174 }
175
176 const round2 = comptime []RoundParam {
177 Rp(0, 1, 2, 3, 5, 4, 0xFFFA3942),
178 Rp(3, 0, 1, 2, 8, 11, 0x8771F681),
179 Rp(2, 3, 0, 1, 11, 16, 0x6D9D6122),
180 Rp(1, 2, 3, 0, 14, 23, 0xFDE5380C),
181 Rp(0, 1, 2, 3, 1, 4, 0xA4BEEA44),
182 Rp(3, 0, 1, 2, 4, 11, 0x4BDECFA9),
183 Rp(2, 3, 0, 1, 7, 16, 0xF6BB4B60),
184 Rp(1, 2, 3, 0, 10, 23, 0xBEBFBC70),
185 Rp(0, 1, 2, 3, 13, 4, 0x289B7EC6),
186 Rp(3, 0, 1, 2, 0, 11, 0xEAA127FA),
187 Rp(2, 3, 0, 1, 3, 16, 0xD4EF3085),
188 Rp(1, 2, 3, 0, 6, 23, 0x04881D05),
189 Rp(0, 1, 2, 3, 9, 4, 0xD9D4D039),
190 Rp(3, 0, 1, 2, 12, 11, 0xE6DB99E5),
191 Rp(2, 3, 0, 1, 15, 16, 0x1FA27CF8),
192 Rp(1, 2, 3, 0, 2, 23, 0xC4AC5665),
193 };
194 inline for (round2) |r| {
195 v[r.a] = v[r.a] +% (v[r.b] ^ v[r.c] ^ v[r.d]) +% r.t +% s[r.k];
196 v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
197 }
198
199 const round3 = comptime []RoundParam {
200 Rp(0, 1, 2, 3, 0, 6, 0xF4292244),
201 Rp(3, 0, 1, 2, 7, 10, 0x432AFF97),
202 Rp(2, 3, 0, 1, 14, 15, 0xAB9423A7),
203 Rp(1, 2, 3, 0, 5, 21, 0xFC93A039),
204 Rp(0, 1, 2, 3, 12, 6, 0x655B59C3),
205 Rp(3, 0, 1, 2, 3, 10, 0x8F0CCC92),
206 Rp(2, 3, 0, 1, 10, 15, 0xFFEFF47D),
207 Rp(1, 2, 3, 0, 1, 21, 0x85845DD1),
208 Rp(0, 1, 2, 3, 8, 6, 0x6FA87E4F),
209 Rp(3, 0, 1, 2, 15, 10, 0xFE2CE6E0),
210 Rp(2, 3, 0, 1, 6, 15, 0xA3014314),
211 Rp(1, 2, 3, 0, 13, 21, 0x4E0811A1),
212 Rp(0, 1, 2, 3, 4, 6, 0xF7537E82),
213 Rp(3, 0, 1, 2, 11, 10, 0xBD3AF235),
214 Rp(2, 3, 0, 1, 2, 15, 0x2AD7D2BB),
215 Rp(1, 2, 3, 0, 9, 21, 0xEB86D391),
216 };
217 inline for (round3) |r| {
218 v[r.a] = v[r.a] +% (v[r.c] ^ (v[r.b] | ~v[r.d])) +% r.t +% s[r.k];
219 v[r.a] = v[r.b] +% math.rotl(u32, v[r.a], r.s);
220 }
221
222 d.s[0] +%= v[0];
223 d.s[1] +%= v[1];
224 d.s[2] +%= v[2];
225 d.s[3] +%= v[3];
226 }
227};
228
229const htest = @import("test.zig");
230
231test "md5 single" {
232 htest.assertEqualHash(Md5, "d41d8cd98f00b204e9800998ecf8427e", "");
233 htest.assertEqualHash(Md5, "0cc175b9c0f1b6a831c399e269772661", "a");
234 htest.assertEqualHash(Md5, "900150983cd24fb0d6963f7d28e17f72", "abc");
235 htest.assertEqualHash(Md5, "f96b697d7cb7938d525a2f31aaf161d0", "message digest");
236 htest.assertEqualHash(Md5, "c3fcd3d76192e4007dfb496cca67e13b", "abcdefghijklmnopqrstuvwxyz");
237 htest.assertEqualHash(Md5, "d174ab98d277d9f5a5611c2c9f419d9f", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
238 htest.assertEqualHash(Md5, "57edf4a22be3c955ac49da2e2107b67a", "12345678901234567890123456789012345678901234567890123456789012345678901234567890");
239}
240
241test "md5 streaming" {
242 var h = Md5.init();
243 var out: [16]u8 = undefined;
244
245 h.final(out[0..]);
246 htest.assertEqual("d41d8cd98f00b204e9800998ecf8427e", out[0..]);
247
248 h.reset();
249 h.update("abc");
250 h.final(out[0..]);
251 htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]);
252
253 h.reset();
254 h.update("a");
255 h.update("b");
256 h.update("c");
257 h.final(out[0..]);
258
259 htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]);
260}
std/crypto/sha1.zig created+284
...@@ -0,0 +1,284 @@
1const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");
3const endian = @import("../endian.zig");
4const debug = @import("../debug/index.zig");
5const builtin = @import("builtin");
6
7pub const u160 = @IntType(false, 160);
8
9const RoundParam = struct {
10 a: usize, b: usize, c: usize, d: usize, e: usize, i: u32,
11};
12
13fn Rp(a: usize, b: usize, c: usize, d: usize, e: usize, i: u32) -> RoundParam {
14 return RoundParam { .a = a, .b = b, .c = c, .d = d, .e = e, .i = i };
15}
16
17pub const Sha1 = struct {
18 const Self = this;
19
20 s: [5]u32,
21 // Streaming Cache
22 buf: [64]u8,
23 buf_len: u8,
24 total_len: u64,
25
26 pub fn init() -> Self {
27 var d: Self = undefined;
28 d.reset();
29 return d;
30 }
31
32 pub fn reset(d: &Self) {
33 d.s[0] = 0x67452301;
34 d.s[1] = 0xEFCDAB89;
35 d.s[2] = 0x98BADCFE;
36 d.s[3] = 0x10325476;
37 d.s[4] = 0xC3D2E1F0;
38 d.buf_len = 0;
39 d.total_len = 0;
40 }
41
42 pub fn hash(b: []const u8, out: []u8) {
43 var d = Sha1.init();
44 d.update(b);
45 d.final(out);
46 }
47
48 pub fn update(d: &Self, b: []const u8) {
49 var off: usize = 0;
50
51 // Partial buffer exists from previous update. Copy into buffer then hash.
52 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
53 off += 64 - d.buf_len;
54 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
55
56 d.round(d.buf[0..]);
57 d.buf_len = 0;
58 }
59
60 // Full middle blocks.
61 while (off + 64 < b.len) : (off += 64) {
62 d.round(b[off..off + 64]);
63 }
64
65 // Copy any remainder for next pass.
66 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
67 d.buf_len += u8(b[off..].len);
68
69 d.total_len += b.len;
70 }
71
72 pub fn final(d: &Self, out: []u8) {
73 debug.assert(out.len >= 20);
74
75 // The buffer here will never be completely full.
76 mem.set(u8, d.buf[d.buf_len..], 0);
77
78 // Append padding bits.
79 d.buf[d.buf_len] = 0x80;
80 d.buf_len += 1;
81
82 // > 448 mod 512 so need to add an extra round to wrap around.
83 if (64 - d.buf_len < 8) {
84 d.round(d.buf[0..]);
85 mem.set(u8, d.buf[0..], 0);
86 }
87
88 // Append message length.
89 var i: usize = 1;
90 var len = d.total_len >> 5;
91 d.buf[63] = u8(d.total_len & 0x1f) << 3;
92 while (i < 8) : (i += 1) {
93 d.buf[63 - i] = u8(len & 0xff);
94 len >>= 8;
95 }
96
97 d.round(d.buf[0..]);
98
99 for (d.s) |s, j| {
100 mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Big);
101 }
102 }
103
104 fn round(d: &Self, b: []const u8) {
105 debug.assert(b.len == 64);
106
107 var s: [16]u32 = undefined;
108
109 var v: [5]u32 = []u32 {
110 d.s[0], d.s[1], d.s[2], d.s[3], d.s[4],
111 };
112
113 const round0a = comptime []RoundParam {
114 Rp(0, 1, 2, 3, 4, 0),
115 Rp(4, 0, 1, 2, 3, 1),
116 Rp(3, 4, 0, 1, 2, 2),
117 Rp(2, 3, 4, 0, 1, 3),
118 Rp(1, 2, 3, 4, 0, 4),
119 Rp(0, 1, 2, 3, 4, 5),
120 Rp(4, 0, 1, 2, 3, 6),
121 Rp(3, 4, 0, 1, 2, 7),
122 Rp(2, 3, 4, 0, 1, 8),
123 Rp(1, 2, 3, 4, 0, 9),
124 Rp(0, 1, 2, 3, 4, 10),
125 Rp(4, 0, 1, 2, 3, 11),
126 Rp(3, 4, 0, 1, 2, 12),
127 Rp(2, 3, 4, 0, 1, 13),
128 Rp(1, 2, 3, 4, 0, 14),
129 Rp(0, 1, 2, 3, 4, 15),
130 };
131 inline for (round0a) |r| {
132 s[r.i] = (u32(b[r.i * 4 + 0]) << 24) |
133 (u32(b[r.i * 4 + 1]) << 16) |
134 (u32(b[r.i * 4 + 2]) << 8) |
135 (u32(b[r.i * 4 + 3]) << 0);
136
137 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x5A827999 +% s[r.i & 0xf]
138 +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
139 v[r.b] = math.rotl(u32, v[r.b], u32(30));
140 }
141
142 const round0b = comptime []RoundParam {
143 Rp(4, 0, 1, 2, 3, 16),
144 Rp(3, 4, 0, 1, 2, 17),
145 Rp(2, 3, 4, 0, 1, 18),
146 Rp(1, 2, 3, 4, 0, 19),
147 };
148 inline for (round0b) |r| {
149 const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
150 s[r.i & 0xf] = math.rotl(u32, t, u32(1));
151
152 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x5A827999 +% s[r.i & 0xf]
153 +% ((v[r.b] & v[r.c]) | (~v[r.b] & v[r.d]));
154 v[r.b] = math.rotl(u32, v[r.b], u32(30));
155 }
156
157 const round1 = comptime []RoundParam {
158 Rp(0, 1, 2, 3, 4, 20),
159 Rp(4, 0, 1, 2, 3, 21),
160 Rp(3, 4, 0, 1, 2, 22),
161 Rp(2, 3, 4, 0, 1, 23),
162 Rp(1, 2, 3, 4, 0, 24),
163 Rp(0, 1, 2, 3, 4, 25),
164 Rp(4, 0, 1, 2, 3, 26),
165 Rp(3, 4, 0, 1, 2, 27),
166 Rp(2, 3, 4, 0, 1, 28),
167 Rp(1, 2, 3, 4, 0, 29),
168 Rp(0, 1, 2, 3, 4, 30),
169 Rp(4, 0, 1, 2, 3, 31),
170 Rp(3, 4, 0, 1, 2, 32),
171 Rp(2, 3, 4, 0, 1, 33),
172 Rp(1, 2, 3, 4, 0, 34),
173 Rp(0, 1, 2, 3, 4, 35),
174 Rp(4, 0, 1, 2, 3, 36),
175 Rp(3, 4, 0, 1, 2, 37),
176 Rp(2, 3, 4, 0, 1, 38),
177 Rp(1, 2, 3, 4, 0, 39),
178 };
179 inline for (round1) |r| {
180 const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
181 s[r.i & 0xf] = math.rotl(u32, t, u32(1));
182
183 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x6ED9EBA1 +% s[r.i & 0xf]
184 +% (v[r.b] ^ v[r.c] ^ v[r.d]);
185 v[r.b] = math.rotl(u32, v[r.b], u32(30));
186 }
187
188 const round2 = comptime []RoundParam {
189 Rp(0, 1, 2, 3, 4, 40),
190 Rp(4, 0, 1, 2, 3, 41),
191 Rp(3, 4, 0, 1, 2, 42),
192 Rp(2, 3, 4, 0, 1, 43),
193 Rp(1, 2, 3, 4, 0, 44),
194 Rp(0, 1, 2, 3, 4, 45),
195 Rp(4, 0, 1, 2, 3, 46),
196 Rp(3, 4, 0, 1, 2, 47),
197 Rp(2, 3, 4, 0, 1, 48),
198 Rp(1, 2, 3, 4, 0, 49),
199 Rp(0, 1, 2, 3, 4, 50),
200 Rp(4, 0, 1, 2, 3, 51),
201 Rp(3, 4, 0, 1, 2, 52),
202 Rp(2, 3, 4, 0, 1, 53),
203 Rp(1, 2, 3, 4, 0, 54),
204 Rp(0, 1, 2, 3, 4, 55),
205 Rp(4, 0, 1, 2, 3, 56),
206 Rp(3, 4, 0, 1, 2, 57),
207 Rp(2, 3, 4, 0, 1, 58),
208 Rp(1, 2, 3, 4, 0, 59),
209 };
210 inline for (round2) |r| {
211 const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
212 s[r.i & 0xf] = math.rotl(u32, t, u32(1));
213
214 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0x8F1BBCDC +% s[r.i & 0xf]
215 +% ((v[r.b] & v[r.c]) ^ (v[r.b] & v[r.d]) ^ (v[r.c] & v[r.d]));
216 v[r.b] = math.rotl(u32, v[r.b], u32(30));
217 }
218
219 const round3 = comptime []RoundParam {
220 Rp(0, 1, 2, 3, 4, 60),
221 Rp(4, 0, 1, 2, 3, 61),
222 Rp(3, 4, 0, 1, 2, 62),
223 Rp(2, 3, 4, 0, 1, 63),
224 Rp(1, 2, 3, 4, 0, 64),
225 Rp(0, 1, 2, 3, 4, 65),
226 Rp(4, 0, 1, 2, 3, 66),
227 Rp(3, 4, 0, 1, 2, 67),
228 Rp(2, 3, 4, 0, 1, 68),
229 Rp(1, 2, 3, 4, 0, 69),
230 Rp(0, 1, 2, 3, 4, 70),
231 Rp(4, 0, 1, 2, 3, 71),
232 Rp(3, 4, 0, 1, 2, 72),
233 Rp(2, 3, 4, 0, 1, 73),
234 Rp(1, 2, 3, 4, 0, 74),
235 Rp(0, 1, 2, 3, 4, 75),
236 Rp(4, 0, 1, 2, 3, 76),
237 Rp(3, 4, 0, 1, 2, 77),
238 Rp(2, 3, 4, 0, 1, 78),
239 Rp(1, 2, 3, 4, 0, 79),
240 };
241 inline for (round3) |r| {
242 const t = s[(r.i-3) & 0xf] ^ s[(r.i-8) & 0xf] ^ s[(r.i-14) & 0xf] ^ s[(r.i-16) & 0xf];
243 s[r.i & 0xf] = math.rotl(u32, t, u32(1));
244
245 v[r.e] = v[r.e] +% math.rotl(u32, v[r.a], u32(5)) +% 0xCA62C1D6 +% s[r.i & 0xf]
246 +% (v[r.b] ^ v[r.c] ^ v[r.d]);
247 v[r.b] = math.rotl(u32, v[r.b], u32(30));
248 }
249
250 d.s[0] +%= v[0];
251 d.s[1] +%= v[1];
252 d.s[2] +%= v[2];
253 d.s[3] +%= v[3];
254 d.s[4] +%= v[4];
255 }
256};
257
258const htest = @import("test.zig");
259
260test "sha1 single" {
261 htest.assertEqualHash(Sha1, "da39a3ee5e6b4b0d3255bfef95601890afd80709", "");
262 htest.assertEqualHash(Sha1, "a9993e364706816aba3e25717850c26c9cd0d89d", "abc");
263 htest.assertEqualHash(Sha1, "a49b2446a02c645bf419f995b67091253a04a259", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
264}
265
266test "sha1 streaming" {
267 var h = Sha1.init();
268 var out: [20]u8 = undefined;
269
270 h.final(out[0..]);
271 htest.assertEqual("da39a3ee5e6b4b0d3255bfef95601890afd80709", out[0..]);
272
273 h.reset();
274 h.update("abc");
275 h.final(out[0..]);
276 htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
277
278 h.reset();
279 h.update("a");
280 h.update("b");
281 h.update("c");
282 h.final(out[0..]);
283 htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
284}
std/crypto/sha2.zig created+670
...@@ -0,0 +1,670 @@
1const mem = @import("../mem.zig");
2const math = @import("../math/index.zig");
3const endian = @import("../endian.zig");
4const debug = @import("../debug/index.zig");
5const builtin = @import("builtin");
6const htest = @import("test.zig");
7
8/////////////////////
9// Sha224 + Sha256
10
11const RoundParam256 = struct {
12 a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize,
13 i: usize, k: u32,
14};
15
16fn Rp256(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u32) -> RoundParam256 {
17 return RoundParam256 { .a = a, .b = b, .c = c, .d = d, .e = e, .f = f, .g = g, .h = h, .i = i, .k = k };
18}
19
20const Sha2Params32 = struct {
21 iv0: u32,
22 iv1: u32,
23 iv2: u32,
24 iv3: u32,
25 iv4: u32,
26 iv5: u32,
27 iv6: u32,
28 iv7: u32,
29 out_len: usize,
30};
31
32const Sha224Params = Sha2Params32 {
33 .iv0 = 0xC1059ED8,
34 .iv1 = 0x367CD507,
35 .iv2 = 0x3070DD17,
36 .iv3 = 0xF70E5939,
37 .iv4 = 0xFFC00B31,
38 .iv5 = 0x68581511,
39 .iv6 = 0x64F98FA7,
40 .iv7 = 0xBEFA4FA4,
41 .out_len = 224,
42};
43
44const Sha256Params = Sha2Params32 {
45 .iv0 = 0x6A09E667,
46 .iv1 = 0xBB67AE85,
47 .iv2 = 0x3C6EF372,
48 .iv3 = 0xA54FF53A,
49 .iv4 = 0x510E527F,
50 .iv5 = 0x9B05688C,
51 .iv6 = 0x1F83D9AB,
52 .iv7 = 0x5BE0CD19,
53 .out_len = 256,
54};
55
56pub const Sha224 = Sha2_32(Sha224Params);
57pub const Sha256 = Sha2_32(Sha256Params);
58
59fn Sha2_32(comptime params: Sha2Params32) -> type { return struct {
60 const Self = this;
61
62 s: [8]u32,
63 // Streaming Cache
64 buf: [64]u8,
65 buf_len: u8,
66 total_len: u64,
67
68 pub fn init() -> Self {
69 var d: Self = undefined;
70 d.reset();
71 return d;
72 }
73
74 pub fn reset(d: &Self) {
75 d.s[0] = params.iv0;
76 d.s[1] = params.iv1;
77 d.s[2] = params.iv2;
78 d.s[3] = params.iv3;
79 d.s[4] = params.iv4;
80 d.s[5] = params.iv5;
81 d.s[6] = params.iv6;
82 d.s[7] = params.iv7;
83 d.buf_len = 0;
84 d.total_len = 0;
85 }
86
87 pub fn hash(b: []const u8, out: []u8) {
88 var d = Self.init();
89 d.update(b);
90 d.final(out);
91 }
92
93 pub fn update(d: &Self, b: []const u8) {
94 var off: usize = 0;
95
96 // Partial buffer exists from previous update. Copy into buffer then hash.
97 if (d.buf_len != 0 and d.buf_len + b.len > 64) {
98 off += 64 - d.buf_len;
99 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
100
101 d.round(d.buf[0..]);
102 d.buf_len = 0;
103 }
104
105 // Full middle blocks.
106 while (off + 64 < b.len) : (off += 64) {
107 d.round(b[off..off + 64]);
108 }
109
110 // Copy any remainder for next pass.
111 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
112 d.buf_len += u8(b[off..].len);
113
114 d.total_len += b.len;
115 }
116
117 pub fn final(d: &Self, out: []u8) {
118 debug.assert(out.len >= params.out_len / 8);
119
120 // The buffer here will never be completely full.
121 mem.set(u8, d.buf[d.buf_len..], 0);
122
123 // Append padding bits.
124 d.buf[d.buf_len] = 0x80;
125 d.buf_len += 1;
126
127 // > 448 mod 512 so need to add an extra round to wrap around.
128 if (64 - d.buf_len < 8) {
129 d.round(d.buf[0..]);
130 mem.set(u8, d.buf[0..], 0);
131 }
132
133 // Append message length.
134 var i: usize = 1;
135 var len = d.total_len >> 5;
136 d.buf[63] = u8(d.total_len & 0x1f) << 3;
137 while (i < 8) : (i += 1) {
138 d.buf[63 - i] = u8(len & 0xff);
139 len >>= 8;
140 }
141
142 d.round(d.buf[0..]);
143
144 // May truncate for possible 224 output
145 const rr = d.s[0 .. params.out_len / 32];
146
147 for (rr) |s, j| {
148 mem.writeInt(out[4*j .. 4*j + 4], s, builtin.Endian.Big);
149 }
150 }
151
152 fn round(d: &Self, b: []const u8) {
153 debug.assert(b.len == 64);
154
155 var s: [64]u32 = undefined;
156
157 // ERROR: Cannot unroll at compile-time.
158 var i: usize = 0;
159 while (i < 16) : (i += 1) {
160 s[i] = 0;
161 s[i] |= u32(b[i*4+0]) << 24;
162 s[i] |= u32(b[i*4+1]) << 16;
163 s[i] |= u32(b[i*4+2]) << 8;
164 s[i] |= u32(b[i*4+3]) << 0;
165 }
166 while (i < 64) : (i += 1) {
167 s[i] =
168 s[i-16] +% s[i-7] +%
169 (math.rotr(u32, s[i-15], u32(7)) ^ math.rotr(u32, s[i-15], u32(18)) ^ (s[i-15] >> 3)) +%
170 (math.rotr(u32, s[i-2], u32(17)) ^ math.rotr(u32, s[i-2], u32(19)) ^ (s[i-2] >> 10));
171 }
172
173 var v: [8]u32 = []u32 {
174 d.s[0], d.s[1], d.s[2], d.s[3], d.s[4], d.s[5], d.s[6], d.s[7],
175 };
176
177 const round0 = comptime []RoundParam256 {
178 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98),
179 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x71374491),
180 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCF),
181 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA5),
182 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25B),
183 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1),
184 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4),
185 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5),
186 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98),
187 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B01),
188 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE),
189 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3),
190 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74),
191 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE),
192 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A7),
193 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174),
194 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C1),
195 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786),
196 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC6),
197 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC),
198 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F),
199 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA),
200 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DC),
201 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA),
202 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152),
203 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D),
204 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C8),
205 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7),
206 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF3),
207 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147),
208 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351),
209 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x14292967),
210 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A85),
211 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B2138),
212 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC),
213 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D13),
214 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A7354),
215 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB),
216 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E),
217 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C85),
218 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A1),
219 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664B),
220 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70),
221 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A3),
222 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819),
223 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD6990624),
224 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E3585),
225 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA070),
226 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116),
227 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C08),
228 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774C),
229 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5),
230 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3),
231 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4A),
232 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F),
233 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3),
234 Rp256(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE),
235 Rp256(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F),
236 Rp256(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814),
237 Rp256(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC70208),
238 Rp256(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA),
239 Rp256(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEB),
240 Rp256(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7),
241 Rp256(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2),
242 };
243 inline for (round0) |r| {
244 v[r.h] =
245 v[r.h] +%
246 (math.rotr(u32, v[r.e], u32(6)) ^ math.rotr(u32, v[r.e], u32(11)) ^ math.rotr(u32, v[r.e], u32(25))) +%
247 (v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +%
248 r.k +% s[r.i];
249
250 v[r.d] = v[r.d] +% v[r.h];
251
252 v[r.h] =
253 v[r.h] +%
254 (math.rotr(u32, v[r.a], u32(2)) ^ math.rotr(u32, v[r.a], u32(13)) ^ math.rotr(u32, v[r.a], u32(22))) +%
255 ((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c]));
256 }
257
258 d.s[0] +%= v[0];
259 d.s[1] +%= v[1];
260 d.s[2] +%= v[2];
261 d.s[3] +%= v[3];
262 d.s[4] +%= v[4];
263 d.s[5] +%= v[5];
264 d.s[6] +%= v[6];
265 d.s[7] +%= v[7];
266 }
267};}
268
269test "sha224 single" {
270 htest.assertEqualHash(Sha224, "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", "");
271 htest.assertEqualHash(Sha224, "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc");
272 htest.assertEqualHash(Sha224, "c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
273}
274
275test "sha224 streaming" {
276 var h = Sha224.init();
277 var out: [28]u8 = undefined;
278
279 h.final(out[0..]);
280 htest.assertEqual("d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", out[0..]);
281
282 h.reset();
283 h.update("abc");
284 h.final(out[0..]);
285 htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]);
286
287 h.reset();
288 h.update("a");
289 h.update("b");
290 h.update("c");
291 h.final(out[0..]);
292 htest.assertEqual("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", out[0..]);
293}
294
295test "sha256 single" {
296 htest.assertEqualHash(Sha256, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "");
297 htest.assertEqualHash(Sha256, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc");
298 htest.assertEqualHash(Sha256, "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
299}
300
301test "sha256 streaming" {
302 var h = Sha256.init();
303 var out: [32]u8 = undefined;
304
305 h.final(out[0..]);
306 htest.assertEqual("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", out[0..]);
307
308 h.reset();
309 h.update("abc");
310 h.final(out[0..]);
311 htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]);
312
313 h.reset();
314 h.update("a");
315 h.update("b");
316 h.update("c");
317 h.final(out[0..]);
318 htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]);
319}
320
321
322/////////////////////
323// Sha384 + Sha512
324
325const RoundParam512 = struct {
326 a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize,
327 i: usize, k: u64,
328};
329
330fn Rp512(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, g: usize, h: usize, i: usize, k: u64) -> RoundParam512 {
331 return RoundParam512 { .a = a, .b = b, .c = c, .d = d, .e = e, .f = f, .g = g, .h = h, .i = i, .k = k };
332}
333
334const Sha2Params64 = struct {
335 iv0: u64,
336 iv1: u64,
337 iv2: u64,
338 iv3: u64,
339 iv4: u64,
340 iv5: u64,
341 iv6: u64,
342 iv7: u64,
343 out_len: usize,
344};
345
346const Sha384Params = Sha2Params64 {
347 .iv0 = 0xCBBB9D5DC1059ED8,
348 .iv1 = 0x629A292A367CD507,
349 .iv2 = 0x9159015A3070DD17,
350 .iv3 = 0x152FECD8F70E5939,
351 .iv4 = 0x67332667FFC00B31,
352 .iv5 = 0x8EB44A8768581511,
353 .iv6 = 0xDB0C2E0D64F98FA7,
354 .iv7 = 0x47B5481DBEFA4FA4,
355 .out_len = 384,
356};
357
358const Sha512Params = Sha2Params64 {
359 .iv0 = 0x6A09E667F3BCC908,
360 .iv1 = 0xBB67AE8584CAA73B,
361 .iv2 = 0x3C6EF372FE94F82B,
362 .iv3 = 0xA54FF53A5F1D36F1,
363 .iv4 = 0x510E527FADE682D1,
364 .iv5 = 0x9B05688C2B3E6C1F,
365 .iv6 = 0x1F83D9ABFB41BD6B,
366 .iv7 = 0x5BE0CD19137E2179,
367 .out_len = 512
368};
369
370pub const Sha384 = Sha2_64(Sha384Params);
371pub const Sha512 = Sha2_64(Sha512Params);
372
373fn Sha2_64(comptime params: Sha2Params64) -> type { return struct {
374 const Self = this;
375 const u9 = @IntType(false, 9);
376
377 s: [8]u64,
378 // Streaming Cache
379 buf: [128]u8,
380 buf_len: u8,
381 total_len: u128,
382
383 pub fn init() -> Self {
384 var d: Self = undefined;
385 d.reset();
386 return d;
387 }
388
389 pub fn reset(d: &Self) {
390 d.s[0] = params.iv0;
391 d.s[1] = params.iv1;
392 d.s[2] = params.iv2;
393 d.s[3] = params.iv3;
394 d.s[4] = params.iv4;
395 d.s[5] = params.iv5;
396 d.s[6] = params.iv6;
397 d.s[7] = params.iv7;
398 d.buf_len = 0;
399 d.total_len = 0;
400 }
401
402 pub fn hash(b: []const u8, out: []u8) {
403 var d = Self.init();
404 d.update(b);
405 d.final(out);
406 }
407
408 pub fn update(d: &Self, b: []const u8) {
409 var off: usize = 0;
410
411 // Partial buffer exists from previous update. Copy into buffer then hash.
412 if (d.buf_len != 0 and d.buf_len + b.len > 128) {
413 off += 128 - d.buf_len;
414 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
415
416 d.round(d.buf[0..]);
417 d.buf_len = 0;
418 }
419
420 // Full middle blocks.
421 while (off + 128 < b.len) : (off += 128) {
422 d.round(b[off..off + 128]);
423 }
424
425 // Copy any remainder for next pass.
426 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
427 d.buf_len += u8(b[off..].len);
428
429 d.total_len += b.len;
430 }
431
432 pub fn final(d: &Self, out: []u8) {
433 debug.assert(out.len >= params.out_len / 8);
434
435 // The buffer here will never be completely full.
436 mem.set(u8, d.buf[d.buf_len..], 0);
437
438 // Append padding bits.
439 d.buf[d.buf_len] = 0x80;
440 d.buf_len += 1;
441
442 // > 896 mod 1024 so need to add an extra round to wrap around.
443 if (128 - d.buf_len < 16) {
444 d.round(d.buf[0..]);
445 mem.set(u8, d.buf[0..], 0);
446 }
447
448 // Append message length.
449 var i: usize = 1;
450 var len = d.total_len >> 5;
451 d.buf[127] = u8(d.total_len & 0x1f) << 3;
452 while (i < 16) : (i += 1) {
453 d.buf[127 - i] = u8(len & 0xff);
454 len >>= 8;
455 }
456
457 d.round(d.buf[0..]);
458
459 // May truncate for possible 384 output
460 const rr = d.s[0 .. params.out_len / 64];
461
462 for (rr) |s, j| {
463 mem.writeInt(out[8*j .. 8*j + 8], s, builtin.Endian.Big);
464 }
465 }
466
467 fn round(d: &Self, b: []const u8) {
468 debug.assert(b.len == 128);
469
470 var s: [80]u64 = undefined;
471
472 // ERROR: Cannot unroll at compile-time.
473 var i: usize = 0;
474 while (i < 16) : (i += 1) {
475 s[i] = 0;
476 s[i] |= u64(b[i*8+0]) << 56;
477 s[i] |= u64(b[i*8+1]) << 48;
478 s[i] |= u64(b[i*8+2]) << 40;
479 s[i] |= u64(b[i*8+3]) << 32;
480 s[i] |= u64(b[i*8+4]) << 24;
481 s[i] |= u64(b[i*8+5]) << 16;
482 s[i] |= u64(b[i*8+6]) << 8;
483 s[i] |= u64(b[i*8+7]) << 0;
484 }
485 while (i < 80) : (i += 1) {
486 s[i] =
487 s[i-16] +% s[i-7] +%
488 (math.rotr(u64, s[i-15], u64(1)) ^ math.rotr(u64, s[i-15], u64(8)) ^ (s[i-15] >> 7)) +%
489 (math.rotr(u64, s[i-2], u64(19)) ^ math.rotr(u64, s[i-2], u64(61)) ^ (s[i-2] >> 6));
490 }
491
492 var v: [8]u64 = []u64 {
493 d.s[0], d.s[1], d.s[2], d.s[3], d.s[4], d.s[5], d.s[6], d.s[7],
494 };
495
496 const round0 = comptime []RoundParam512 {
497 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 0, 0x428A2F98D728AE22),
498 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 1, 0x7137449123EF65CD),
499 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 2, 0xB5C0FBCFEC4D3B2F),
500 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 3, 0xE9B5DBA58189DBBC),
501 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 4, 0x3956C25BF348B538),
502 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 5, 0x59F111F1B605D019),
503 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 6, 0x923F82A4AF194F9B),
504 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 7, 0xAB1C5ED5DA6D8118),
505 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 8, 0xD807AA98A3030242),
506 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 9, 0x12835B0145706FBE),
507 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 10, 0x243185BE4EE4B28C),
508 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 11, 0x550C7DC3D5FFB4E2),
509 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 12, 0x72BE5D74F27B896F),
510 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 13, 0x80DEB1FE3B1696B1),
511 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 14, 0x9BDC06A725C71235),
512 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 15, 0xC19BF174CF692694),
513 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 16, 0xE49B69C19EF14AD2),
514 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 17, 0xEFBE4786384F25E3),
515 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 18, 0x0FC19DC68B8CD5B5),
516 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 19, 0x240CA1CC77AC9C65),
517 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 20, 0x2DE92C6F592B0275),
518 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 21, 0x4A7484AA6EA6E483),
519 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 22, 0x5CB0A9DCBD41FBD4),
520 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 23, 0x76F988DA831153B5),
521 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 24, 0x983E5152EE66DFAB),
522 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 25, 0xA831C66D2DB43210),
523 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 26, 0xB00327C898FB213F),
524 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 27, 0xBF597FC7BEEF0EE4),
525 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 28, 0xC6E00BF33DA88FC2),
526 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 29, 0xD5A79147930AA725),
527 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 30, 0x06CA6351E003826F),
528 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 31, 0x142929670A0E6E70),
529 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 32, 0x27B70A8546D22FFC),
530 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 33, 0x2E1B21385C26C926),
531 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 34, 0x4D2C6DFC5AC42AED),
532 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 35, 0x53380D139D95B3DF),
533 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 36, 0x650A73548BAF63DE),
534 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 37, 0x766A0ABB3C77B2A8),
535 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 38, 0x81C2C92E47EDAEE6),
536 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 39, 0x92722C851482353B),
537 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 40, 0xA2BFE8A14CF10364),
538 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 41, 0xA81A664BBC423001),
539 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 42, 0xC24B8B70D0F89791),
540 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 43, 0xC76C51A30654BE30),
541 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 44, 0xD192E819D6EF5218),
542 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 45, 0xD69906245565A910),
543 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 46, 0xF40E35855771202A),
544 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 47, 0x106AA07032BBD1B8),
545 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 48, 0x19A4C116B8D2D0C8),
546 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 49, 0x1E376C085141AB53),
547 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 50, 0x2748774CDF8EEB99),
548 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 51, 0x34B0BCB5E19B48A8),
549 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 52, 0x391C0CB3C5C95A63),
550 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 53, 0x4ED8AA4AE3418ACB),
551 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 54, 0x5B9CCA4F7763E373),
552 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 55, 0x682E6FF3D6B2B8A3),
553 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 56, 0x748F82EE5DEFB2FC),
554 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 57, 0x78A5636F43172F60),
555 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 58, 0x84C87814A1F0AB72),
556 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 59, 0x8CC702081A6439EC),
557 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 60, 0x90BEFFFA23631E28),
558 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 61, 0xA4506CEBDE82BDE9),
559 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 62, 0xBEF9A3F7B2C67915),
560 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 63, 0xC67178F2E372532B),
561 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 64, 0xCA273ECEEA26619C),
562 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 65, 0xD186B8C721C0C207),
563 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 66, 0xEADA7DD6CDE0EB1E),
564 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 67, 0xF57D4F7FEE6ED178),
565 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 68, 0x06F067AA72176FBA),
566 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 69, 0x0A637DC5A2C898A6),
567 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 70, 0x113F9804BEF90DAE),
568 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 71, 0x1B710B35131C471B),
569 Rp512(0, 1, 2, 3, 4, 5, 6, 7, 72, 0x28DB77F523047D84),
570 Rp512(7, 0, 1, 2, 3, 4, 5, 6, 73, 0x32CAAB7B40C72493),
571 Rp512(6, 7, 0, 1, 2, 3, 4, 5, 74, 0x3C9EBE0A15C9BEBC),
572 Rp512(5, 6, 7, 0, 1, 2, 3, 4, 75, 0x431D67C49C100D4C),
573 Rp512(4, 5, 6, 7, 0, 1, 2, 3, 76, 0x4CC5D4BECB3E42B6),
574 Rp512(3, 4, 5, 6, 7, 0, 1, 2, 77, 0x597F299CFC657E2A),
575 Rp512(2, 3, 4, 5, 6, 7, 0, 1, 78, 0x5FCB6FAB3AD6FAEC),
576 Rp512(1, 2, 3, 4, 5, 6, 7, 0, 79, 0x6C44198C4A475817),
577 };
578 inline for (round0) |r| {
579 v[r.h] =
580 v[r.h] +%
581 (math.rotr(u64, v[r.e], u64(14)) ^ math.rotr(u64, v[r.e], u64(18)) ^ math.rotr(u64, v[r.e], u64(41))) +%
582 (v[r.g] ^ (v[r.e] & (v[r.f] ^ v[r.g]))) +%
583 r.k +% s[r.i];
584
585 v[r.d] = v[r.d] +% v[r.h];
586
587 v[r.h] =
588 v[r.h] +%
589 (math.rotr(u64, v[r.a], u64(28)) ^ math.rotr(u64, v[r.a], u64(34)) ^ math.rotr(u64, v[r.a], u64(39))) +%
590 ((v[r.a] & (v[r.b] | v[r.c])) | (v[r.b] & v[r.c]));
591 }
592
593 d.s[0] +%= v[0];
594 d.s[1] +%= v[1];
595 d.s[2] +%= v[2];
596 d.s[3] +%= v[3];
597 d.s[4] +%= v[4];
598 d.s[5] +%= v[5];
599 d.s[6] +%= v[6];
600 d.s[7] +%= v[7];
601 }
602};}
603
604test "sha384 single" {
605 const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
606 htest.assertEqualHash(Sha384, h1, "");
607
608 const h2 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7";
609 htest.assertEqualHash(Sha384, h2, "abc");
610
611 const h3 = "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039";
612 htest.assertEqualHash(Sha384, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
613}
614
615test "sha384 streaming" {
616 var h = Sha384.init();
617 var out: [48]u8 = undefined;
618
619 const h1 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b";
620 h.final(out[0..]);
621 htest.assertEqual(h1, out[0..]);
622
623 const h2 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7";
624
625 h.reset();
626 h.update("abc");
627 h.final(out[0..]);
628 htest.assertEqual(h2, out[0..]);
629
630 h.reset();
631 h.update("a");
632 h.update("b");
633 h.update("c");
634 h.final(out[0..]);
635 htest.assertEqual(h2, out[0..]);
636}
637
638test "sha512 single" {
639 const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";
640 htest.assertEqualHash(Sha512, h1, "");
641
642 const h2 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";
643 htest.assertEqualHash(Sha512, h2, "abc");
644
645 const h3 = "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909";
646 htest.assertEqualHash(Sha512, h3, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu");
647}
648
649test "sha512 streaming" {
650 var h = Sha512.init();
651 var out: [64]u8 = undefined;
652
653 const h1 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e";
654 h.final(out[0..]);
655 htest.assertEqual(h1, out[0..]);
656
657 const h2 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f";
658
659 h.reset();
660 h.update("abc");
661 h.final(out[0..]);
662 htest.assertEqual(h2, out[0..]);
663
664 h.reset();
665 h.update("a");
666 h.update("b");
667 h.update("c");
668 h.final(out[0..]);
669 htest.assertEqual(h2, out[0..]);
670}
std/crypto/test.zig created+22
...@@ -0,0 +1,22 @@
1const debug = @import("../debug/index.zig");
2const mem = @import("../mem.zig");
3const fmt = @import("../fmt/index.zig");
4
5// Hash using the specified hasher `H` asserting `expected == H(input)`.
6pub fn assertEqualHash(comptime Hasher: var, comptime expected: []const u8, input: []const u8) {
7 var h: [expected.len / 2]u8 = undefined;
8 Hasher.hash(input, h[0..]);
9
10 assertEqual(expected, h);
11}
12
13// Assert `expected` == `input` where `input` is a bytestring.
14pub fn assertEqual(comptime expected: []const u8, input: []const u8) {
15 var expected_bytes: [expected.len / 2]u8 = undefined;
16 for (expected_bytes) |*r, i| {
17 *r = fmt.parseInt(u8, expected[2*i .. 2*i+2], 16) catch unreachable;
18 }
19
20 debug.assert(mem.eql(u8, expected_bytes, input));
21}
22
std/debug/index.zig+149-63
...@@ -13,6 +13,10 @@ pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;...@@ -13,6 +13,10 @@ pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;
13error MissingDebugInfo;13error MissingDebugInfo;
14error InvalidDebugInfo;14error InvalidDebugInfo;
15error UnsupportedDebugInfo;15error UnsupportedDebugInfo;
16error UnknownObjectFormat;
17error TodoSupportCoffDebugInfo;
18error TodoSupportMachoDebugInfo;
19error TodoSupportCOFFDebugInfo;
1620
1721
18/// Tries to write to stderr, unbuffered, and ignores any error returned.22/// Tries to write to stderr, unbuffered, and ignores any error returned.
...@@ -37,10 +41,43 @@ fn getStderrStream() -> %&io.OutStream {...@@ -37,10 +41,43 @@ fn getStderrStream() -> %&io.OutStream {
37 }41 }
38}42}
3943
44var self_debug_info: ?&ElfStackTrace = null;
45pub fn getSelfDebugInfo() -> %&ElfStackTrace {
46 if (self_debug_info) |info| {
47 return info;
48 } else {
49 const info = try openSelfDebugInfo(global_allocator);
50 self_debug_info = info;
51 return info;
52 }
53}
54
55/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
56pub fn dumpCurrentStackTrace() {
57 const stderr = getStderrStream() catch return;
58 const debug_info = getSelfDebugInfo() catch |err| {
59 stderr.print("Unable to open debug info: {}\n", @errorName(err)) catch return;
60 return;
61 };
62 defer debug_info.close();
63 writeCurrentStackTrace(stderr, global_allocator, debug_info, stderr_file.isTty(), 1) catch |err| {
64 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
65 return;
66 };
67}
68
40/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.69/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
41pub fn dumpStackTrace() {70pub fn dumpStackTrace(stack_trace: &const builtin.StackTrace) {
42 const stderr = getStderrStream() catch return;71 const stderr = getStderrStream() catch return;
43 writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) catch return;72 const debug_info = getSelfDebugInfo() catch |err| {
73 stderr.print("Unable to open debug info: {}\n", @errorName(err)) catch return;
74 return;
75 };
76 defer debug_info.close();
77 writeStackTrace(stack_trace, stderr, global_allocator, debug_info, stderr_file.isTty()) catch |err| {
78 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
79 return;
80 };
44}81}
4582
46/// This function invokes undefined behavior when `ok` is `false`.83/// This function invokes undefined behavior when `ok` is `false`.
...@@ -88,7 +125,21 @@ pub fn panic(comptime format: []const u8, args: ...) -> noreturn {...@@ -88,7 +125,21 @@ pub fn panic(comptime format: []const u8, args: ...) -> noreturn {
88125
89 const stderr = getStderrStream() catch os.abort();126 const stderr = getStderrStream() catch os.abort();
90 stderr.print(format ++ "\n", args) catch os.abort();127 stderr.print(format ++ "\n", args) catch os.abort();
91 writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) catch os.abort();128 dumpCurrentStackTrace();
129
130 os.abort();
131}
132
133pub fn panicWithTrace(trace: &const builtin.StackTrace, comptime format: []const u8, args: ...) -> noreturn {
134 if (panicking) {
135 os.abort();
136 } else {
137 panicking = true;
138 }
139 const stderr = getStderrStream() catch os.abort();
140 stderr.print(format ++ "\n", args) catch os.abort();
141 dumpStackTrace(trace);
142 dumpCurrentStackTrace();
92143
93 os.abort();144 os.abort();
94}145}
...@@ -101,12 +152,91 @@ const RESET = "\x1b[0m";...@@ -101,12 +152,91 @@ const RESET = "\x1b[0m";
101error PathNotFound;152error PathNotFound;
102error InvalidDebugInfo;153error InvalidDebugInfo;
103154
104pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty_color: bool,155pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.OutStream, allocator: &mem.Allocator,
105 ignore_frame_count: usize) -> %void156 debug_info: &ElfStackTrace, tty_color: bool) -> %void
106{157{
158 var frame_index: usize = undefined;
159 var frames_left: usize = undefined;
160 if (stack_trace.index < stack_trace.instruction_addresses.len) {
161 frame_index = 0;
162 frames_left = stack_trace.index;
163 } else {
164 frame_index = (stack_trace.index + 1) % stack_trace.instruction_addresses.len;
165 frames_left = stack_trace.instruction_addresses.len;
166 }
167
168 while (frames_left != 0) : ({
169 frames_left -= 1;
170 frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len;
171 }) {
172 const return_address = stack_trace.instruction_addresses[frame_index];
173 try printSourceAtAddress(debug_info, out_stream, return_address);
174 }
175}
176
177pub fn writeCurrentStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator,
178 debug_info: &ElfStackTrace, tty_color: bool, ignore_frame_count: usize) -> %void
179{
180 var ignored_count: usize = 0;
181
182 var fp = @ptrToInt(@frameAddress());
183 while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {
184 if (ignored_count < ignore_frame_count) {
185 ignored_count += 1;
186 continue;
187 }
188
189 const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));
190 try printSourceAtAddress(debug_info, out_stream, return_address);
191 }
192}
193
194fn printSourceAtAddress(debug_info: &ElfStackTrace, out_stream: &io.OutStream, address: usize) -> %void {
195 if (builtin.os == builtin.Os.windows) {
196 return error.UnsupportedDebugInfo;
197 }
198 // TODO we really should be able to convert @sizeOf(usize) * 2 to a string literal
199 // at compile time. I'll call it issue #313
200 const ptr_hex = if (@sizeOf(usize) == 4) "0x{x8}" else "0x{x16}";
201
202 const compile_unit = findCompileUnit(debug_info, address) catch {
203 try out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
204 address);
205 return;
206 };
207 const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
208 if (getLineNumberInfo(debug_info, compile_unit, address - 1)) |line_info| {
209 defer line_info.deinit();
210 try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++
211 DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n",
212 line_info.file_name, line_info.line, line_info.column,
213 address, compile_unit_name);
214 if (printLineFromFile(debug_info.allocator(), out_stream, line_info)) {
215 if (line_info.column == 0) {
216 try out_stream.write("\n");
217 } else {
218 {var col_i: usize = 1; while (col_i < line_info.column) : (col_i += 1) {
219 try out_stream.writeByte(' ');
220 }}
221 try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
222 }
223 } else |err| switch (err) {
224 error.EndOfFile, error.PathNotFound => {},
225 else => return err,
226 }
227 } else |err| switch (err) {
228 error.MissingDebugInfo, error.InvalidDebugInfo => {
229 try out_stream.print(ptr_hex ++ " in ??? ({})\n", address, compile_unit_name);
230 },
231 else => return err,
232 }
233}
234
235pub fn openSelfDebugInfo(allocator: &mem.Allocator) -> %&ElfStackTrace {
107 switch (builtin.object_format) {236 switch (builtin.object_format) {
108 builtin.ObjectFormat.elf => {237 builtin.ObjectFormat.elf => {
109 var stack_trace = ElfStackTrace {238 const st = try allocator.create(ElfStackTrace);
239 *st = ElfStackTrace {
110 .self_exe_file = undefined,240 .self_exe_file = undefined,
111 .elf = undefined,241 .elf = undefined,
112 .debug_info = undefined,242 .debug_info = undefined,
...@@ -117,12 +247,11 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty...@@ -117,12 +247,11 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
117 .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),247 .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
118 .compile_unit_list = ArrayList(CompileUnit).init(allocator),248 .compile_unit_list = ArrayList(CompileUnit).init(allocator),
119 };249 };
120 const st = &stack_trace;
121 st.self_exe_file = try os.openSelfExe();250 st.self_exe_file = try os.openSelfExe();
122 defer st.self_exe_file.close();251 %defer st.self_exe_file.close();
123252
124 try st.elf.openFile(allocator, &st.self_exe_file);253 try st.elf.openFile(allocator, &st.self_exe_file);
125 defer st.elf.close();254 %defer st.elf.close();
126255
127 st.debug_info = (try st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;256 st.debug_info = (try st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;
128 st.debug_abbrev = (try st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo;257 st.debug_abbrev = (try st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo;
...@@ -130,67 +259,19 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty...@@ -130,67 +259,19 @@ pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty
130 st.debug_line = (try st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo;259 st.debug_line = (try st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo;
131 st.debug_ranges = (try st.elf.findSection(".debug_ranges"));260 st.debug_ranges = (try st.elf.findSection(".debug_ranges"));
132 try scanAllCompileUnits(st);261 try scanAllCompileUnits(st);
133262 return st;
134 var ignored_count: usize = 0;
135
136 var fp = @ptrToInt(@frameAddress());
137 while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {
138 if (ignored_count < ignore_frame_count) {
139 ignored_count += 1;
140 continue;
141 }
142
143 const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));
144
145 // TODO we really should be able to convert @sizeOf(usize) * 2 to a string literal
146 // at compile time. I'll call it issue #313
147 const ptr_hex = if (@sizeOf(usize) == 4) "0x{x8}" else "0x{x16}";
148
149 const compile_unit = findCompileUnit(st, return_address) catch {
150 try out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
151 return_address);
152 continue;
153 };
154 const compile_unit_name = try compile_unit.die.getAttrString(st, DW.AT_name);
155 if (getLineNumberInfo(st, compile_unit, usize(return_address) - 1)) |line_info| {
156 defer line_info.deinit();
157 try out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++
158 DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n",
159 line_info.file_name, line_info.line, line_info.column,
160 return_address, compile_unit_name);
161 if (printLineFromFile(st.allocator(), out_stream, line_info)) {
162 if (line_info.column == 0) {
163 try out_stream.write("\n");
164 } else {
165 {var col_i: usize = 1; while (col_i < line_info.column) : (col_i += 1) {
166 try out_stream.writeByte(' ');
167 }}
168 try out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
169 }
170 } else |err| switch (err) {
171 error.EndOfFile, error.PathNotFound => {},
172 else => return err,
173 }
174 } else |err| switch (err) {
175 error.MissingDebugInfo, error.InvalidDebugInfo => {
176 try out_stream.print(ptr_hex ++ " in ??? ({})\n",
177 return_address, compile_unit_name);
178 },
179 else => return err,
180 }
181 }
182 },263 },
183 builtin.ObjectFormat.coff => {264 builtin.ObjectFormat.coff => {
184 try out_stream.write("(stack trace unavailable for COFF object format)\n");265 return error.TodoSupportCoffDebugInfo;
185 },266 },
186 builtin.ObjectFormat.macho => {267 builtin.ObjectFormat.macho => {
187 try out_stream.write("(stack trace unavailable for Mach-O object format)\n");268 return error.TodoSupportMachoDebugInfo;
188 },269 },
189 builtin.ObjectFormat.wasm => {270 builtin.ObjectFormat.wasm => {
190 try out_stream.write("(stack trace unavailable for WASM object format)\n");271 return error.TodoSupportCOFFDebugInfo;
191 },272 },
192 builtin.ObjectFormat.unknown => {273 builtin.ObjectFormat.unknown => {
193 try out_stream.write("(stack trace unavailable for unknown object format)\n");274 return error.UnknownObjectFormat;
194 },275 },
195 }276 }
196}277}
...@@ -228,7 +309,7 @@ fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_...@@ -228,7 +309,7 @@ fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_
228 }309 }
229}310}
230311
231const ElfStackTrace = struct {312pub const ElfStackTrace = struct {
232 self_exe_file: io.File,313 self_exe_file: io.File,
233 elf: elf.Elf,314 elf: elf.Elf,
234 debug_info: &elf.SectionHeader,315 debug_info: &elf.SectionHeader,
...@@ -248,6 +329,11 @@ const ElfStackTrace = struct {...@@ -248,6 +329,11 @@ const ElfStackTrace = struct {
248 const in_stream = &in_file_stream.stream;329 const in_stream = &in_file_stream.stream;
249 return readStringRaw(self.allocator(), in_stream);330 return readStringRaw(self.allocator(), in_stream);
250 }331 }
332
333 pub fn close(self: &ElfStackTrace) {
334 self.self_exe_file.close();
335 self.elf.close();
336 }
251};337};
252338
253const PcRange = struct {339const PcRange = struct {
std/index.zig+2
...@@ -10,6 +10,7 @@ pub const LinkedList = @import("linked_list.zig").LinkedList;...@@ -10,6 +10,7 @@ pub const LinkedList = @import("linked_list.zig").LinkedList;
10pub const base64 = @import("base64.zig");10pub const base64 = @import("base64.zig");
11pub const build = @import("build.zig");11pub const build = @import("build.zig");
12pub const c = @import("c/index.zig");12pub const c = @import("c/index.zig");
13pub const crypto = @import("crypto/index.zig");
13pub const cstr = @import("cstr.zig");14pub const cstr = @import("cstr.zig");
14pub const debug = @import("debug/index.zig");15pub const debug = @import("debug/index.zig");
15pub const dwarf = @import("dwarf.zig");16pub const dwarf = @import("dwarf.zig");
...@@ -39,6 +40,7 @@ test "std" {...@@ -39,6 +40,7 @@ test "std" {
39 _ = @import("base64.zig");40 _ = @import("base64.zig");
40 _ = @import("build.zig");41 _ = @import("build.zig");
41 _ = @import("c/index.zig");42 _ = @import("c/index.zig");
43 _ = @import("crypto/index.zig");
42 _ = @import("cstr.zig");44 _ = @import("cstr.zig");
43 _ = @import("debug/index.zig");45 _ = @import("debug/index.zig");
44 _ = @import("dwarf.zig");46 _ = @import("dwarf.zig");
std/io.zig+1-1
...@@ -224,7 +224,7 @@ pub const File = struct {...@@ -224,7 +224,7 @@ pub const File = struct {
224 };224 };
225 }225 }
226 },226 },
227 else => @compileError("unsupported OS"),227 else => @compileError("unsupported OS: " ++ @tagName(builtin.os)),
228 }228 }
229 }229 }
230230
std/io_test.zig-5
...@@ -8,11 +8,6 @@ const os = std.os;...@@ -8,11 +8,6 @@ const os = std.os;
8const builtin = @import("builtin");8const builtin = @import("builtin");
99
10test "write a file, read it, then delete it" {10test "write a file, read it, then delete it" {
11 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
12 // TODO get this test passing
13 // https://github.com/zig-lang/zig/issues/537
14 return;
15 }
16 var data: [1024]u8 = undefined;11 var data: [1024]u8 = undefined;
17 var rng = Rand.init(1234);12 var rng = Rand.init(1234);
18 rng.fillBytes(data[0..]);13 rng.fillBytes(data[0..]);
std/math/acosh.zig-5
...@@ -55,11 +55,6 @@ fn acosh64(x: f64) -> f64 {...@@ -55,11 +55,6 @@ fn acosh64(x: f64) -> f64 {
55}55}
5656
57test "math.acosh" {57test "math.acosh" {
58 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
59 // TODO get this test passing
60 // https://github.com/zig-lang/zig/issues/537
61 return;
62 }
63 assert(acosh(f32(1.5)) == acosh32(1.5));58 assert(acosh(f32(1.5)) == acosh32(1.5));
64 assert(acosh(f64(1.5)) == acosh64(1.5));59 assert(acosh(f64(1.5)) == acosh64(1.5));
65}60}
std/math/cos.zig-5
...@@ -146,11 +146,6 @@ test "math.cos" {...@@ -146,11 +146,6 @@ test "math.cos" {
146}146}
147147
148test "math.cos32" {148test "math.cos32" {
149 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
150 // TODO get this test passing
151 // https://github.com/zig-lang/zig/issues/537
152 return;
153 }
154 const epsilon = 0.000001;149 const epsilon = 0.000001;
155150
156 assert(math.approxEq(f32, cos32(0.0), 1.0, epsilon));151 assert(math.approxEq(f32, cos32(0.0), 1.0, epsilon));
std/math/cosh.zig-5
...@@ -81,11 +81,6 @@ fn cosh64(x: f64) -> f64 {...@@ -81,11 +81,6 @@ fn cosh64(x: f64) -> f64 {
81}81}
8282
83test "math.cosh" {83test "math.cosh" {
84 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
85 // TODO get this test passing
86 // https://github.com/zig-lang/zig/issues/537
87 return;
88 }
89 assert(cosh(f32(1.5)) == cosh32(1.5));84 assert(cosh(f32(1.5)) == cosh32(1.5));
90 assert(cosh(f64(1.5)) == cosh64(1.5));85 assert(cosh(f64(1.5)) == cosh64(1.5));
91}86}
std/math/index.zig+39-15
...@@ -267,6 +267,45 @@ test "math.shr" {...@@ -267,6 +267,45 @@ test "math.shr" {
267 assert(shr(u8, 0b11111111, isize(-2)) == 0b11111100);267 assert(shr(u8, 0b11111111, isize(-2)) == 0b11111100);
268}268}
269269
270/// Rotates right. Only unsigned values can be rotated.
271/// Negative shift values results in shift modulo the bit count.
272pub fn rotr(comptime T: type, x: T, r: var) -> T {
273 if (T.is_signed) {
274 @compileError("cannot rotate signed integer");
275 } else {
276 const ar = @mod(r, T.bit_count);
277 return shr(T, x, ar) | shl(T, x, T.bit_count - ar);
278 }
279}
280
281test "math.rotr" {
282 assert(rotr(u8, 0b00000001, usize(0)) == 0b00000001);
283 assert(rotr(u8, 0b00000001, usize(9)) == 0b10000000);
284 assert(rotr(u8, 0b00000001, usize(8)) == 0b00000001);
285 assert(rotr(u8, 0b00000001, usize(4)) == 0b00010000);
286 assert(rotr(u8, 0b00000001, isize(-1)) == 0b00000010);
287}
288
289/// Rotates left. Only unsigned values can be rotated.
290/// Negative shift values results in shift modulo the bit count.
291pub fn rotl(comptime T: type, x: T, r: var) -> T {
292 if (T.is_signed) {
293 @compileError("cannot rotate signed integer");
294 } else {
295 const ar = @mod(r, T.bit_count);
296 return shl(T, x, ar) | shr(T, x, T.bit_count - ar);
297 }
298}
299
300test "math.rotl" {
301 assert(rotl(u8, 0b00000001, usize(0)) == 0b00000001);
302 assert(rotl(u8, 0b00000001, usize(9)) == 0b00000010);
303 assert(rotl(u8, 0b00000001, usize(8)) == 0b00000001);
304 assert(rotl(u8, 0b00000001, usize(4)) == 0b00010000);
305 assert(rotl(u8, 0b00000001, isize(-1)) == 0b10000000);
306}
307
308
270pub fn Log2Int(comptime T: type) -> type {309pub fn Log2Int(comptime T: type) -> type {
271 return @IntType(false, log2(T.bit_count));310 return @IntType(false, log2(T.bit_count));
272}311}
...@@ -320,11 +359,6 @@ pub fn divTrunc(comptime T: type, numerator: T, denominator: T) -> %T {...@@ -320,11 +359,6 @@ pub fn divTrunc(comptime T: type, numerator: T, denominator: T) -> %T {
320}359}
321360
322test "math.divTrunc" {361test "math.divTrunc" {
323 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
324 // TODO get this test passing
325 // https://github.com/zig-lang/zig/issues/537
326 return;
327 }
328 testDivTrunc();362 testDivTrunc();
329 comptime testDivTrunc();363 comptime testDivTrunc();
330}364}
...@@ -350,11 +384,6 @@ pub fn divFloor(comptime T: type, numerator: T, denominator: T) -> %T {...@@ -350,11 +384,6 @@ pub fn divFloor(comptime T: type, numerator: T, denominator: T) -> %T {
350}384}
351385
352test "math.divFloor" {386test "math.divFloor" {
353 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
354 // TODO get this test passing
355 // https://github.com/zig-lang/zig/issues/537
356 return;
357 }
358 testDivFloor();387 testDivFloor();
359 comptime testDivFloor();388 comptime testDivFloor();
360}389}
...@@ -384,11 +413,6 @@ pub fn divExact(comptime T: type, numerator: T, denominator: T) -> %T {...@@ -384,11 +413,6 @@ pub fn divExact(comptime T: type, numerator: T, denominator: T) -> %T {
384}413}
385414
386test "math.divExact" {415test "math.divExact" {
387 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
388 // TODO get this test passing
389 // https://github.com/zig-lang/zig/issues/537
390 return;
391 }
392 testDivExact();416 testDivExact();
393 comptime testDivExact();417 comptime testDivExact();
394}418}
std/math/ln.zig-5
...@@ -147,11 +147,6 @@ pub fn ln_64(x_: f64) -> f64 {...@@ -147,11 +147,6 @@ pub fn ln_64(x_: f64) -> f64 {
147}147}
148148
149test "math.ln" {149test "math.ln" {
150 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
151 // TODO get this test passing
152 // https://github.com/zig-lang/zig/issues/537
153 return;
154 }
155 assert(ln(f32(0.2)) == ln_32(0.2));150 assert(ln(f32(0.2)) == ln_32(0.2));
156 assert(ln(f64(0.2)) == ln_64(0.2));151 assert(ln(f64(0.2)) == ln_64(0.2));
157}152}
std/math/log.zig-5
...@@ -56,11 +56,6 @@ test "math.log float" {...@@ -56,11 +56,6 @@ test "math.log float" {
56}56}
5757
58test "math.log float_special" {58test "math.log float_special" {
59 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
60 // TODO get this test passing
61 // https://github.com/zig-lang/zig/issues/537
62 return;
63 }
64 assert(log(f32, 2, 0.2301974) == math.log2(f32(0.2301974)));59 assert(log(f32, 2, 0.2301974) == math.log2(f32(0.2301974)));
65 assert(log(f32, 10, 0.2301974) == math.log10(f32(0.2301974)));60 assert(log(f32, 10, 0.2301974) == math.log10(f32(0.2301974)));
6661
std/math/log10.zig-5
...@@ -172,11 +172,6 @@ pub fn log10_64(x_: f64) -> f64 {...@@ -172,11 +172,6 @@ pub fn log10_64(x_: f64) -> f64 {
172}172}
173173
174test "math.log10" {174test "math.log10" {
175 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
176 // TODO get this test passing
177 // https://github.com/zig-lang/zig/issues/537
178 return;
179 }
180 assert(log10(f32(0.2)) == log10_32(0.2));175 assert(log10(f32(0.2)) == log10_32(0.2));
181 assert(log10(f64(0.2)) == log10_64(0.2));176 assert(log10(f64(0.2)) == log10_64(0.2));
182}177}
std/math/log2.zig-5
...@@ -170,11 +170,6 @@ pub fn log2_64(x_: f64) -> f64 {...@@ -170,11 +170,6 @@ pub fn log2_64(x_: f64) -> f64 {
170}170}
171171
172test "math.log2" {172test "math.log2" {
173 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
174 // TODO get this test passing
175 // https://github.com/zig-lang/zig/issues/537
176 return;
177 }
178 assert(log2(f32(0.2)) == log2_32(0.2));173 assert(log2(f32(0.2)) == log2_32(0.2));
179 assert(log2(f64(0.2)) == log2_64(0.2));174 assert(log2(f64(0.2)) == log2_64(0.2));
180}175}
std/math/pow.zig-6
...@@ -176,12 +176,6 @@ fn isOddInteger(x: f64) -> bool {...@@ -176,12 +176,6 @@ fn isOddInteger(x: f64) -> bool {
176}176}
177177
178test "math.pow" {178test "math.pow" {
179 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
180 // TODO get this test passing
181 // https://github.com/zig-lang/zig/issues/537
182 return;
183 }
184
185 const epsilon = 0.000001;179 const epsilon = 0.000001;
186180
187 assert(math.approxEq(f32, pow(f32, 0.0, 3.3), 0.0, epsilon));181 assert(math.approxEq(f32, pow(f32, 0.0, 3.3), 0.0, epsilon));
std/math/round.zig-5
...@@ -98,11 +98,6 @@ test "math.round" {...@@ -98,11 +98,6 @@ test "math.round" {
98}98}
9999
100test "math.round32" {100test "math.round32" {
101 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
102 // TODO get this test passing
103 // https://github.com/zig-lang/zig/issues/537
104 return;
105 }
106 assert(round32(1.3) == 1.0);101 assert(round32(1.3) == 1.0);
107 assert(round32(-1.3) == -1.0);102 assert(round32(-1.3) == -1.0);
108 assert(round32(0.2) == 0.0);103 assert(round32(0.2) == 0.0);
std/math/sin.zig-5
...@@ -150,11 +150,6 @@ test "math.sin" {...@@ -150,11 +150,6 @@ test "math.sin" {
150}150}
151151
152test "math.sin32" {152test "math.sin32" {
153 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
154 // TODO get this test passing
155 // https://github.com/zig-lang/zig/issues/537
156 return;
157 }
158 const epsilon = 0.000001;153 const epsilon = 0.000001;
159154
160 assert(math.approxEq(f32, sin32(0.0), 0.0, epsilon));155 assert(math.approxEq(f32, sin32(0.0), 0.0, epsilon));
std/math/sinh.zig-5
...@@ -88,11 +88,6 @@ fn sinh64(x: f64) -> f64 {...@@ -88,11 +88,6 @@ fn sinh64(x: f64) -> f64 {
88}88}
8989
90test "math.sinh" {90test "math.sinh" {
91 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
92 // TODO get this test passing
93 // https://github.com/zig-lang/zig/issues/537
94 return;
95 }
96 assert(sinh(f32(1.5)) == sinh32(1.5));91 assert(sinh(f32(1.5)) == sinh32(1.5));
97 assert(sinh(f64(1.5)) == sinh64(1.5));92 assert(sinh(f64(1.5)) == sinh64(1.5));
98}93}
std/math/tan.zig-5
...@@ -136,11 +136,6 @@ test "math.tan" {...@@ -136,11 +136,6 @@ test "math.tan" {
136}136}
137137
138test "math.tan32" {138test "math.tan32" {
139 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
140 // TODO get this test passing
141 // https://github.com/zig-lang/zig/issues/537
142 return;
143 }
144 const epsilon = 0.000001;139 const epsilon = 0.000001;
145140
146 assert(math.approxEq(f32, tan32(0.0), 0.0, epsilon));141 assert(math.approxEq(f32, tan32(0.0), 0.0, epsilon));
std/math/tanh.zig-5
...@@ -112,11 +112,6 @@ fn tanh64(x: f64) -> f64 {...@@ -112,11 +112,6 @@ fn tanh64(x: f64) -> f64 {
112}112}
113113
114test "math.tanh" {114test "math.tanh" {
115 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
116 // TODO get this test passing
117 // https://github.com/zig-lang/zig/issues/537
118 return;
119 }
120 assert(tanh(f32(1.5)) == tanh32(1.5));115 assert(tanh(f32(1.5)) == tanh32(1.5));
121 assert(tanh(f64(1.5)) == tanh64(1.5));116 assert(tanh(f64(1.5)) == tanh64(1.5));
122}117}
std/os/index.zig+2-9
...@@ -148,7 +148,7 @@ pub coldcc fn abort() -> noreturn {...@@ -148,7 +148,7 @@ pub coldcc fn abort() -> noreturn {
148}148}
149149
150/// Exits the program cleanly with the specified status code.150/// Exits the program cleanly with the specified status code.
151pub coldcc fn exit(status: i32) -> noreturn {151pub coldcc fn exit(status: u8) -> noreturn {
152 if (builtin.link_libc) {152 if (builtin.link_libc) {
153 c.exit(status);153 c.exit(status);
154 }154 }
...@@ -157,14 +157,7 @@ pub coldcc fn exit(status: i32) -> noreturn {...@@ -157,14 +157,7 @@ pub coldcc fn exit(status: i32) -> noreturn {
157 posix.exit(status);157 posix.exit(status);
158 },158 },
159 Os.windows => {159 Os.windows => {
160 // Map a possibly negative status code to a non-negative status for the systems default160 windows.ExitProcess(status);
161 // integer width.
162 const p_status = if (@sizeOf(c_uint) < @sizeOf(u32))
163 @truncate(c_uint, @bitCast(u32, status))
164 else
165 c_uint(@bitCast(u32, status));
166
167 windows.ExitProcess(p_status);
168 },161 },
169 else => @compileError("Unsupported OS"),162 else => @compileError("Unsupported OS"),
170 }163 }
std/rand.zig-20
...@@ -194,11 +194,6 @@ fn MersenneTwister(...@@ -194,11 +194,6 @@ fn MersenneTwister(
194}194}
195195
196test "rand float 32" {196test "rand float 32" {
197 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
198 // TODO get this test passing
199 // https://github.com/zig-lang/zig/issues/537
200 return;
201 }
202 var r = Rand.init(42);197 var r = Rand.init(42);
203 var i: usize = 0;198 var i: usize = 0;
204 while (i < 1000) : (i += 1) {199 while (i < 1000) : (i += 1) {
...@@ -209,11 +204,6 @@ test "rand float 32" {...@@ -209,11 +204,6 @@ test "rand float 32" {
209}204}
210205
211test "rand.MT19937_64" {206test "rand.MT19937_64" {
212 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
213 // TODO get this test passing
214 // https://github.com/zig-lang/zig/issues/537
215 return;
216 }
217 var rng = MT19937_64.init(rand_test.mt64_seed);207 var rng = MT19937_64.init(rand_test.mt64_seed);
218 for (rand_test.mt64_data) |value| {208 for (rand_test.mt64_data) |value| {
219 assert(value == rng.get());209 assert(value == rng.get());
...@@ -221,11 +211,6 @@ test "rand.MT19937_64" {...@@ -221,11 +211,6 @@ test "rand.MT19937_64" {
221}211}
222212
223test "rand.MT19937_32" {213test "rand.MT19937_32" {
224 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
225 // TODO get this test passing
226 // https://github.com/zig-lang/zig/issues/537
227 return;
228 }
229 var rng = MT19937_32.init(rand_test.mt32_seed);214 var rng = MT19937_32.init(rand_test.mt32_seed);
230 for (rand_test.mt32_data) |value| {215 for (rand_test.mt32_data) |value| {
231 assert(value == rng.get());216 assert(value == rng.get());
...@@ -233,11 +218,6 @@ test "rand.MT19937_32" {...@@ -233,11 +218,6 @@ test "rand.MT19937_32" {
233}218}
234219
235test "rand.Rand.range" {220test "rand.Rand.range" {
236 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
237 // TODO get this test passing
238 // https://github.com/zig-lang/zig/issues/537
239 return;
240 }
241 var r = Rand.init(42);221 var r = Rand.init(42);
242 testRange(&r, -4, 3);222 testRange(&r, -4, 3);
243 testRange(&r, -4, -1);223 testRange(&r, -4, -1);
std/sort.zig-20
...@@ -1020,11 +1020,6 @@ fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) -> bool {...@@ -1020,11 +1020,6 @@ fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) -> bool {
1020}1020}
10211021
1022test "std.sort" {1022test "std.sort" {
1023 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
1024 // TODO get this test passing
1025 // https://github.com/zig-lang/zig/issues/537
1026 return;
1027 }
1028 const u8cases = [][]const []const u8 {1023 const u8cases = [][]const []const u8 {
1029 [][]const u8{"", ""},1024 [][]const u8{"", ""},
1030 [][]const u8{"a", "a"},1025 [][]const u8{"a", "a"},
...@@ -1061,11 +1056,6 @@ test "std.sort" {...@@ -1061,11 +1056,6 @@ test "std.sort" {
1061}1056}
10621057
1063test "std.sort descending" {1058test "std.sort descending" {
1064 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
1065 // TODO get this test passing
1066 // https://github.com/zig-lang/zig/issues/537
1067 return;
1068 }
1069 const rev_cases = [][]const []const i32 {1059 const rev_cases = [][]const []const i32 {
1070 [][]const i32{[]i32{}, []i32{}},1060 [][]const i32{[]i32{}, []i32{}},
1071 [][]const i32{[]i32{1}, []i32{1}},1061 [][]const i32{[]i32{1}, []i32{1}},
...@@ -1085,11 +1075,6 @@ test "std.sort descending" {...@@ -1085,11 +1075,6 @@ test "std.sort descending" {
1085}1075}
10861076
1087test "another sort case" {1077test "another sort case" {
1088 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
1089 // TODO get this test passing
1090 // https://github.com/zig-lang/zig/issues/537
1091 return;
1092 }
1093 var arr = []i32{ 5, 3, 1, 2, 4 };1078 var arr = []i32{ 5, 3, 1, 2, 4 };
1094 sort(i32, arr[0..], i32asc);1079 sort(i32, arr[0..], i32asc);
10951080
...@@ -1097,11 +1082,6 @@ test "another sort case" {...@@ -1097,11 +1082,6 @@ test "another sort case" {
1097}1082}
10981083
1099test "sort fuzz testing" {1084test "sort fuzz testing" {
1100 if (builtin.os == builtin.Os.windows and builtin.arch == builtin.Arch.i386) {
1101 // TODO get this test passing
1102 // https://github.com/zig-lang/zig/issues/537
1103 return;
1104 }
1105 var rng = std.rand.Rand.init(0x12345678);1085 var rng = std.rand.Rand.init(0x12345678);
1106 const test_case_count = 10;1086 const test_case_count = 10;
1107 var i: usize = 0;1087 var i: usize = 0;
std/special/bootstrap.zig+35-10
...@@ -21,8 +21,7 @@ comptime {...@@ -21,8 +21,7 @@ comptime {
21}21}
2222
23extern fn zenMain() -> noreturn {23extern fn zenMain() -> noreturn {
24 root.main() catch std.os.posix.exit(1);24 std.os.posix.exit(callMain());
25 std.os.posix.exit(0);
26}25}
2726
28nakedcc fn _start() -> noreturn {27nakedcc fn _start() -> noreturn {
...@@ -43,29 +42,55 @@ nakedcc fn _start() -> noreturn {...@@ -43,29 +42,55 @@ nakedcc fn _start() -> noreturn {
43extern fn WinMainCRTStartup() -> noreturn {42extern fn WinMainCRTStartup() -> noreturn {
44 @setAlignStack(16);43 @setAlignStack(16);
4544
46 root.main() catch std.os.windows.ExitProcess(1);45 std.os.windows.ExitProcess(callMain());
47 std.os.windows.ExitProcess(0);
48}46}
4947
50fn posixCallMainAndExit() -> noreturn {48fn posixCallMainAndExit() -> noreturn {
51 const argc = *argc_ptr;49 const argc = *argc_ptr;
52 const argv = @ptrCast(&&u8, &argc_ptr[1]);50 const argv = @ptrCast(&&u8, &argc_ptr[1]);
53 const envp = @ptrCast(&?&u8, &argv[argc + 1]);51 const envp = @ptrCast(&?&u8, &argv[argc + 1]);
54 callMain(argc, argv, envp) catch std.os.posix.exit(1);52 std.os.posix.exit(callMainWithArgs(argc, argv, envp));
55 std.os.posix.exit(0);
56}53}
5754
58fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void {55fn callMainWithArgs(argc: usize, argv: &&u8, envp: &?&u8) -> u8 {
59 std.os.ArgIteratorPosix.raw = argv[0..argc];56 std.os.ArgIteratorPosix.raw = argv[0..argc];
6057
61 var env_count: usize = 0;58 var env_count: usize = 0;
62 while (envp[env_count] != null) : (env_count += 1) {}59 while (envp[env_count] != null) : (env_count += 1) {}
63 std.os.posix_environ_raw = @ptrCast(&&u8, envp)[0..env_count];60 std.os.posix_environ_raw = @ptrCast(&&u8, envp)[0..env_count];
6461
65 return root.main();62 return callMain();
66}63}
6764
68extern fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 {65extern fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 {
69 callMain(usize(c_argc), c_argv, c_envp) catch return 1;66 return callMainWithArgs(usize(c_argc), c_argv, c_envp);
70 return 0;67}
68
69fn callMain() -> u8 {
70 switch (@typeId(@typeOf(root.main).ReturnType)) {
71 builtin.TypeId.NoReturn => {
72 root.main();
73 },
74 builtin.TypeId.Void => {
75 root.main();
76 return 0;
77 },
78 builtin.TypeId.Int => {
79 if (@typeOf(root.main).ReturnType.bit_count != 8) {
80 @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '%void'");
81 }
82 return root.main();
83 },
84 builtin.TypeId.ErrorUnion => {
85 root.main() catch |err| {
86 std.debug.warn("error: {}\n", @errorName(err));
87 if (@errorReturnTrace()) |trace| {
88 std.debug.dumpStackTrace(trace);
89 }
90 return 1;
91 };
92 return 0;
93 },
94 else => @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '%void'"),
95 }
71}96}
std/special/build_runner.zig+4-4
...@@ -14,7 +14,7 @@ pub fn main() -> %void {...@@ -14,7 +14,7 @@ pub fn main() -> %void {
14 var arg_it = os.args();14 var arg_it = os.args();
1515
16 // TODO use a more general purpose allocator here16 // TODO use a more general purpose allocator here
17 var inc_allocator = std.heap.IncrementingAllocator.init(40 * 1024 * 1024) catch unreachable;17 var inc_allocator = try std.heap.IncrementingAllocator.init(40 * 1024 * 1024);
18 defer inc_allocator.deinit();18 defer inc_allocator.deinit();
1919
20 const allocator = &inc_allocator.allocator;20 const allocator = &inc_allocator.allocator;
...@@ -107,12 +107,12 @@ pub fn main() -> %void {...@@ -107,12 +107,12 @@ pub fn main() -> %void {
107 return usageAndErr(&builder, false, try stderr_stream);107 return usageAndErr(&builder, false, try stderr_stream);
108 }108 }
109 } else {109 } else {
110 targets.append(arg) catch unreachable;110 try targets.append(arg);
111 }111 }
112 }112 }
113113
114 builder.setInstallPrefix(prefix);114 builder.setInstallPrefix(prefix);
115 root.build(&builder);115 try root.build(&builder);
116116
117 if (builder.validateUserInputDidItFail())117 if (builder.validateUserInputDidItFail())
118 return usageAndErr(&builder, true, try stderr_stream);118 return usageAndErr(&builder, true, try stderr_stream);
...@@ -129,7 +129,7 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)...@@ -129,7 +129,7 @@ fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream)
129 // run the build script to collect the options129 // run the build script to collect the options
130 if (!already_ran_build) {130 if (!already_ran_build) {
131 builder.setInstallPrefix(null);131 builder.setInstallPrefix(null);
132 root.build(builder);132 try root.build(builder);
133 }133 }
134134
135 // This usage text has to be synchronized with src/main.cpp135 // This usage text has to be synchronized with src/main.cpp
std/special/builtin.zig+1-1
...@@ -5,7 +5,7 @@ const builtin = @import("builtin");...@@ -5,7 +5,7 @@ const builtin = @import("builtin");
55
6// Avoid dragging in the debug safety mechanisms into this .o file,6// Avoid dragging in the debug safety mechanisms into this .o file,
7// unless we're trying to test this file.7// unless we're trying to test this file.
8pub coldcc fn panic(msg: []const u8) -> noreturn {8pub coldcc fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) -> noreturn {
9 if (builtin.is_test) {9 if (builtin.is_test) {
10 @import("std").debug.panic("{}", msg);10 @import("std").debug.panic("{}", msg);
11 } else {11 } else {
std/special/compiler_rt/index.zig+1-1
...@@ -74,7 +74,7 @@ const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;...@@ -74,7 +74,7 @@ const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
7474
75// Avoid dragging in the debug safety mechanisms into this .o file,75// Avoid dragging in the debug safety mechanisms into this .o file,
76// unless we're trying to test this file.76// unless we're trying to test this file.
77pub coldcc fn panic(msg: []const u8) -> noreturn {77pub coldcc fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) -> noreturn {
78 if (is_test) {78 if (is_test) {
79 @import("std").debug.panic("{}", msg);79 @import("std").debug.panic("{}", msg);
80 } else {80 } else {
std/special/panic.zig+5-1
...@@ -4,14 +4,18 @@...@@ -4,14 +4,18 @@
4// have to be added in the compiler.4// have to be added in the compiler.
55
6const builtin = @import("builtin");6const builtin = @import("builtin");
7const std = @import("std");
78
8pub coldcc fn panic(msg: []const u8) -> noreturn {9pub coldcc fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) -> noreturn {
9 switch (builtin.os) {10 switch (builtin.os) {
10 // TODO: fix panic in zen.11 // TODO: fix panic in zen.
11 builtin.Os.freestanding, builtin.Os.zen => {12 builtin.Os.freestanding, builtin.Os.zen => {
12 while (true) {}13 while (true) {}
13 },14 },
14 else => {15 else => {
16 if (error_return_trace) |trace| {
17 @import("std").debug.panicWithTrace(trace, "{}", msg);
18 }
15 @import("std").debug.panic("{}", msg);19 @import("std").debug.panic("{}", msg);
16 },20 },
17 }21 }
std/special/test_runner.zig+1-4
...@@ -8,10 +8,7 @@ pub fn main() -> %void {...@@ -8,10 +8,7 @@ pub fn main() -> %void {
8 for (test_fn_list) |test_fn, i| {8 for (test_fn_list) |test_fn, i| {
9 warn("Test {}/{} {}...", i + 1, test_fn_list.len, test_fn.name);9 warn("Test {}/{} {}...", i + 1, test_fn_list.len, test_fn.name);
1010
11 test_fn.func() catch |err| {11 try test_fn.func();
12 warn("{}\n", err);
13 return err;
14 };
1512
16 warn("OK\n");13 warn("OK\n");
17 }14 }
test/build_examples.zig+1
...@@ -16,4 +16,5 @@ pub fn addCases(cases: &tests.BuildExamplesContext) {...@@ -16,4 +16,5 @@ pub fn addCases(cases: &tests.BuildExamplesContext) {
16 cases.addBuildFile("test/standalone/issue_339/build.zig");16 cases.addBuildFile("test/standalone/issue_339/build.zig");
17 cases.addBuildFile("test/standalone/pkg_import/build.zig");17 cases.addBuildFile("test/standalone/pkg_import/build.zig");
18 cases.addBuildFile("test/standalone/use_alias/build.zig");18 cases.addBuildFile("test/standalone/use_alias/build.zig");
19 cases.addBuildFile("test/standalone/brace_expansion/build.zig");
19}20}
test/cases/math.zig+23
...@@ -26,6 +26,29 @@ fn testDivision() {...@@ -26,6 +26,29 @@ fn testDivision() {
26 assert(divTrunc(i32, -5, 3) == -1);26 assert(divTrunc(i32, -5, 3) == -1);
27 assert(divTrunc(f32, 5.0, 3.0) == 1.0);27 assert(divTrunc(f32, 5.0, 3.0) == 1.0);
28 assert(divTrunc(f32, -5.0, 3.0) == -1.0);28 assert(divTrunc(f32, -5.0, 3.0) == -1.0);
29
30 comptime {
31 assert(
32 1194735857077236777412821811143690633098347576 %
33 508740759824825164163191790951174292733114988 ==
34 177254337427586449086438229241342047632117600);
35 assert(@rem(-1194735857077236777412821811143690633098347576,
36 508740759824825164163191790951174292733114988) ==
37 -177254337427586449086438229241342047632117600);
38 assert(1194735857077236777412821811143690633098347576 /
39 508740759824825164163191790951174292733114988 ==
40 2);
41 assert(@divTrunc(-1194735857077236777412821811143690633098347576,
42 508740759824825164163191790951174292733114988) ==
43 -2);
44 assert(@divTrunc(1194735857077236777412821811143690633098347576,
45 -508740759824825164163191790951174292733114988) ==
46 -2);
47 assert(@divTrunc(-1194735857077236777412821811143690633098347576,
48 -508740759824825164163191790951174292733114988) ==
49 2);
50 assert(4126227191251978491697987544882340798050766755606969681711 % 10 == 1);
51 }
29}52}
30fn div(comptime T: type, a: T, b: T) -> T {53fn div(comptime T: type, a: T, b: T) -> T {
31 return a / b;54 return a / b;
test/compile_errors.zig+9-9
...@@ -1,6 +1,15 @@...@@ -1,6 +1,15 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: &tests.CompileErrorContext) {3pub fn addCases(cases: &tests.CompileErrorContext) {
4 cases.add("wrong return type for main",
5 \\pub fn main() -> f32 { }
6 , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '%void'");
7
8 cases.add("double ?? on main return value",
9 \\pub fn main() -> ??void {
10 \\}
11 , "error: expected return type of main to be 'u8', 'noreturn', 'void', or '%void'");
12
4 cases.add("bad identifier in function with struct defined inside function which references local const",13 cases.add("bad identifier in function with struct defined inside function which references local const",
5 \\export fn entry() {14 \\export fn entry() {
6 \\ const BlockKind = u32;15 \\ const BlockKind = u32;
...@@ -1059,15 +1068,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -1059,15 +1068,6 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
1059 ,1068 ,
1060 ".tmp_source.zig:2:5: error: expected type 'void', found 'error'");1069 ".tmp_source.zig:2:5: error: expected type 'void', found 'error'");
10611070
1062 cases.add("wrong return type for main",
1063 \\pub fn main() { }
1064 , ".tmp_source.zig:1:15: error: expected return type of main to be '%void', instead is 'void'");
1065
1066 cases.add("double ?? on main return value",
1067 \\pub fn main() -> ??void {
1068 \\}
1069 , ".tmp_source.zig:1:18: error: expected return type of main to be '%void', instead is '??void'");
1070
1071 cases.add("invalid pointer for var type",1071 cases.add("invalid pointer for var type",
1072 \\extern fn ext() -> usize;1072 \\extern fn ext() -> usize;
1073 \\var bytes: [ext()]u8 = undefined;1073 \\var bytes: [ext()]u8 = undefined;
test/debug_safety.zig+20-20
...@@ -2,7 +2,7 @@ const tests = @import("tests.zig");...@@ -2,7 +2,7 @@ const tests = @import("tests.zig");
22
3pub fn addCases(cases: &tests.CompareOutputContext) {3pub fn addCases(cases: &tests.CompareOutputContext) {
4 cases.addDebugSafety("calling panic",4 cases.addDebugSafety("calling panic",
5 \\pub fn panic(message: []const u8) -> noreturn {5 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
6 \\ @import("std").os.exit(126);6 \\ @import("std").os.exit(126);
7 \\}7 \\}
8 \\pub fn main() -> %void {8 \\pub fn main() -> %void {
...@@ -11,7 +11,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -11,7 +11,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
11 );11 );
1212
13 cases.addDebugSafety("out of bounds slice access",13 cases.addDebugSafety("out of bounds slice access",
14 \\pub fn panic(message: []const u8) -> noreturn {14 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
15 \\ @import("std").os.exit(126);15 \\ @import("std").os.exit(126);
16 \\}16 \\}
17 \\pub fn main() -> %void {17 \\pub fn main() -> %void {
...@@ -25,7 +25,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -25,7 +25,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
25 );25 );
2626
27 cases.addDebugSafety("integer addition overflow",27 cases.addDebugSafety("integer addition overflow",
28 \\pub fn panic(message: []const u8) -> noreturn {28 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
29 \\ @import("std").os.exit(126);29 \\ @import("std").os.exit(126);
30 \\}30 \\}
31 \\error Whatever;31 \\error Whatever;
...@@ -39,7 +39,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -39,7 +39,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
39 );39 );
4040
41 cases.addDebugSafety("integer subtraction overflow",41 cases.addDebugSafety("integer subtraction overflow",
42 \\pub fn panic(message: []const u8) -> noreturn {42 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
43 \\ @import("std").os.exit(126);43 \\ @import("std").os.exit(126);
44 \\}44 \\}
45 \\error Whatever;45 \\error Whatever;
...@@ -53,7 +53,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -53,7 +53,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
53 );53 );
5454
55 cases.addDebugSafety("integer multiplication overflow",55 cases.addDebugSafety("integer multiplication overflow",
56 \\pub fn panic(message: []const u8) -> noreturn {56 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
57 \\ @import("std").os.exit(126);57 \\ @import("std").os.exit(126);
58 \\}58 \\}
59 \\error Whatever;59 \\error Whatever;
...@@ -67,7 +67,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -67,7 +67,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
67 );67 );
6868
69 cases.addDebugSafety("integer negation overflow",69 cases.addDebugSafety("integer negation overflow",
70 \\pub fn panic(message: []const u8) -> noreturn {70 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
71 \\ @import("std").os.exit(126);71 \\ @import("std").os.exit(126);
72 \\}72 \\}
73 \\error Whatever;73 \\error Whatever;
...@@ -81,7 +81,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -81,7 +81,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
81 );81 );
8282
83 cases.addDebugSafety("signed integer division overflow",83 cases.addDebugSafety("signed integer division overflow",
84 \\pub fn panic(message: []const u8) -> noreturn {84 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
85 \\ @import("std").os.exit(126);85 \\ @import("std").os.exit(126);
86 \\}86 \\}
87 \\error Whatever;87 \\error Whatever;
...@@ -95,7 +95,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -95,7 +95,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
95 );95 );
9696
97 cases.addDebugSafety("signed shift left overflow",97 cases.addDebugSafety("signed shift left overflow",
98 \\pub fn panic(message: []const u8) -> noreturn {98 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
99 \\ @import("std").os.exit(126);99 \\ @import("std").os.exit(126);
100 \\}100 \\}
101 \\error Whatever;101 \\error Whatever;
...@@ -109,7 +109,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -109,7 +109,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
109 );109 );
110110
111 cases.addDebugSafety("unsigned shift left overflow",111 cases.addDebugSafety("unsigned shift left overflow",
112 \\pub fn panic(message: []const u8) -> noreturn {112 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
113 \\ @import("std").os.exit(126);113 \\ @import("std").os.exit(126);
114 \\}114 \\}
115 \\error Whatever;115 \\error Whatever;
...@@ -123,7 +123,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -123,7 +123,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
123 );123 );
124124
125 cases.addDebugSafety("signed shift right overflow",125 cases.addDebugSafety("signed shift right overflow",
126 \\pub fn panic(message: []const u8) -> noreturn {126 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
127 \\ @import("std").os.exit(126);127 \\ @import("std").os.exit(126);
128 \\}128 \\}
129 \\error Whatever;129 \\error Whatever;
...@@ -137,7 +137,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -137,7 +137,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
137 );137 );
138138
139 cases.addDebugSafety("unsigned shift right overflow",139 cases.addDebugSafety("unsigned shift right overflow",
140 \\pub fn panic(message: []const u8) -> noreturn {140 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
141 \\ @import("std").os.exit(126);141 \\ @import("std").os.exit(126);
142 \\}142 \\}
143 \\error Whatever;143 \\error Whatever;
...@@ -151,7 +151,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -151,7 +151,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
151 );151 );
152152
153 cases.addDebugSafety("integer division by zero",153 cases.addDebugSafety("integer division by zero",
154 \\pub fn panic(message: []const u8) -> noreturn {154 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
155 \\ @import("std").os.exit(126);155 \\ @import("std").os.exit(126);
156 \\}156 \\}
157 \\error Whatever;157 \\error Whatever;
...@@ -164,7 +164,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -164,7 +164,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
164 );164 );
165165
166 cases.addDebugSafety("exact division failure",166 cases.addDebugSafety("exact division failure",
167 \\pub fn panic(message: []const u8) -> noreturn {167 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
168 \\ @import("std").os.exit(126);168 \\ @import("std").os.exit(126);
169 \\}169 \\}
170 \\error Whatever;170 \\error Whatever;
...@@ -178,7 +178,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -178,7 +178,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
178 );178 );
179179
180 cases.addDebugSafety("cast []u8 to bigger slice of wrong size",180 cases.addDebugSafety("cast []u8 to bigger slice of wrong size",
181 \\pub fn panic(message: []const u8) -> noreturn {181 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
182 \\ @import("std").os.exit(126);182 \\ @import("std").os.exit(126);
183 \\}183 \\}
184 \\error Whatever;184 \\error Whatever;
...@@ -192,7 +192,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -192,7 +192,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
192 );192 );
193193
194 cases.addDebugSafety("value does not fit in shortening cast",194 cases.addDebugSafety("value does not fit in shortening cast",
195 \\pub fn panic(message: []const u8) -> noreturn {195 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
196 \\ @import("std").os.exit(126);196 \\ @import("std").os.exit(126);
197 \\}197 \\}
198 \\error Whatever;198 \\error Whatever;
...@@ -206,7 +206,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -206,7 +206,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
206 );206 );
207207
208 cases.addDebugSafety("signed integer not fitting in cast to unsigned integer",208 cases.addDebugSafety("signed integer not fitting in cast to unsigned integer",
209 \\pub fn panic(message: []const u8) -> noreturn {209 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
210 \\ @import("std").os.exit(126);210 \\ @import("std").os.exit(126);
211 \\}211 \\}
212 \\error Whatever;212 \\error Whatever;
...@@ -220,7 +220,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -220,7 +220,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
220 );220 );
221221
222 cases.addDebugSafety("unwrap error",222 cases.addDebugSafety("unwrap error",
223 \\pub fn panic(message: []const u8) -> noreturn {223 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
224 \\ if (@import("std").mem.eql(u8, message, "attempt to unwrap error: Whatever")) {224 \\ if (@import("std").mem.eql(u8, message, "attempt to unwrap error: Whatever")) {
225 \\ @import("std").os.exit(126); // good225 \\ @import("std").os.exit(126); // good
226 \\ }226 \\ }
...@@ -236,7 +236,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -236,7 +236,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
236 );236 );
237237
238 cases.addDebugSafety("cast integer to error and no code matches",238 cases.addDebugSafety("cast integer to error and no code matches",
239 \\pub fn panic(message: []const u8) -> noreturn {239 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
240 \\ @import("std").os.exit(126);240 \\ @import("std").os.exit(126);
241 \\}241 \\}
242 \\pub fn main() -> %void {242 \\pub fn main() -> %void {
...@@ -248,7 +248,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -248,7 +248,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
248 );248 );
249249
250 cases.addDebugSafety("@alignCast misaligned",250 cases.addDebugSafety("@alignCast misaligned",
251 \\pub fn panic(message: []const u8) -> noreturn {251 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
252 \\ @import("std").os.exit(126);252 \\ @import("std").os.exit(126);
253 \\}253 \\}
254 \\error Wrong;254 \\error Wrong;
...@@ -265,7 +265,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {...@@ -265,7 +265,7 @@ pub fn addCases(cases: &tests.CompareOutputContext) {
265 );265 );
266266
267 cases.addDebugSafety("bad union field access",267 cases.addDebugSafety("bad union field access",
268 \\pub fn panic(message: []const u8) -> noreturn {268 \\pub fn panic(message: []const u8, stack_trace: ?&@import("builtin").StackTrace) -> noreturn {
269 \\ @import("std").os.exit(126);269 \\ @import("std").os.exit(126);
270 \\}270 \\}
271 \\271 \\
test/standalone/brace_expansion/build.zig created+9
...@@ -0,0 +1,9 @@
1const Builder = @import("std").build.Builder;
2
3pub fn build(b: &Builder) -> %void {
4 const main = b.addTest("main.zig");
5 main.setBuildMode(b.standardReleaseOptions());
6
7 const test_step = b.step("test", "Test it");
8 test_step.dependOn(&main.step);
9}
test/standalone/brace_expansion/main.zig created+254
...@@ -0,0 +1,254 @@
1const std = @import("std");
2const io = std.io;
3const mem = std.mem;
4const debug = std.debug;
5const assert = debug.assert;
6const Buffer = std.Buffer;
7const ArrayList = std.ArrayList;
8
9error InvalidInput;
10error OutOfMem;
11
12const Token = union(enum) {
13 Word: []const u8,
14 OpenBrace,
15 CloseBrace,
16 Comma,
17 Eof,
18};
19
20var global_allocator: &mem.Allocator = undefined;
21
22fn tokenize(input:[] const u8) -> %ArrayList(Token) {
23 const State = enum {
24 Start,
25 Word,
26 };
27
28 var token_list = ArrayList(Token).init(global_allocator);
29 var tok_begin: usize = undefined;
30 var state = State.Start;
31
32 for (input) |b, i| {
33 switch (state) {
34 State.Start => switch (b) {
35 'a'...'z', 'A'...'Z' => {
36 state = State.Word;
37 tok_begin = i;
38 },
39 '{' => try token_list.append(Token.OpenBrace),
40 '}' => try token_list.append(Token.CloseBrace),
41 ',' => try token_list.append(Token.Comma),
42 else => return error.InvalidInput,
43 },
44 State.Word => switch (b) {
45 'a'...'z', 'A'...'Z' => {},
46 '{', '}', ',' => {
47 try token_list.append(Token { .Word = input[tok_begin..i] });
48 switch (b) {
49 '{' => try token_list.append(Token.OpenBrace),
50 '}' => try token_list.append(Token.CloseBrace),
51 ',' => try token_list.append(Token.Comma),
52 else => unreachable,
53 }
54 state = State.Start;
55 },
56 else => return error.InvalidInput,
57 },
58 }
59 }
60 switch (state) {
61 State.Start => {},
62 State.Word => try token_list.append(Token {.Word = input[tok_begin..] }),
63 }
64 try token_list.append(Token.Eof);
65 return token_list;
66}
67
68const Node = union(enum) {
69 Scalar: []const u8,
70 List: ArrayList(Node),
71 Combine: []Node,
72};
73
74fn parse(tokens: &const ArrayList(Token), token_index: &usize) -> %Node {
75 const first_token = tokens.items[*token_index];
76 *token_index += 1;
77
78 const result_node = switch (first_token) {
79 Token.Word => |word| Node { .Scalar = word },
80 Token.OpenBrace => blk: {
81 var list = ArrayList(Node).init(global_allocator);
82 while (true) {
83 try list.append(try parse(tokens, token_index));
84
85 const token = tokens.items[*token_index];
86 *token_index += 1;
87
88 switch (token) {
89 Token.CloseBrace => break,
90 Token.Comma => continue,
91 else => return error.InvalidInput,
92 }
93 }
94 break :blk Node { .List = list };
95 },
96 else => return error.InvalidInput,
97 };
98
99 switch (tokens.items[*token_index]) {
100 Token.Word, Token.OpenBrace => {
101 const pair = try global_allocator.alloc(Node, 2);
102 pair[0] = result_node;
103 pair[1] = try parse(tokens, token_index);
104 return Node { .Combine = pair };
105 },
106 else => return result_node,
107 }
108}
109
110fn expandString(input: []const u8, output: &Buffer) -> %void {
111 const tokens = try tokenize(input);
112 if (tokens.len == 1) {
113 return output.resize(0);
114 }
115
116 var token_index: usize = 0;
117 const root = try parse(tokens, &token_index);
118 const last_token = tokens.items[token_index];
119 switch (last_token) {
120 Token.Eof => {},
121 else => return error.InvalidInput,
122 }
123
124 var result_list = ArrayList(Buffer).init(global_allocator);
125 defer result_list.deinit();
126
127 try expandNode(root, &result_list);
128
129 try output.resize(0);
130 for (result_list.toSliceConst()) |buf, i| {
131 if (i != 0) {
132 try output.appendByte(' ');
133 }
134 try output.append(buf.toSliceConst());
135 }
136}
137
138const ListOfBuffer0 = ArrayList(Buffer); // TODO this is working around a compiler bug, fix and delete this
139
140fn expandNode(node: &const Node, output: &ListOfBuffer0) -> %void {
141 assert(output.len == 0);
142 switch (*node) {
143 Node.Scalar => |scalar| {
144 try output.append(try Buffer.init(global_allocator, scalar));
145 },
146 Node.Combine => |pair| {
147 const a_node = pair[0];
148 const b_node = pair[1];
149
150 var child_list_a = ArrayList(Buffer).init(global_allocator);
151 try expandNode(a_node, &child_list_a);
152
153 var child_list_b = ArrayList(Buffer).init(global_allocator);
154 try expandNode(b_node, &child_list_b);
155
156 for (child_list_a.toSliceConst()) |buf_a| {
157 for (child_list_b.toSliceConst()) |buf_b| {
158 var combined_buf = try Buffer.initFromBuffer(buf_a);
159 try combined_buf.append(buf_b.toSliceConst());
160 try output.append(combined_buf);
161 }
162 }
163 },
164 Node.List => |list| {
165 for (list.toSliceConst()) |child_node| {
166 var child_list = ArrayList(Buffer).init(global_allocator);
167 try expandNode(child_node, &child_list);
168
169 for (child_list.toSliceConst()) |buf| {
170 try output.append(buf);
171 }
172 }
173 },
174 }
175}
176
177pub fn main() -> %void {
178 var stdin_file = try io.getStdIn();
179 var stdout_file = try io.getStdOut();
180
181 var inc_allocator = try std.heap.IncrementingAllocator.init(2 * 1024 * 1024);
182 defer inc_allocator.deinit();
183
184 global_allocator = &inc_allocator.allocator;
185
186 var stdin_buf = try Buffer.initSize(global_allocator, 0);
187 defer stdin_buf.deinit();
188
189 var stdin_adapter = io.FileInStream.init(&stdin_file);
190 try stdin_adapter.stream.readAllBuffer(&stdin_buf, @maxValue(usize));
191
192 var result_buf = try Buffer.initSize(global_allocator, 0);
193 defer result_buf.deinit();
194
195 try expandString(stdin_buf.toSlice(), &result_buf);
196 try stdout_file.write(result_buf.toSliceConst());
197}
198
199test "invalid inputs" {
200 global_allocator = std.debug.global_allocator;
201
202 expectError("}ABC", error.InvalidInput);
203 expectError("{ABC", error.InvalidInput);
204 expectError("}{", error.InvalidInput);
205 expectError("{}", error.InvalidInput);
206 expectError("A,B,C", error.InvalidInput);
207 expectError("{A{B,C}", error.InvalidInput);
208 expectError("{A,}", error.InvalidInput);
209
210 expectError("\n", error.InvalidInput);
211}
212
213fn expectError(test_input: []const u8, expected_err: error) {
214 var output_buf = Buffer.initSize(global_allocator, 0) catch unreachable;
215 defer output_buf.deinit();
216
217 if (expandString("}ABC", &output_buf)) {
218 unreachable;
219 } else |err| {
220 assert(expected_err == err);
221 }
222}
223
224test "valid inputs" {
225 global_allocator = std.debug.global_allocator;
226
227 expectExpansion("{x,y,z}", "x y z");
228 expectExpansion("{A,B}{x,y}", "Ax Ay Bx By");
229 expectExpansion("{A,B{x,y}}", "A Bx By");
230
231 expectExpansion("{ABC}", "ABC");
232 expectExpansion("{A,B,C}", "A B C");
233 expectExpansion("ABC", "ABC");
234
235 expectExpansion("", "");
236 expectExpansion("{A,B}{C,{x,y}}{g,h}", "ACg ACh Axg Axh Ayg Ayh BCg BCh Bxg Bxh Byg Byh");
237 expectExpansion("{A,B}{C,C{x,y}}{g,h}", "ACg ACh ACxg ACxh ACyg ACyh BCg BCh BCxg BCxh BCyg BCyh");
238 expectExpansion("{A,B}a", "Aa Ba");
239 expectExpansion("{C,{x,y}}", "C x y");
240 expectExpansion("z{C,{x,y}}", "zC zx zy");
241 expectExpansion("a{b,c{d,e{f,g}}}", "ab acd acef aceg");
242 expectExpansion("a{x,y}b", "axb ayb");
243 expectExpansion("z{{a,b}}", "za zb");
244 expectExpansion("a{b}", "ab");
245}
246
247fn expectExpansion(test_input: []const u8, expected_result: []const u8) {
248 var result = Buffer.initSize(global_allocator, 0) catch unreachable;
249 defer result.deinit();
250
251 expandString(test_input, &result) catch unreachable;
252
253 assert(mem.eql(u8, result.toSlice(), expected_result));
254}
test/standalone/issue_339/build.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const Builder = @import("std").build.Builder;1const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) {3pub fn build(b: &Builder) -> %void {
4 const obj = b.addObject("test", "test.zig");4 const obj = b.addObject("test", "test.zig");
55
6 const test_step = b.step("test", "Test the program");6 const test_step = b.step("test", "Test the program");
test/standalone/issue_339/test.zig+2-1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1pub fn panic(msg: []const u8) -> noreturn { @breakpoint(); while (true) {} }1const StackTrace = @import("builtin").StackTrace;
2pub fn panic(msg: []const u8, stack_trace: ?&StackTrace) -> noreturn { @breakpoint(); while (true) {} }
23
3fn bar() -> %void {}4fn bar() -> %void {}
45
test/standalone/pkg_import/build.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const Builder = @import("std").build.Builder;1const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) {3pub fn build(b: &Builder) -> %void {
4 const exe = b.addExecutable("test", "test.zig");4 const exe = b.addExecutable("test", "test.zig");
5 exe.addPackagePath("my_pkg", "pkg.zig");5 exe.addPackagePath("my_pkg", "pkg.zig");
66
test/standalone/use_alias/build.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const Builder = @import("std").build.Builder;1const Builder = @import("std").build.Builder;
22
3pub fn build(b: &Builder) {3pub fn build(b: &Builder) -> %void {
4 b.addCIncludePath(".");4 b.addCIncludePath(".");
55
6 const main = b.addTest("main.zig");6 const main = b.addTest("main.zig");
test/tests.zig+2-7
...@@ -42,14 +42,10 @@ const test_targets = []TestTarget {...@@ -42,14 +42,10 @@ const test_targets = []TestTarget {
42 .arch = builtin.Arch.x86_64,42 .arch = builtin.Arch.x86_64,
43 .environ = builtin.Environ.msvc,43 .environ = builtin.Environ.msvc,
44 },44 },
45 TestTarget {
46 .os = builtin.Os.windows,
47 .arch = builtin.Arch.i386,
48 .environ = builtin.Environ.msvc,
49 },
50};45};
5146
52error TestFailed;47error TestFailed;
48error CompilationIncorrectlySucceeded;
5349
54const max_stdout_size = 1 * 1024 * 1024; // 1 MB50const max_stdout_size = 1 * 1024 * 1024; // 1 MB
5551
...@@ -607,8 +603,7 @@ pub const CompileErrorContext = struct {...@@ -607,8 +603,7 @@ pub const CompileErrorContext = struct {
607 switch (term) {603 switch (term) {
608 Term.Exited => |code| {604 Term.Exited => |code| {
609 if (code == 0) {605 if (code == 0) {
610 warn("Compilation incorrectly succeeded\n");606 return error.CompilationIncorrectlySucceeded;
611 return error.TestFailed;
612 }607 }
613 },608 },
614 else => {609 else => {
test/translate_c.zig+26-5
...@@ -408,7 +408,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {...@@ -408,7 +408,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
408 \\}408 \\}
409 ,409 ,
410 \\pub export fn s(a: c_int, b: c_int) -> c_int {410 \\pub export fn s(a: c_int, b: c_int) -> c_int {
411 \\ var c: c_int;411 \\ var c: c_int = undefined;
412 \\ c = (a + b);412 \\ c = (a + b);
413 \\ c = (a - b);413 \\ c = (a - b);
414 \\ c = (a * b);414 \\ c = (a * b);
...@@ -416,7 +416,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {...@@ -416,7 +416,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
416 \\ c = @rem(a, b);416 \\ c = @rem(a, b);
417 \\}417 \\}
418 \\pub export fn u(a: c_uint, b: c_uint) -> c_uint {418 \\pub export fn u(a: c_uint, b: c_uint) -> c_uint {
419 \\ var c: c_uint;419 \\ var c: c_uint = undefined;
420 \\ c = (a +% b);420 \\ c = (a +% b);
421 \\ c = (a -% b);421 \\ c = (a -% b);
422 \\ c = (a *% b);422 \\ c = (a *% b);
...@@ -460,7 +460,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {...@@ -460,7 +460,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
460 ,460 ,
461 \\pub export fn max(_arg_a: c_int) -> c_int {461 \\pub export fn max(_arg_a: c_int) -> c_int {
462 \\ var a = _arg_a;462 \\ var a = _arg_a;
463 \\ var tmp: c_int;463 \\ var tmp: c_int = undefined;
464 \\ tmp = a;464 \\ tmp = a;
465 \\ a = tmp;465 \\ a = tmp;
466 \\}466 \\}
...@@ -473,8 +473,8 @@ pub fn addCases(cases: &tests.TranslateCContext) {...@@ -473,8 +473,8 @@ pub fn addCases(cases: &tests.TranslateCContext) {
473 \\}473 \\}
474 ,474 ,
475 \\pub export fn max(a: c_int) {475 \\pub export fn max(a: c_int) {
476 \\ var b: c_int;476 \\ var b: c_int = undefined;
477 \\ var c: c_int;477 \\ var c: c_int = undefined;
478 \\ c = x: {478 \\ c = x: {
479 \\ const _tmp = a;479 \\ const _tmp = a;
480 \\ b = _tmp;480 \\ b = _tmp;
...@@ -1114,4 +1114,25 @@ pub fn addCases(cases: &tests.TranslateCContext) {...@@ -1114,4 +1114,25 @@ pub fn addCases(cases: &tests.TranslateCContext) {
1114 ,1114 ,
1115 \\pub const NRF_GPIO = if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast(&NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr(&NRF_GPIO_Type, NRF_GPIO_BASE) else (&NRF_GPIO_Type)(NRF_GPIO_BASE);1115 \\pub const NRF_GPIO = if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast(&NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr(&NRF_GPIO_Type, NRF_GPIO_BASE) else (&NRF_GPIO_Type)(NRF_GPIO_BASE);
1116 );1116 );
1117
1118 cases.add("if on int",
1119 \\int if_int(int i) {
1120 \\ if (i) {
1121 \\ return 0;
1122 \\ } else {
1123 \\ return 1;
1124 \\ }
1125 \\}
1126 ,
1127 \\pub fn if_int(i: c_int) -> c_int {
1128 \\ {
1129 \\ const _tmp = i;
1130 \\ if (@bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0) {
1131 \\ return 0;
1132 \\ } else {
1133 \\ return 1;
1134 \\ };
1135 \\ };
1136 \\}
1137 );
1117}1138}