| ... | ... | @@ -474,6 +474,31 @@ static void clear_debug_source_node(CodeGen *g) { |
| 474 | 474 | ZigLLVMClearCurrentDebugLocation(g->builder); |
| 475 | 475 | } |
| 476 | 476 | |
| 477 | struct BuilderState { |
| 478 | LLVMValueRef debug_loc; |
| 479 | LLVMBasicBlockRef basic_block; |
| 480 | bool is_clear; |
| 481 | }; |
| 482 | |
| 483 | static BuilderState save_and_clear_builder_state(CodeGen *g) { |
| 484 | BuilderState prev_state; |
| 485 | prev_state.debug_loc = LLVMGetCurrentDebugLocation(g->builder); |
| 486 | prev_state.basic_block = LLVMGetInsertBlock(g->builder); |
| 487 | prev_state.is_clear = g->dbg_clear; |
| 488 | |
| 489 | ZigLLVMClearCurrentDebugLocation(g->builder); |
| 490 | g->dbg_clear = true; |
| 491 | |
| 492 | return prev_state; |
| 493 | } |
| 494 | |
| 495 | static void restore_builder_state(CodeGen *g, const BuilderState &prev_state) { |
| 496 | LLVMPositionBuilderAtEnd(g->builder, prev_state.basic_block); |
| 497 | if (!prev_state.is_clear) |
| 498 | LLVMSetCurrentDebugLocation(g->builder, prev_state.debug_loc); |
| 499 | g->dbg_clear = prev_state.is_clear; |
| 500 | } |
| 501 | |
| 477 | 502 | static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, TypeTableEntry *type_entry, |
| 478 | 503 | const char *signed_name, const char *unsigned_name) |
| 479 | 504 | { |
| ... | ... | @@ -662,9 +687,8 @@ static LLVMValueRef get_panic_slice_fn(CodeGen *g) { |
| 662 | 687 | LLVMSetLinkage(fn_val, LLVMInternalLinkage); |
| 663 | 688 | LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv); |
| 664 | 689 | |
| 690 | auto prev_state = save_and_clear_builder_state(g); |
| 665 | 691 | LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); |
| 666 | | LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); |
| 667 | | LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); |
| 668 | 692 | LLVMPositionBuilderAtEnd(g->builder, entry_block); |
| 669 | 693 | |
| 670 | 694 | LLVMValueRef msg_arg = LLVMGetParam(fn_val, 0); |
| ... | ... | @@ -678,8 +702,7 @@ static LLVMValueRef get_panic_slice_fn(CodeGen *g) { |
| 678 | 702 | LLVMValueRef msg_len = LLVMBuildLoad(g->builder, len_ptr, ""); |
| 679 | 703 | gen_panic_raw(g, msg_ptr, msg_len); |
| 680 | 704 | |
| 681 | | LLVMPositionBuilderAtEnd(g->builder, prev_block); |
| 682 | | LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); |
| 705 | restore_builder_state(g, prev_state); |
| 683 | 706 | g->panic_slice_fn = fn_val; |
| 684 | 707 | return g->panic_slice_fn; |
| 685 | 708 | } |
| ... | ... | @@ -744,11 +767,9 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 744 | 767 | LLVMSetLinkage(fn_val, LLVMInternalLinkage); |
| 745 | 768 | LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv); |
| 746 | 769 | |
| 770 | auto prev_state = save_and_clear_builder_state(g); |
| 747 | 771 | LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); |
| 748 | | LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); |
| 749 | | LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); |
| 750 | 772 | LLVMPositionBuilderAtEnd(g->builder, entry_block); |
| 751 | | ZigLLVMClearCurrentDebugLocation(g->builder); |
| 752 | 773 | |
| 753 | 774 | LLVMValueRef err_val = LLVMGetParam(fn_val, 0); |
| 754 | 775 | |
| ... | ... | @@ -779,8 +800,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 779 | 800 | |
| 780 | 801 | gen_panic_raw(g, full_buf_ptr, full_buf_len); |
| 781 | 802 | |
| 782 | | LLVMPositionBuilderAtEnd(g->builder, prev_block); |
| 783 | | LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); |
| 803 | restore_builder_state(g, prev_state); |
| 784 | 804 | |
| 785 | 805 | g->safety_crash_err_fn = fn_val; |
| 786 | 806 | return fn_val; |
| ... | ... | @@ -905,26 +925,74 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_debug_safety, Typ |
| 905 | 925 | } |
| 906 | 926 | } |
| 907 | 927 | |
| 908 | | static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddSubMul op, |
| 909 | | LLVMValueRef val1, LLVMValueRef val2) |
| 910 | | { |
| 911 | | LLVMValueRef fn_val = get_int_overflow_fn(g, type_entry, op); |
| 928 | static const char *add_sub_mul_name(AddSubMul op) { |
| 929 | switch (op) { |
| 930 | case AddSubMulAdd: return "add"; |
| 931 | case AddSubMulSub: return "sub"; |
| 932 | case AddSubMulMul: return "mul"; |
| 933 | } |
| 934 | zig_unreachable(); |
| 935 | } |
| 936 | static LLVMValueRef get_int_overflow_panic_fn(CodeGen *g, TypeTableEntry *type_entry, AddSubMul op) { |
| 937 | ZigLLVMFnKey key = {}; |
| 938 | key.id = ZigLLVMFnIdOverflowArithmeticPanic; |
| 939 | key.data.overflow_arithmetic.is_signed = type_entry->data.integral.is_signed; |
| 940 | key.data.overflow_arithmetic.add_sub_mul = op; |
| 941 | key.data.overflow_arithmetic.bit_count = (uint32_t)type_entry->data.integral.bit_count; |
| 942 | |
| 943 | auto existing_entry = g->llvm_fn_table.maybe_get(key); |
| 944 | if (existing_entry) |
| 945 | return existing_entry->value; |
| 946 | |
| 947 | Buf *desired_name = buf_sprintf("__zig_checked_%s_%c%" PRIu32, add_sub_mul_name(op), |
| 948 | type_entry->data.integral.is_signed ? 'i' : 'u', type_entry->data.integral.bit_count); |
| 949 | Buf *fn_name = get_mangled_name(g, desired_name, false); |
| 950 | LLVMTypeRef arg_types[] = { type_entry->type_ref, type_entry->type_ref }; |
| 951 | LLVMTypeRef fn_type_ref = LLVMFunctionType(type_entry->type_ref, arg_types, 2, false); |
| 952 | LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); |
| 953 | LLVMSetLinkage(fn_val, LLVMInternalLinkage); |
| 954 | LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv); |
| 955 | |
| 956 | auto prev_state = save_and_clear_builder_state(g); |
| 957 | |
| 958 | LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); |
| 959 | LLVMPositionBuilderAtEnd(g->builder, entry_block); |
| 960 | |
| 961 | LLVMValueRef val1 = LLVMGetParam(fn_val, 0); |
| 962 | LLVMValueRef val2 = LLVMGetParam(fn_val, 1); |
| 963 | |
| 964 | LLVMValueRef overflow_fn_val = get_int_overflow_fn(g, type_entry, op); |
| 912 | 965 | LLVMValueRef params[] = { |
| 913 | 966 | val1, |
| 914 | 967 | val2, |
| 915 | 968 | }; |
| 916 | | LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, ""); |
| 917 | | LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, ""); |
| 969 | LLVMValueRef result_struct = LLVMBuildCall(g->builder, overflow_fn_val, params, 2, ""); |
| 918 | 970 | LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, ""); |
| 919 | | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail"); |
| 920 | | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk"); |
| 971 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(fn_val, "OverflowFail"); |
| 972 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(fn_val, "OverflowOk"); |
| 921 | 973 | LLVMBuildCondBr(g->builder, overflow_bit, fail_block, ok_block); |
| 922 | 974 | |
| 923 | 975 | LLVMPositionBuilderAtEnd(g->builder, fail_block); |
| 924 | 976 | gen_debug_safety_crash(g, PanicMsgIdIntegerOverflow); |
| 925 | 977 | |
| 926 | 978 | LLVMPositionBuilderAtEnd(g->builder, ok_block); |
| 927 | | return result; |
| 979 | LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, ""); |
| 980 | LLVMBuildRet(g->builder, result); |
| 981 | |
| 982 | restore_builder_state(g, prev_state); |
| 983 | g->llvm_fn_table.put(key, fn_val); |
| 984 | return fn_val; |
| 985 | } |
| 986 | |
| 987 | static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddSubMul op, |
| 988 | LLVMValueRef val1, LLVMValueRef val2) |
| 989 | { |
| 990 | LLVMValueRef fn_val = get_int_overflow_panic_fn(g, type_entry, op); |
| 991 | LLVMValueRef params[] = { |
| 992 | val1, |
| 993 | val2, |
| 994 | }; |
| 995 | return LLVMBuildCall(g->builder, fn_val, params, 2, ""); |
| 928 | 996 | } |
| 929 | 997 | |
| 930 | 998 | static LLVMIntPredicate cmp_op_to_int_predicate(IrBinOp cmp_op, bool is_signed) { |
| ... | ... | @@ -2882,6 +2950,7 @@ static void set_debug_location(CodeGen *g, IrInstruction *instruction) { |
| 2882 | 2950 | |
| 2883 | 2951 | ZigLLVMSetCurrentDebugLocation(g->builder, (int)source_node->line + 1, |
| 2884 | 2952 | (int)source_node->column + 1, get_di_scope(g, scope)); |
| 2953 | g->dbg_clear = false; |
| 2885 | 2954 | } |
| 2886 | 2955 | |
| 2887 | 2956 | static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) { |