| ... | ... | @@ -757,6 +757,25 @@ static void gen_debug_safety_crash(CodeGen *g, PanicMsgId msg_id) { |
| 757 | 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 | 779 | static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 761 | 780 | if (g->safety_crash_err_fn != nullptr) |
| 762 | 781 | return g->safety_crash_err_fn; |
| ... | ... | @@ -840,7 +859,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 840 | 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 | 864 | LLVMValueRef const_prefix_len = LLVMConstInt(LLVMTypeOf(err_name_len), strlen(unwrap_err_msg_text), false); |
| 846 | 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 | 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 | 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 | 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 | 1988 | static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, |
| 1951 | 1989 | IrInstructionDeclVar *decl_var_instruction) |
| 1952 | 1990 | { |
| ... | ... | @@ -1993,7 +2031,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, |
| 1993 | 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 | 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 | 2696 | return nullptr; |
| 2659 | 2697 | } |
| 2660 | 2698 | |
| ... | ... | @@ -2685,7 +2723,7 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutable *executable, IrIns |
| 2685 | 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 | 2727 | return nullptr; |
| 2690 | 2728 | } |
| 2691 | 2729 | |
| ... | ... | @@ -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 | 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 | 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 | 2871 | static LLVMValueRef ir_render_return_address(CodeGen *g, IrExecutable *executable, |
| 2808 | 2872 | IrInstructionReturnAddress *instruction) |
| 2809 | 2873 | { |
| 2810 | 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 | 2892 | static LLVMValueRef ir_render_frame_address(CodeGen *g, IrExecutable *executable, |
| 2815 | 2893 | IrInstructionFrameAddress *instruction) |
| 2816 | 2894 | { |
| 2817 | 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 | 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 | 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 | 3841 | static void generate_error_name_table(CodeGen *g) { |
| 3781 | 3842 | if (g->err_name_table != nullptr || !g->generate_error_name_table || g->error_decls.length == 1) { |
| 3782 | 3843 | return; |
| ... | ... | @@ -3936,7 +3997,6 @@ static void do_code_gen(CodeGen *g) { |
| 3936 | 3997 | |
| 3937 | 3998 | codegen_add_time_event(g, "Code Generation"); |
| 3938 | 3999 | |
| 3939 | | delete_unused_builtin_fns(g); |
| 3940 | 4000 | generate_error_name_table(g); |
| 3941 | 4001 | generate_enum_name_tables(g); |
| 3942 | 4002 | |
| ... | ... | @@ -4528,81 +4588,11 @@ static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char |
| 4528 | 4588 | } |
| 4529 | 4589 | |
| 4530 | 4590 | static void define_builtin_fns(CodeGen *g) { |
| 4531 | | { |
| 4532 | | // TODO make lazy and get rid of delete_unused_builtin_fns |
| 4533 | | BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdBreakpoint, "breakpoint", 0); |
| 4534 | | builtin_fn->ref_count = 1; |
| 4535 | | |
| 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 | | } |
| 4591 | create_builtin_fn(g, BuiltinFnIdBreakpoint, "breakpoint", 0); |
| 4592 | create_builtin_fn(g, BuiltinFnIdReturnAddress, "returnAddress", 0); |
| 4593 | create_builtin_fn(g, BuiltinFnIdFrameAddress, "frameAddress", 0); |
| 4594 | create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy", 3); |
| 4595 | create_builtin_fn(g, BuiltinFnIdMemset, "memset", 3); |
| 4606 | 4596 | create_builtin_fn(g, BuiltinFnIdSizeof, "sizeOf", 1); |
| 4607 | 4597 | create_builtin_fn(g, BuiltinFnIdAlignof, "alignOf", 1); |
| 4608 | 4598 | create_builtin_fn(g, BuiltinFnIdMaxValue, "maxValue", 1); |