| ... | ... | @@ -466,7 +466,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { |
| 466 | 466 | } |
| 467 | 467 | |
| 468 | 468 | bool external_linkage = linkage != GlobalLinkageIdInternal; |
| 469 | | if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionStdcall && external_linkage && |
| 469 | CallingConvention cc = fn_table_entry->type_entry->data.fn.fn_type_id.cc; |
| 470 | if (cc == CallingConventionStdcall && external_linkage && |
| 470 | 471 | g->zig_target.arch.arch == ZigLLVM_x86) |
| 471 | 472 | { |
| 472 | 473 | // prevent llvm name mangling |
| ... | ... | @@ -510,17 +511,17 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { |
| 510 | 511 | break; |
| 511 | 512 | } |
| 512 | 513 | |
| 513 | | if (fn_type->data.fn.fn_type_id.cc == CallingConventionNaked) { |
| 514 | if (cc == CallingConventionNaked) { |
| 514 | 515 | addLLVMFnAttr(fn_table_entry->llvm_value, "naked"); |
| 515 | 516 | } else { |
| 516 | 517 | LLVMSetFunctionCallConv(fn_table_entry->llvm_value, get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc)); |
| 517 | 518 | } |
| 518 | | if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) { |
| 519 | if (cc == CallingConventionAsync) { |
| 519 | 520 | addLLVMFnAttr(fn_table_entry->llvm_value, "optnone"); |
| 520 | 521 | addLLVMFnAttr(fn_table_entry->llvm_value, "noinline"); |
| 521 | 522 | } |
| 522 | 523 | |
| 523 | | bool want_cold = fn_table_entry->is_cold || fn_type->data.fn.fn_type_id.cc == CallingConventionCold; |
| 524 | bool want_cold = fn_table_entry->is_cold || cc == CallingConventionCold; |
| 524 | 525 | if (want_cold) { |
| 525 | 526 | ZigLLVMAddFunctionAttrCold(fn_table_entry->llvm_value); |
| 526 | 527 | } |
| ... | ... | @@ -576,37 +577,16 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { |
| 576 | 577 | // nothing to do |
| 577 | 578 | } else if (type_is_codegen_pointer(return_type)) { |
| 578 | 579 | addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull"); |
| 579 | | } else if (handle_is_ptr(return_type) && |
| 580 | | calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc)) |
| 581 | | { |
| 580 | } else if (handle_is_ptr(return_type) && calling_convention_does_first_arg_return(cc)) { |
| 582 | 581 | addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret"); |
| 583 | 582 | addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull"); |
| 584 | 583 | } |
| 585 | 584 | |
| 586 | | |
| 587 | 585 | // set parameter attributes |
| 588 | | for (size_t param_i = 0; param_i < fn_type->data.fn.fn_type_id.param_count; param_i += 1) { |
| 589 | | FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i]; |
| 590 | | size_t gen_index = gen_info->gen_index; |
| 591 | | bool is_byval = gen_info->is_byval; |
| 592 | | |
| 593 | | if (gen_index == SIZE_MAX) { |
| 594 | | continue; |
| 595 | | } |
| 596 | | |
| 597 | | FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[param_i]; |
| 598 | | |
| 599 | | ZigType *param_type = gen_info->type; |
| 600 | | if (param_info->is_noalias) { |
| 601 | | addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "noalias"); |
| 602 | | } |
| 603 | | if ((param_type->id == ZigTypeIdPointer && param_type->data.pointer.is_const) || is_byval) { |
| 604 | | addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "readonly"); |
| 605 | | } |
| 606 | | if (param_type->id == ZigTypeIdPointer) { |
| 607 | | addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "nonnull"); |
| 608 | | } |
| 609 | | } |
| 586 | FnWalk fn_walk = {}; |
| 587 | fn_walk.id = FnWalkIdAttrs; |
| 588 | fn_walk.data.attrs.fn = fn_table_entry; |
| 589 | walk_function_params(g, fn_type, &fn_walk); |
| 610 | 590 | |
| 611 | 591 | uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); |
| 612 | 592 | if (err_ret_trace_arg_index != UINT32_MAX) { |
| ... | ... | @@ -1888,6 +1868,216 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) { |
| 1888 | 1868 | return instruction->llvm_value; |
| 1889 | 1869 | } |
| 1890 | 1870 | |
| 1871 | ATTRIBUTE_NORETURN |
| 1872 | static void report_errors_and_exit(CodeGen *g) { |
| 1873 | assert(g->errors.length != 0); |
| 1874 | for (size_t i = 0; i < g->errors.length; i += 1) { |
| 1875 | ErrorMsg *err = g->errors.at(i); |
| 1876 | print_err_msg(err, g->err_color); |
| 1877 | } |
| 1878 | exit(1); |
| 1879 | } |
| 1880 | |
| 1881 | static void report_errors_and_maybe_exit(CodeGen *g) { |
| 1882 | if (g->errors.length != 0) { |
| 1883 | report_errors_and_exit(g); |
| 1884 | } |
| 1885 | } |
| 1886 | |
| 1887 | ATTRIBUTE_NORETURN |
| 1888 | static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) { |
| 1889 | ErrorMsg *msg = add_node_error(g, source_node, |
| 1890 | buf_sprintf("TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481")); |
| 1891 | add_error_note(g, msg, source_node, |
| 1892 | buf_sprintf("pointers, integers, floats, bools, and enums work on all targets")); |
| 1893 | report_errors_and_exit(g); |
| 1894 | } |
| 1895 | |
| 1896 | static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk, size_t src_i) { |
| 1897 | // Initialized from the type for some walks, but because of C var args, |
| 1898 | // initialized based on callsite instructions for that one. |
| 1899 | FnTypeParamInfo *param_info = nullptr; |
| 1900 | ZigType *ty; |
| 1901 | AstNode *source_node = nullptr; |
| 1902 | LLVMValueRef val; |
| 1903 | LLVMValueRef llvm_fn; |
| 1904 | switch (fn_walk->id) { |
| 1905 | case FnWalkIdAttrs: |
| 1906 | if (src_i >= fn_type->data.fn.fn_type_id.param_count) |
| 1907 | return false; |
| 1908 | param_info = &fn_type->data.fn.fn_type_id.param_info[src_i]; |
| 1909 | ty = param_info->type; |
| 1910 | source_node = fn_walk->data.attrs.fn->proto_node; |
| 1911 | llvm_fn = fn_walk->data.attrs.fn->llvm_value; |
| 1912 | break; |
| 1913 | case FnWalkIdCall: { |
| 1914 | if (src_i >= fn_walk->data.call.inst->arg_count) |
| 1915 | return false; |
| 1916 | IrInstruction *arg = fn_walk->data.call.inst->args[src_i]; |
| 1917 | ty = arg->value.type; |
| 1918 | source_node = arg->source_node; |
| 1919 | val = ir_llvm_value(g, arg); |
| 1920 | break; |
| 1921 | } |
| 1922 | } |
| 1923 | if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat || |
| 1924 | ty->id == ZigTypeIdInt // TODO investigate if we need to change this |
| 1925 | ) { |
| 1926 | switch (fn_walk->id) { |
| 1927 | case FnWalkIdAttrs: { |
| 1928 | ZigType *ptr_type = get_codegen_ptr_type(ty); |
| 1929 | if (ptr_type != nullptr) { |
| 1930 | if (ty->id != ZigTypeIdOptional) { |
| 1931 | addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull"); |
| 1932 | } |
| 1933 | if (ptr_type->data.pointer.is_const) { |
| 1934 | addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "readonly"); |
| 1935 | } |
| 1936 | if (param_info->is_noalias) { |
| 1937 | addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "noalias"); |
| 1938 | } |
| 1939 | } |
| 1940 | fn_walk->data.attrs.gen_i += 1; |
| 1941 | break; |
| 1942 | } |
| 1943 | case FnWalkIdCall: |
| 1944 | fn_walk->data.call.gen_param_values->append(val); |
| 1945 | break; |
| 1946 | } |
| 1947 | return true; |
| 1948 | } |
| 1949 | |
| 1950 | // Arrays are just pointers |
| 1951 | if (ty->id == ZigTypeIdArray) { |
| 1952 | assert(handle_is_ptr(ty)); |
| 1953 | switch (fn_walk->id) { |
| 1954 | case FnWalkIdAttrs: |
| 1955 | addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull"); |
| 1956 | fn_walk->data.attrs.gen_i += 1; |
| 1957 | break; |
| 1958 | case FnWalkIdCall: |
| 1959 | fn_walk->data.call.gen_param_values->append(val); |
| 1960 | break; |
| 1961 | } |
| 1962 | return true; |
| 1963 | } |
| 1964 | |
| 1965 | if (g->zig_target.arch.arch == ZigLLVM_x86_64) { |
| 1966 | size_t ty_size = type_size(g, ty); |
| 1967 | if (ty->id == ZigTypeIdStruct || ty->id == ZigTypeIdUnion) { |
| 1968 | assert(handle_is_ptr(ty)); |
| 1969 | |
| 1970 | // "If the size of an object is larger than four eightbytes, or it contains unaligned |
| 1971 | // fields, it has class MEMORY" |
| 1972 | if (ty_size > 32) { |
| 1973 | switch (fn_walk->id) { |
| 1974 | case FnWalkIdAttrs: |
| 1975 | addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "byval"); |
| 1976 | addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull"); |
| 1977 | fn_walk->data.attrs.gen_i += 1; |
| 1978 | break; |
| 1979 | case FnWalkIdCall: |
| 1980 | fn_walk->data.call.gen_param_values->append(val); |
| 1981 | break; |
| 1982 | } |
| 1983 | return true; |
| 1984 | } |
| 1985 | } |
| 1986 | if (ty->id == ZigTypeIdStruct) { |
| 1987 | assert(handle_is_ptr(ty)); |
| 1988 | // "If the size of the aggregate exceeds a single eightbyte, each is classified |
| 1989 | // separately. Each eightbyte gets initialized to class NO_CLASS." |
| 1990 | if (ty_size <= 8) { |
| 1991 | bool contains_int = false; |
| 1992 | for (size_t i = 0; i < ty->data.structure.src_field_count; i += 1) { |
| 1993 | if (type_is_c_abi_int(g, ty->data.structure.fields[i].type_entry)) { |
| 1994 | contains_int = true; |
| 1995 | break; |
| 1996 | } |
| 1997 | } |
| 1998 | if (contains_int) { |
| 1999 | switch (fn_walk->id) { |
| 2000 | case FnWalkIdAttrs: |
| 2001 | fn_walk->data.attrs.gen_i += 1; |
| 2002 | break; |
| 2003 | case FnWalkIdCall: { |
| 2004 | LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0); |
| 2005 | LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, val, ptr_to_int_type_ref, ""); |
| 2006 | LLVMValueRef loaded = LLVMBuildLoad(g->builder, bitcasted, ""); |
| 2007 | fn_walk->data.call.gen_param_values->append(loaded); |
| 2008 | break; |
| 2009 | } |
| 2010 | } |
| 2011 | return true; |
| 2012 | } |
| 2013 | } |
| 2014 | } |
| 2015 | } |
| 2016 | if (source_node != nullptr) { |
| 2017 | give_up_with_c_abi_error(g, source_node); |
| 2018 | } |
| 2019 | // otherwise allow codegen code to report a compile error |
| 2020 | return false; |
| 2021 | } |
| 2022 | |
| 2023 | void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { |
| 2024 | CallingConvention cc = fn_type->data.fn.fn_type_id.cc; |
| 2025 | if (cc == CallingConventionC) { |
| 2026 | size_t src_i = 0; |
| 2027 | for (;;) { |
| 2028 | if (!iter_function_params_c_abi(g, fn_type, fn_walk, src_i)) |
| 2029 | break; |
| 2030 | src_i += 1; |
| 2031 | } |
| 2032 | return; |
| 2033 | } |
| 2034 | if (fn_walk->id == FnWalkIdCall) { |
| 2035 | IrInstructionCall *instruction = fn_walk->data.call.inst; |
| 2036 | bool is_var_args = fn_walk->data.call.is_var_args; |
| 2037 | for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) { |
| 2038 | IrInstruction *param_instruction = instruction->args[call_i]; |
| 2039 | ZigType *param_type = param_instruction->value.type; |
| 2040 | if (is_var_args || type_has_bits(param_type)) { |
| 2041 | LLVMValueRef param_value = ir_llvm_value(g, param_instruction); |
| 2042 | assert(param_value); |
| 2043 | fn_walk->data.call.gen_param_values->append(param_value); |
| 2044 | } |
| 2045 | } |
| 2046 | return; |
| 2047 | } |
| 2048 | for (size_t param_i = 0; param_i < fn_type->data.fn.fn_type_id.param_count; param_i += 1) { |
| 2049 | FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i]; |
| 2050 | size_t gen_index = gen_info->gen_index; |
| 2051 | |
| 2052 | if (gen_index == SIZE_MAX) { |
| 2053 | continue; |
| 2054 | } |
| 2055 | |
| 2056 | switch (fn_walk->id) { |
| 2057 | case FnWalkIdAttrs: { |
| 2058 | LLVMValueRef llvm_fn = fn_walk->data.attrs.fn->llvm_value; |
| 2059 | bool is_byval = gen_info->is_byval; |
| 2060 | FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[param_i]; |
| 2061 | |
| 2062 | ZigType *param_type = gen_info->type; |
| 2063 | if (param_info->is_noalias) { |
| 2064 | addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "noalias"); |
| 2065 | } |
| 2066 | if ((param_type->id == ZigTypeIdPointer && param_type->data.pointer.is_const) || is_byval) { |
| 2067 | addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "readonly"); |
| 2068 | } |
| 2069 | if (param_type->id == ZigTypeIdPointer) { |
| 2070 | addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "nonnull"); |
| 2071 | } |
| 2072 | break; |
| 2073 | } |
| 2074 | case FnWalkIdCall: |
| 2075 | // handled before for loop |
| 2076 | zig_unreachable(); |
| 2077 | } |
| 2078 | } |
| 2079 | } |
| 2080 | |
| 1891 | 2081 | static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable, |
| 1892 | 2082 | IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction) |
| 1893 | 2083 | { |
| ... | ... | @@ -3111,31 +3301,6 @@ static void set_call_instr_sret(CodeGen *g, LLVMValueRef call_instr) { |
| 3111 | 3301 | LLVMAddCallSiteAttribute(call_instr, 1, sret_attr); |
| 3112 | 3302 | } |
| 3113 | 3303 | |
| 3114 | | ATTRIBUTE_NORETURN |
| 3115 | | static void report_errors_and_exit(CodeGen *g) { |
| 3116 | | assert(g->errors.length != 0); |
| 3117 | | for (size_t i = 0; i < g->errors.length; i += 1) { |
| 3118 | | ErrorMsg *err = g->errors.at(i); |
| 3119 | | print_err_msg(err, g->err_color); |
| 3120 | | } |
| 3121 | | exit(1); |
| 3122 | | } |
| 3123 | | |
| 3124 | | static void report_errors_and_maybe_exit(CodeGen *g) { |
| 3125 | | if (g->errors.length != 0) { |
| 3126 | | report_errors_and_exit(g); |
| 3127 | | } |
| 3128 | | } |
| 3129 | | |
| 3130 | | ATTRIBUTE_NORETURN |
| 3131 | | static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) { |
| 3132 | | ErrorMsg *msg = add_node_error(g, source_node, |
| 3133 | | buf_sprintf("TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481")); |
| 3134 | | add_error_note(g, msg, source_node, |
| 3135 | | buf_sprintf("pointers, integers, floats, bools, and enums work on all targets")); |
| 3136 | | report_errors_and_exit(g); |
| 3137 | | } |
| 3138 | | |
| 3139 | 3304 | static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) { |
| 3140 | 3305 | assert(alignment > 0); |
| 3141 | 3306 | LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name); |
| ... | ... | @@ -3144,67 +3309,6 @@ static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *na |
| 3144 | 3309 | } |
| 3145 | 3310 | |
| 3146 | 3311 | // If you edit this function you have to edit the corresponding code: |
| 3147 | | // codegen.cpp:gen_c_abi_param |
| 3148 | | // analyze.cpp:gen_c_abi_param_type |
| 3149 | | // codegen.cpp:gen_c_abi_param_var |
| 3150 | | // codegen.cpp:gen_c_abi_param_var_init |
| 3151 | | static void gen_c_abi_param(CodeGen *g, ZigList<LLVMValueRef> *gen_param_values, LLVMValueRef val, |
| 3152 | | ZigType *ty, AstNode *source_node) |
| 3153 | | { |
| 3154 | | if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat || |
| 3155 | | ty->id == ZigTypeIdInt // TODO investigate if we need to change this |
| 3156 | | ) { |
| 3157 | | gen_param_values->append(val); |
| 3158 | | return; |
| 3159 | | } |
| 3160 | | |
| 3161 | | // Arrays are just pointers |
| 3162 | | if (ty->id == ZigTypeIdArray) { |
| 3163 | | assert(handle_is_ptr(ty)); |
| 3164 | | gen_param_values->append(val); |
| 3165 | | return; |
| 3166 | | } |
| 3167 | | |
| 3168 | | if (g->zig_target.arch.arch == ZigLLVM_x86_64) { |
| 3169 | | // This code all assumes that val is a pointer. |
| 3170 | | assert(handle_is_ptr(ty)); |
| 3171 | | |
| 3172 | | size_t ty_size = type_size(g, ty); |
| 3173 | | if (ty->id == ZigTypeIdStruct || ty->id == ZigTypeIdUnion) { |
| 3174 | | // "If the size of an object is larger than four eightbytes, or it contains unaligned |
| 3175 | | // fields, it has class MEMORY" |
| 3176 | | if (ty_size > 32) { |
| 3177 | | gen_param_values->append(val); |
| 3178 | | return; |
| 3179 | | } |
| 3180 | | } |
| 3181 | | if (ty->id == ZigTypeIdStruct) { |
| 3182 | | // "If the size of the aggregate exceeds a single eightbyte, each is classified |
| 3183 | | // separately. Each eightbyte gets initialized to class NO_CLASS." |
| 3184 | | if (ty_size <= 8) { |
| 3185 | | bool contains_int = false; |
| 3186 | | for (size_t i = 0; i < ty->data.structure.src_field_count; i += 1) { |
| 3187 | | if (type_is_c_abi_int(g, ty->data.structure.fields[i].type_entry)) { |
| 3188 | | contains_int = true; |
| 3189 | | break; |
| 3190 | | } |
| 3191 | | } |
| 3192 | | if (contains_int) { |
| 3193 | | LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0); |
| 3194 | | LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, val, ptr_to_int_type_ref, ""); |
| 3195 | | LLVMValueRef loaded = LLVMBuildLoad(g->builder, bitcasted, ""); |
| 3196 | | gen_param_values->append(loaded); |
| 3197 | | return; |
| 3198 | | } |
| 3199 | | } |
| 3200 | | } |
| 3201 | | } |
| 3202 | | |
| 3203 | | give_up_with_c_abi_error(g, source_node); |
| 3204 | | } |
| 3205 | | |
| 3206 | | // If you edit this function you have to edit the corresponding code: |
| 3207 | | // codegen.cpp:gen_c_abi_param |
| 3208 | 3312 | // analyze.cpp:gen_c_abi_param_type |
| 3209 | 3313 | // codegen.cpp:gen_c_abi_param_var |
| 3210 | 3314 | // codegen.cpp:gen_c_abi_param_var_init |
| ... | ... | @@ -3283,7 +3387,6 @@ ok: |
| 3283 | 3387 | } |
| 3284 | 3388 | |
| 3285 | 3389 | // If you edit this function you have to edit the corresponding code: |
| 3286 | | // codegen.cpp:gen_c_abi_param |
| 3287 | 3390 | // analyze.cpp:gen_c_abi_param_type |
| 3288 | 3391 | // codegen.cpp:gen_c_abi_param_var |
| 3289 | 3392 | // codegen.cpp:gen_c_abi_param_var_init |
| ... | ... | @@ -3376,7 +3479,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3376 | 3479 | bool ret_has_bits = type_has_bits(src_return_type); |
| 3377 | 3480 | |
| 3378 | 3481 | CallingConvention cc = fn_type->data.fn.fn_type_id.cc; |
| 3379 | | bool is_c_abi = cc == CallingConventionC; |
| 3380 | 3482 | |
| 3381 | 3483 | bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type) && |
| 3382 | 3484 | calling_convention_does_first_arg_return(cc); |
| ... | ... | @@ -3395,19 +3497,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3395 | 3497 | LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, ""); |
| 3396 | 3498 | gen_param_values.append(err_val_ptr); |
| 3397 | 3499 | } |
| 3398 | | for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) { |
| 3399 | | IrInstruction *param_instruction = instruction->args[call_i]; |
| 3400 | | ZigType *param_type = param_instruction->value.type; |
| 3401 | | if (is_var_args || type_has_bits(param_type)) { |
| 3402 | | LLVMValueRef param_value = ir_llvm_value(g, param_instruction); |
| 3403 | | assert(param_value); |
| 3404 | | if (is_c_abi) { |
| 3405 | | gen_c_abi_param(g, &gen_param_values, param_value, param_type, param_instruction->source_node); |
| 3406 | | } else { |
| 3407 | | gen_param_values.append(param_value); |
| 3408 | | } |
| 3409 | | } |
| 3410 | | } |
| 3500 | FnWalk fn_walk = {}; |
| 3501 | fn_walk.id = FnWalkIdCall; |
| 3502 | fn_walk.data.call.inst = instruction; |
| 3503 | fn_walk.data.call.is_var_args = is_var_args; |
| 3504 | fn_walk.data.call.gen_param_values = &gen_param_values; |
| 3505 | walk_function_params(g, fn_type, &fn_walk); |
| 3411 | 3506 | |
| 3412 | 3507 | ZigLLVM_FnInline fn_inline; |
| 3413 | 3508 | switch (instruction->fn_inline) { |