| ... | ... | @@ -1904,14 +1904,24 @@ static bool type_is_c_abi_int(CodeGen *g, ZigType *ty) { |
| 1904 | 1904 | get_codegen_ptr_type(ty) != nullptr); |
| 1905 | 1905 | } |
| 1906 | 1906 | |
| 1907 | static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) { |
| 1908 | assert(alignment > 0); |
| 1909 | LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name); |
| 1910 | LLVMSetAlignment(result, alignment); |
| 1911 | return result; |
| 1912 | } |
| 1913 | |
| 1907 | 1914 | static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk, size_t src_i) { |
| 1908 | 1915 | // Initialized from the type for some walks, but because of C var args, |
| 1909 | 1916 | // initialized based on callsite instructions for that one. |
| 1910 | 1917 | FnTypeParamInfo *param_info = nullptr; |
| 1911 | 1918 | ZigType *ty; |
| 1919 | ZigType *dest_ty = nullptr; |
| 1912 | 1920 | AstNode *source_node = nullptr; |
| 1913 | 1921 | LLVMValueRef val; |
| 1914 | 1922 | LLVMValueRef llvm_fn; |
| 1923 | unsigned di_arg_index; |
| 1924 | ZigVar *var; |
| 1915 | 1925 | switch (fn_walk->id) { |
| 1916 | 1926 | case FnWalkIdAttrs: |
| 1917 | 1927 | if (src_i >= fn_type->data.fn.fn_type_id.param_count) |
| ... | ... | @@ -1936,6 +1946,14 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ |
| 1936 | 1946 | param_info = &fn_type->data.fn.fn_type_id.param_info[src_i]; |
| 1937 | 1947 | ty = param_info->type; |
| 1938 | 1948 | break; |
| 1949 | case FnWalkIdVars: |
| 1950 | assert(src_i < fn_type->data.fn.fn_type_id.param_count); |
| 1951 | param_info = &fn_type->data.fn.fn_type_id.param_info[src_i]; |
| 1952 | ty = param_info->type; |
| 1953 | var = fn_walk->data.vars.var; |
| 1954 | source_node = var->decl_node; |
| 1955 | llvm_fn = fn_walk->data.vars.llvm_fn; |
| 1956 | break; |
| 1939 | 1957 | } |
| 1940 | 1958 | |
| 1941 | 1959 | if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat || |
| ... | ... | @@ -1965,6 +1983,13 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ |
| 1965 | 1983 | fn_walk->data.types.gen_param_types->append(ty->type_ref); |
| 1966 | 1984 | fn_walk->data.types.param_di_types->append(ty->di_type); |
| 1967 | 1985 | break; |
| 1986 | case FnWalkIdVars: { |
| 1987 | var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes); |
| 1988 | di_arg_index = fn_walk->data.vars.gen_i; |
| 1989 | fn_walk->data.vars.gen_i += 1; |
| 1990 | dest_ty = ty; |
| 1991 | goto var_ok; |
| 1992 | } |
| 1968 | 1993 | } |
| 1969 | 1994 | return true; |
| 1970 | 1995 | } |
| ... | ... | @@ -1986,6 +2011,13 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ |
| 1986 | 2011 | fn_walk->data.types.param_di_types->append(gen_type->di_type); |
| 1987 | 2012 | break; |
| 1988 | 2013 | } |
| 2014 | case FnWalkIdVars: { |
| 2015 | var->value_ref = LLVMGetParam(llvm_fn, fn_walk->data.vars.gen_i); |
| 2016 | di_arg_index = fn_walk->data.vars.gen_i; |
| 2017 | dest_ty = get_pointer_to_type(g, ty, false); |
| 2018 | fn_walk->data.vars.gen_i += 1; |
| 2019 | goto var_ok; |
| 2020 | } |
| 1989 | 2021 | } |
| 1990 | 2022 | return true; |
| 1991 | 2023 | } |
| ... | ... | @@ -2013,6 +2045,13 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ |
| 2013 | 2045 | fn_walk->data.types.param_di_types->append(gen_type->di_type); |
| 2014 | 2046 | break; |
| 2015 | 2047 | } |
| 2048 | case FnWalkIdVars: { |
| 2049 | di_arg_index = fn_walk->data.vars.gen_i; |
| 2050 | var->value_ref = LLVMGetParam(llvm_fn, fn_walk->data.vars.gen_i); |
| 2051 | dest_ty = get_pointer_to_type(g, ty, false); |
| 2052 | fn_walk->data.vars.gen_i += 1; |
| 2053 | goto var_ok; |
| 2054 | } |
| 2016 | 2055 | } |
| 2017 | 2056 | return true; |
| 2018 | 2057 | } |
| ... | ... | @@ -2047,6 +2086,12 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ |
| 2047 | 2086 | fn_walk->data.types.param_di_types->append(gen_type->di_type); |
| 2048 | 2087 | break; |
| 2049 | 2088 | } |
| 2089 | case FnWalkIdVars: { |
| 2090 | di_arg_index = fn_walk->data.vars.gen_i; |
| 2091 | var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes); |
| 2092 | fn_walk->data.vars.gen_i += 1; |
| 2093 | goto var_ok; |
| 2094 | } |
| 2050 | 2095 | } |
| 2051 | 2096 | return true; |
| 2052 | 2097 | } |
| ... | ... | @@ -2058,6 +2103,16 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ |
| 2058 | 2103 | } |
| 2059 | 2104 | // otherwise allow codegen code to report a compile error |
| 2060 | 2105 | return false; |
| 2106 | |
| 2107 | var_ok: |
| 2108 | if (dest_ty != nullptr && var->decl_node) { |
| 2109 | // arg index + 1 because the 0 index is return value |
| 2110 | var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope), |
| 2111 | buf_ptr(&var->name), fn_walk->data.vars.import->di_file, |
| 2112 | (unsigned)(var->decl_node->line + 1), |
| 2113 | dest_ty->di_type, !g->strip_debug_symbols, 0, di_arg_index + 1); |
| 2114 | } |
| 2115 | return true; |
| 2061 | 2116 | } |
| 2062 | 2117 | |
| 2063 | 2118 | void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { |
| ... | ... | @@ -2117,6 +2172,9 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { |
| 2117 | 2172 | case FnWalkIdTypes: |
| 2118 | 2173 | // Not called for non-c-abi |
| 2119 | 2174 | zig_unreachable(); |
| 2175 | case FnWalkIdVars: |
| 2176 | // iter_function_params_c_abi is called directly for this one |
| 2177 | zig_unreachable(); |
| 2120 | 2178 | } |
| 2121 | 2179 | } |
| 2122 | 2180 | } |
| ... | ... | @@ -3344,93 +3402,7 @@ static void set_call_instr_sret(CodeGen *g, LLVMValueRef call_instr) { |
| 3344 | 3402 | LLVMAddCallSiteAttribute(call_instr, 1, sret_attr); |
| 3345 | 3403 | } |
| 3346 | 3404 | |
| 3347 | | static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) { |
| 3348 | | assert(alignment > 0); |
| 3349 | | LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name); |
| 3350 | | LLVMSetAlignment(result, alignment); |
| 3351 | | return result; |
| 3352 | | } |
| 3353 | | |
| 3354 | | // If you edit this function you have to edit the corresponding code: |
| 3355 | | // analyze.cpp:gen_c_abi_param_type |
| 3356 | | // codegen.cpp:gen_c_abi_param_var |
| 3357 | | // codegen.cpp:gen_c_abi_param_var_init |
| 3358 | | static void gen_c_abi_param_var(CodeGen *g, ImportTableEntry *import, LLVMValueRef llvm_fn, ZigFn *fn, |
| 3359 | | ZigVar *var, unsigned *arg_index) |
| 3360 | | { |
| 3361 | | ZigType *ty = var->value->type; |
| 3362 | | |
| 3363 | | ZigType *dest_ty = nullptr; |
| 3364 | | unsigned di_arg_index; |
| 3365 | | |
| 3366 | | if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat || |
| 3367 | | ty->id == ZigTypeIdInt // TODO investigate if we need to change this |
| 3368 | | ) { |
| 3369 | | var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes); |
| 3370 | | di_arg_index = *arg_index; |
| 3371 | | *arg_index += 1; |
| 3372 | | dest_ty = ty; |
| 3373 | | goto ok; |
| 3374 | | } |
| 3375 | | |
| 3376 | | // Arrays are just pointers |
| 3377 | | if (ty->id == ZigTypeIdArray) { |
| 3378 | | di_arg_index = *arg_index; |
| 3379 | | var->value_ref = LLVMGetParam(llvm_fn, *arg_index); |
| 3380 | | dest_ty = get_pointer_to_type(g, ty, false); |
| 3381 | | *arg_index += 1; |
| 3382 | | goto ok; |
| 3383 | | } |
| 3384 | | |
| 3385 | | if (g->zig_target.arch.arch == ZigLLVM_x86_64) { |
| 3386 | | assert(handle_is_ptr(ty)); |
| 3387 | | size_t ty_size = type_size(g, ty); |
| 3388 | | |
| 3389 | | if (ty->id == ZigTypeIdStruct || ty->id == ZigTypeIdUnion) { |
| 3390 | | // "If the size of an object is larger than four eightbytes, or it contains unaligned |
| 3391 | | // fields, it has class MEMORY" |
| 3392 | | if (ty_size > 32) { |
| 3393 | | di_arg_index = *arg_index; |
| 3394 | | var->value_ref = LLVMGetParam(llvm_fn, *arg_index); |
| 3395 | | dest_ty = get_pointer_to_type(g, ty, false); |
| 3396 | | *arg_index += 1; |
| 3397 | | goto ok; |
| 3398 | | } |
| 3399 | | } |
| 3400 | | if (ty->id == ZigTypeIdStruct) { |
| 3401 | | // "If the size of the aggregate exceeds a single eightbyte, each is classified |
| 3402 | | // separately. Each eightbyte gets initialized to class NO_CLASS." |
| 3403 | | if (ty_size <= 8) { |
| 3404 | | bool contains_int = false; |
| 3405 | | for (size_t i = 0; i < ty->data.structure.src_field_count; i += 1) { |
| 3406 | | if (type_is_c_abi_int(g, ty->data.structure.fields[i].type_entry)) { |
| 3407 | | contains_int = true; |
| 3408 | | break; |
| 3409 | | } |
| 3410 | | } |
| 3411 | | if (contains_int) { |
| 3412 | | var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes); |
| 3413 | | *arg_index += 1; |
| 3414 | | goto ok; |
| 3415 | | } |
| 3416 | | } |
| 3417 | | } |
| 3418 | | } |
| 3419 | | |
| 3420 | | give_up_with_c_abi_error(g, fn->proto_node); |
| 3421 | | |
| 3422 | | ok: |
| 3423 | | if (dest_ty != nullptr && var->decl_node) { |
| 3424 | | // arg index + 1 because the 0 index is return value |
| 3425 | | var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope), |
| 3426 | | buf_ptr(&var->name), import->di_file, |
| 3427 | | (unsigned)(var->decl_node->line + 1), |
| 3428 | | dest_ty->di_type, !g->strip_debug_symbols, 0, di_arg_index + 1); |
| 3429 | | } |
| 3430 | | } |
| 3431 | | |
| 3432 | 3405 | // If you edit this function you have to edit the corresponding code: |
| 3433 | | // analyze.cpp:gen_c_abi_param_type |
| 3434 | 3406 | // codegen.cpp:gen_c_abi_param_var |
| 3435 | 3407 | // codegen.cpp:gen_c_abi_param_var_init |
| 3436 | 3408 | static void gen_c_abi_param_var_init(CodeGen *g, ImportTableEntry *import, LLVMValueRef llvm_fn, ZigFn *fn, |
| ... | ... | @@ -6317,7 +6289,12 @@ static void do_code_gen(CodeGen *g) { |
| 6317 | 6289 | ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base); |
| 6318 | 6290 | |
| 6319 | 6291 | // create debug variable declarations for variables and allocate all local variables |
| 6320 | | unsigned c_abi_arg_index = 0; |
| 6292 | FnWalk fn_walk = {}; |
| 6293 | fn_walk.id = FnWalkIdVars; |
| 6294 | fn_walk.data.vars.import = import; |
| 6295 | fn_walk.data.vars.fn = fn_table_entry; |
| 6296 | fn_walk.data.vars.llvm_fn = fn; |
| 6297 | fn_walk.data.vars.gen_i = 0; |
| 6321 | 6298 | for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) { |
| 6322 | 6299 | ZigVar *var = fn_table_entry->variable_list.at(var_i); |
| 6323 | 6300 | |
| ... | ... | @@ -6337,7 +6314,8 @@ static void do_code_gen(CodeGen *g) { |
| 6337 | 6314 | var->value->type->di_type, !g->strip_debug_symbols, 0); |
| 6338 | 6315 | |
| 6339 | 6316 | } else if (is_c_abi) { |
| 6340 | | gen_c_abi_param_var(g, import, fn, fn_table_entry, var, &c_abi_arg_index); |
| 6317 | fn_walk.data.vars.var = var; |
| 6318 | iter_function_params_c_abi(g, fn_table_entry->type_entry, &fn_walk, var->src_arg_index); |
| 6341 | 6319 | } else { |
| 6342 | 6320 | assert(var->gen_arg_index != SIZE_MAX); |
| 6343 | 6321 | ZigType *gen_type; |
| ... | ... | @@ -6423,7 +6401,6 @@ static void do_code_gen(CodeGen *g) { |
| 6423 | 6401 | gen_var_debug_decl(g, variable); |
| 6424 | 6402 | } |
| 6425 | 6403 | } |
| 6426 | | assert(c_abi_arg_index == c_abi_arg_init_index); |
| 6427 | 6404 | |
| 6428 | 6405 | ir_render(g, fn_table_entry); |
| 6429 | 6406 | |