| ... | @@ -1904,14 +1904,24 @@ static bool type_is_c_abi_int(CodeGen *g, ZigType *ty) { | ... | @@ -1904,14 +1904,24 @@ static bool type_is_c_abi_int(CodeGen *g, ZigType *ty) { |
| 1904 | get_codegen_ptr_type(ty) != nullptr); | 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 | static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk, size_t src_i) { | 1914 | static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk, size_t src_i) { |
| 1908 | // Initialized from the type for some walks, but because of C var args, | 1915 | // Initialized from the type for some walks, but because of C var args, |
| 1909 | // initialized based on callsite instructions for that one. | 1916 | // initialized based on callsite instructions for that one. |
| 1910 | FnTypeParamInfo *param_info = nullptr; | 1917 | FnTypeParamInfo *param_info = nullptr; |
| 1911 | ZigType *ty; | 1918 | ZigType *ty; |
| | 1919 | ZigType *dest_ty = nullptr; |
| 1912 | AstNode *source_node = nullptr; | 1920 | AstNode *source_node = nullptr; |
| 1913 | LLVMValueRef val; | 1921 | LLVMValueRef val; |
| 1914 | LLVMValueRef llvm_fn; | 1922 | LLVMValueRef llvm_fn; |
| | 1923 | unsigned di_arg_index; |
| | 1924 | ZigVar *var; |
| 1915 | switch (fn_walk->id) { | 1925 | switch (fn_walk->id) { |
| 1916 | case FnWalkIdAttrs: | 1926 | case FnWalkIdAttrs: |
| 1917 | if (src_i >= fn_type->data.fn.fn_type_id.param_count) | 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,6 +1946,14 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ |
| 1936 | param_info = &fn_type->data.fn.fn_type_id.param_info[src_i]; | 1946 | param_info = &fn_type->data.fn.fn_type_id.param_info[src_i]; |
| 1937 | ty = param_info->type; | 1947 | ty = param_info->type; |
| 1938 | break; | 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 | if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat || | 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,6 +1983,13 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ |
| 1965 | fn_walk->data.types.gen_param_types->append(ty->type_ref); | 1983 | fn_walk->data.types.gen_param_types->append(ty->type_ref); |
| 1966 | fn_walk->data.types.param_di_types->append(ty->di_type); | 1984 | fn_walk->data.types.param_di_types->append(ty->di_type); |
| 1967 | break; | 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 | return true; | 1994 | return true; |
| 1970 | } | 1995 | } |
| ... | @@ -1986,6 +2011,13 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ | ... | @@ -1986,6 +2011,13 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ |
| 1986 | fn_walk->data.types.param_di_types->append(gen_type->di_type); | 2011 | fn_walk->data.types.param_di_types->append(gen_type->di_type); |
| 1987 | break; | 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 | return true; | 2022 | return true; |
| 1991 | } | 2023 | } |
| ... | @@ -2013,6 +2045,13 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ | ... | @@ -2013,6 +2045,13 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ |
| 2013 | fn_walk->data.types.param_di_types->append(gen_type->di_type); | 2045 | fn_walk->data.types.param_di_types->append(gen_type->di_type); |
| 2014 | break; | 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 | return true; | 2056 | return true; |
| 2018 | } | 2057 | } |
| ... | @@ -2047,6 +2086,12 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ | ... | @@ -2047,6 +2086,12 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ |
| 2047 | fn_walk->data.types.param_di_types->append(gen_type->di_type); | 2086 | fn_walk->data.types.param_di_types->append(gen_type->di_type); |
| 2048 | break; | 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 | return true; | 2096 | return true; |
| 2052 | } | 2097 | } |
| ... | @@ -2058,6 +2103,16 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ | ... | @@ -2058,6 +2103,16 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_ |
| 2058 | } | 2103 | } |
| 2059 | // otherwise allow codegen code to report a compile error | 2104 | // otherwise allow codegen code to report a compile error |
| 2060 | return false; | 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 | void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { | 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,6 +2172,9 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { |
| 2117 | case FnWalkIdTypes: | 2172 | case FnWalkIdTypes: |
| 2118 | // Not called for non-c-abi | 2173 | // Not called for non-c-abi |
| 2119 | zig_unreachable(); | 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,93 +3402,7 @@ static void set_call_instr_sret(CodeGen *g, LLVMValueRef call_instr) { |
| 3344 | LLVMAddCallSiteAttribute(call_instr, 1, sret_attr); | 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 | // If you edit this function you have to edit the corresponding code: | 3405 | // If you edit this function you have to edit the corresponding code: |
| 3433 | // analyze.cpp:gen_c_abi_param_type | | |
| 3434 | // codegen.cpp:gen_c_abi_param_var | 3406 | // codegen.cpp:gen_c_abi_param_var |
| 3435 | // codegen.cpp:gen_c_abi_param_var_init | 3407 | // codegen.cpp:gen_c_abi_param_var_init |
| 3436 | static void gen_c_abi_param_var_init(CodeGen *g, ImportTableEntry *import, LLVMValueRef llvm_fn, ZigFn *fn, | 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,7 +6289,12 @@ static void do_code_gen(CodeGen *g) { |
| 6317 | ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base); | 6289 | ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base); |
| 6318 | | 6290 | |
| 6319 | // create debug variable declarations for variables and allocate all local variables | 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 | for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) { | 6298 | for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) { |
| 6322 | ZigVar *var = fn_table_entry->variable_list.at(var_i); | 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,7 +6314,8 @@ static void do_code_gen(CodeGen *g) { |
| 6337 | var->value->type->di_type, !g->strip_debug_symbols, 0); | 6314 | var->value->type->di_type, !g->strip_debug_symbols, 0); |
| 6338 | | 6315 | |
| 6339 | } else if (is_c_abi) { | 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 | } else { | 6319 | } else { |
| 6342 | assert(var->gen_arg_index != SIZE_MAX); | 6320 | assert(var->gen_arg_index != SIZE_MAX); |
| 6343 | ZigType *gen_type; | 6321 | ZigType *gen_type; |
| ... | @@ -6423,7 +6401,6 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -6423,7 +6401,6 @@ static void do_code_gen(CodeGen *g) { |
| 6423 | gen_var_debug_decl(g, variable); | 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 | ir_render(g, fn_table_entry); | 6405 | ir_render(g, fn_table_entry); |
| 6429 | | 6406 | |