| ... | @@ -757,6 +757,25 @@ static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) { | ... | @@ -757,6 +757,25 @@ static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) { |
| 757 | gen_panic(g, get_panic_msg_ptr_val(g, msg_id)); | 757 | gen_panic(g, get_panic_msg_ptr_val(g, msg_id)); |
| 758 | } | 758 | } |
| 759 | | 759 | |
| | 760 | static LLVMValueRef get_memcpy_fn_val(CodeGen *g) { |
| | 761 | if (g->memcpy_fn_val) |
| | 762 | return g->memcpy_fn_val; |
| | 763 | |
| | 764 | LLVMTypeRef param_types[] = { |
| | 765 | LLVMPointerType(LLVMInt8Type(), 0), |
| | 766 | LLVMPointerType(LLVMInt8Type(), 0), |
| | 767 | LLVMIntType(g->pointer_size_bytes * 8), |
| | 768 | LLVMInt32Type(), |
| | 769 | LLVMInt1Type(), |
| | 770 | }; |
| | 771 | LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 5, false); |
| | 772 | Buf *name = buf_sprintf("llvm.memcpy.p0i8.p0i8.i%d", g->pointer_size_bytes * 8); |
| | 773 | g->memcpy_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type); |
| | 774 | assert(LLVMGetIntrinsicID(g->memcpy_fn_val)); |
| | 775 | |
| | 776 | return g->memcpy_fn_val; |
| | 777 | } |
| | 778 | |
| 760 | static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { | 779 | static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 761 | if (g->safety_crash_err_fn != nullptr) | 780 | if (g->safety_crash_err_fn != nullptr) |
| 762 | return g->safety_crash_err_fn; | 781 | return g->safety_crash_err_fn; |
| ... | @@ -840,7 +859,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { | ... | @@ -840,7 +859,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 840 | LLVMConstNull(LLVMInt1Type()), // is volatile | 859 | LLVMConstNull(LLVMInt1Type()), // is volatile |
| 841 | }; | 860 | }; |
| 842 | | 861 | |
| 843 | LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, ""); | 862 | LLVMBuildCall(g->builder, get_memcpy_fn_val(g), params, 5, ""); |
| 844 | | 863 | |
| 845 | LLVMValueRef const_prefix_len = LLVMConstInt(LLVMTypeOf(err_name_len), strlen(unwrap_err_msg_text), false); | 864 | LLVMValueRef const_prefix_len = LLVMConstInt(LLVMTypeOf(err_name_len), strlen(unwrap_err_msg_text), false); |
| 846 | LLVMValueRef full_buf_len = LLVMBuildNUWAdd(g->builder, const_prefix_len, err_name_len, ""); | 865 | LLVMValueRef full_buf_len = LLVMBuildNUWAdd(g->builder, const_prefix_len, err_name_len, ""); |
| ... | @@ -1060,7 +1079,7 @@ static LLVMValueRef gen_struct_memcpy(CodeGen *g, LLVMValueRef src, LLVMValueRef | ... | @@ -1060,7 +1079,7 @@ static LLVMValueRef gen_struct_memcpy(CodeGen *g, LLVMValueRef src, LLVMValueRef |
| 1060 | LLVMConstNull(LLVMInt1Type()), // is volatile | 1079 | LLVMConstNull(LLVMInt1Type()), // is volatile |
| 1061 | }; | 1080 | }; |
| 1062 | | 1081 | |
| 1063 | return LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, ""); | 1082 | return LLVMBuildCall(g->builder, get_memcpy_fn_val(g), params, 5, ""); |
| 1064 | } | 1083 | } |
| 1065 | | 1084 | |
| 1066 | static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, TypeTableEntry *ptr_type, | 1085 | static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, TypeTableEntry *ptr_type, |
| ... | @@ -1947,6 +1966,25 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI | ... | @@ -1947,6 +1966,25 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI |
| 1947 | return LLVMBuildICmp(g->builder, LLVMIntEQ, value, zero, ""); | 1966 | return LLVMBuildICmp(g->builder, LLVMIntEQ, value, zero, ""); |
| 1948 | } | 1967 | } |
| 1949 | | 1968 | |
| | 1969 | static LLVMValueRef get_memset_fn_val(CodeGen *g) { |
| | 1970 | if (g->memset_fn_val) |
| | 1971 | return g->memset_fn_val; |
| | 1972 | |
| | 1973 | LLVMTypeRef param_types[] = { |
| | 1974 | LLVMPointerType(LLVMInt8Type(), 0), |
| | 1975 | LLVMInt8Type(), |
| | 1976 | LLVMIntType(g->pointer_size_bytes * 8), |
| | 1977 | LLVMInt32Type(), |
| | 1978 | LLVMInt1Type(), |
| | 1979 | }; |
| | 1980 | LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 5, false); |
| | 1981 | Buf *name = buf_sprintf("llvm.memset.p0i8.i%d", g->pointer_size_bytes * 8); |
| | 1982 | g->memset_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type); |
| | 1983 | assert(LLVMGetIntrinsicID(g->memset_fn_val)); |
| | 1984 | |
| | 1985 | return g->memset_fn_val; |
| | 1986 | } |
| | 1987 | |
| 1950 | static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, | 1988 | static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, |
| 1951 | IrInstructionDeclVar *decl_var_instruction) | 1989 | IrInstructionDeclVar *decl_var_instruction) |
| 1952 | { | 1990 | { |
| ... | @@ -1993,7 +2031,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, | ... | @@ -1993,7 +2031,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, |
| 1993 | LLVMConstNull(LLVMInt1Type()), // is volatile | 2031 | LLVMConstNull(LLVMInt1Type()), // is volatile |
| 1994 | }; | 2032 | }; |
| 1995 | | 2033 | |
| 1996 | LLVMBuildCall(g->builder, g->memset_fn_val, params, 5, ""); | 2034 | LLVMBuildCall(g->builder, get_memset_fn_val(g), params, 5, ""); |
| 1997 | } | 2035 | } |
| 1998 | } | 2036 | } |
| 1999 | | 2037 | |
| ... | @@ -2654,7 +2692,7 @@ static LLVMValueRef ir_render_memset(CodeGen *g, IrExecutable *executable, IrIns | ... | @@ -2654,7 +2692,7 @@ static LLVMValueRef ir_render_memset(CodeGen *g, IrExecutable *executable, IrIns |
| 2654 | is_volatile, | 2692 | is_volatile, |
| 2655 | }; | 2693 | }; |
| 2656 | | 2694 | |
| 2657 | LLVMBuildCall(g->builder, g->memset_fn_val, params, 5, ""); | 2695 | LLVMBuildCall(g->builder, get_memset_fn_val(g), params, 5, ""); |
| 2658 | return nullptr; | 2696 | return nullptr; |
| 2659 | } | 2697 | } |
| 2660 | | 2698 | |
| ... | @@ -2685,7 +2723,7 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutable *executable, IrIns | ... | @@ -2685,7 +2723,7 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutable *executable, IrIns |
| 2685 | is_volatile, | 2723 | is_volatile, |
| 2686 | }; | 2724 | }; |
| 2687 | | 2725 | |
| 2688 | LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, ""); | 2726 | LLVMBuildCall(g->builder, get_memcpy_fn_val(g), params, 5, ""); |
| 2689 | return nullptr; | 2727 | return nullptr; |
| 2690 | } | 2728 | } |
| 2691 | | 2729 | |
| ... | @@ -2799,23 +2837,63 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst | ... | @@ -2799,23 +2837,63 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst |
| 2799 | } | 2837 | } |
| 2800 | } | 2838 | } |
| 2801 | | 2839 | |
| | 2840 | static LLVMValueRef get_trap_fn_val(CodeGen *g) { |
| | 2841 | if (g->trap_fn_val) |
| | 2842 | return g->trap_fn_val; |
| | 2843 | |
| | 2844 | LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), nullptr, 0, false); |
| | 2845 | g->trap_fn_val = LLVMAddFunction(g->module, "llvm.debugtrap", fn_type); |
| | 2846 | assert(LLVMGetIntrinsicID(g->trap_fn_val)); |
| | 2847 | |
| | 2848 | return g->trap_fn_val; |
| | 2849 | } |
| | 2850 | |
| | 2851 | |
| 2802 | static LLVMValueRef ir_render_breakpoint(CodeGen *g, IrExecutable *executable, IrInstructionBreakpoint *instruction) { | 2852 | static LLVMValueRef ir_render_breakpoint(CodeGen *g, IrExecutable *executable, IrInstructionBreakpoint *instruction) { |
| 2803 | LLVMBuildCall(g->builder, g->trap_fn_val, nullptr, 0, ""); | 2853 | LLVMBuildCall(g->builder, get_trap_fn_val(g), nullptr, 0, ""); |
| 2804 | return nullptr; | 2854 | return nullptr; |
| 2805 | } | 2855 | } |
| 2806 | | 2856 | |
| | 2857 | static LLVMValueRef get_return_address_fn_val(CodeGen *g) { |
| | 2858 | if (g->return_address_fn_val) |
| | 2859 | return g->return_address_fn_val; |
| | 2860 | |
| | 2861 | TypeTableEntry *return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); |
| | 2862 | |
| | 2863 | LLVMTypeRef fn_type = LLVMFunctionType(return_type->type_ref, |
| | 2864 | &g->builtin_types.entry_i32->type_ref, 1, false); |
| | 2865 | g->return_address_fn_val = LLVMAddFunction(g->module, "llvm.returnaddress", fn_type); |
| | 2866 | assert(LLVMGetIntrinsicID(g->return_address_fn_val)); |
| | 2867 | |
| | 2868 | return g->return_address_fn_val; |
| | 2869 | } |
| | 2870 | |
| 2807 | static LLVMValueRef ir_render_return_address(CodeGen *g, IrExecutable *executable, | 2871 | static LLVMValueRef ir_render_return_address(CodeGen *g, IrExecutable *executable, |
| 2808 | IrInstructionReturnAddress *instruction) | 2872 | IrInstructionReturnAddress *instruction) |
| 2809 | { | 2873 | { |
| 2810 | LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref); | 2874 | LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref); |
| 2811 | return LLVMBuildCall(g->builder, g->return_address_fn_val, &zero, 1, ""); | 2875 | return LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, ""); |
| | 2876 | } |
| | 2877 | |
| | 2878 | static LLVMValueRef get_frame_address_fn_val(CodeGen *g) { |
| | 2879 | if (g->frame_address_fn_val) |
| | 2880 | return g->frame_address_fn_val; |
| | 2881 | |
| | 2882 | TypeTableEntry *return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); |
| | 2883 | |
| | 2884 | LLVMTypeRef fn_type = LLVMFunctionType(return_type->type_ref, |
| | 2885 | &g->builtin_types.entry_i32->type_ref, 1, false); |
| | 2886 | g->frame_address_fn_val = LLVMAddFunction(g->module, "llvm.frameaddress", fn_type); |
| | 2887 | assert(LLVMGetIntrinsicID(g->frame_address_fn_val)); |
| | 2888 | |
| | 2889 | return g->frame_address_fn_val; |
| 2812 | } | 2890 | } |
| 2813 | | 2891 | |
| 2814 | static LLVMValueRef ir_render_frame_address(CodeGen *g, IrExecutable *executable, | 2892 | static LLVMValueRef ir_render_frame_address(CodeGen *g, IrExecutable *executable, |
| 2815 | IrInstructionFrameAddress *instruction) | 2893 | IrInstructionFrameAddress *instruction) |
| 2816 | { | 2894 | { |
| 2817 | LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref); | 2895 | LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref); |
| 2818 | return LLVMBuildCall(g->builder, g->frame_address_fn_val, &zero, 1, ""); | 2896 | return LLVMBuildCall(g->builder, get_frame_address_fn_val(g), &zero, 1, ""); |
| 2819 | } | 2897 | } |
| 2820 | | 2898 | |
| 2821 | static LLVMValueRef render_shl_with_overflow(CodeGen *g, IrInstructionOverflowOp *instruction) { | 2899 | static LLVMValueRef render_shl_with_overflow(CodeGen *g, IrInstructionOverflowOp *instruction) { |
| ... | @@ -3760,23 +3838,6 @@ static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const | ... | @@ -3760,23 +3838,6 @@ static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const |
| 3760 | LLVMSetInitializer(const_val->global_refs->llvm_global, const_val->global_refs->llvm_value); | 3838 | LLVMSetInitializer(const_val->global_refs->llvm_global, const_val->global_refs->llvm_value); |
| 3761 | } | 3839 | } |
| 3762 | | 3840 | |
| 3763 | static void delete_unused_builtin_fns(CodeGen *g) { | | |
| 3764 | // TODO get rid of this function | | |
| 3765 | auto it = g->builtin_fn_table.entry_iterator(); | | |
| 3766 | for (;;) { | | |
| 3767 | auto *entry = it.next(); | | |
| 3768 | if (!entry) | | |
| 3769 | break; | | |
| 3770 | | | |
| 3771 | BuiltinFnEntry *builtin_fn = entry->value; | | |
| 3772 | if (builtin_fn->ref_count == 0 && | | |
| 3773 | builtin_fn->fn_val) | | |
| 3774 | { | | |
| 3775 | LLVMDeleteFunction(entry->value->fn_val); | | |
| 3776 | } | | |
| 3777 | } | | |
| 3778 | } | | |
| 3779 | | | |
| 3780 | static void generate_error_name_table(CodeGen *g) { | 3841 | static void generate_error_name_table(CodeGen *g) { |
| 3781 | if (g->err_name_table != nullptr || !g->generate_error_name_table || g->error_decls.length == 1) { | 3842 | if (g->err_name_table != nullptr || !g->generate_error_name_table || g->error_decls.length == 1) { |
| 3782 | return; | 3843 | return; |
| ... | @@ -3936,7 +3997,6 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -3936,7 +3997,6 @@ static void do_code_gen(CodeGen *g) { |
| 3936 | | 3997 | |
| 3937 | codegen_add_time_event(g, "Code Generation"); | 3998 | codegen_add_time_event(g, "Code Generation"); |
| 3938 | | 3999 | |
| 3939 | delete_unused_builtin_fns(g); | | |
| 3940 | generate_error_name_table(g); | 4000 | generate_error_name_table(g); |
| 3941 | generate_enum_name_tables(g); | 4001 | generate_enum_name_tables(g); |
| 3942 | | 4002 | |
| ... | @@ -4528,81 +4588,11 @@ static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char | ... | @@ -4528,81 +4588,11 @@ static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char |
| 4528 | } | 4588 | } |
| 4529 | | 4589 | |
| 4530 | static void define_builtin_fns(CodeGen *g) { | 4590 | static void define_builtin_fns(CodeGen *g) { |
| 4531 | { | 4591 | create_builtin_fn(g, BuiltinFnIdBreakpoint, "breakpoint", 0); |
| 4532 | // TODO make lazy and get rid of delete_unused_builtin_fns | 4592 | create_builtin_fn(g, BuiltinFnIdReturnAddress, "returnAddress", 0); |
| 4533 | BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdBreakpoint, "breakpoint", 0); | 4593 | create_builtin_fn(g, BuiltinFnIdFrameAddress, "frameAddress", 0); |
| 4534 | builtin_fn->ref_count = 1; | 4594 | create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy", 3); |
| 4535 | | 4595 | create_builtin_fn(g, BuiltinFnIdMemset, "memset", 3); |
| 4536 | LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), nullptr, 0, false); | | |
| 4537 | builtin_fn->fn_val = LLVMAddFunction(g->module, "llvm.debugtrap", fn_type); | | |
| 4538 | assert(LLVMGetIntrinsicID(builtin_fn->fn_val)); | | |
| 4539 | | | |
| 4540 | g->trap_fn_val = builtin_fn->fn_val; | | |
| 4541 | } | | |
| 4542 | { | | |
| 4543 | // TODO make lazy and get rid of delete_unused_builtin_fns | | |
| 4544 | BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdReturnAddress, | | |
| 4545 | "returnAddress", 0); | | |
| 4546 | TypeTableEntry *return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); | | |
| 4547 | | | |
| 4548 | LLVMTypeRef fn_type = LLVMFunctionType(return_type->type_ref, | | |
| 4549 | &g->builtin_types.entry_i32->type_ref, 1, false); | | |
| 4550 | builtin_fn->fn_val = LLVMAddFunction(g->module, "llvm.returnaddress", fn_type); | | |
| 4551 | assert(LLVMGetIntrinsicID(builtin_fn->fn_val)); | | |
| 4552 | | | |
| 4553 | g->return_address_fn_val = builtin_fn->fn_val; | | |
| 4554 | } | | |
| 4555 | { | | |
| 4556 | // TODO make lazy and get rid of delete_unused_builtin_fns | | |
| 4557 | BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdFrameAddress, | | |
| 4558 | "frameAddress", 0); | | |
| 4559 | TypeTableEntry *return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); | | |
| 4560 | | | |
| 4561 | LLVMTypeRef fn_type = LLVMFunctionType(return_type->type_ref, | | |
| 4562 | &g->builtin_types.entry_i32->type_ref, 1, false); | | |
| 4563 | builtin_fn->fn_val = LLVMAddFunction(g->module, "llvm.frameaddress", fn_type); | | |
| 4564 | assert(LLVMGetIntrinsicID(builtin_fn->fn_val)); | | |
| 4565 | | | |
| 4566 | g->frame_address_fn_val = builtin_fn->fn_val; | | |
| 4567 | } | | |
| 4568 | { | | |
| 4569 | // TODO make lazy and get rid of delete_unused_builtin_fns | | |
| 4570 | BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy", 3); | | |
| 4571 | builtin_fn->ref_count = 1; | | |
| 4572 | | | |
| 4573 | LLVMTypeRef param_types[] = { | | |
| 4574 | LLVMPointerType(LLVMInt8Type(), 0), | | |
| 4575 | LLVMPointerType(LLVMInt8Type(), 0), | | |
| 4576 | LLVMIntType(g->pointer_size_bytes * 8), | | |
| 4577 | LLVMInt32Type(), | | |
| 4578 | LLVMInt1Type(), | | |
| 4579 | }; | | |
| 4580 | LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 5, false); | | |
| 4581 | Buf *name = buf_sprintf("llvm.memcpy.p0i8.p0i8.i%d", g->pointer_size_bytes * 8); | | |
| 4582 | builtin_fn->fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type); | | |
| 4583 | assert(LLVMGetIntrinsicID(builtin_fn->fn_val)); | | |
| 4584 | | | |
| 4585 | g->memcpy_fn_val = builtin_fn->fn_val; | | |
| 4586 | } | | |
| 4587 | { | | |
| 4588 | // TODO make lazy and get rid of delete_unused_builtin_fns | | |
| 4589 | BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdMemset, "memset", 3); | | |
| 4590 | builtin_fn->ref_count = 1; | | |
| 4591 | | | |
| 4592 | LLVMTypeRef param_types[] = { | | |
| 4593 | LLVMPointerType(LLVMInt8Type(), 0), | | |
| 4594 | LLVMInt8Type(), | | |
| 4595 | LLVMIntType(g->pointer_size_bytes * 8), | | |
| 4596 | LLVMInt32Type(), | | |
| 4597 | LLVMInt1Type(), | | |
| 4598 | }; | | |
| 4599 | LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidType(), param_types, 5, false); | | |
| 4600 | Buf *name = buf_sprintf("llvm.memset.p0i8.i%d", g->pointer_size_bytes * 8); | | |
| 4601 | builtin_fn->fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type); | | |
| 4602 | assert(LLVMGetIntrinsicID(builtin_fn->fn_val)); | | |
| 4603 | | | |
| 4604 | g->memset_fn_val = builtin_fn->fn_val; | | |
| 4605 | } | | |
| 4606 | create_builtin_fn(g, BuiltinFnIdSizeof, "sizeOf", 1); | 4596 | create_builtin_fn(g, BuiltinFnIdSizeof, "sizeOf", 1); |
| 4607 | create_builtin_fn(g, BuiltinFnIdAlignof, "alignOf", 1); | 4597 | create_builtin_fn(g, BuiltinFnIdAlignof, "alignOf", 1); |
| 4608 | create_builtin_fn(g, BuiltinFnIdMaxValue, "maxValue", 1); | 4598 | create_builtin_fn(g, BuiltinFnIdMaxValue, "maxValue", 1); |