| author | |
| committer | |
| log | 63dfca97159fd66563693039606c0bca30aa1f85 |
| tree | 7975692d2f2934f19d13a1784db87619c525bcaf |
| parent | e42d86b657c2fae093fb2545e8b4b85614a0c906 |
| parent | 4e985123447dba40e282e9663e3ca669d3f9243a |
| signature |
add -DZIG_ENABLE_MEM_PROFILE option and -fmem-report flag13 files changed, 315 insertions(+), 83 deletions(-)
CMakeLists.txt+2| ... | @@ -46,6 +46,7 @@ message("Configuring zig version ${ZIG_VERSION}") | ... | @@ -46,6 +46,7 @@ message("Configuring zig version ${ZIG_VERSION}") |
| 46 | set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)") | 46 | set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)") |
| 47 | set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries") | 47 | set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries") |
| 48 | set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL "Disable copying lib/ files to install prefix") | 48 | set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL "Disable copying lib/ files to install prefix") |
| 49 | set(ZIG_ENABLE_MEM_PROFILE off CACHE BOOL "Activate memory usage instrumentation") | ||
| 49 | 50 | ||
| 50 | if(ZIG_STATIC) | 51 | if(ZIG_STATIC) |
| 51 | set(ZIG_STATIC_LLVM "on") | 52 | set(ZIG_STATIC_LLVM "on") |
| ... | @@ -455,6 +456,7 @@ set(ZIG_SOURCES | ... | @@ -455,6 +456,7 @@ set(ZIG_SOURCES |
| 455 | "${CMAKE_SOURCE_DIR}/src/ir_print.cpp" | 456 | "${CMAKE_SOURCE_DIR}/src/ir_print.cpp" |
| 456 | "${CMAKE_SOURCE_DIR}/src/libc_installation.cpp" | 457 | "${CMAKE_SOURCE_DIR}/src/libc_installation.cpp" |
| 457 | "${CMAKE_SOURCE_DIR}/src/link.cpp" | 458 | "${CMAKE_SOURCE_DIR}/src/link.cpp" |
| 459 | "${CMAKE_SOURCE_DIR}/src/memory_profiling.cpp" | ||
| 458 | "${CMAKE_SOURCE_DIR}/src/os.cpp" | 460 | "${CMAKE_SOURCE_DIR}/src/os.cpp" |
| 459 | "${CMAKE_SOURCE_DIR}/src/parser.cpp" | 461 | "${CMAKE_SOURCE_DIR}/src/parser.cpp" |
| 460 | "${CMAKE_SOURCE_DIR}/src/range_set.cpp" | 462 | "${CMAKE_SOURCE_DIR}/src/range_set.cpp" |
src/all_types.hpp+3-3| ... | @@ -2569,12 +2569,12 @@ enum IrInstructionId { | ... | @@ -2569,12 +2569,12 @@ enum IrInstructionId { |
| 2569 | struct IrInstruction { | 2569 | struct IrInstruction { |
| 2570 | Scope *scope; | 2570 | Scope *scope; |
| 2571 | AstNode *source_node; | 2571 | AstNode *source_node; |
| 2572 | ConstExprValue value; | ||
| 2573 | size_t debug_id; | ||
| 2574 | LLVMValueRef llvm_value; | 2572 | LLVMValueRef llvm_value; |
| 2573 | ConstExprValue value; | ||
| 2574 | uint32_t debug_id; | ||
| 2575 | // if ref_count is zero and the instruction has no side effects, | 2575 | // if ref_count is zero and the instruction has no side effects, |
| 2576 | // the instruction can be omitted in codegen | 2576 | // the instruction can be omitted in codegen |
| 2577 | size_t ref_count; | 2577 | uint32_t ref_count; |
| 2578 | // When analyzing IR, instructions that point to this instruction in the "old ir" | 2578 | // When analyzing IR, instructions that point to this instruction in the "old ir" |
| 2579 | // can find the instruction that corresponds to this value in the "new ir" | 2579 | // can find the instruction that corresponds to this value in the "new ir" |
| 2580 | // with this child field. | 2580 | // with this child field. |
src/analyze.cpp+2-2| ... | @@ -5783,8 +5783,8 @@ ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_ | ... | @@ -5783,8 +5783,8 @@ ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_ |
| 5783 | 5783 | ||
| 5784 | 5784 | ||
| 5785 | ConstExprValue *create_const_vals(size_t count) { | 5785 | ConstExprValue *create_const_vals(size_t count) { |
| 5786 | ConstGlobalRefs *global_refs = allocate<ConstGlobalRefs>(count); | 5786 | ConstGlobalRefs *global_refs = allocate<ConstGlobalRefs>(count, "ConstGlobalRefs"); |
| 5787 | ConstExprValue *vals = allocate<ConstExprValue>(count); | 5787 | ConstExprValue *vals = allocate<ConstExprValue>(count, "ConstExprValue"); |
| 5788 | for (size_t i = 0; i < count; i += 1) { | 5788 | for (size_t i = 0; i < count; i += 1) { |
| 5789 | vals[i].global_refs = &global_refs[i]; | 5789 | vals[i].global_refs = &global_refs[i]; |
| 5790 | } | 5790 | } |
src/config.h.in+2-3| ... | @@ -13,9 +13,6 @@ | ... | @@ -13,9 +13,6 @@ |
| 13 | #define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@ | 13 | #define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@ |
| 14 | #define ZIG_VERSION_STRING "@ZIG_VERSION@" | 14 | #define ZIG_VERSION_STRING "@ZIG_VERSION@" |
| 15 | 15 | ||
| 16 | // Only used for running tests before installing. | ||
| 17 | #define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test" | ||
| 18 | |||
| 19 | // Used for communicating build information to self hosted build. | 16 | // Used for communicating build information to self hosted build. |
| 20 | #define ZIG_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@" | 17 | #define ZIG_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@" |
| 21 | #define ZIG_CXX_COMPILER "@CMAKE_CXX_COMPILER@" | 18 | #define ZIG_CXX_COMPILER "@CMAKE_CXX_COMPILER@" |
| ... | @@ -24,4 +21,6 @@ | ... | @@ -24,4 +21,6 @@ |
| 24 | #define ZIG_LLVM_CONFIG_EXE "@LLVM_CONFIG_EXE@" | 21 | #define ZIG_LLVM_CONFIG_EXE "@LLVM_CONFIG_EXE@" |
| 25 | #define ZIG_DIA_GUIDS_LIB "@ZIG_DIA_GUIDS_LIB_ESCAPED@" | 22 | #define ZIG_DIA_GUIDS_LIB "@ZIG_DIA_GUIDS_LIB_ESCAPED@" |
| 26 | 23 | ||
| 24 | #cmakedefine ZIG_ENABLE_MEM_PROFILE | ||
| 25 | |||
| 27 | #endif | 26 | #endif |
src/dump_analysis.cpp+1-18| ... | @@ -240,23 +240,6 @@ static void jw_string(JsonWriter *jw, const char *s) { | ... | @@ -240,23 +240,6 @@ static void jw_string(JsonWriter *jw, const char *s) { |
| 240 | 240 | ||
| 241 | static void tree_print(FILE *f, ZigType *ty, size_t indent); | 241 | static void tree_print(FILE *f, ZigType *ty, size_t indent); |
| 242 | 242 | ||
| 243 | static void pretty_print_bytes(FILE *f, double n) { | ||
| 244 | if (n > 1024.0 * 1024.0 * 1024.0) { | ||
| 245 | fprintf(f, "%.02f GiB", n / 1024.0 / 1024.0 / 1024.0); | ||
| 246 | return; | ||
| 247 | } | ||
| 248 | if (n > 1024.0 * 1024.0) { | ||
| 249 | fprintf(f, "%.02f MiB", n / 1024.0 / 1024.0); | ||
| 250 | return; | ||
| 251 | } | ||
| 252 | if (n > 1024.0) { | ||
| 253 | fprintf(f, "%.02f KiB", n / 1024.0); | ||
| 254 | return; | ||
| 255 | } | ||
| 256 | fprintf(f, "%.02f bytes", n ); | ||
| 257 | return; | ||
| 258 | } | ||
| 259 | |||
| 260 | static int compare_type_abi_sizes_desc(const void *a, const void *b) { | 243 | static int compare_type_abi_sizes_desc(const void *a, const void *b) { |
| 261 | uint64_t size_a = (*(ZigType * const*)(a))->abi_size; | 244 | uint64_t size_a = (*(ZigType * const*)(a))->abi_size; |
| 262 | uint64_t size_b = (*(ZigType * const*)(b))->abi_size; | 245 | uint64_t size_b = (*(ZigType * const*)(b))->abi_size; |
| ... | @@ -322,7 +305,7 @@ static void tree_print(FILE *f, ZigType *ty, size_t indent) { | ... | @@ -322,7 +305,7 @@ static void tree_print(FILE *f, ZigType *ty, size_t indent) { |
| 322 | 305 | ||
| 323 | start_peer(f, indent); | 306 | start_peer(f, indent); |
| 324 | fprintf(f, "\"sizef\": \""); | 307 | fprintf(f, "\"sizef\": \""); |
| 325 | pretty_print_bytes(f, ty->abi_size); | 308 | zig_pretty_print_bytes(f, ty->abi_size); |
| 326 | fprintf(f, "\""); | 309 | fprintf(f, "\""); |
| 327 | 310 | ||
| 328 | start_peer(f, indent); | 311 | start_peer(f, indent); |
src/ir.cpp+35-24| ... | @@ -413,7 +413,7 @@ ZigType *ir_analyze_type_expr(IrAnalyze *ira, Scope *scope, AstNode *node) { | ... | @@ -413,7 +413,7 @@ ZigType *ir_analyze_type_expr(IrAnalyze *ira, Scope *scope, AstNode *node) { |
| 413 | } | 413 | } |
| 414 | 414 | ||
| 415 | static IrBasicBlock *ir_create_basic_block(IrBuilder *irb, Scope *scope, const char *name_hint) { | 415 | static IrBasicBlock *ir_create_basic_block(IrBuilder *irb, Scope *scope, const char *name_hint) { |
| 416 | IrBasicBlock *result = allocate<IrBasicBlock>(1); | 416 | IrBasicBlock *result = allocate<IrBasicBlock>(1, "IrBasicBlock"); |
| 417 | result->scope = scope; | 417 | result->scope = scope; |
| 418 | result->name_hint = name_hint; | 418 | result->name_hint = name_hint; |
| 419 | result->debug_id = exec_next_debug_id(irb->exec); | 419 | result->debug_id = exec_next_debug_id(irb->exec); |
| ... | @@ -1085,13 +1085,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSpillEnd *) { | ... | @@ -1085,13 +1085,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSpillEnd *) { |
| 1085 | 1085 | ||
| 1086 | template<typename T> | 1086 | template<typename T> |
| 1087 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { | 1087 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 1088 | T *special_instruction = allocate<T>(1); | 1088 | const char *name = nullptr; |
| 1089 | #ifdef ZIG_ENABLE_MEM_PROFILE | ||
| 1090 | T *dummy = nullptr; | ||
| 1091 | name = ir_instruction_type_str(ir_instruction_id(dummy)); | ||
| 1092 | #endif | ||
| 1093 | T *special_instruction = allocate<T>(1, name); | ||
| 1089 | special_instruction->base.id = ir_instruction_id(special_instruction); | 1094 | special_instruction->base.id = ir_instruction_id(special_instruction); |
| 1090 | special_instruction->base.scope = scope; | 1095 | special_instruction->base.scope = scope; |
| 1091 | special_instruction->base.source_node = source_node; | 1096 | special_instruction->base.source_node = source_node; |
| 1092 | special_instruction->base.debug_id = exec_next_debug_id(irb->exec); | 1097 | special_instruction->base.debug_id = exec_next_debug_id(irb->exec); |
| 1093 | special_instruction->base.owner_bb = irb->current_basic_block; | 1098 | special_instruction->base.owner_bb = irb->current_basic_block; |
| 1094 | special_instruction->base.value.global_refs = allocate<ConstGlobalRefs>(1); | 1099 | special_instruction->base.value.global_refs = allocate<ConstGlobalRefs>(1, "ConstGlobalRefs"); |
| 1095 | return special_instruction; | 1100 | return special_instruction; |
| 1096 | } | 1101 | } |
| 1097 | 1102 | ||
| ... | @@ -3569,7 +3574,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, | ... | @@ -3569,7 +3574,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 3569 | switch (node->data.return_expr.kind) { | 3574 | switch (node->data.return_expr.kind) { |
| 3570 | case ReturnKindUnconditional: | 3575 | case ReturnKindUnconditional: |
| 3571 | { | 3576 | { |
| 3572 | ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1); | 3577 | ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1, "ResultLocReturn"); |
| 3573 | result_loc_ret->base.id = ResultLocIdReturn; | 3578 | result_loc_ret->base.id = ResultLocIdReturn; |
| 3574 | ir_build_reset_result(irb, scope, node, &result_loc_ret->base); | 3579 | ir_build_reset_result(irb, scope, node, &result_loc_ret->base); |
| 3575 | 3580 | ||
| ... | @@ -3664,7 +3669,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, | ... | @@ -3664,7 +3669,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 3664 | ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, err_val, nullptr)); | 3669 | ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, err_val, nullptr)); |
| 3665 | IrInstructionSpillBegin *spill_begin = ir_build_spill_begin(irb, scope, node, err_val, | 3670 | IrInstructionSpillBegin *spill_begin = ir_build_spill_begin(irb, scope, node, err_val, |
| 3666 | SpillIdRetErrCode); | 3671 | SpillIdRetErrCode); |
| 3667 | ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1); | 3672 | ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1, "ResultLocReturn"); |
| 3668 | result_loc_ret->base.id = ResultLocIdReturn; | 3673 | result_loc_ret->base.id = ResultLocIdReturn; |
| 3669 | ir_build_reset_result(irb, scope, node, &result_loc_ret->base); | 3674 | ir_build_reset_result(irb, scope, node, &result_loc_ret->base); |
| 3670 | ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base); | 3675 | ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base); |
| ... | @@ -3692,7 +3697,7 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s | ... | @@ -3692,7 +3697,7 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s |
| 3692 | Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime, | 3697 | Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime, |
| 3693 | bool skip_name_check) | 3698 | bool skip_name_check) |
| 3694 | { | 3699 | { |
| 3695 | ZigVar *variable_entry = allocate<ZigVar>(1); | 3700 | ZigVar *variable_entry = allocate<ZigVar>(1, "ZigVar"); |
| 3696 | variable_entry->parent_scope = parent_scope; | 3701 | variable_entry->parent_scope = parent_scope; |
| 3697 | variable_entry->shadowable = is_shadowable; | 3702 | variable_entry->shadowable = is_shadowable; |
| 3698 | variable_entry->mem_slot_index = SIZE_MAX; | 3703 | variable_entry->mem_slot_index = SIZE_MAX; |
| ... | @@ -3767,7 +3772,7 @@ static ZigVar *ir_create_var(IrBuilder *irb, AstNode *node, Scope *scope, Buf *n | ... | @@ -3767,7 +3772,7 @@ static ZigVar *ir_create_var(IrBuilder *irb, AstNode *node, Scope *scope, Buf *n |
| 3767 | } | 3772 | } |
| 3768 | 3773 | ||
| 3769 | static ResultLocPeer *create_peer_result(ResultLocPeerParent *peer_parent) { | 3774 | static ResultLocPeer *create_peer_result(ResultLocPeerParent *peer_parent) { |
| 3770 | ResultLocPeer *result = allocate<ResultLocPeer>(1); | 3775 | ResultLocPeer *result = allocate<ResultLocPeer>(1, "ResultLocPeer"); |
| 3771 | result->base.id = ResultLocIdPeer; | 3776 | result->base.id = ResultLocIdPeer; |
| 3772 | result->base.source_instruction = peer_parent->base.source_instruction; | 3777 | result->base.source_instruction = peer_parent->base.source_instruction; |
| 3773 | result->parent = peer_parent; | 3778 | result->parent = peer_parent; |
| ... | @@ -3806,7 +3811,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode | ... | @@ -3806,7 +3811,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode |
| 3806 | scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node, | 3811 | scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node, |
| 3807 | ir_should_inline(irb->exec, parent_scope)); | 3812 | ir_should_inline(irb->exec, parent_scope)); |
| 3808 | 3813 | ||
| 3809 | scope_block->peer_parent = allocate<ResultLocPeerParent>(1); | 3814 | scope_block->peer_parent = allocate<ResultLocPeerParent>(1, "ResultLocPeerParent"); |
| 3810 | scope_block->peer_parent->base.id = ResultLocIdPeerParent; | 3815 | scope_block->peer_parent->base.id = ResultLocIdPeerParent; |
| 3811 | scope_block->peer_parent->base.source_instruction = scope_block->is_comptime; | 3816 | scope_block->peer_parent->base.source_instruction = scope_block->is_comptime; |
| 3812 | scope_block->peer_parent->end_bb = scope_block->end_block; | 3817 | scope_block->peer_parent->end_bb = scope_block->end_block; |
| ... | @@ -3933,7 +3938,7 @@ static IrInstruction *ir_gen_assign(IrBuilder *irb, Scope *scope, AstNode *node) | ... | @@ -3933,7 +3938,7 @@ static IrInstruction *ir_gen_assign(IrBuilder *irb, Scope *scope, AstNode *node) |
| 3933 | if (lvalue == irb->codegen->invalid_instruction) | 3938 | if (lvalue == irb->codegen->invalid_instruction) |
| 3934 | return irb->codegen->invalid_instruction; | 3939 | return irb->codegen->invalid_instruction; |
| 3935 | 3940 | ||
| 3936 | ResultLocInstruction *result_loc_inst = allocate<ResultLocInstruction>(1); | 3941 | ResultLocInstruction *result_loc_inst = allocate<ResultLocInstruction>(1, "ResultLocInstruction"); |
| 3937 | result_loc_inst->base.id = ResultLocIdInstruction; | 3942 | result_loc_inst->base.id = ResultLocIdInstruction; |
| 3938 | result_loc_inst->base.source_instruction = lvalue; | 3943 | result_loc_inst->base.source_instruction = lvalue; |
| 3939 | ir_ref_instruction(lvalue, irb->current_basic_block); | 3944 | ir_ref_instruction(lvalue, irb->current_basic_block); |
| ... | @@ -4005,10 +4010,10 @@ static IrInstruction *ir_gen_bool_or(IrBuilder *irb, Scope *scope, AstNode *node | ... | @@ -4005,10 +4010,10 @@ static IrInstruction *ir_gen_bool_or(IrBuilder *irb, Scope *scope, AstNode *node |
| 4005 | 4010 | ||
| 4006 | ir_set_cursor_at_end_and_append_block(irb, true_block); | 4011 | ir_set_cursor_at_end_and_append_block(irb, true_block); |
| 4007 | 4012 | ||
| 4008 | IrInstruction **incoming_values = allocate<IrInstruction *>(2); | 4013 | IrInstruction **incoming_values = allocate<IrInstruction *>(2, "IrInstruction *"); |
| 4009 | incoming_values[0] = val1; | 4014 | incoming_values[0] = val1; |
| 4010 | incoming_values[1] = val2; | 4015 | incoming_values[1] = val2; |
| 4011 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); | 4016 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *"); |
| 4012 | incoming_blocks[0] = post_val1_block; | 4017 | incoming_blocks[0] = post_val1_block; |
| 4013 | incoming_blocks[1] = post_val2_block; | 4018 | incoming_blocks[1] = post_val2_block; |
| 4014 | 4019 | ||
| ... | @@ -8017,7 +8022,8 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A | ... | @@ -8017,7 +8022,8 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A |
| 8017 | err_set_type->abi_size = irb->codegen->builtin_types.entry_global_error_set->abi_size; | 8022 | err_set_type->abi_size = irb->codegen->builtin_types.entry_global_error_set->abi_size; |
| 8018 | err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(err_count); | 8023 | err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(err_count); |
| 8019 | 8024 | ||
| 8020 | ErrorTableEntry **errors = allocate<ErrorTableEntry *>(irb->codegen->errors_by_index.length + err_count); | 8025 | size_t errors_count = irb->codegen->errors_by_index.length + err_count; |
| 8026 | ErrorTableEntry **errors = allocate<ErrorTableEntry *>(errors_count, "ErrorTableEntry *"); | ||
| 8021 | 8027 | ||
| 8022 | for (uint32_t i = 0; i < err_count; i += 1) { | 8028 | for (uint32_t i = 0; i < err_count; i += 1) { |
| 8023 | AstNode *field_node = node->data.err_set_decl.decls.at(i); | 8029 | AstNode *field_node = node->data.err_set_decl.decls.at(i); |
| ... | @@ -8048,7 +8054,7 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A | ... | @@ -8048,7 +8054,7 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A |
| 8048 | } | 8054 | } |
| 8049 | errors[err->value] = err; | 8055 | errors[err->value] = err; |
| 8050 | } | 8056 | } |
| 8051 | free(errors); | 8057 | deallocate(errors, errors_count, "ErrorTableEntry *"); |
| 8052 | return ir_build_const_type(irb, parent_scope, node, err_set_type); | 8058 | return ir_build_const_type(irb, parent_scope, node, err_set_type); |
| 8053 | } | 8059 | } |
| 8054 | 8060 | ||
| ... | @@ -9574,7 +9580,8 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp | ... | @@ -9574,7 +9580,8 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp |
| 9574 | if (type_is_global_error_set(set2)) { | 9580 | if (type_is_global_error_set(set2)) { |
| 9575 | return set1; | 9581 | return set1; |
| 9576 | } | 9582 | } |
| 9577 | ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length); | 9583 | size_t errors_count = ira->codegen->errors_by_index.length; |
| 9584 | ErrorTableEntry **errors = allocate<ErrorTableEntry *>(errors_count, "ErrorTableEntry *"); | ||
| 9578 | populate_error_set_table(errors, set1); | 9585 | populate_error_set_table(errors, set1); |
| 9579 | ZigList<ErrorTableEntry *> intersection_list = {}; | 9586 | ZigList<ErrorTableEntry *> intersection_list = {}; |
| 9580 | 9587 | ||
| ... | @@ -9595,7 +9602,7 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp | ... | @@ -9595,7 +9602,7 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp |
| 9595 | buf_appendf(&err_set_type->name, "%s%s", comma, buf_ptr(&existing_entry_with_docs->name)); | 9602 | buf_appendf(&err_set_type->name, "%s%s", comma, buf_ptr(&existing_entry_with_docs->name)); |
| 9596 | } | 9603 | } |
| 9597 | } | 9604 | } |
| 9598 | free(errors); | 9605 | deallocate(errors, errors_count, "ErrorTableEntry *"); |
| 9599 | 9606 | ||
| 9600 | err_set_type->data.error_set.err_count = intersection_list.length; | 9607 | err_set_type->data.error_set.err_count = intersection_list.length; |
| 9601 | err_set_type->data.error_set.errors = intersection_list.items; | 9608 | err_set_type->data.error_set.errors = intersection_list.items; |
| ... | @@ -9792,7 +9799,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted | ... | @@ -9792,7 +9799,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted |
| 9792 | return result; | 9799 | return result; |
| 9793 | } | 9800 | } |
| 9794 | 9801 | ||
| 9795 | ErrorTableEntry **errors = allocate<ErrorTableEntry *>(g->errors_by_index.length); | 9802 | size_t errors_count = g->errors_by_index.length; |
| 9803 | ErrorTableEntry **errors = allocate<ErrorTableEntry *>(errors_count, "ErrorTableEntry *"); | ||
| 9796 | for (uint32_t i = 0; i < container_set->data.error_set.err_count; i += 1) { | 9804 | for (uint32_t i = 0; i < container_set->data.error_set.err_count; i += 1) { |
| 9797 | ErrorTableEntry *error_entry = container_set->data.error_set.errors[i]; | 9805 | ErrorTableEntry *error_entry = container_set->data.error_set.errors[i]; |
| 9798 | assert(errors[error_entry->value] == nullptr); | 9806 | assert(errors[error_entry->value] == nullptr); |
| ... | @@ -9809,7 +9817,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted | ... | @@ -9809,7 +9817,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted |
| 9809 | result.data.error_set_mismatch->missing_errors.append(contained_error_entry); | 9817 | result.data.error_set_mismatch->missing_errors.append(contained_error_entry); |
| 9810 | } | 9818 | } |
| 9811 | } | 9819 | } |
| 9812 | free(errors); | 9820 | deallocate(errors, errors_count, "ErrorTableEntry *"); |
| 9813 | return result; | 9821 | return result; |
| 9814 | } | 9822 | } |
| 9815 | 9823 | ||
| ... | @@ -10814,7 +10822,8 @@ static IrInstruction *ira_suspend(IrAnalyze *ira, IrInstruction *old_instruction | ... | @@ -10814,7 +10822,8 @@ static IrInstruction *ira_suspend(IrAnalyze *ira, IrInstruction *old_instruction |
| 10814 | IrSuspendPosition *suspend_pos) | 10822 | IrSuspendPosition *suspend_pos) |
| 10815 | { | 10823 | { |
| 10816 | if (ira->codegen->verbose_ir) { | 10824 | if (ira->codegen->verbose_ir) { |
| 10817 | fprintf(stderr, "suspend %s_%zu %s_%zu #%zu (%zu,%zu)\n", ira->old_irb.current_basic_block->name_hint, | 10825 | fprintf(stderr, "suspend %s_%zu %s_%zu #%" PRIu32 " (%zu,%zu)\n", |
| 10826 | ira->old_irb.current_basic_block->name_hint, | ||
| 10818 | ira->old_irb.current_basic_block->debug_id, | 10827 | ira->old_irb.current_basic_block->debug_id, |
| 10819 | ira->old_irb.exec->basic_block_list.at(ira->old_bb_index)->name_hint, | 10828 | ira->old_irb.exec->basic_block_list.at(ira->old_bb_index)->name_hint, |
| 10820 | ira->old_irb.exec->basic_block_list.at(ira->old_bb_index)->debug_id, | 10829 | ira->old_irb.exec->basic_block_list.at(ira->old_bb_index)->debug_id, |
| ... | @@ -10852,7 +10861,7 @@ static IrInstruction *ira_resume(IrAnalyze *ira) { | ... | @@ -10852,7 +10861,7 @@ static IrInstruction *ira_resume(IrAnalyze *ira) { |
| 10852 | ira->instruction_index = pos.instruction_index; | 10861 | ira->instruction_index = pos.instruction_index; |
| 10853 | assert(pos.instruction_index < ira->old_irb.current_basic_block->instruction_list.length); | 10862 | assert(pos.instruction_index < ira->old_irb.current_basic_block->instruction_list.length); |
| 10854 | if (ira->codegen->verbose_ir) { | 10863 | if (ira->codegen->verbose_ir) { |
| 10855 | fprintf(stderr, "%s_%zu #%zu\n", ira->old_irb.current_basic_block->name_hint, | 10864 | fprintf(stderr, "%s_%zu #%" PRIu32 "\n", ira->old_irb.current_basic_block->name_hint, |
| 10856 | ira->old_irb.current_basic_block->debug_id, | 10865 | ira->old_irb.current_basic_block->debug_id, |
| 10857 | ira->old_irb.current_basic_block->instruction_list.at(pos.instruction_index)->debug_id); | 10866 | ira->old_irb.current_basic_block->instruction_list.at(pos.instruction_index)->debug_id); |
| 10858 | } | 10867 | } |
| ... | @@ -14686,14 +14695,15 @@ static IrInstruction *ir_analyze_instruction_merge_err_sets(IrAnalyze *ira, | ... | @@ -14686,14 +14695,15 @@ static IrInstruction *ir_analyze_instruction_merge_err_sets(IrAnalyze *ira, |
| 14686 | return ira->codegen->invalid_instruction; | 14695 | return ira->codegen->invalid_instruction; |
| 14687 | } | 14696 | } |
| 14688 | 14697 | ||
| 14689 | ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length); | 14698 | size_t errors_count = ira->codegen->errors_by_index.length; |
| 14699 | ErrorTableEntry **errors = allocate<ErrorTableEntry *>(errors_count, "ErrorTableEntry *"); | ||
| 14690 | for (uint32_t i = 0, count = op1_type->data.error_set.err_count; i < count; i += 1) { | 14700 | for (uint32_t i = 0, count = op1_type->data.error_set.err_count; i < count; i += 1) { |
| 14691 | ErrorTableEntry *error_entry = op1_type->data.error_set.errors[i]; | 14701 | ErrorTableEntry *error_entry = op1_type->data.error_set.errors[i]; |
| 14692 | assert(errors[error_entry->value] == nullptr); | 14702 | assert(errors[error_entry->value] == nullptr); |
| 14693 | errors[error_entry->value] = error_entry; | 14703 | errors[error_entry->value] = error_entry; |
| 14694 | } | 14704 | } |
| 14695 | ZigType *result_type = get_error_set_union(ira->codegen, errors, op1_type, op2_type, instruction->type_name); | 14705 | ZigType *result_type = get_error_set_union(ira->codegen, errors, op1_type, op2_type, instruction->type_name); |
| 14696 | free(errors); | 14706 | deallocate(errors, errors_count, "ErrorTableEntry *"); |
| 14697 | 14707 | ||
| 14698 | return ir_const_type(ira, &instruction->base, result_type); | 14708 | return ir_const_type(ira, &instruction->base, result_type); |
| 14699 | } | 14709 | } |
| ... | @@ -24034,7 +24044,8 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, | ... | @@ -24034,7 +24044,8 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, |
| 24034 | return ira->codegen->invalid_instruction; | 24044 | return ira->codegen->invalid_instruction; |
| 24035 | } | 24045 | } |
| 24036 | 24046 | ||
| 24037 | AstNode **field_prev_uses = allocate<AstNode *>(ira->codegen->errors_by_index.length); | 24047 | size_t field_prev_uses_count = ira->codegen->errors_by_index.length; |
| 24048 | AstNode **field_prev_uses = allocate<AstNode *>(field_prev_uses_count, "AstNode *"); | ||
| 24038 | 24049 | ||
| 24039 | for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { | 24050 | for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { |
| 24040 | IrInstructionCheckSwitchProngsRange *range = &instruction->ranges[range_i]; | 24051 | IrInstructionCheckSwitchProngsRange *range = &instruction->ranges[range_i]; |
| ... | @@ -24091,7 +24102,7 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, | ... | @@ -24091,7 +24102,7 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, |
| 24091 | } | 24102 | } |
| 24092 | } | 24103 | } |
| 24093 | 24104 | ||
| 24094 | free(field_prev_uses); | 24105 | deallocate(field_prev_uses, field_prev_uses_count, "AstNode *"); |
| 24095 | } else if (switch_type->id == ZigTypeIdInt) { | 24106 | } else if (switch_type->id == ZigTypeIdInt) { |
| 24096 | RangeSet rs = {0}; | 24107 | RangeSet rs = {0}; |
| 24097 | for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { | 24108 | for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { |
| ... | @@ -26318,7 +26329,7 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ | ... | @@ -26318,7 +26329,7 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ |
| 26318 | } | 26329 | } |
| 26319 | 26330 | ||
| 26320 | if (ira->codegen->verbose_ir) { | 26331 | if (ira->codegen->verbose_ir) { |
| 26321 | fprintf(stderr, "analyze #%zu\n", old_instruction->debug_id); | 26332 | fprintf(stderr, "analyze #%" PRIu32 "\n", old_instruction->debug_id); |
| 26322 | } | 26333 | } |
| 26323 | IrInstruction *new_instruction = ir_analyze_instruction_base(ira, old_instruction); | 26334 | IrInstruction *new_instruction = ir_analyze_instruction_base(ira, old_instruction); |
| 26324 | if (new_instruction != nullptr) { | 26335 | if (new_instruction != nullptr) { |
src/ir_print.cpp+6-6| ... | @@ -38,8 +38,8 @@ struct IrPrint { | ... | @@ -38,8 +38,8 @@ struct IrPrint { |
| 38 | 38 | ||
| 39 | static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction); | 39 | static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction); |
| 40 | 40 | ||
| 41 | static const char* ir_instruction_type_str(IrInstruction* instruction) { | 41 | const char* ir_instruction_type_str(IrInstructionId id) { |
| 42 | switch (instruction->id) { | 42 | switch (id) { |
| 43 | case IrInstructionIdInvalid: | 43 | case IrInstructionIdInvalid: |
| 44 | return "Invalid"; | 44 | return "Invalid"; |
| 45 | case IrInstructionIdShuffleVector: | 45 | case IrInstructionIdShuffleVector: |
| ... | @@ -385,9 +385,9 @@ static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction, bool trail | ... | @@ -385,9 +385,9 @@ static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction, bool trail |
| 385 | const char mark = trailing ? ':' : '#'; | 385 | const char mark = trailing ? ':' : '#'; |
| 386 | const char *type_name = instruction->value.type ? buf_ptr(&instruction->value.type->name) : "(unknown)"; | 386 | const char *type_name = instruction->value.type ? buf_ptr(&instruction->value.type->name) : "(unknown)"; |
| 387 | const char *ref_count = ir_has_side_effects(instruction) ? | 387 | const char *ref_count = ir_has_side_effects(instruction) ? |
| 388 | "-" : buf_ptr(buf_sprintf("%" ZIG_PRI_usize "", instruction->ref_count)); | 388 | "-" : buf_ptr(buf_sprintf("%" PRIu32 "", instruction->ref_count)); |
| 389 | fprintf(irp->f, "%c%-3zu| %-22s| %-12s| %-2s| ", mark, instruction->debug_id, | 389 | fprintf(irp->f, "%c%-3" PRIu32 "| %-22s| %-12s| %-2s| ", mark, instruction->debug_id, |
| 390 | ir_instruction_type_str(instruction), type_name, ref_count); | 390 | ir_instruction_type_str(instruction->id), type_name, ref_count); |
| 391 | } | 391 | } |
| 392 | 392 | ||
| 393 | static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) { | 393 | static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) { |
| ... | @@ -398,7 +398,7 @@ static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) { | ... | @@ -398,7 +398,7 @@ static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) { |
| 398 | } | 398 | } |
| 399 | 399 | ||
| 400 | static void ir_print_var_instruction(IrPrint *irp, IrInstruction *instruction) { | 400 | static void ir_print_var_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 401 | fprintf(irp->f, "#%" ZIG_PRI_usize "", instruction->debug_id); | 401 | fprintf(irp->f, "#%" PRIu32 "", instruction->debug_id); |
| 402 | if (irp->pass != IrPassSrc && irp->printed.maybe_get(instruction) == nullptr) { | 402 | if (irp->pass != IrPassSrc && irp->printed.maybe_get(instruction) == nullptr) { |
| 403 | irp->printed.put(instruction, 0); | 403 | irp->printed.put(instruction, 0); |
| 404 | irp->pending.append(instruction); | 404 | irp->pending.append(instruction); |
src/ir_print.hpp+2| ... | @@ -15,4 +15,6 @@ | ... | @@ -15,4 +15,6 @@ |
| 15 | void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size, IrPass pass); | 15 | void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size, IrPass pass); |
| 16 | void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size, IrPass pass); | 16 | void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size, IrPass pass); |
| 17 | 17 | ||
| 18 | const char* ir_instruction_type_str(IrInstructionId id); | ||
| 19 | |||
| 18 | #endif | 20 | #endif |
src/main.cpp+52-23| ... | @@ -64,6 +64,9 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { | ... | @@ -64,6 +64,9 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { |
| 64 | " -fno-PIC disable Position Independent Code\n" | 64 | " -fno-PIC disable Position Independent Code\n" |
| 65 | " -ftime-report print timing diagnostics\n" | 65 | " -ftime-report print timing diagnostics\n" |
| 66 | " -fstack-report print stack size diagnostics\n" | 66 | " -fstack-report print stack size diagnostics\n" |
| 67 | #ifdef ZIG_ENABLE_MEM_PROFILE | ||
| 68 | " -fmem-report print memory usage diagnostics\n" | ||
| 69 | #endif | ||
| 67 | " -fdump-analysis write analysis.json file with type information\n" | 70 | " -fdump-analysis write analysis.json file with type information\n" |
| 68 | " -femit-docs create a docs/ dir with html documentation\n" | 71 | " -femit-docs create a docs/ dir with html documentation\n" |
| 69 | " -fno-emit-bin skip emitting machine code\n" | 72 | " -fno-emit-bin skip emitting machine code\n" |
| ... | @@ -306,9 +309,29 @@ static int zig_error_no_build_file(void) { | ... | @@ -306,9 +309,29 @@ static int zig_error_no_build_file(void) { |
| 306 | 309 | ||
| 307 | extern "C" int ZigClang_main(int argc, char **argv); | 310 | extern "C" int ZigClang_main(int argc, char **argv); |
| 308 | 311 | ||
| 312 | #ifdef ZIG_ENABLE_MEM_PROFILE | ||
| 313 | bool mem_report = false; | ||
| 314 | #endif | ||
| 315 | |||
| 316 | int main_exit(Stage2ProgressNode *root_progress_node, int exit_code) { | ||
| 317 | if (root_progress_node != nullptr) { | ||
| 318 | stage2_progress_end(root_progress_node); | ||
| 319 | } | ||
| 320 | #ifdef ZIG_ENABLE_MEM_PROFILE | ||
| 321 | if (mem_report) { | ||
| 322 | memprof_dump_stats(stderr); | ||
| 323 | } | ||
| 324 | #endif | ||
| 325 | return exit_code; | ||
| 326 | } | ||
| 327 | |||
| 309 | int main(int argc, char **argv) { | 328 | int main(int argc, char **argv) { |
| 310 | stage2_attach_segfault_handler(); | 329 | stage2_attach_segfault_handler(); |
| 311 | 330 | ||
| 331 | #ifdef ZIG_ENABLE_MEM_PROFILE | ||
| 332 | memprof_init(); | ||
| 333 | #endif | ||
| 334 | |||
| 312 | char *arg0 = argv[0]; | 335 | char *arg0 = argv[0]; |
| 313 | Error err; | 336 | Error err; |
| 314 | 337 | ||
| ... | @@ -670,6 +693,13 @@ int main(int argc, char **argv) { | ... | @@ -670,6 +693,13 @@ int main(int argc, char **argv) { |
| 670 | timing_info = true; | 693 | timing_info = true; |
| 671 | } else if (strcmp(arg, "-fstack-report") == 0) { | 694 | } else if (strcmp(arg, "-fstack-report") == 0) { |
| 672 | stack_report = true; | 695 | stack_report = true; |
| 696 | } else if (strcmp(arg, "-fmem-report") == 0) { | ||
| 697 | #ifdef ZIG_ENABLE_MEM_PROFILE | ||
| 698 | mem_report = true; | ||
| 699 | #else | ||
| 700 | fprintf(stderr, "-fmem-report requires configuring with -DZIG_ENABLE_MEM_PROFILE=ON\n"); | ||
| 701 | return print_error_usage(arg0); | ||
| 702 | #endif | ||
| 673 | } else if (strcmp(arg, "-fdump-analysis") == 0) { | 703 | } else if (strcmp(arg, "-fdump-analysis") == 0) { |
| 674 | enable_dump_analysis = true; | 704 | enable_dump_analysis = true; |
| 675 | } else if (strcmp(arg, "-femit-docs") == 0) { | 705 | } else if (strcmp(arg, "-femit-docs") == 0) { |
| ... | @@ -1038,16 +1068,14 @@ int main(int argc, char **argv) { | ... | @@ -1038,16 +1068,14 @@ int main(int argc, char **argv) { |
| 1038 | if (in_file) { | 1068 | if (in_file) { |
| 1039 | ZigLibCInstallation libc; | 1069 | ZigLibCInstallation libc; |
| 1040 | if ((err = zig_libc_parse(&libc, buf_create_from_str(in_file), &target, true))) | 1070 | if ((err = zig_libc_parse(&libc, buf_create_from_str(in_file), &target, true))) |
| 1041 | return EXIT_FAILURE; | 1071 | return main_exit(root_progress_node, EXIT_FAILURE); |
| 1042 | stage2_progress_end(root_progress_node); | 1072 | return main_exit(root_progress_node, EXIT_SUCCESS); |
| 1043 | return EXIT_SUCCESS; | ||
| 1044 | } | 1073 | } |
| 1045 | ZigLibCInstallation libc; | 1074 | ZigLibCInstallation libc; |
| 1046 | if ((err = zig_libc_find_native(&libc, true))) | 1075 | if ((err = zig_libc_find_native(&libc, true))) |
| 1047 | return EXIT_FAILURE; | 1076 | return main_exit(root_progress_node, EXIT_FAILURE); |
| 1048 | zig_libc_render(&libc, stdout); | 1077 | zig_libc_render(&libc, stdout); |
| 1049 | stage2_progress_end(root_progress_node); | 1078 | return main_exit(root_progress_node, EXIT_SUCCESS); |
| 1050 | return EXIT_SUCCESS; | ||
| 1051 | } | 1079 | } |
| 1052 | case CmdBuiltin: { | 1080 | case CmdBuiltin: { |
| 1053 | CodeGen *g = codegen_create(main_pkg_path, nullptr, &target, | 1081 | CodeGen *g = codegen_create(main_pkg_path, nullptr, &target, |
| ... | @@ -1065,10 +1093,9 @@ int main(int argc, char **argv) { | ... | @@ -1065,10 +1093,9 @@ int main(int argc, char **argv) { |
| 1065 | Buf *builtin_source = codegen_generate_builtin_source(g); | 1093 | Buf *builtin_source = codegen_generate_builtin_source(g); |
| 1066 | if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) { | 1094 | if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) { |
| 1067 | fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout))); | 1095 | fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout))); |
| 1068 | return EXIT_FAILURE; | 1096 | return main_exit(root_progress_node, EXIT_FAILURE); |
| 1069 | } | 1097 | } |
| 1070 | stage2_progress_end(root_progress_node); | 1098 | return main_exit(root_progress_node, EXIT_SUCCESS); |
| 1071 | return EXIT_SUCCESS; | ||
| 1072 | } | 1099 | } |
| 1073 | case CmdRun: | 1100 | case CmdRun: |
| 1074 | case CmdBuild: | 1101 | case CmdBuild: |
| ... | @@ -1142,7 +1169,7 @@ int main(int argc, char **argv) { | ... | @@ -1142,7 +1169,7 @@ int main(int argc, char **argv) { |
| 1142 | libc = allocate<ZigLibCInstallation>(1); | 1169 | libc = allocate<ZigLibCInstallation>(1); |
| 1143 | if ((err = zig_libc_parse(libc, buf_create_from_str(libc_txt), &target, true))) { | 1170 | if ((err = zig_libc_parse(libc, buf_create_from_str(libc_txt), &target, true))) { |
| 1144 | fprintf(stderr, "Unable to parse --libc text file: %s\n", err_str(err)); | 1171 | fprintf(stderr, "Unable to parse --libc text file: %s\n", err_str(err)); |
| 1145 | return EXIT_FAILURE; | 1172 | return main_exit(root_progress_node, EXIT_FAILURE); |
| 1146 | } | 1173 | } |
| 1147 | } | 1174 | } |
| 1148 | Buf *cache_dir_buf; | 1175 | Buf *cache_dir_buf; |
| ... | @@ -1219,7 +1246,7 @@ int main(int argc, char **argv) { | ... | @@ -1219,7 +1246,7 @@ int main(int argc, char **argv) { |
| 1219 | codegen_set_rdynamic(g, rdynamic); | 1246 | codegen_set_rdynamic(g, rdynamic); |
| 1220 | if (mmacosx_version_min && mios_version_min) { | 1247 | if (mmacosx_version_min && mios_version_min) { |
| 1221 | fprintf(stderr, "-mmacosx-version-min and -mios-version-min options not allowed together\n"); | 1248 | fprintf(stderr, "-mmacosx-version-min and -mios-version-min options not allowed together\n"); |
| 1222 | return EXIT_FAILURE; | 1249 | return main_exit(root_progress_node, EXIT_FAILURE); |
| 1223 | } | 1250 | } |
| 1224 | 1251 | ||
| 1225 | if (mmacosx_version_min) { | 1252 | if (mmacosx_version_min) { |
| ... | @@ -1259,6 +1286,11 @@ int main(int argc, char **argv) { | ... | @@ -1259,6 +1286,11 @@ int main(int argc, char **argv) { |
| 1259 | zig_print_stack_report(g, stdout); | 1286 | zig_print_stack_report(g, stdout); |
| 1260 | 1287 | ||
| 1261 | if (cmd == CmdRun) { | 1288 | if (cmd == CmdRun) { |
| 1289 | stage2_progress_end(root_progress_node); | ||
| 1290 | #ifdef ZIG_ENABLE_MEM_PROFILE | ||
| 1291 | memprof_dump_stats(stderr); | ||
| 1292 | #endif | ||
| 1293 | |||
| 1262 | const char *exec_path = buf_ptr(&g->output_file_path); | 1294 | const char *exec_path = buf_ptr(&g->output_file_path); |
| 1263 | ZigList<const char*> args = {0}; | 1295 | ZigList<const char*> args = {0}; |
| 1264 | 1296 | ||
| ... | @@ -1282,10 +1314,9 @@ int main(int argc, char **argv) { | ... | @@ -1282,10 +1314,9 @@ int main(int argc, char **argv) { |
| 1282 | buf_replace(&g->output_file_path, '/', '\\'); | 1314 | buf_replace(&g->output_file_path, '/', '\\'); |
| 1283 | #endif | 1315 | #endif |
| 1284 | if (printf("%s\n", buf_ptr(&g->output_file_path)) < 0) | 1316 | if (printf("%s\n", buf_ptr(&g->output_file_path)) < 0) |
| 1285 | return EXIT_FAILURE; | 1317 | return main_exit(root_progress_node, EXIT_FAILURE); |
| 1286 | } | 1318 | } |
| 1287 | stage2_progress_end(root_progress_node); | 1319 | return main_exit(root_progress_node, EXIT_SUCCESS); |
| 1288 | return EXIT_SUCCESS; | ||
| 1289 | } else { | 1320 | } else { |
| 1290 | zig_unreachable(); | 1321 | zig_unreachable(); |
| 1291 | } | 1322 | } |
| ... | @@ -1293,8 +1324,7 @@ int main(int argc, char **argv) { | ... | @@ -1293,8 +1324,7 @@ int main(int argc, char **argv) { |
| 1293 | codegen_translate_c(g, in_file_buf, stdout, cmd == CmdTranslateCUserland); | 1324 | codegen_translate_c(g, in_file_buf, stdout, cmd == CmdTranslateCUserland); |
| 1294 | if (timing_info) | 1325 | if (timing_info) |
| 1295 | codegen_print_timing_report(g, stderr); | 1326 | codegen_print_timing_report(g, stderr); |
| 1296 | stage2_progress_end(root_progress_node); | 1327 | return main_exit(root_progress_node, EXIT_SUCCESS); |
| 1297 | return EXIT_SUCCESS; | ||
| 1298 | } else if (cmd == CmdTest) { | 1328 | } else if (cmd == CmdTest) { |
| 1299 | codegen_set_emit_file_type(g, emit_file_type); | 1329 | codegen_set_emit_file_type(g, emit_file_type); |
| 1300 | 1330 | ||
| ... | @@ -1314,7 +1344,7 @@ int main(int argc, char **argv) { | ... | @@ -1314,7 +1344,7 @@ int main(int argc, char **argv) { |
| 1314 | 1344 | ||
| 1315 | if (g->disable_bin_generation) { | 1345 | if (g->disable_bin_generation) { |
| 1316 | fprintf(stderr, "Semantic analysis complete. No binary produced due to -fno-emit-bin.\n"); | 1346 | fprintf(stderr, "Semantic analysis complete. No binary produced due to -fno-emit-bin.\n"); |
| 1317 | return 0; | 1347 | return main_exit(root_progress_node, EXIT_SUCCESS); |
| 1318 | } | 1348 | } |
| 1319 | 1349 | ||
| 1320 | Buf *test_exe_path_unresolved = &g->output_file_path; | 1350 | Buf *test_exe_path_unresolved = &g->output_file_path; |
| ... | @@ -1324,7 +1354,7 @@ int main(int argc, char **argv) { | ... | @@ -1324,7 +1354,7 @@ int main(int argc, char **argv) { |
| 1324 | if (emit_file_type != EmitFileTypeBinary) { | 1354 | if (emit_file_type != EmitFileTypeBinary) { |
| 1325 | fprintf(stderr, "Created %s but skipping execution because it is non executable.\n", | 1355 | fprintf(stderr, "Created %s but skipping execution because it is non executable.\n", |
| 1326 | buf_ptr(test_exe_path)); | 1356 | buf_ptr(test_exe_path)); |
| 1327 | return 0; | 1357 | return main_exit(root_progress_node, EXIT_SUCCESS); |
| 1328 | } | 1358 | } |
| 1329 | 1359 | ||
| 1330 | for (size_t i = 0; i < test_exec_args.length; i += 1) { | 1360 | for (size_t i = 0; i < test_exec_args.length; i += 1) { |
| ... | @@ -1336,7 +1366,7 @@ int main(int argc, char **argv) { | ... | @@ -1336,7 +1366,7 @@ int main(int argc, char **argv) { |
| 1336 | if (!target_can_exec(&native, &target) && test_exec_args.length == 0) { | 1366 | if (!target_can_exec(&native, &target) && test_exec_args.length == 0) { |
| 1337 | fprintf(stderr, "Created %s but skipping execution because it is non-native.\n", | 1367 | fprintf(stderr, "Created %s but skipping execution because it is non-native.\n", |
| 1338 | buf_ptr(test_exe_path)); | 1368 | buf_ptr(test_exe_path)); |
| 1339 | return 0; | 1369 | return main_exit(root_progress_node, EXIT_SUCCESS); |
| 1340 | } | 1370 | } |
| 1341 | 1371 | ||
| 1342 | Termination term; | 1372 | Termination term; |
| ... | @@ -1348,21 +1378,20 @@ int main(int argc, char **argv) { | ... | @@ -1348,21 +1378,20 @@ int main(int argc, char **argv) { |
| 1348 | fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n"); | 1378 | fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n"); |
| 1349 | fprintf(stderr, "%s\n", buf_ptr(test_exe_path)); | 1379 | fprintf(stderr, "%s\n", buf_ptr(test_exe_path)); |
| 1350 | } | 1380 | } |
| 1351 | stage2_progress_end(root_progress_node); | 1381 | return main_exit(root_progress_node, (term.how == TerminationIdClean) ? term.code : -1); |
| 1352 | return (term.how == TerminationIdClean) ? term.code : -1; | ||
| 1353 | } else { | 1382 | } else { |
| 1354 | zig_unreachable(); | 1383 | zig_unreachable(); |
| 1355 | } | 1384 | } |
| 1356 | } | 1385 | } |
| 1357 | case CmdVersion: | 1386 | case CmdVersion: |
| 1358 | printf("%s\n", ZIG_VERSION_STRING); | 1387 | printf("%s\n", ZIG_VERSION_STRING); |
| 1359 | return EXIT_SUCCESS; | 1388 | return main_exit(root_progress_node, EXIT_SUCCESS); |
| 1360 | case CmdZen: { | 1389 | case CmdZen: { |
| 1361 | const char *ptr; | 1390 | const char *ptr; |
| 1362 | size_t len; | 1391 | size_t len; |
| 1363 | stage2_zen(&ptr, &len); | 1392 | stage2_zen(&ptr, &len); |
| 1364 | fwrite(ptr, len, 1, stdout); | 1393 | fwrite(ptr, len, 1, stdout); |
| 1365 | return EXIT_SUCCESS; | 1394 | return main_exit(root_progress_node, EXIT_SUCCESS); |
| 1366 | } | 1395 | } |
| 1367 | case CmdTargets: | 1396 | case CmdTargets: |
| 1368 | return print_target_list(stdout); | 1397 | return print_target_list(stdout); |
src/memory_profiling.cpp created+139| ... | @@ -0,0 +1,139 @@ | ||
| 1 | #include "memory_profiling.hpp" | ||
| 2 | #include "hash_map.hpp" | ||
| 3 | #include "list.hpp" | ||
| 4 | #include "util.hpp" | ||
| 5 | #include <string.h> | ||
| 6 | |||
| 7 | #ifdef ZIG_ENABLE_MEM_PROFILE | ||
| 8 | |||
| 9 | static bool str_eql_str(const char *a, const char *b) { | ||
| 10 | return strcmp(a, b) == 0; | ||
| 11 | } | ||
| 12 | |||
| 13 | static uint32_t str_hash(const char *s) { | ||
| 14 | // FNV 32-bit hash | ||
| 15 | uint32_t h = 2166136261; | ||
| 16 | for (; *s; s += 1) { | ||
| 17 | h = h ^ *s; | ||
| 18 | h = h * 16777619; | ||
| 19 | } | ||
| 20 | return h; | ||
| 21 | } | ||
| 22 | |||
| 23 | struct CountAndSize { | ||
| 24 | size_t item_count; | ||
| 25 | size_t type_size; | ||
| 26 | }; | ||
| 27 | |||
| 28 | ZigList<const char *> unknown_names = {}; | ||
| 29 | HashMap<const char *, CountAndSize, str_hash, str_eql_str> usage_table = {}; | ||
| 30 | bool table_active = false; | ||
| 31 | |||
| 32 | |||
| 33 | static const char *get_default_name(const char *name_or_null, size_t type_size) { | ||
| 34 | if (name_or_null != nullptr) return name_or_null; | ||
| 35 | if (type_size >= unknown_names.length) { | ||
| 36 | table_active = false; | ||
| 37 | unknown_names.resize(type_size + 1); | ||
| 38 | table_active = true; | ||
| 39 | } | ||
| 40 | if (unknown_names.at(type_size) == nullptr) { | ||
| 41 | char buf[100]; | ||
| 42 | sprintf(buf, "Unknown_%zu%c", type_size, 0); | ||
| 43 | unknown_names.at(type_size) = strdup(buf); | ||
| 44 | } | ||
| 45 | return unknown_names.at(type_size); | ||
| 46 | } | ||
| 47 | |||
| 48 | void memprof_alloc(const char *name, size_t count, size_t type_size) { | ||
| 49 | if (!table_active) return; | ||
| 50 | if (count == 0) return; | ||
| 51 | // temporarily disable during table put | ||
| 52 | table_active = false; | ||
| 53 | name = get_default_name(name, type_size); | ||
| 54 | auto existing_entry = usage_table.put_unique(name, {count, type_size}); | ||
| 55 | if (existing_entry != nullptr) { | ||
| 56 | assert(existing_entry->value.type_size == type_size); // allocated name does not match type | ||
| 57 | existing_entry->value.item_count += count; | ||
| 58 | } | ||
| 59 | table_active = true; | ||
| 60 | } | ||
| 61 | |||
| 62 | void memprof_dealloc(const char *name, size_t count, size_t type_size) { | ||
| 63 | if (!table_active) return; | ||
| 64 | if (count == 0) return; | ||
| 65 | name = get_default_name(name, type_size); | ||
| 66 | auto existing_entry = usage_table.maybe_get(name); | ||
| 67 | if (existing_entry == nullptr) { | ||
| 68 | zig_panic("deallocated more than allocated; compromised memory usage stats"); | ||
| 69 | } | ||
| 70 | if (existing_entry->value.type_size != type_size) { | ||
| 71 | zig_panic("deallocated name '%s' does not match expected type size %zu", name, type_size); | ||
| 72 | } | ||
| 73 | existing_entry->value.item_count -= count; | ||
| 74 | } | ||
| 75 | |||
| 76 | void memprof_init(void) { | ||
| 77 | usage_table.init(1024); | ||
| 78 | table_active = true; | ||
| 79 | } | ||
| 80 | |||
| 81 | struct MemItem { | ||
| 82 | const char *type_name; | ||
| 83 | CountAndSize count_and_size; | ||
| 84 | }; | ||
| 85 | |||
| 86 | static size_t get_bytes(const MemItem *item) { | ||
| 87 | return item->count_and_size.item_count * item->count_and_size.type_size; | ||
| 88 | } | ||
| 89 | |||
| 90 | static int compare_bytes_desc(const void *a, const void *b) { | ||
| 91 | size_t size_a = get_bytes((const MemItem *)(a)); | ||
| 92 | size_t size_b = get_bytes((const MemItem *)(b)); | ||
| 93 | if (size_a > size_b) | ||
| 94 | return -1; | ||
| 95 | if (size_a < size_b) | ||
| 96 | return 1; | ||
| 97 | return 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | void memprof_dump_stats(FILE *file) { | ||
| 101 | assert(table_active); | ||
| 102 | // disable modifications from this function | ||
| 103 | table_active = false; | ||
| 104 | |||
| 105 | ZigList<MemItem> list = {}; | ||
| 106 | |||
| 107 | auto it = usage_table.entry_iterator(); | ||
| 108 | for (;;) { | ||
| 109 | auto *entry = it.next(); | ||
| 110 | if (!entry) | ||
| 111 | break; | ||
| 112 | |||
| 113 | list.append({entry->key, entry->value}); | ||
| 114 | } | ||
| 115 | |||
| 116 | qsort(list.items, list.length, sizeof(MemItem), compare_bytes_desc); | ||
| 117 | |||
| 118 | size_t total_bytes_used = 0; | ||
| 119 | |||
| 120 | for (size_t i = 0; i < list.length; i += 1) { | ||
| 121 | const MemItem *item = &list.at(i); | ||
| 122 | fprintf(file, "%s: %zu items, %zu bytes each, total ", item->type_name, | ||
| 123 | item->count_and_size.item_count, item->count_and_size.type_size); | ||
| 124 | size_t bytes = get_bytes(item); | ||
| 125 | zig_pretty_print_bytes(file, bytes); | ||
| 126 | fprintf(file, "\n"); | ||
| 127 | |||
| 128 | total_bytes_used += bytes; | ||
| 129 | } | ||
| 130 | |||
| 131 | fprintf(stderr, "Total bytes used: "); | ||
| 132 | zig_pretty_print_bytes(file, total_bytes_used); | ||
| 133 | fprintf(file, "\n"); | ||
| 134 | |||
| 135 | list.deinit(); | ||
| 136 | table_active = true; | ||
| 137 | } | ||
| 138 | |||
| 139 | #endif | ||
src/memory_profiling.hpp created+22| ... | @@ -0,0 +1,22 @@ | ||
| 1 | /* | ||
| 2 | * Copyright (c) 2019 Andrew Kelley | ||
| 3 | * | ||
| 4 | * This file is part of zig, which is MIT licensed. | ||
| 5 | * See http://opensource.org/licenses/MIT | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef ZIG_MEMORY_PROFILING_HPP | ||
| 9 | #define ZIG_MEMORY_PROFILING_HPP | ||
| 10 | |||
| 11 | #include "config.h" | ||
| 12 | |||
| 13 | #include <stddef.h> | ||
| 14 | #include <stdio.h> | ||
| 15 | |||
| 16 | void memprof_init(void); | ||
| 17 | |||
| 18 | void memprof_alloc(const char *name, size_t item_count, size_t type_size); | ||
| 19 | void memprof_dealloc(const char *name, size_t item_count, size_t type_size); | ||
| 20 | |||
| 21 | void memprof_dump_stats(FILE *file); | ||
| 22 | #endif | ||
src/util.cpp+18| ... | @@ -119,3 +119,21 @@ Slice<uint8_t> SplitIterator_rest(SplitIterator *self) { | ... | @@ -119,3 +119,21 @@ Slice<uint8_t> SplitIterator_rest(SplitIterator *self) { |
| 119 | SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes) { | 119 | SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes) { |
| 120 | return SplitIterator{0, buffer, split_bytes}; | 120 | return SplitIterator{0, buffer, split_bytes}; |
| 121 | } | 121 | } |
| 122 | |||
| 123 | void zig_pretty_print_bytes(FILE *f, double n) { | ||
| 124 | if (n > 1024.0 * 1024.0 * 1024.0) { | ||
| 125 | fprintf(f, "%.02f GiB", n / 1024.0 / 1024.0 / 1024.0); | ||
| 126 | return; | ||
| 127 | } | ||
| 128 | if (n > 1024.0 * 1024.0) { | ||
| 129 | fprintf(f, "%.02f MiB", n / 1024.0 / 1024.0); | ||
| 130 | return; | ||
| 131 | } | ||
| 132 | if (n > 1024.0) { | ||
| 133 | fprintf(f, "%.02f KiB", n / 1024.0); | ||
| 134 | return; | ||
| 135 | } | ||
| 136 | fprintf(f, "%.02f bytes", n ); | ||
| 137 | return; | ||
| 138 | } | ||
| 139 |
src/util.hpp+31-4| ... | @@ -8,6 +8,8 @@ | ... | @@ -8,6 +8,8 @@ |
| 8 | #ifndef ZIG_UTIL_HPP | 8 | #ifndef ZIG_UTIL_HPP |
| 9 | #define ZIG_UTIL_HPP | 9 | #define ZIG_UTIL_HPP |
| 10 | 10 | ||
| 11 | #include "memory_profiling.hpp" | ||
| 12 | |||
| 11 | #include <stdlib.h> | 13 | #include <stdlib.h> |
| 12 | #include <stdint.h> | 14 | #include <stdint.h> |
| 13 | #include <string.h> | 15 | #include <string.h> |
| ... | @@ -96,7 +98,10 @@ static inline int ctzll(unsigned long long mask) { | ... | @@ -96,7 +98,10 @@ static inline int ctzll(unsigned long long mask) { |
| 96 | 98 | ||
| 97 | 99 | ||
| 98 | template<typename T> | 100 | template<typename T> |
| 99 | ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate_nonzero(size_t count) { | 101 | ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate_nonzero(size_t count, const char *name = nullptr) { |
| 102 | #ifdef ZIG_ENABLE_MEM_PROFILE | ||
| 103 | memprof_alloc(name, count, sizeof(T)); | ||
| 104 | #endif | ||
| 100 | #ifndef NDEBUG | 105 | #ifndef NDEBUG |
| 101 | // make behavior when size == 0 portable | 106 | // make behavior when size == 0 portable |
| 102 | if (count == 0) | 107 | if (count == 0) |
| ... | @@ -109,7 +114,10 @@ ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate_nonzero(size_t count) { | ... | @@ -109,7 +114,10 @@ ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate_nonzero(size_t count) { |
| 109 | } | 114 | } |
| 110 | 115 | ||
| 111 | template<typename T> | 116 | template<typename T> |
| 112 | ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate(size_t count) { | 117 | ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate(size_t count, const char *name = nullptr) { |
| 118 | #ifdef ZIG_ENABLE_MEM_PROFILE | ||
| 119 | memprof_alloc(name, count, sizeof(T)); | ||
| 120 | #endif | ||
| 113 | #ifndef NDEBUG | 121 | #ifndef NDEBUG |
| 114 | // make behavior when size == 0 portable | 122 | // make behavior when size == 0 portable |
| 115 | if (count == 0) | 123 | if (count == 0) |
| ... | @@ -122,7 +130,7 @@ ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate(size_t count) { | ... | @@ -122,7 +130,7 @@ ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate(size_t count) { |
| 122 | } | 130 | } |
| 123 | 131 | ||
| 124 | template<typename T> | 132 | template<typename T> |
| 125 | static inline T *reallocate(T *old, size_t old_count, size_t new_count) { | 133 | static inline T *reallocate(T *old, size_t old_count, size_t new_count, const char *name = nullptr) { |
| 126 | T *ptr = reallocate_nonzero(old, old_count, new_count); | 134 | T *ptr = reallocate_nonzero(old, old_count, new_count); |
| 127 | if (new_count > old_count) { | 135 | if (new_count > old_count) { |
| 128 | memset(&ptr[old_count], 0, (new_count - old_count) * sizeof(T)); | 136 | memset(&ptr[old_count], 0, (new_count - old_count) * sizeof(T)); |
| ... | @@ -131,7 +139,11 @@ static inline T *reallocate(T *old, size_t old_count, size_t new_count) { | ... | @@ -131,7 +139,11 @@ static inline T *reallocate(T *old, size_t old_count, size_t new_count) { |
| 131 | } | 139 | } |
| 132 | 140 | ||
| 133 | template<typename T> | 141 | template<typename T> |
| 134 | static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count) { | 142 | static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count, const char *name = nullptr) { |
| 143 | #ifdef ZIG_ENABLE_MEM_PROFILE | ||
| 144 | memprof_dealloc(name, old_count, sizeof(T)); | ||
| 145 | memprof_alloc(name, new_count, sizeof(T)); | ||
| 146 | #endif | ||
| 135 | #ifndef NDEBUG | 147 | #ifndef NDEBUG |
| 136 | // make behavior when size == 0 portable | 148 | // make behavior when size == 0 portable |
| 137 | if (new_count == 0 && old == nullptr) | 149 | if (new_count == 0 && old == nullptr) |
| ... | @@ -143,6 +155,19 @@ static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count) | ... | @@ -143,6 +155,19 @@ static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count) |
| 143 | return ptr; | 155 | return ptr; |
| 144 | } | 156 | } |
| 145 | 157 | ||
| 158 | template<typename T> | ||
| 159 | static inline void deallocate(T *old, size_t count, const char *name = nullptr) { | ||
| 160 | #ifdef ZIG_ENABLE_MEM_PROFILE | ||
| 161 | memprof_dealloc(name, count, sizeof(T)); | ||
| 162 | #endif | ||
| 163 | free(old); | ||
| 164 | } | ||
| 165 | |||
| 166 | template<typename T> | ||
| 167 | static inline void destroy(T *old, const char *name = nullptr) { | ||
| 168 | return deallocate(old, 1); | ||
| 169 | } | ||
| 170 | |||
| 146 | template <typename T, size_t n> | 171 | template <typename T, size_t n> |
| 147 | constexpr size_t array_length(const T (&)[n]) { | 172 | constexpr size_t array_length(const T (&)[n]) { |
| 148 | return n; | 173 | return n; |
| ... | @@ -225,6 +250,8 @@ static inline double zig_f16_to_double(float16_t x) { | ... | @@ -225,6 +250,8 @@ static inline double zig_f16_to_double(float16_t x) { |
| 225 | return z; | 250 | return z; |
| 226 | } | 251 | } |
| 227 | 252 | ||
| 253 | void zig_pretty_print_bytes(FILE *f, double n); | ||
| 254 | |||
| 228 | template<typename T> | 255 | template<typename T> |
| 229 | struct Optional { | 256 | struct Optional { |
| 230 | T value; | 257 | T value; |