| ... | ... | @@ -474,31 +474,6 @@ 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 | | |
| 502 | 477 | static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, TypeTableEntry *type_entry, |
| 503 | 478 | const char *signed_name, const char *unsigned_name) |
| 504 | 479 | { |
| ... | ... | @@ -672,27 +647,8 @@ static void gen_panic_raw(CodeGen *g, LLVMValueRef msg_ptr, LLVMValueRef msg_len |
| 672 | 647 | LLVMBuildUnreachable(g->builder); |
| 673 | 648 | } |
| 674 | 649 | |
| 675 | | static LLVMValueRef get_panic_slice_fn(CodeGen *g) { |
| 676 | | if (g->panic_slice_fn != nullptr) |
| 677 | | return g->panic_slice_fn; |
| 678 | | |
| 650 | static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) { |
| 679 | 651 | TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true); |
| 680 | | TypeTableEntry *ptr_to_str_type = get_pointer_to_type(g, str_type, true); |
| 681 | | |
| 682 | | Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_panic_slice"), false); |
| 683 | | LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), &ptr_to_str_type->type_ref, 1, false); |
| 684 | | LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); |
| 685 | | addLLVMFnAttr(fn_val, "noreturn"); |
| 686 | | addLLVMFnAttr(fn_val, "cold"); |
| 687 | | LLVMSetLinkage(fn_val, LLVMInternalLinkage); |
| 688 | | LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv); |
| 689 | | |
| 690 | | auto prev_state = save_and_clear_builder_state(g); |
| 691 | | LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); |
| 692 | | LLVMPositionBuilderAtEnd(g->builder, entry_block); |
| 693 | | |
| 694 | | LLVMValueRef msg_arg = LLVMGetParam(fn_val, 0); |
| 695 | | |
| 696 | 652 | size_t ptr_index = str_type->data.structure.fields[slice_ptr_index].gen_index; |
| 697 | 653 | size_t len_index = str_type->data.structure.fields[slice_len_index].gen_index; |
| 698 | 654 | LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, msg_arg, (unsigned)ptr_index, ""); |
| ... | ... | @@ -701,16 +657,6 @@ static LLVMValueRef get_panic_slice_fn(CodeGen *g) { |
| 701 | 657 | LLVMValueRef msg_ptr = LLVMBuildLoad(g->builder, ptr_ptr, ""); |
| 702 | 658 | LLVMValueRef msg_len = LLVMBuildLoad(g->builder, len_ptr, ""); |
| 703 | 659 | gen_panic_raw(g, msg_ptr, msg_len); |
| 704 | | |
| 705 | | restore_builder_state(g, prev_state); |
| 706 | | g->panic_slice_fn = fn_val; |
| 707 | | return g->panic_slice_fn; |
| 708 | | } |
| 709 | | |
| 710 | | static void gen_panic(CodeGen *g, LLVMValueRef msg_arg) { |
| 711 | | LLVMValueRef fn_val = get_panic_slice_fn(g); |
| 712 | | LLVMBuildCall(g->builder, fn_val, &msg_arg, 1, ""); |
| 713 | | LLVMBuildUnreachable(g->builder); |
| 714 | 660 | } |
| 715 | 661 | |
| 716 | 662 | static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) { |
| ... | ... | @@ -767,9 +713,11 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 767 | 713 | LLVMSetLinkage(fn_val, LLVMInternalLinkage); |
| 768 | 714 | LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv); |
| 769 | 715 | |
| 770 | | auto prev_state = save_and_clear_builder_state(g); |
| 771 | 716 | LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); |
| 717 | LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); |
| 718 | LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); |
| 772 | 719 | LLVMPositionBuilderAtEnd(g->builder, entry_block); |
| 720 | ZigLLVMClearCurrentDebugLocation(g->builder); |
| 773 | 721 | |
| 774 | 722 | LLVMValueRef err_val = LLVMGetParam(fn_val, 0); |
| 775 | 723 | |
| ... | ... | @@ -800,7 +748,8 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 800 | 748 | |
| 801 | 749 | gen_panic_raw(g, full_buf_ptr, full_buf_len); |
| 802 | 750 | |
| 803 | | restore_builder_state(g, prev_state); |
| 751 | LLVMPositionBuilderAtEnd(g->builder, prev_block); |
| 752 | LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); |
| 804 | 753 | |
| 805 | 754 | g->safety_crash_err_fn = fn_val; |
| 806 | 755 | return fn_val; |
| ... | ... | @@ -812,102 +761,37 @@ static void gen_debug_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val) { |
| 812 | 761 | LLVMBuildUnreachable(g->builder); |
| 813 | 762 | } |
| 814 | 763 | |
| 815 | | static const char *pred_name(LLVMIntPredicate pred) { |
| 816 | | switch (pred) { |
| 817 | | case LLVMIntEQ: return "eq"; |
| 818 | | case LLVMIntNE: return "ne"; |
| 819 | | case LLVMIntULT: return "lt"; |
| 820 | | case LLVMIntULE: return "le"; |
| 821 | | default: |
| 822 | | zig_unreachable(); |
| 764 | static void add_bounds_check(CodeGen *g, LLVMValueRef target_val, |
| 765 | LLVMIntPredicate lower_pred, LLVMValueRef lower_value, |
| 766 | LLVMIntPredicate upper_pred, LLVMValueRef upper_value) |
| 767 | { |
| 768 | if (!lower_value && !upper_value) { |
| 769 | return; |
| 770 | } |
| 771 | if (upper_value && !lower_value) { |
| 772 | lower_value = upper_value; |
| 773 | lower_pred = upper_pred; |
| 774 | upper_value = nullptr; |
| 823 | 775 | } |
| 824 | | } |
| 825 | | |
| 826 | | static LLVMValueRef get_bounds_check_fn_val(CodeGen *g, LLVMIntPredicate pred, uint32_t bit_count) { |
| 827 | | ZigLLVMFnKey key = {}; |
| 828 | | key.id = ZigLLVMFnIdBoundsCheck; |
| 829 | | key.data.bounds_check.pred = pred; |
| 830 | | key.data.bounds_check.bit_count = bit_count; |
| 831 | | |
| 832 | | auto existing_entry = g->llvm_fn_table.maybe_get(key); |
| 833 | | if (existing_entry) |
| 834 | | return existing_entry->value; |
| 835 | | |
| 836 | | Buf *desired_name = buf_sprintf("__zig_bounds_check_%s_%" PRIu32, pred_name(pred), bit_count); |
| 837 | | Buf *fn_name = get_mangled_name(g, desired_name, false); |
| 838 | | LLVMTypeRef type_ref = LLVMIntType(bit_count); |
| 839 | | LLVMTypeRef arg_types[] = { type_ref, type_ref }; |
| 840 | | LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false); |
| 841 | | LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); |
| 842 | | LLVMSetLinkage(fn_val, LLVMInternalLinkage); |
| 843 | | LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv); |
| 844 | | |
| 845 | | auto prev_state = save_and_clear_builder_state(g); |
| 846 | | |
| 847 | | LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); |
| 848 | | LLVMPositionBuilderAtEnd(g->builder, entry_block); |
| 849 | | |
| 850 | | LLVMValueRef target_val = LLVMGetParam(fn_val, 0); |
| 851 | | LLVMValueRef bound_val = LLVMGetParam(fn_val, 1); |
| 852 | 776 | |
| 853 | | LLVMBasicBlockRef bounds_check_fail_block = LLVMAppendBasicBlock(fn_val, "BoundsCheckFail"); |
| 854 | | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(fn_val, "BoundsCheckOk"); |
| 777 | LLVMBasicBlockRef bounds_check_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "BoundsCheckFail"); |
| 778 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "BoundsCheckOk"); |
| 779 | LLVMBasicBlockRef lower_ok_block = upper_value ? |
| 780 | LLVMAppendBasicBlock(g->cur_fn_val, "FirstBoundsCheckOk") : ok_block; |
| 855 | 781 | |
| 856 | | LLVMValueRef ok_val = LLVMBuildICmp(g->builder, pred, target_val, bound_val, ""); |
| 857 | | LLVMBuildCondBr(g->builder, ok_val, ok_block, bounds_check_fail_block); |
| 782 | LLVMValueRef lower_ok_val = LLVMBuildICmp(g->builder, lower_pred, target_val, lower_value, ""); |
| 783 | LLVMBuildCondBr(g->builder, lower_ok_val, lower_ok_block, bounds_check_fail_block); |
| 858 | 784 | |
| 859 | 785 | LLVMPositionBuilderAtEnd(g->builder, bounds_check_fail_block); |
| 860 | 786 | gen_debug_safety_crash(g, PanicMsgIdBoundsCheckFailure); |
| 861 | 787 | |
| 862 | | LLVMPositionBuilderAtEnd(g->builder, ok_block); |
| 863 | | LLVMBuildRetVoid(g->builder); |
| 864 | | |
| 865 | | restore_builder_state(g, prev_state); |
| 866 | | g->llvm_fn_table.put(key, fn_val); |
| 867 | | return fn_val; |
| 868 | | } |
| 869 | | |
| 870 | | static void add_one_bounds_check(CodeGen *g, LLVMValueRef target_val, LLVMIntPredicate pred, LLVMValueRef bound_val) { |
| 871 | | LLVMValueRef arg1; |
| 872 | | LLVMValueRef arg2; |
| 873 | | switch (pred) { |
| 874 | | case LLVMIntEQ: |
| 875 | | case LLVMIntNE: |
| 876 | | case LLVMIntULT: |
| 877 | | case LLVMIntULE: |
| 878 | | arg1 = target_val; |
| 879 | | arg2 = bound_val; |
| 880 | | break; |
| 881 | | case LLVMIntUGT: |
| 882 | | arg1 = bound_val; |
| 883 | | arg2 = target_val; |
| 884 | | pred = LLVMIntULE; |
| 885 | | break; |
| 886 | | case LLVMIntUGE: |
| 887 | | arg1 = bound_val; |
| 888 | | arg2 = target_val; |
| 889 | | pred = LLVMIntULT; |
| 890 | | break; |
| 891 | | default: |
| 892 | | zig_unreachable(); |
| 893 | | } |
| 894 | | uint32_t bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(target_val)); |
| 895 | | LLVMValueRef fn_val = get_bounds_check_fn_val(g, pred, bit_count); |
| 896 | | LLVMValueRef params[] = { arg1, arg2, }; |
| 897 | | LLVMBuildCall(g->builder, fn_val, params, 2, ""); |
| 898 | | } |
| 899 | | |
| 900 | | static void add_bounds_check(CodeGen *g, LLVMValueRef target_val, |
| 901 | | LLVMIntPredicate lower_pred, LLVMValueRef lower_value, |
| 902 | | LLVMIntPredicate upper_pred, LLVMValueRef upper_value) |
| 903 | | { |
| 904 | | if (lower_value) { |
| 905 | | add_one_bounds_check(g, target_val, lower_pred, lower_value); |
| 906 | | } |
| 907 | | |
| 908 | 788 | if (upper_value) { |
| 909 | | add_one_bounds_check(g, target_val, upper_pred, upper_value); |
| 789 | LLVMPositionBuilderAtEnd(g->builder, lower_ok_block); |
| 790 | LLVMValueRef upper_ok_val = LLVMBuildICmp(g->builder, upper_pred, target_val, upper_value, ""); |
| 791 | LLVMBuildCondBr(g->builder, upper_ok_val, ok_block, bounds_check_fail_block); |
| 910 | 792 | } |
| 793 | |
| 794 | LLVMPositionBuilderAtEnd(g->builder, ok_block); |
| 911 | 795 | } |
| 912 | 796 | |
| 913 | 797 | static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_debug_safety, TypeTableEntry *actual_type, |
| ... | ... | @@ -990,74 +874,26 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_debug_safety, Typ |
| 990 | 874 | } |
| 991 | 875 | } |
| 992 | 876 | |
| 993 | | static const char *add_sub_mul_name(AddSubMul op) { |
| 994 | | switch (op) { |
| 995 | | case AddSubMulAdd: return "add"; |
| 996 | | case AddSubMulSub: return "sub"; |
| 997 | | case AddSubMulMul: return "mul"; |
| 998 | | } |
| 999 | | zig_unreachable(); |
| 1000 | | } |
| 1001 | | static LLVMValueRef get_int_overflow_panic_fn(CodeGen *g, TypeTableEntry *type_entry, AddSubMul op) { |
| 1002 | | ZigLLVMFnKey key = {}; |
| 1003 | | key.id = ZigLLVMFnIdOverflowArithmeticPanic; |
| 1004 | | key.data.overflow_arithmetic.is_signed = type_entry->data.integral.is_signed; |
| 1005 | | key.data.overflow_arithmetic.add_sub_mul = op; |
| 1006 | | key.data.overflow_arithmetic.bit_count = (uint32_t)type_entry->data.integral.bit_count; |
| 1007 | | |
| 1008 | | auto existing_entry = g->llvm_fn_table.maybe_get(key); |
| 1009 | | if (existing_entry) |
| 1010 | | return existing_entry->value; |
| 1011 | | |
| 1012 | | Buf *desired_name = buf_sprintf("__zig_checked_%s_%c%" PRIu32, add_sub_mul_name(op), |
| 1013 | | type_entry->data.integral.is_signed ? 'i' : 'u', type_entry->data.integral.bit_count); |
| 1014 | | Buf *fn_name = get_mangled_name(g, desired_name, false); |
| 1015 | | LLVMTypeRef arg_types[] = { type_entry->type_ref, type_entry->type_ref }; |
| 1016 | | LLVMTypeRef fn_type_ref = LLVMFunctionType(type_entry->type_ref, arg_types, 2, false); |
| 1017 | | LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); |
| 1018 | | LLVMSetLinkage(fn_val, LLVMInternalLinkage); |
| 1019 | | LLVMSetFunctionCallConv(fn_val, LLVMFastCallConv); |
| 1020 | | |
| 1021 | | auto prev_state = save_and_clear_builder_state(g); |
| 1022 | | |
| 1023 | | LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); |
| 1024 | | LLVMPositionBuilderAtEnd(g->builder, entry_block); |
| 1025 | | |
| 1026 | | LLVMValueRef val1 = LLVMGetParam(fn_val, 0); |
| 1027 | | LLVMValueRef val2 = LLVMGetParam(fn_val, 1); |
| 1028 | | |
| 1029 | | LLVMValueRef overflow_fn_val = get_int_overflow_fn(g, type_entry, op); |
| 877 | static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddSubMul op, |
| 878 | LLVMValueRef val1, LLVMValueRef val2) |
| 879 | { |
| 880 | LLVMValueRef fn_val = get_int_overflow_fn(g, type_entry, op); |
| 1030 | 881 | LLVMValueRef params[] = { |
| 1031 | 882 | val1, |
| 1032 | 883 | val2, |
| 1033 | 884 | }; |
| 1034 | | LLVMValueRef result_struct = LLVMBuildCall(g->builder, overflow_fn_val, params, 2, ""); |
| 885 | LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, ""); |
| 886 | LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, ""); |
| 1035 | 887 | LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, ""); |
| 1036 | | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(fn_val, "OverflowFail"); |
| 1037 | | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(fn_val, "OverflowOk"); |
| 888 | LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail"); |
| 889 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk"); |
| 1038 | 890 | LLVMBuildCondBr(g->builder, overflow_bit, fail_block, ok_block); |
| 1039 | 891 | |
| 1040 | 892 | LLVMPositionBuilderAtEnd(g->builder, fail_block); |
| 1041 | 893 | gen_debug_safety_crash(g, PanicMsgIdIntegerOverflow); |
| 1042 | 894 | |
| 1043 | 895 | LLVMPositionBuilderAtEnd(g->builder, ok_block); |
| 1044 | | LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, ""); |
| 1045 | | LLVMBuildRet(g->builder, result); |
| 1046 | | |
| 1047 | | restore_builder_state(g, prev_state); |
| 1048 | | g->llvm_fn_table.put(key, fn_val); |
| 1049 | | return fn_val; |
| 1050 | | } |
| 1051 | | |
| 1052 | | static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddSubMul op, |
| 1053 | | LLVMValueRef val1, LLVMValueRef val2) |
| 1054 | | { |
| 1055 | | LLVMValueRef fn_val = get_int_overflow_panic_fn(g, type_entry, op); |
| 1056 | | LLVMValueRef params[] = { |
| 1057 | | val1, |
| 1058 | | val2, |
| 1059 | | }; |
| 1060 | | return LLVMBuildCall(g->builder, fn_val, params, 2, ""); |
| 896 | return result; |
| 1061 | 897 | } |
| 1062 | 898 | |
| 1063 | 899 | static LLVMIntPredicate cmp_op_to_int_predicate(IrBinOp cmp_op, bool is_signed) { |
| ... | ... | @@ -3015,7 +2851,6 @@ static void set_debug_location(CodeGen *g, IrInstruction *instruction) { |
| 3015 | 2851 | |
| 3016 | 2852 | ZigLLVMSetCurrentDebugLocation(g->builder, (int)source_node->line + 1, |
| 3017 | 2853 | (int)source_node->column + 1, get_di_scope(g, scope)); |
| 3018 | | g->dbg_clear = false; |
| 3019 | 2854 | } |
| 3020 | 2855 | |
| 3021 | 2856 | static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) { |