| author | |
| committer | |
| log | b897e98d30b7e471cdabf6b8f0baab44998265cd |
| tree | 642a2e9b0eb824c9cae69bfd29a72c11eb4b7101 |
| parent | eb3726c502e92ec4a3689732a76479c6d561cff5 |
| parent | ee9ab15679ee04a40bdc582779faf43fb10836ce |
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. |
| 54 | 54 | ||
| 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. |
| 125 | 125 | ||
| 126 | ##### POSIX | 126 | ##### POSIX |
| 127 | 127 | ||
| 128 | * gcc >= 5.0.0 or clang >= 3.6.0 | ||
| 129 | * cmake >= 2.8.5 | 128 | * 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 above | 130 | * LLVM, Clang, LLD libraries == 6.x, compiled with the same gcc or clang version above |
| 131 | 131 | ||
| 132 | ##### Windows | 132 | ##### Windows |
| 133 | 133 | ||
| 134 | * cmake >= 2.8.5 | ||
| 134 | * Microsoft Visual Studio 2015 | 135 | * Microsoft Visual Studio 2015 |
| 135 | * LLVM, Clang, LLD libraries == 6.x, compiled with the same MSVC version above | 136 | * LLVM, Clang, LLD libraries == 6.x, compiled with the same MSVC version above |
| 136 | 137 | ||
| 137 | #### Instructions | 138 | #### Instructions |
| 138 | 139 | ||
| 140 | ##### POSIX | ||
| 141 | |||
| 139 | If you have gcc or clang installed, you can find out what `ZIG_LIBC_LIB_DIR`, | 142 | If 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 to | 143 | `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; |
| 10 | const Buffer = std.Buffer; | 10 | const Buffer = std.Buffer; |
| 11 | const io = std.io; | 11 | const io = std.io; |
| 12 | 12 | ||
| 13 | pub fn build(b: &Builder) { | 13 | pub fn build(b: &Builder) -> %void { |
| 14 | const mode = b.standardReleaseOptions(); | 14 | const mode = b.standardReleaseOptions(); |
| 15 | 15 | ||
| 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"); |
| 37 | 37 | ||
| 38 | // find the stage0 build artifacts because we're going to re-use config.h and zig_cpp library | 38 | // 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); |
| 69 | 69 | ||
| 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); |
| 74 | 74 | ||
| ... | @@ -155,9 +155,9 @@ const LibraryDep = struct { | ... | @@ -155,9 +155,9 @@ const LibraryDep = struct { |
| 155 | }; | 155 | }; |
| 156 | 156 | ||
| 157 | fn findLLVM(b: &Builder, llvm_config_exe: []const u8) -> %LibraryDep { | 157 | fn 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"}); |
| 161 | 161 | ||
| 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 no | 4413 | 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 @@ |
| 1 | const Builder = @import("std").build.Builder; | 1 | const Builder = @import("std").build.Builder; |
| 2 | 2 | ||
| 3 | pub fn build(b: &Builder) { | 3 | pub fn build(b: &Builder) -> %void { |
| 4 | const obj = b.addObject("base64", "base64.zig"); | 4 | const obj = b.addObject("base64", "base64.zig"); |
| 5 | 5 | ||
| 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 @@ |
| 1 | const Builder = @import("std").build.Builder; | 1 | const Builder = @import("std").build.Builder; |
| 2 | 2 | ||
| 3 | pub fn build(b: &Builder) { | 3 | pub 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)); |
| 5 | 5 | ||
| 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 | } |
| 1147 | 1147 | ||
| 1148 | test "zig fmt" { | 1148 | test "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; |
| 1206 | 1206 | ||
| 1207 | ZigList<FnExport> export_list; | 1207 | ZigList<FnExport> export_list; |
| 1208 | bool calls_errorable_function; | ||
| 1208 | }; | 1209 | }; |
| 1209 | 1210 | ||
| 1210 | uint32_t fn_table_entry_hash(FnTableEntry*); | 1211 | uint32_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 | }; |
| 1277 | 1279 | ||
| 1278 | struct BuiltinFnEntry { | 1280 | struct 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; |
| 1574 | 1578 | ||
| 1579 | LLVMValueRef return_err_fn; | ||
| 1580 | |||
| 1575 | IrInstruction *invalid_instruction; | 1581 | IrInstruction *invalid_instruction; |
| 1576 | ConstExprValue const_void_val; | 1582 | ConstExprValue const_void_val; |
| 1577 | 1583 | ||
| ... | @@ -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; |
| 1596 | 1602 | ||
| 1597 | TypeTableEntry *align_amt_type; | 1603 | TypeTableEntry *align_amt_type; |
| 1604 | TypeTableEntry *stack_trace_type; | ||
| 1605 | TypeTableEntry *ptr_to_stack_trace_type; | ||
| 1598 | }; | 1606 | }; |
| 1599 | 1607 | ||
| 1600 | enum VarLinkage { | 1608 | enum 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 | }; |
| 1900 | 1909 | ||
| 1901 | struct IrInstruction { | 1910 | struct IrInstruction { |
| ... | @@ -2717,6 +2726,10 @@ struct IrInstructionExport { | ... | @@ -2717,6 +2726,10 @@ struct IrInstructionExport { |
| 2717 | IrInstruction *target; | 2726 | IrInstruction *target; |
| 2718 | }; | 2727 | }; |
| 2719 | 2728 | ||
| 2729 | struct IrInstructionErrorReturnTrace { | ||
| 2730 | IrInstruction base; | ||
| 2731 | }; | ||
| 2732 | |||
| 2720 | static const size_t slice_ptr_index = 0; | 2733 | static const size_t slice_ptr_index = 0; |
| 2721 | static const size_t slice_len_index = 1; | 2734 | static const size_t slice_len_index = 1; |
| 2722 | 2735 |
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 | } |
| 871 | 871 | ||
| 872 | TypeTableEntry *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 | |||
| 872 | TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { | 882 | TypeTableEntry *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 value | 931 | // +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 val | 933 | 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; |
| 938 | 954 | ||
| 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 | } |
| 1169 | 1193 | ||
| 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 that | 2231 | // 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) { |
| 2558 | 2586 | ||
| 2559 | static void wrong_panic_prototype(CodeGen *g, AstNode *proto_node, TypeTableEntry *fn_type) { | 2587 | static 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 | } |
| 2564 | 2592 | ||
| ... | @@ -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 | } |
| 2578 | 2606 | ||
| 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 | } |
| 5529 | 5555 | ||
| 5556 | ConstExprValue *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); |
| 185 | Buf *const_value_to_buffer(ConstExprValue *const_val); | 185 | Buf *const_value_to_buffer(ConstExprValue *const_val); |
| 186 | void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage, bool ccc); | 186 | void add_fn_export(CodeGen *g, FnTableEntry *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage, bool ccc); |
| 187 | 187 | ||
| 188 | |||
| 189 | ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name); | ||
| 190 | TypeTableEntry *get_ptr_to_stack_trace_type(CodeGen *g); | ||
| 191 | |||
| 192 | |||
| 188 | #endif | 193 | #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" |
| 14 | 14 | ||
| 15 | #include <limits> | ||
| 16 | #include <algorithm> | ||
| 17 | |||
| 15 | static void bigint_normalize(BigInt *dest) { | 18 | static void bigint_normalize(BigInt *dest) { |
| 16 | const uint64_t *digits = bigint_ptr(dest); | 19 | const uint64_t *digits = bigint_ptr(dest); |
| 17 | 20 | ||
| ... | @@ -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; |
| 541 | 544 | ||
| 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 | } |
| 672 | 675 | ||
| 676 | enum 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 | |||
| 685 | template <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) | ||
| 704 | template <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) | ||
| 720 | template <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. | ||
| 744 | template <typename T> | ||
| 745 | std::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. | ||
| 753 | constexpr 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. | ||
| 758 | constexpr 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. | ||
| 763 | constexpr 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. | ||
| 771 | static 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 | ||
| 892 | static 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 | |||
| 673 | void bigint_div_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2) { | 1045 | void bigint_div_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2) { |
| 674 | assert(op2->digit_count != 0); // division by zero | 1046 | 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 divisor | 1127 | // 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 | } |
| 406 | 406 | ||
| 407 | static 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 | |||
| 407 | static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) { | 420 | static 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 | } |
| 485 | 498 | ||
| 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 | } |
| 489 | 503 | ||
| ... | @@ -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 | } |
| 522 | 536 | ||
| 523 | if (!type_has_bits(fn_type->data.fn.fn_type_id.return_type)) { | 537 | if (!type_has_bits(return_type)) { |
| 524 | // nothing to do | 538 | // 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 | } |
| 565 | 577 | ||
| 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 | } |
| 568 | 585 | ||
| ... | @@ -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 | } |
| 866 | 883 | ||
| 867 | static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) { | 884 | static 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 | } |
| 874 | 900 | ||
| 875 | static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) { | 901 | static 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 | } |
| 878 | 904 | ||
| 879 | static LLVMValueRef get_memcpy_fn_val(CodeGen *g) { | 905 | static 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 | } |
| 897 | 923 | ||
| 924 | static 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 | |||
| 898 | static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { | 1005 | static 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); |
| 954 | 1061 | ||
| 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); |
| 977 | 1088 | ||
| 978 | LLVMValueRef err_val = LLVMGetParam(fn_val, 0); | 1089 | LLVMValueRef err_val = LLVMGetParam(fn_val, 1); |
| 979 | 1090 | ||
| 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); |
| 1007 | 1118 | ||
| 1008 | gen_panic(g, global_slice); | 1119 | gen_panic(g, global_slice, LLVMGetParam(fn_val, 0)); |
| 1009 | 1120 | ||
| 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) { |
| 1016 | 1127 | ||
| 1017 | static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) { | 1128 | static 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 | } |
| 1023 | 1144 | ||
| ... | @@ -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) { |
| 1296 | static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) { | 1417 | static 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 | } |
| 2883 | 3038 | ||
| 3039 | static 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 | |||
| 2884 | static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) { | 3049 | static 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 | } |
| 3475 | 3640 | ||
| 3476 | static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) { | 3641 | static 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 | } |
| 3480 | 3645 | ||
| ... | @@ -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); |
| 4504 | 4672 | ||
| 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 data | 4709 | // 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 | } |
| 5068 | 5273 | ||
| 5069 | static const char *bool_to_str(bool b) { | 5274 | static 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(); |
| 5090 | 5295 | ||
| 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)); | ||
| 5236 | 5448 | ||
| 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"); |
| 5238 | 5450 | ||
| ... | @@ -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 | } |
| 5255 | 5468 | ||
| 5256 | static void init(CodeGen *g) { | 5469 | static 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 | } |
| 5361 | 5574 | ||
| 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 | } |
| 574 | 574 | ||
| 575 | static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorReturnTrace *) { | ||
| 576 | return IrInstructionIdErrorReturnTrace; | ||
| 577 | } | ||
| 578 | |||
| 575 | template<typename T> | 579 | template<typename T> |
| 576 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { | 580 | static 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 | } |
| 2307 | 2311 | ||
| 2312 | static 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 | |||
| 2308 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { | 2318 | static 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 |
| 3731 | 3741 | ||
| 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 | } |
| 8232 | 8246 | ||
| 8233 | static 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 | |||
| 8243 | static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, AtomicOrder *out) { | 8247 | static 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 | } |
| 9580 | 9584 | ||
| 9585 | static 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 | |||
| 9581 | static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, | 9603 | static 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 |
| 9836 | 9858 | ||
| 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 | } |
| 9842 | 9864 | ||
| ... | @@ -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); |
| 10055 | 10077 | ||
| 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 | } |
| 10058 | 10084 | ||
| 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); |
| 13979 | 14013 | ||
| 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; |
| 13983 | 14017 | ||
| ... | @@ -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 | } |
| 998 | 998 | ||
| 999 | static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) { | ||
| 1000 | fprintf(irp->f, "@errorReturnTrace()"); | ||
| 1001 | } | ||
| 1002 | |||
| 999 | 1003 | ||
| 1000 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | 1004 | static 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; |
| 1966 | 1966 | ||
| 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 e | 2226 | // if (c) t else e |
| 2225 | AstNode *if_node = trans_create_node(c, NodeTypeIfBoolExpr); | 2227 | AstNode *if_node = trans_create_node(c, NodeTypeIfBoolExpr); |
| 2226 | 2228 | ||
| 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 | } |
| 2242 | 2238 | ||
| 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 | } |
| 2245 | 2321 | ||
| 2246 | static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *scope, const CallExpr *stmt) { | 2322 | static 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(); |
| 248 | 248 | ||
| 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 | } |
| 257 | 257 | ||
| ... | @@ -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 | } |
| 723 | 723 | ||
| 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 @@ | ||
| 1 | const mem = @import("../mem.zig"); | ||
| 2 | const math = @import("../math/index.zig"); | ||
| 3 | const endian = @import("../endian.zig"); | ||
| 4 | const debug = @import("../debug/index.zig"); | ||
| 5 | const builtin = @import("builtin"); | ||
| 6 | const htest = @import("test.zig"); | ||
| 7 | |||
| 8 | const RoundParam = struct { | ||
| 9 | a: usize, b: usize, c: usize, d: usize, x: usize, y: usize, | ||
| 10 | }; | ||
| 11 | |||
| 12 | fn 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 | |||
| 19 | pub const Blake2s224 = Blake2s(224); | ||
| 20 | pub const Blake2s256 = Blake2s(256); | ||
| 21 | |||
| 22 | fn 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 | |||
| 160 | test "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 | |||
| 171 | test "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 | |||
| 195 | test "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 | |||
| 206 | test "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 | |||
| 234 | pub const Blake2b384 = Blake2b(384); | ||
| 235 | pub const Blake2b512 = Blake2b(512); | ||
| 236 | |||
| 237 | fn 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 | |||
| 377 | test "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 | |||
| 388 | test "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 | |||
| 412 | test "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 | |||
| 423 | test "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 @@ | ||
| 1 | pub const Md5 = @import("sha1.zig").Md5; | ||
| 2 | pub const Sha1 = @import("md5.zig").Sha1; | ||
| 3 | |||
| 4 | const sha2 = @import("sha2.zig"); | ||
| 5 | pub const Sha224 = sha2.Sha224; | ||
| 6 | pub const Sha256 = sha2.Sha256; | ||
| 7 | pub const Sha384 = sha2.Sha384; | ||
| 8 | pub const Sha512 = sha2.Sha512; | ||
| 9 | |||
| 10 | const blake2 = @import("blake2.zig"); | ||
| 11 | pub const Blake2s224 = blake2.Blake2s224; | ||
| 12 | pub const Blake2s256 = blake2.Blake2s256; | ||
| 13 | pub const Blake2b384 = blake2.Blake2b384; | ||
| 14 | pub const Blake2b512 = blake2.Blake2b512; | ||
| 15 | |||
| 16 | test "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 @@ | ||
| 1 | const mem = @import("../mem.zig"); | ||
| 2 | const math = @import("../math/index.zig"); | ||
| 3 | const endian = @import("../endian.zig"); | ||
| 4 | const builtin = @import("builtin"); | ||
| 5 | const debug = @import("../debug/index.zig"); | ||
| 6 | const fmt = @import("../fmt/index.zig"); | ||
| 7 | |||
| 8 | const RoundParam = struct { | ||
| 9 | a: usize, b: usize, c: usize, d: usize, | ||
| 10 | k: usize, s: u32, t: u32 | ||
| 11 | }; | ||
| 12 | |||
| 13 | fn 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(); | ||
| 23 | pub 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 | |||
| 229 | const htest = @import("test.zig"); | ||
| 230 | |||
| 231 | test "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 | |||
| 241 | test "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 @@ | ||
| 1 | const mem = @import("../mem.zig"); | ||
| 2 | const math = @import("../math/index.zig"); | ||
| 3 | const endian = @import("../endian.zig"); | ||
| 4 | const debug = @import("../debug/index.zig"); | ||
| 5 | const builtin = @import("builtin"); | ||
| 6 | |||
| 7 | pub const u160 = @IntType(false, 160); | ||
| 8 | |||
| 9 | const RoundParam = struct { | ||
| 10 | a: usize, b: usize, c: usize, d: usize, e: usize, i: u32, | ||
| 11 | }; | ||
| 12 | |||
| 13 | fn 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 | |||
| 17 | pub 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 | |||
| 258 | const htest = @import("test.zig"); | ||
| 259 | |||
| 260 | test "sha1 single" { | ||
| 261 | htest.assertEqualHash(Sha1, "da39a3ee5e6b4b0d3255bfef95601890afd80709", ""); | ||
| 262 | htest.assertEqualHash(Sha1, "a9993e364706816aba3e25717850c26c9cd0d89d", "abc"); | ||
| 263 | htest.assertEqualHash(Sha1, "a49b2446a02c645bf419f995b67091253a04a259", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); | ||
| 264 | } | ||
| 265 | |||
| 266 | test "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 @@ | ||
| 1 | const mem = @import("../mem.zig"); | ||
| 2 | const math = @import("../math/index.zig"); | ||
| 3 | const endian = @import("../endian.zig"); | ||
| 4 | const debug = @import("../debug/index.zig"); | ||
| 5 | const builtin = @import("builtin"); | ||
| 6 | const htest = @import("test.zig"); | ||
| 7 | |||
| 8 | ///////////////////// | ||
| 9 | // Sha224 + Sha256 | ||
| 10 | |||
| 11 | const 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 | |||
| 16 | fn 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 | |||
| 20 | const 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 | |||
| 32 | const 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 | |||
| 44 | const 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 | |||
| 56 | pub const Sha224 = Sha2_32(Sha224Params); | ||
| 57 | pub const Sha256 = Sha2_32(Sha256Params); | ||
| 58 | |||
| 59 | fn 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 | |||
| 269 | test "sha224 single" { | ||
| 270 | htest.assertEqualHash(Sha224, "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", ""); | ||
| 271 | htest.assertEqualHash(Sha224, "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc"); | ||
| 272 | htest.assertEqualHash(Sha224, "c97ca9a559850ce97a04a96def6d99a9e0e0e2ab14e6b8df265fc0b3", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); | ||
| 273 | } | ||
| 274 | |||
| 275 | test "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 | |||
| 295 | test "sha256 single" { | ||
| 296 | htest.assertEqualHash(Sha256, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""); | ||
| 297 | htest.assertEqualHash(Sha256, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc"); | ||
| 298 | htest.assertEqualHash(Sha256, "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"); | ||
| 299 | } | ||
| 300 | |||
| 301 | test "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 | |||
| 325 | const 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 | |||
| 330 | fn 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 | |||
| 334 | const 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 | |||
| 346 | const 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 | |||
| 358 | const 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 | |||
| 370 | pub const Sha384 = Sha2_64(Sha384Params); | ||
| 371 | pub const Sha512 = Sha2_64(Sha512Params); | ||
| 372 | |||
| 373 | fn 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 | |||
| 604 | test "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 | |||
| 615 | test "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 | |||
| 638 | test "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 | |||
| 649 | test "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 @@ | ||
| 1 | const debug = @import("../debug/index.zig"); | ||
| 2 | const mem = @import("../mem.zig"); | ||
| 3 | const fmt = @import("../fmt/index.zig"); | ||
| 4 | |||
| 5 | // Hash using the specified hasher `H` asserting `expected == H(input)`. | ||
| 6 | pub 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. | ||
| 14 | pub 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; |
| 13 | error MissingDebugInfo; | 13 | error MissingDebugInfo; |
| 14 | error InvalidDebugInfo; | 14 | error InvalidDebugInfo; |
| 15 | error UnsupportedDebugInfo; | 15 | error UnsupportedDebugInfo; |
| 16 | error UnknownObjectFormat; | ||
| 17 | error TodoSupportCoffDebugInfo; | ||
| 18 | error TodoSupportMachoDebugInfo; | ||
| 19 | error TodoSupportCOFFDebugInfo; | ||
| 16 | 20 | ||
| 17 | 21 | ||
| 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 | } |
| 39 | 43 | ||
| 44 | var self_debug_info: ?&ElfStackTrace = null; | ||
| 45 | pub 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. | ||
| 56 | pub 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. |
| 41 | pub fn dumpStackTrace() { | 70 | pub 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 | } |
| 45 | 82 | ||
| 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 { |
| 88 | 125 | ||
| 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 | |||
| 133 | pub 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(); | ||
| 92 | 143 | ||
| 93 | os.abort(); | 144 | os.abort(); |
| 94 | } | 145 | } |
| ... | @@ -101,12 +152,91 @@ const RESET = "\x1b[0m"; | ... | @@ -101,12 +152,91 @@ const RESET = "\x1b[0m"; |
| 101 | error PathNotFound; | 152 | error PathNotFound; |
| 102 | error InvalidDebugInfo; | 153 | error InvalidDebugInfo; |
| 103 | 154 | ||
| 104 | pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty_color: bool, | 155 | pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: &io.OutStream, allocator: &mem.Allocator, |
| 105 | ignore_frame_count: usize) -> %void | 156 | 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 | |||
| 177 | pub 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 | |||
| 194 | fn 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 | |||
| 235 | pub 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(); |
| 123 | 252 | ||
| 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(); |
| 126 | 255 | ||
| 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); |
| 133 | 262 | 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 | } |
| 230 | 311 | ||
| 231 | const ElfStackTrace = struct { | 312 | pub 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 | }; |
| 252 | 338 | ||
| 253 | const PcRange = struct { | 339 | const 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; |
| 10 | pub const base64 = @import("base64.zig"); | 10 | pub const base64 = @import("base64.zig"); |
| 11 | pub const build = @import("build.zig"); | 11 | pub const build = @import("build.zig"); |
| 12 | pub const c = @import("c/index.zig"); | 12 | pub const c = @import("c/index.zig"); |
| 13 | pub const crypto = @import("crypto/index.zig"); | ||
| 13 | pub const cstr = @import("cstr.zig"); | 14 | pub const cstr = @import("cstr.zig"); |
| 14 | pub const debug = @import("debug/index.zig"); | 15 | pub const debug = @import("debug/index.zig"); |
| 15 | pub const dwarf = @import("dwarf.zig"); | 16 | pub 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 | } |
| 230 | 230 |
std/io_test.zig-5| ... | @@ -8,11 +8,6 @@ const os = std.os; | ... | @@ -8,11 +8,6 @@ const os = std.os; |
| 8 | const builtin = @import("builtin"); | 8 | const builtin = @import("builtin"); |
| 9 | 9 | ||
| 10 | test "write a file, read it, then delete it" { | 10 | test "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 | } |
| 56 | 56 | ||
| 57 | test "math.acosh" { | 57 | test "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 | } |
| 147 | 147 | ||
| 148 | test "math.cos32" { | 148 | test "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; |
| 155 | 150 | ||
| 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 | } |
| 82 | 82 | ||
| 83 | test "math.cosh" { | 83 | test "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 | } |
| 269 | 269 | ||
| 270 | /// Rotates right. Only unsigned values can be rotated. | ||
| 271 | /// Negative shift values results in shift modulo the bit count. | ||
| 272 | pub 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 | |||
| 281 | test "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. | ||
| 291 | pub 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 | |||
| 300 | test "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 | |||
| 270 | pub fn Log2Int(comptime T: type) -> type { | 309 | pub 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 | } |
| 321 | 360 | ||
| 322 | test "math.divTrunc" { | 361 | test "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 | } |
| 351 | 385 | ||
| 352 | test "math.divFloor" { | 386 | test "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 | } |
| 385 | 414 | ||
| 386 | test "math.divExact" { | 415 | test "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 | } |
| 148 | 148 | ||
| 149 | test "math.ln" { | 149 | test "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 | } |
| 57 | 57 | ||
| 58 | test "math.log float_special" { | 58 | test "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))); |
| 66 | 61 |
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 | } |
| 173 | 173 | ||
| 174 | test "math.log10" { | 174 | test "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 | } |
| 171 | 171 | ||
| 172 | test "math.log2" { | 172 | test "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 | } |
| 177 | 177 | ||
| 178 | test "math.pow" { | 178 | test "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; |
| 186 | 180 | ||
| 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 | } |
| 99 | 99 | ||
| 100 | test "math.round32" { | 100 | test "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 | } |
| 151 | 151 | ||
| 152 | test "math.sin32" { | 152 | test "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; |
| 159 | 154 | ||
| 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 | } |
| 89 | 89 | ||
| 90 | test "math.sinh" { | 90 | test "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 | } |
| 137 | 137 | ||
| 138 | test "math.tan32" { | 138 | test "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; |
| 145 | 140 | ||
| 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 | } |
| 113 | 113 | ||
| 114 | test "math.tanh" { | 114 | test "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 | } |
| 149 | 149 | ||
| 150 | /// Exits the program cleanly with the specified status code. | 150 | /// Exits the program cleanly with the specified status code. |
| 151 | pub coldcc fn exit(status: i32) -> noreturn { | 151 | pub 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 default | 160 | 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 | } |
| 195 | 195 | ||
| 196 | test "rand float 32" { | 196 | test "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 | } |
| 210 | 205 | ||
| 211 | test "rand.MT19937_64" { | 206 | test "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 | } |
| 222 | 212 | ||
| 223 | test "rand.MT19937_32" { | 213 | test "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 | } |
| 234 | 219 | ||
| 235 | test "rand.Rand.range" { | 220 | test "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 | } |
| 1021 | 1021 | ||
| 1022 | test "std.sort" { | 1022 | test "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 | } |
| 1062 | 1057 | ||
| 1063 | test "std.sort descending" { | 1058 | test "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 | } |
| 1086 | 1076 | ||
| 1087 | test "another sort case" { | 1077 | test "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); |
| 1095 | 1080 | ||
| ... | @@ -1097,11 +1082,6 @@ test "another sort case" { | ... | @@ -1097,11 +1082,6 @@ test "another sort case" { |
| 1097 | } | 1082 | } |
| 1098 | 1083 | ||
| 1099 | test "sort fuzz testing" { | 1084 | test "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 | } |
| 22 | 22 | ||
| 23 | extern fn zenMain() -> noreturn { | 23 | extern 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 | } |
| 27 | 26 | ||
| 28 | nakedcc fn _start() -> noreturn { | 27 | nakedcc fn _start() -> noreturn { |
| ... | @@ -43,29 +42,55 @@ nakedcc fn _start() -> noreturn { | ... | @@ -43,29 +42,55 @@ nakedcc fn _start() -> noreturn { |
| 43 | extern fn WinMainCRTStartup() -> noreturn { | 42 | extern fn WinMainCRTStartup() -> noreturn { |
| 44 | @setAlignStack(16); | 43 | @setAlignStack(16); |
| 45 | 44 | ||
| 46 | root.main() catch std.os.windows.ExitProcess(1); | 45 | std.os.windows.ExitProcess(callMain()); |
| 47 | std.os.windows.ExitProcess(0); | ||
| 48 | } | 46 | } |
| 49 | 47 | ||
| 50 | fn posixCallMainAndExit() -> noreturn { | 48 | fn 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 | } |
| 57 | 54 | ||
| 58 | fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void { | 55 | fn callMainWithArgs(argc: usize, argv: &&u8, envp: &?&u8) -> u8 { |
| 59 | std.os.ArgIteratorPosix.raw = argv[0..argc]; | 56 | std.os.ArgIteratorPosix.raw = argv[0..argc]; |
| 60 | 57 | ||
| 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]; |
| 64 | 61 | ||
| 65 | return root.main(); | 62 | return callMain(); |
| 66 | } | 63 | } |
| 67 | 64 | ||
| 68 | extern fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 { | 65 | extern 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 | |||
| 69 | fn 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(); |
| 15 | 15 | ||
| 16 | // TODO use a more general purpose allocator here | 16 | // 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(); |
| 19 | 19 | ||
| 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 | } |
| 113 | 113 | ||
| 114 | builder.setInstallPrefix(prefix); | 114 | builder.setInstallPrefix(prefix); |
| 115 | root.build(&builder); | 115 | try root.build(&builder); |
| 116 | 116 | ||
| 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 options | 129 | // 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 | } |
| 134 | 134 | ||
| 135 | // This usage text has to be synchronized with src/main.cpp | 135 | // 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"); |
| 5 | 5 | ||
| 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. |
| 8 | pub coldcc fn panic(msg: []const u8) -> noreturn { | 8 | pub 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; |
| 74 | 74 | ||
| 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. |
| 77 | pub coldcc fn panic(msg: []const u8) -> noreturn { | 77 | pub 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. |
| 5 | 5 | ||
| 6 | const builtin = @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 7 | const std = @import("std"); | ||
| 7 | 8 | ||
| 8 | pub coldcc fn panic(msg: []const u8) -> noreturn { | 9 | pub 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); |
| 10 | 10 | ||
| 11 | test_fn.func() catch |err| { | 11 | try test_fn.func(); |
| 12 | warn("{}\n", err); | ||
| 13 | return err; | ||
| 14 | }; | ||
| 15 | 12 | ||
| 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 | } |
| 30 | fn div(comptime T: type, a: T, b: T) -> T { | 53 | fn 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 @@ |
| 1 | const tests = @import("tests.zig"); | 1 | const tests = @import("tests.zig"); |
| 2 | 2 | ||
| 3 | pub fn addCases(cases: &tests.CompileErrorContext) { | 3 | pub 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'"); |
| 1061 | 1070 | ||
| 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"); |
| 2 | 2 | ||
| 3 | pub fn addCases(cases: &tests.CompareOutputContext) { | 3 | pub 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 | ); |
| 12 | 12 | ||
| 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 | ); |
| 26 | 26 | ||
| 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 | ); |
| 40 | 40 | ||
| 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 | ); |
| 54 | 54 | ||
| 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 | ); |
| 68 | 68 | ||
| 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 | ); |
| 82 | 82 | ||
| 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 | ); |
| 96 | 96 | ||
| 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 | ); |
| 110 | 110 | ||
| 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 | ); |
| 124 | 124 | ||
| 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 | ); |
| 138 | 138 | ||
| 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 | ); |
| 152 | 152 | ||
| 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 | ); |
| 165 | 165 | ||
| 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 | ); |
| 179 | 179 | ||
| 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 | ); |
| 193 | 193 | ||
| 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 | ); |
| 207 | 207 | ||
| 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 | ); |
| 221 | 221 | ||
| 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); // good | 225 | \\ @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 | ); |
| 237 | 237 | ||
| 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 | ); |
| 249 | 249 | ||
| 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 | ); |
| 266 | 266 | ||
| 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 @@ | ||
| 1 | const Builder = @import("std").build.Builder; | ||
| 2 | |||
| 3 | pub 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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const io = std.io; | ||
| 3 | const mem = std.mem; | ||
| 4 | const debug = std.debug; | ||
| 5 | const assert = debug.assert; | ||
| 6 | const Buffer = std.Buffer; | ||
| 7 | const ArrayList = std.ArrayList; | ||
| 8 | |||
| 9 | error InvalidInput; | ||
| 10 | error OutOfMem; | ||
| 11 | |||
| 12 | const Token = union(enum) { | ||
| 13 | Word: []const u8, | ||
| 14 | OpenBrace, | ||
| 15 | CloseBrace, | ||
| 16 | Comma, | ||
| 17 | Eof, | ||
| 18 | }; | ||
| 19 | |||
| 20 | var global_allocator: &mem.Allocator = undefined; | ||
| 21 | |||
| 22 | fn 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 | |||
| 68 | const Node = union(enum) { | ||
| 69 | Scalar: []const u8, | ||
| 70 | List: ArrayList(Node), | ||
| 71 | Combine: []Node, | ||
| 72 | }; | ||
| 73 | |||
| 74 | fn 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 | |||
| 110 | fn 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 | |||
| 138 | const ListOfBuffer0 = ArrayList(Buffer); // TODO this is working around a compiler bug, fix and delete this | ||
| 139 | |||
| 140 | fn 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 | |||
| 177 | pub 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 | |||
| 199 | test "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 | |||
| 213 | fn 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 | |||
| 224 | test "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 | |||
| 247 | fn 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 @@ |
| 1 | const Builder = @import("std").build.Builder; | 1 | const Builder = @import("std").build.Builder; |
| 2 | 2 | ||
| 3 | pub fn build(b: &Builder) { | 3 | pub fn build(b: &Builder) -> %void { |
| 4 | const obj = b.addObject("test", "test.zig"); | 4 | const obj = b.addObject("test", "test.zig"); |
| 5 | 5 | ||
| 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 @@ |
| 1 | pub fn panic(msg: []const u8) -> noreturn { @breakpoint(); while (true) {} } | 1 | const StackTrace = @import("builtin").StackTrace; |
| 2 | pub fn panic(msg: []const u8, stack_trace: ?&StackTrace) -> noreturn { @breakpoint(); while (true) {} } | ||
| 2 | 3 | ||
| 3 | fn bar() -> %void {} | 4 | fn bar() -> %void {} |
| 4 | 5 |
test/standalone/pkg_import/build.zig+1-1| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | const Builder = @import("std").build.Builder; | 1 | const Builder = @import("std").build.Builder; |
| 2 | 2 | ||
| 3 | pub fn build(b: &Builder) { | 3 | pub 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"); |
| 6 | 6 |
test/standalone/use_alias/build.zig+1-1| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | const Builder = @import("std").build.Builder; | 1 | const Builder = @import("std").build.Builder; |
| 2 | 2 | ||
| 3 | pub fn build(b: &Builder) { | 3 | pub fn build(b: &Builder) -> %void { |
| 4 | b.addCIncludePath("."); | 4 | b.addCIncludePath("."); |
| 5 | 5 | ||
| 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 | }; |
| 51 | 46 | ||
| 52 | error TestFailed; | 47 | error TestFailed; |
| 48 | error CompilationIncorrectlySucceeded; | ||
| 53 | 49 | ||
| 54 | const max_stdout_size = 1 * 1024 * 1024; // 1 MB | 50 | const max_stdout_size = 1 * 1024 * 1024; // 1 MB |
| 55 | 51 | ||
| ... | @@ -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 | } |