| ... | @@ -466,7 +466,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { | ... | @@ -466,7 +466,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { |
| 466 | } | 466 | } |
| 467 | | 467 | |
| 468 | bool external_linkage = linkage != GlobalLinkageIdInternal; | 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 | g->zig_target.arch.arch == ZigLLVM_x86) | 471 | g->zig_target.arch.arch == ZigLLVM_x86) |
| 471 | { | 472 | { |
| 472 | // prevent llvm name mangling | 473 | // prevent llvm name mangling |
| ... | @@ -510,17 +511,17 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { | ... | @@ -510,17 +511,17 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { |
| 510 | break; | 511 | break; |
| 511 | } | 512 | } |
| 512 | | 513 | |
| 513 | if (fn_type->data.fn.fn_type_id.cc == CallingConventionNaked) { | 514 | if (cc == CallingConventionNaked) { |
| 514 | addLLVMFnAttr(fn_table_entry->llvm_value, "naked"); | 515 | addLLVMFnAttr(fn_table_entry->llvm_value, "naked"); |
| 515 | } else { | 516 | } else { |
| 516 | LLVMSetFunctionCallConv(fn_table_entry->llvm_value, get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc)); | 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 | addLLVMFnAttr(fn_table_entry->llvm_value, "optnone"); | 520 | addLLVMFnAttr(fn_table_entry->llvm_value, "optnone"); |
| 520 | addLLVMFnAttr(fn_table_entry->llvm_value, "noinline"); | 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 | if (want_cold) { | 525 | if (want_cold) { |
| 525 | ZigLLVMAddFunctionAttrCold(fn_table_entry->llvm_value); | 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,37 +577,16 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { |
| 576 | // nothing to do | 577 | // nothing to do |
| 577 | } else if (type_is_codegen_pointer(return_type)) { | 578 | } else if (type_is_codegen_pointer(return_type)) { |
| 578 | addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull"); | 579 | addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull"); |
| 579 | } else if (handle_is_ptr(return_type) && | 580 | } else if (handle_is_ptr(return_type) && calling_convention_does_first_arg_return(cc)) { |
| 580 | calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc)) | | |
| 581 | { | | |
| 582 | addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret"); | 581 | addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret"); |
| 583 | addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull"); | 582 | addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull"); |
| 584 | } | 583 | } |
| 585 | | 584 | |
| 586 | | | |
| 587 | // set parameter attributes | 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) { | 586 | FnWalk fn_walk = {}; |
| 589 | FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i]; | 587 | fn_walk.id = FnWalkIdAttrs; |
| 590 | size_t gen_index = gen_info->gen_index; | 588 | fn_walk.data.attrs.fn = fn_table_entry; |
| 591 | bool is_byval = gen_info->is_byval; | 589 | walk_function_params(g, fn_type, &fn_walk); |
| 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 | } | | |
| 610 | | 590 | |
| 611 | uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); | 591 | uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); |
| 612 | if (err_ret_trace_arg_index != UINT32_MAX) { | 592 | if (err_ret_trace_arg_index != UINT32_MAX) { |
| ... | @@ -1858,6 +1838,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty | ... | @@ -1858,6 +1838,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty |
| 1858 | } | 1838 | } |
| 1859 | | 1839 | |
| 1860 | static void gen_var_debug_decl(CodeGen *g, ZigVar *var) { | 1840 | static void gen_var_debug_decl(CodeGen *g, ZigVar *var) { |
| | 1841 | assert(var->di_loc_var != nullptr); |
| 1861 | AstNode *source_node = var->decl_node; | 1842 | AstNode *source_node = var->decl_node; |
| 1862 | ZigLLVMDILocation *debug_loc = ZigLLVMGetDebugLoc((unsigned)source_node->line + 1, | 1843 | ZigLLVMDILocation *debug_loc = ZigLLVMGetDebugLoc((unsigned)source_node->line + 1, |
| 1863 | (unsigned)source_node->column + 1, get_di_scope(g, var->parent_scope)); | 1844 | (unsigned)source_node->column + 1, get_di_scope(g, var->parent_scope)); |
| ... | @@ -1888,6 +1869,381 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) { | ... | @@ -1888,6 +1869,381 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) { |
| 1888 | return instruction->llvm_value; | 1869 | return instruction->llvm_value; |
| 1889 | } | 1870 | } |
| 1890 | | 1871 | |
| | 1872 | ATTRIBUTE_NORETURN |
| | 1873 | static void report_errors_and_exit(CodeGen *g) { |
| | 1874 | assert(g->errors.length != 0); |
| | 1875 | for (size_t i = 0; i < g->errors.length; i += 1) { |
| | 1876 | ErrorMsg *err = g->errors.at(i); |
| | 1877 | print_err_msg(err, g->err_color); |
| | 1878 | } |
| | 1879 | exit(1); |
| | 1880 | } |
| | 1881 | |
| | 1882 | static void report_errors_and_maybe_exit(CodeGen *g) { |
| | 1883 | if (g->errors.length != 0) { |
| | 1884 | report_errors_and_exit(g); |
| | 1885 | } |
| | 1886 | } |
| | 1887 | |
| | 1888 | ATTRIBUTE_NORETURN |
| | 1889 | static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) { |
| | 1890 | ErrorMsg *msg = add_node_error(g, source_node, |
| | 1891 | buf_sprintf("TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481")); |
| | 1892 | add_error_note(g, msg, source_node, |
| | 1893 | buf_sprintf("pointers, integers, floats, bools, and enums work on all targets")); |
| | 1894 | report_errors_and_exit(g); |
| | 1895 | } |
| | 1896 | |
| | 1897 | static bool type_is_c_abi_int(CodeGen *g, ZigType *ty) { |
| | 1898 | size_t ty_size = type_size(g, ty); |
| | 1899 | if (ty_size > g->pointer_size_bytes) |
| | 1900 | return false; |
| | 1901 | return (ty->id == ZigTypeIdInt || |
| | 1902 | ty->id == ZigTypeIdFloat || |
| | 1903 | ty->id == ZigTypeIdBool || |
| | 1904 | ty->id == ZigTypeIdEnum || |
| | 1905 | get_codegen_ptr_type(ty) != nullptr); |
| | 1906 | } |
| | 1907 | |
| | 1908 | static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) { |
| | 1909 | assert(alignment > 0); |
| | 1910 | LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name); |
| | 1911 | LLVMSetAlignment(result, alignment); |
| | 1912 | return result; |
| | 1913 | } |
| | 1914 | |
| | 1915 | static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk, size_t src_i) { |
| | 1916 | // Initialized from the type for some walks, but because of C var args, |
| | 1917 | // initialized based on callsite instructions for that one. |
| | 1918 | FnTypeParamInfo *param_info = nullptr; |
| | 1919 | ZigType *ty; |
| | 1920 | ZigType *dest_ty = nullptr; |
| | 1921 | AstNode *source_node = nullptr; |
| | 1922 | LLVMValueRef val; |
| | 1923 | LLVMValueRef llvm_fn; |
| | 1924 | unsigned di_arg_index; |
| | 1925 | ZigVar *var; |
| | 1926 | switch (fn_walk->id) { |
| | 1927 | case FnWalkIdAttrs: |
| | 1928 | if (src_i >= fn_type->data.fn.fn_type_id.param_count) |
| | 1929 | return false; |
| | 1930 | param_info = &fn_type->data.fn.fn_type_id.param_info[src_i]; |
| | 1931 | ty = param_info->type; |
| | 1932 | source_node = fn_walk->data.attrs.fn->proto_node; |
| | 1933 | llvm_fn = fn_walk->data.attrs.fn->llvm_value; |
| | 1934 | break; |
| | 1935 | case FnWalkIdCall: { |
| | 1936 | if (src_i >= fn_walk->data.call.inst->arg_count) |
| | 1937 | return false; |
| | 1938 | IrInstruction *arg = fn_walk->data.call.inst->args[src_i]; |
| | 1939 | ty = arg->value.type; |
| | 1940 | source_node = arg->source_node; |
| | 1941 | val = ir_llvm_value(g, arg); |
| | 1942 | break; |
| | 1943 | } |
| | 1944 | case FnWalkIdTypes: |
| | 1945 | if (src_i >= fn_type->data.fn.fn_type_id.param_count) |
| | 1946 | return false; |
| | 1947 | param_info = &fn_type->data.fn.fn_type_id.param_info[src_i]; |
| | 1948 | ty = param_info->type; |
| | 1949 | break; |
| | 1950 | case FnWalkIdVars: |
| | 1951 | assert(src_i < fn_type->data.fn.fn_type_id.param_count); |
| | 1952 | param_info = &fn_type->data.fn.fn_type_id.param_info[src_i]; |
| | 1953 | ty = param_info->type; |
| | 1954 | var = fn_walk->data.vars.var; |
| | 1955 | source_node = var->decl_node; |
| | 1956 | llvm_fn = fn_walk->data.vars.llvm_fn; |
| | 1957 | break; |
| | 1958 | case FnWalkIdInits: |
| | 1959 | if (src_i >= fn_type->data.fn.fn_type_id.param_count) |
| | 1960 | return false; |
| | 1961 | param_info = &fn_type->data.fn.fn_type_id.param_info[src_i]; |
| | 1962 | ty = param_info->type; |
| | 1963 | var = fn_walk->data.inits.fn->variable_list.at(src_i); |
| | 1964 | source_node = fn_walk->data.inits.fn->proto_node; |
| | 1965 | llvm_fn = fn_walk->data.inits.llvm_fn; |
| | 1966 | break; |
| | 1967 | } |
| | 1968 | |
| | 1969 | if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat || |
| | 1970 | ty->id == ZigTypeIdInt // TODO investigate if we need to change this |
| | 1971 | ) { |
| | 1972 | switch (fn_walk->id) { |
| | 1973 | case FnWalkIdAttrs: { |
| | 1974 | ZigType *ptr_type = get_codegen_ptr_type(ty); |
| | 1975 | if (ptr_type != nullptr) { |
| | 1976 | if (ty->id != ZigTypeIdOptional) { |
| | 1977 | addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull"); |
| | 1978 | } |
| | 1979 | if (ptr_type->data.pointer.is_const) { |
| | 1980 | addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "readonly"); |
| | 1981 | } |
| | 1982 | if (param_info->is_noalias) { |
| | 1983 | addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "noalias"); |
| | 1984 | } |
| | 1985 | } |
| | 1986 | fn_walk->data.attrs.gen_i += 1; |
| | 1987 | break; |
| | 1988 | } |
| | 1989 | case FnWalkIdCall: |
| | 1990 | fn_walk->data.call.gen_param_values->append(val); |
| | 1991 | break; |
| | 1992 | case FnWalkIdTypes: |
| | 1993 | fn_walk->data.types.gen_param_types->append(ty->type_ref); |
| | 1994 | fn_walk->data.types.param_di_types->append(ty->di_type); |
| | 1995 | break; |
| | 1996 | case FnWalkIdVars: { |
| | 1997 | var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes); |
| | 1998 | di_arg_index = fn_walk->data.vars.gen_i; |
| | 1999 | fn_walk->data.vars.gen_i += 1; |
| | 2000 | dest_ty = ty; |
| | 2001 | goto var_ok; |
| | 2002 | } |
| | 2003 | case FnWalkIdInits: |
| | 2004 | clear_debug_source_node(g); |
| | 2005 | gen_store_untyped(g, LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i), var->value_ref, var->align_bytes, false); |
| | 2006 | if (var->decl_node) { |
| | 2007 | gen_var_debug_decl(g, var); |
| | 2008 | } |
| | 2009 | fn_walk->data.inits.gen_i += 1; |
| | 2010 | break; |
| | 2011 | } |
| | 2012 | return true; |
| | 2013 | } |
| | 2014 | |
| | 2015 | // Arrays are just pointers |
| | 2016 | if (ty->id == ZigTypeIdArray) { |
| | 2017 | assert(handle_is_ptr(ty)); |
| | 2018 | switch (fn_walk->id) { |
| | 2019 | case FnWalkIdAttrs: |
| | 2020 | addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull"); |
| | 2021 | fn_walk->data.attrs.gen_i += 1; |
| | 2022 | break; |
| | 2023 | case FnWalkIdCall: |
| | 2024 | fn_walk->data.call.gen_param_values->append(val); |
| | 2025 | break; |
| | 2026 | case FnWalkIdTypes: { |
| | 2027 | ZigType *gen_type = get_pointer_to_type(g, ty, true); |
| | 2028 | fn_walk->data.types.gen_param_types->append(gen_type->type_ref); |
| | 2029 | fn_walk->data.types.param_di_types->append(gen_type->di_type); |
| | 2030 | break; |
| | 2031 | } |
| | 2032 | case FnWalkIdVars: { |
| | 2033 | var->value_ref = LLVMGetParam(llvm_fn, fn_walk->data.vars.gen_i); |
| | 2034 | di_arg_index = fn_walk->data.vars.gen_i; |
| | 2035 | dest_ty = get_pointer_to_type(g, ty, false); |
| | 2036 | fn_walk->data.vars.gen_i += 1; |
| | 2037 | goto var_ok; |
| | 2038 | } |
| | 2039 | case FnWalkIdInits: |
| | 2040 | if (var->decl_node) { |
| | 2041 | gen_var_debug_decl(g, var); |
| | 2042 | } |
| | 2043 | fn_walk->data.inits.gen_i += 1; |
| | 2044 | break; |
| | 2045 | } |
| | 2046 | return true; |
| | 2047 | } |
| | 2048 | |
| | 2049 | if (g->zig_target.arch.arch == ZigLLVM_x86_64) { |
| | 2050 | size_t ty_size = type_size(g, ty); |
| | 2051 | if (ty->id == ZigTypeIdStruct || ty->id == ZigTypeIdUnion) { |
| | 2052 | assert(handle_is_ptr(ty)); |
| | 2053 | |
| | 2054 | // "If the size of an object is larger than four eightbytes, or it contains unaligned |
| | 2055 | // fields, it has class MEMORY" |
| | 2056 | if (ty_size > 32) { |
| | 2057 | switch (fn_walk->id) { |
| | 2058 | case FnWalkIdAttrs: |
| | 2059 | addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "byval"); |
| | 2060 | addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull"); |
| | 2061 | fn_walk->data.attrs.gen_i += 1; |
| | 2062 | break; |
| | 2063 | case FnWalkIdCall: |
| | 2064 | fn_walk->data.call.gen_param_values->append(val); |
| | 2065 | break; |
| | 2066 | case FnWalkIdTypes: { |
| | 2067 | ZigType *gen_type = get_pointer_to_type(g, ty, true); |
| | 2068 | fn_walk->data.types.gen_param_types->append(gen_type->type_ref); |
| | 2069 | fn_walk->data.types.param_di_types->append(gen_type->di_type); |
| | 2070 | break; |
| | 2071 | } |
| | 2072 | case FnWalkIdVars: { |
| | 2073 | di_arg_index = fn_walk->data.vars.gen_i; |
| | 2074 | var->value_ref = LLVMGetParam(llvm_fn, fn_walk->data.vars.gen_i); |
| | 2075 | dest_ty = get_pointer_to_type(g, ty, false); |
| | 2076 | fn_walk->data.vars.gen_i += 1; |
| | 2077 | goto var_ok; |
| | 2078 | } |
| | 2079 | case FnWalkIdInits: |
| | 2080 | if (var->decl_node) { |
| | 2081 | gen_var_debug_decl(g, var); |
| | 2082 | } |
| | 2083 | fn_walk->data.inits.gen_i += 1; |
| | 2084 | break; |
| | 2085 | } |
| | 2086 | return true; |
| | 2087 | } |
| | 2088 | } |
| | 2089 | if (ty->id == ZigTypeIdStruct) { |
| | 2090 | assert(handle_is_ptr(ty)); |
| | 2091 | // "If the size of the aggregate exceeds a single eightbyte, each is classified |
| | 2092 | // separately. Each eightbyte gets initialized to class NO_CLASS." |
| | 2093 | if (ty_size <= 8) { |
| | 2094 | bool contains_int = false; |
| | 2095 | for (size_t i = 0; i < ty->data.structure.src_field_count; i += 1) { |
| | 2096 | if (type_is_c_abi_int(g, ty->data.structure.fields[i].type_entry)) { |
| | 2097 | contains_int = true; |
| | 2098 | break; |
| | 2099 | } |
| | 2100 | } |
| | 2101 | if (contains_int) { |
| | 2102 | switch (fn_walk->id) { |
| | 2103 | case FnWalkIdAttrs: |
| | 2104 | fn_walk->data.attrs.gen_i += 1; |
| | 2105 | break; |
| | 2106 | case FnWalkIdCall: { |
| | 2107 | LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0); |
| | 2108 | LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, val, ptr_to_int_type_ref, ""); |
| | 2109 | LLVMValueRef loaded = LLVMBuildLoad(g->builder, bitcasted, ""); |
| | 2110 | fn_walk->data.call.gen_param_values->append(loaded); |
| | 2111 | break; |
| | 2112 | } |
| | 2113 | case FnWalkIdTypes: { |
| | 2114 | ZigType *gen_type = get_int_type(g, false, ty_size * 8); |
| | 2115 | fn_walk->data.types.gen_param_types->append(gen_type->type_ref); |
| | 2116 | fn_walk->data.types.param_di_types->append(gen_type->di_type); |
| | 2117 | break; |
| | 2118 | } |
| | 2119 | case FnWalkIdVars: { |
| | 2120 | di_arg_index = fn_walk->data.vars.gen_i; |
| | 2121 | var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes); |
| | 2122 | fn_walk->data.vars.gen_i += 1; |
| | 2123 | dest_ty = ty; |
| | 2124 | goto var_ok; |
| | 2125 | } |
| | 2126 | case FnWalkIdInits: { |
| | 2127 | clear_debug_source_node(g); |
| | 2128 | LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i); |
| | 2129 | LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0); |
| | 2130 | LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, ""); |
| | 2131 | gen_store_untyped(g, arg, bitcasted, var->align_bytes, false); |
| | 2132 | if (var->decl_node) { |
| | 2133 | gen_var_debug_decl(g, var); |
| | 2134 | } |
| | 2135 | fn_walk->data.inits.gen_i += 1; |
| | 2136 | break; |
| | 2137 | } |
| | 2138 | } |
| | 2139 | return true; |
| | 2140 | } |
| | 2141 | } |
| | 2142 | } |
| | 2143 | } |
| | 2144 | if (source_node != nullptr) { |
| | 2145 | give_up_with_c_abi_error(g, source_node); |
| | 2146 | } |
| | 2147 | // otherwise allow codegen code to report a compile error |
| | 2148 | return false; |
| | 2149 | |
| | 2150 | var_ok: |
| | 2151 | if (dest_ty != nullptr && var->decl_node) { |
| | 2152 | // arg index + 1 because the 0 index is return value |
| | 2153 | var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope), |
| | 2154 | buf_ptr(&var->name), fn_walk->data.vars.import->di_file, |
| | 2155 | (unsigned)(var->decl_node->line + 1), |
| | 2156 | dest_ty->di_type, !g->strip_debug_symbols, 0, di_arg_index + 1); |
| | 2157 | } |
| | 2158 | return true; |
| | 2159 | } |
| | 2160 | |
| | 2161 | void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { |
| | 2162 | CallingConvention cc = fn_type->data.fn.fn_type_id.cc; |
| | 2163 | if (cc == CallingConventionC) { |
| | 2164 | size_t src_i = 0; |
| | 2165 | for (;;) { |
| | 2166 | if (!iter_function_params_c_abi(g, fn_type, fn_walk, src_i)) |
| | 2167 | break; |
| | 2168 | src_i += 1; |
| | 2169 | } |
| | 2170 | return; |
| | 2171 | } |
| | 2172 | if (fn_walk->id == FnWalkIdCall) { |
| | 2173 | IrInstructionCall *instruction = fn_walk->data.call.inst; |
| | 2174 | bool is_var_args = fn_walk->data.call.is_var_args; |
| | 2175 | for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) { |
| | 2176 | IrInstruction *param_instruction = instruction->args[call_i]; |
| | 2177 | ZigType *param_type = param_instruction->value.type; |
| | 2178 | if (is_var_args || type_has_bits(param_type)) { |
| | 2179 | LLVMValueRef param_value = ir_llvm_value(g, param_instruction); |
| | 2180 | assert(param_value); |
| | 2181 | fn_walk->data.call.gen_param_values->append(param_value); |
| | 2182 | } |
| | 2183 | } |
| | 2184 | return; |
| | 2185 | } |
| | 2186 | size_t next_var_i = 0; |
| | 2187 | for (size_t param_i = 0; param_i < fn_type->data.fn.fn_type_id.param_count; param_i += 1) { |
| | 2188 | FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i]; |
| | 2189 | size_t gen_index = gen_info->gen_index; |
| | 2190 | |
| | 2191 | if (gen_index == SIZE_MAX) { |
| | 2192 | continue; |
| | 2193 | } |
| | 2194 | |
| | 2195 | switch (fn_walk->id) { |
| | 2196 | case FnWalkIdAttrs: { |
| | 2197 | LLVMValueRef llvm_fn = fn_walk->data.attrs.fn->llvm_value; |
| | 2198 | bool is_byval = gen_info->is_byval; |
| | 2199 | FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[param_i]; |
| | 2200 | |
| | 2201 | ZigType *param_type = gen_info->type; |
| | 2202 | if (param_info->is_noalias) { |
| | 2203 | addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "noalias"); |
| | 2204 | } |
| | 2205 | if ((param_type->id == ZigTypeIdPointer && param_type->data.pointer.is_const) || is_byval) { |
| | 2206 | addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "readonly"); |
| | 2207 | } |
| | 2208 | if (param_type->id == ZigTypeIdPointer) { |
| | 2209 | addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "nonnull"); |
| | 2210 | } |
| | 2211 | break; |
| | 2212 | } |
| | 2213 | case FnWalkIdInits: { |
| | 2214 | ZigFn *fn_table_entry = fn_walk->data.inits.fn; |
| | 2215 | LLVMValueRef llvm_fn = fn_table_entry->llvm_value; |
| | 2216 | ZigVar *variable = fn_table_entry->variable_list.at(next_var_i); |
| | 2217 | assert(variable->src_arg_index != SIZE_MAX); |
| | 2218 | next_var_i += 1; |
| | 2219 | |
| | 2220 | assert(variable); |
| | 2221 | assert(variable->value_ref); |
| | 2222 | |
| | 2223 | if (!handle_is_ptr(variable->value->type)) { |
| | 2224 | clear_debug_source_node(g); |
| | 2225 | gen_store_untyped(g, LLVMGetParam(llvm_fn, (unsigned)variable->gen_arg_index), variable->value_ref, |
| | 2226 | variable->align_bytes, false); |
| | 2227 | } |
| | 2228 | |
| | 2229 | if (variable->decl_node) { |
| | 2230 | gen_var_debug_decl(g, variable); |
| | 2231 | } |
| | 2232 | break; |
| | 2233 | } |
| | 2234 | case FnWalkIdCall: |
| | 2235 | // handled before for loop |
| | 2236 | zig_unreachable(); |
| | 2237 | case FnWalkIdTypes: |
| | 2238 | // Not called for non-c-abi |
| | 2239 | zig_unreachable(); |
| | 2240 | case FnWalkIdVars: |
| | 2241 | // iter_function_params_c_abi is called directly for this one |
| | 2242 | zig_unreachable(); |
| | 2243 | } |
| | 2244 | } |
| | 2245 | } |
| | 2246 | |
| 1891 | static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable, | 2247 | static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable, |
| 1892 | IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction) | 2248 | IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction) |
| 1893 | { | 2249 | { |
| ... | @@ -3128,40 +3484,31 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr | ... | @@ -3128,40 +3484,31 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3128 | ZigType *src_return_type = fn_type_id->return_type; | 3484 | ZigType *src_return_type = fn_type_id->return_type; |
| 3129 | bool ret_has_bits = type_has_bits(src_return_type); | 3485 | bool ret_has_bits = type_has_bits(src_return_type); |
| 3130 | | 3486 | |
| | 3487 | CallingConvention cc = fn_type->data.fn.fn_type_id.cc; |
| | 3488 | |
| 3131 | bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type) && | 3489 | bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type) && |
| 3132 | calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc); | 3490 | calling_convention_does_first_arg_return(cc); |
| 3133 | bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id); | 3491 | bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id); |
| 3134 | // +2 for the async args | | |
| 3135 | size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0) + 2; | | |
| 3136 | bool is_var_args = fn_type_id->is_var_args; | 3492 | bool is_var_args = fn_type_id->is_var_args; |
| 3137 | LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count); | 3493 | ZigList<LLVMValueRef> gen_param_values = {}; |
| 3138 | size_t gen_param_index = 0; | | |
| 3139 | if (first_arg_ret) { | 3494 | if (first_arg_ret) { |
| 3140 | gen_param_values[gen_param_index] = instruction->tmp_ptr; | 3495 | gen_param_values.append(instruction->tmp_ptr); |
| 3141 | gen_param_index += 1; | | |
| 3142 | } | 3496 | } |
| 3143 | if (prefix_arg_err_ret_stack) { | 3497 | if (prefix_arg_err_ret_stack) { |
| 3144 | gen_param_values[gen_param_index] = get_cur_err_ret_trace_val(g, instruction->base.scope); | 3498 | gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope)); |
| 3145 | gen_param_index += 1; | | |
| 3146 | } | 3499 | } |
| 3147 | if (instruction->is_async) { | 3500 | if (instruction->is_async) { |
| 3148 | gen_param_values[gen_param_index] = ir_llvm_value(g, instruction->async_allocator); | 3501 | gen_param_values.append(ir_llvm_value(g, instruction->async_allocator)); |
| 3149 | gen_param_index += 1; | | |
| 3150 | | 3502 | |
| 3151 | LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, ""); | 3503 | LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, ""); |
| 3152 | gen_param_values[gen_param_index] = err_val_ptr; | 3504 | gen_param_values.append(err_val_ptr); |
| 3153 | gen_param_index += 1; | | |
| 3154 | } | | |
| 3155 | for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) { | | |
| 3156 | IrInstruction *param_instruction = instruction->args[call_i]; | | |
| 3157 | ZigType *param_type = param_instruction->value.type; | | |
| 3158 | if (is_var_args || type_has_bits(param_type)) { | | |
| 3159 | LLVMValueRef param_value = ir_llvm_value(g, param_instruction); | | |
| 3160 | assert(param_value); | | |
| 3161 | gen_param_values[gen_param_index] = param_value; | | |
| 3162 | gen_param_index += 1; | | |
| 3163 | } | | |
| 3164 | } | 3505 | } |
| | 3506 | FnWalk fn_walk = {}; |
| | 3507 | fn_walk.id = FnWalkIdCall; |
| | 3508 | fn_walk.data.call.inst = instruction; |
| | 3509 | fn_walk.data.call.is_var_args = is_var_args; |
| | 3510 | fn_walk.data.call.gen_param_values = &gen_param_values; |
| | 3511 | walk_function_params(g, fn_type, &fn_walk); |
| 3165 | | 3512 | |
| 3166 | ZigLLVM_FnInline fn_inline; | 3513 | ZigLLVM_FnInline fn_inline; |
| 3167 | switch (instruction->fn_inline) { | 3514 | switch (instruction->fn_inline) { |
| ... | @@ -3176,12 +3523,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr | ... | @@ -3176,12 +3523,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3176 | break; | 3523 | break; |
| 3177 | } | 3524 | } |
| 3178 | | 3525 | |
| 3179 | LLVMCallConv llvm_cc = get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc); | 3526 | LLVMCallConv llvm_cc = get_llvm_cc(g, cc); |
| 3180 | LLVMValueRef result; | 3527 | LLVMValueRef result; |
| 3181 | | 3528 | |
| 3182 | if (instruction->new_stack == nullptr) { | 3529 | if (instruction->new_stack == nullptr) { |
| 3183 | result = ZigLLVMBuildCall(g->builder, fn_val, | 3530 | result = ZigLLVMBuildCall(g->builder, fn_val, |
| 3184 | gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, ""); | 3531 | gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, ""); |
| 3185 | } else { | 3532 | } else { |
| 3186 | LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g); | 3533 | LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g); |
| 3187 | LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g); | 3534 | LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g); |
| ... | @@ -3190,7 +3537,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr | ... | @@ -3190,7 +3537,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3190 | LLVMValueRef old_stack_ref = LLVMBuildCall(g->builder, stacksave_fn_val, nullptr, 0, ""); | 3537 | LLVMValueRef old_stack_ref = LLVMBuildCall(g->builder, stacksave_fn_val, nullptr, 0, ""); |
| 3191 | gen_set_stack_pointer(g, new_stack_addr); | 3538 | gen_set_stack_pointer(g, new_stack_addr); |
| 3192 | result = ZigLLVMBuildCall(g->builder, fn_val, | 3539 | result = ZigLLVMBuildCall(g->builder, fn_val, |
| 3193 | gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, ""); | 3540 | gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, ""); |
| 3194 | LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, ""); | 3541 | LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, ""); |
| 3195 | } | 3542 | } |
| 3196 | | 3543 | |
| ... | @@ -5721,13 +6068,6 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val, | ... | @@ -5721,13 +6068,6 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val, |
| 5721 | // TODO ^^ make an actual global variable | 6068 | // TODO ^^ make an actual global variable |
| 5722 | } | 6069 | } |
| 5723 | | 6070 | |
| 5724 | static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) { | | |
| 5725 | assert(alignment > 0); | | |
| 5726 | LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name); | | |
| 5727 | LLVMSetAlignment(result, alignment); | | |
| 5728 | return result; | | |
| 5729 | } | | |
| 5730 | | | |
| 5731 | static void ensure_cache_dir(CodeGen *g) { | 6071 | static void ensure_cache_dir(CodeGen *g) { |
| 5732 | int err; | 6072 | int err; |
| 5733 | if ((err = os_make_path(&g->cache_dir))) { | 6073 | if ((err = os_make_path(&g->cache_dir))) { |
| ... | @@ -5735,16 +6075,6 @@ static void ensure_cache_dir(CodeGen *g) { | ... | @@ -5735,16 +6075,6 @@ static void ensure_cache_dir(CodeGen *g) { |
| 5735 | } | 6075 | } |
| 5736 | } | 6076 | } |
| 5737 | | 6077 | |
| 5738 | static void report_errors_and_maybe_exit(CodeGen *g) { | | |
| 5739 | if (g->errors.length != 0) { | | |
| 5740 | for (size_t i = 0; i < g->errors.length; i += 1) { | | |
| 5741 | ErrorMsg *err = g->errors.at(i); | | |
| 5742 | print_err_msg(err, g->err_color); | | |
| 5743 | } | | |
| 5744 | exit(1); | | |
| 5745 | } | | |
| 5746 | } | | |
| 5747 | | | |
| 5748 | static void validate_inline_fns(CodeGen *g) { | 6078 | static void validate_inline_fns(CodeGen *g) { |
| 5749 | for (size_t i = 0; i < g->inline_fns.length; i += 1) { | 6079 | for (size_t i = 0; i < g->inline_fns.length; i += 1) { |
| 5750 | ZigFn *fn_entry = g->inline_fns.at(i); | 6080 | ZigFn *fn_entry = g->inline_fns.at(i); |
| ... | @@ -5865,6 +6195,8 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -5865,6 +6195,8 @@ static void do_code_gen(CodeGen *g) { |
| 5865 | // Generate function definitions. | 6195 | // Generate function definitions. |
| 5866 | for (size_t fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) { | 6196 | for (size_t fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) { |
| 5867 | ZigFn *fn_table_entry = g->fn_defs.at(fn_i); | 6197 | ZigFn *fn_table_entry = g->fn_defs.at(fn_i); |
| | 6198 | CallingConvention cc = fn_table_entry->type_entry->data.fn.fn_type_id.cc; |
| | 6199 | bool is_c_abi = cc == CallingConventionC; |
| 5868 | | 6200 | |
| 5869 | LLVMValueRef fn = fn_llvm_value(g, fn_table_entry); | 6201 | LLVMValueRef fn = fn_llvm_value(g, fn_table_entry); |
| 5870 | g->cur_fn = fn_table_entry; | 6202 | g->cur_fn = fn_table_entry; |
| ... | @@ -5888,7 +6220,7 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -5888,7 +6220,7 @@ static void do_code_gen(CodeGen *g) { |
| 5888 | } | 6220 | } |
| 5889 | | 6221 | |
| 5890 | // error return tracing setup | 6222 | // error return tracing setup |
| 5891 | bool is_async = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; | 6223 | bool is_async = cc == CallingConventionAsync; |
| 5892 | bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn && !is_async && !have_err_ret_trace_arg; | 6224 | bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn && !is_async && !have_err_ret_trace_arg; |
| 5893 | LLVMValueRef err_ret_array_val = nullptr; | 6225 | LLVMValueRef err_ret_array_val = nullptr; |
| 5894 | if (have_err_ret_trace_stack) { | 6226 | if (have_err_ret_trace_stack) { |
| ... | @@ -5948,6 +6280,12 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -5948,6 +6280,12 @@ static void do_code_gen(CodeGen *g) { |
| 5948 | ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base); | 6280 | ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base); |
| 5949 | | 6281 | |
| 5950 | // create debug variable declarations for variables and allocate all local variables | 6282 | // create debug variable declarations for variables and allocate all local variables |
| | 6283 | FnWalk fn_walk_var = {}; |
| | 6284 | fn_walk_var.id = FnWalkIdVars; |
| | 6285 | fn_walk_var.data.vars.import = import; |
| | 6286 | fn_walk_var.data.vars.fn = fn_table_entry; |
| | 6287 | fn_walk_var.data.vars.llvm_fn = fn; |
| | 6288 | fn_walk_var.data.vars.gen_i = 0; |
| 5951 | for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) { | 6289 | for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) { |
| 5952 | ZigVar *var = fn_table_entry->variable_list.at(var_i); | 6290 | ZigVar *var = fn_table_entry->variable_list.at(var_i); |
| 5953 | | 6291 | |
| ... | @@ -5966,6 +6304,9 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -5966,6 +6304,9 @@ static void do_code_gen(CodeGen *g) { |
| 5966 | buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1), | 6304 | buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1), |
| 5967 | var->value->type->di_type, !g->strip_debug_symbols, 0); | 6305 | var->value->type->di_type, !g->strip_debug_symbols, 0); |
| 5968 | | 6306 | |
| | 6307 | } else if (is_c_abi) { |
| | 6308 | fn_walk_var.data.vars.var = var; |
| | 6309 | iter_function_params_c_abi(g, fn_table_entry->type_entry, &fn_walk_var, var->src_arg_index); |
| 5969 | } else { | 6310 | } else { |
| 5970 | assert(var->gen_arg_index != SIZE_MAX); | 6311 | assert(var->gen_arg_index != SIZE_MAX); |
| 5971 | ZigType *gen_type; | 6312 | ZigType *gen_type; |
| ... | @@ -6017,33 +6358,13 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -6017,33 +6358,13 @@ static void do_code_gen(CodeGen *g) { |
| 6017 | gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false)); | 6358 | gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false)); |
| 6018 | } | 6359 | } |
| 6019 | | 6360 | |
| 6020 | FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; | | |
| 6021 | | | |
| 6022 | // create debug variable declarations for parameters | 6361 | // create debug variable declarations for parameters |
| 6023 | // rely on the first variables in the variable_list being parameters. | 6362 | // rely on the first variables in the variable_list being parameters. |
| 6024 | size_t next_var_i = 0; | 6363 | FnWalk fn_walk_init = {}; |
| 6025 | for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) { | 6364 | fn_walk_init.id = FnWalkIdInits; |
| 6026 | FnGenParamInfo *info = &fn_table_entry->type_entry->data.fn.gen_param_info[param_i]; | 6365 | fn_walk_init.data.inits.fn = fn_table_entry; |
| 6027 | if (info->gen_index == SIZE_MAX) | 6366 | fn_walk_init.data.inits.llvm_fn = fn; |
| 6028 | continue; | 6367 | walk_function_params(g, fn_table_entry->type_entry, &fn_walk_init); |
| 6029 | | | |
| 6030 | ZigVar *variable = fn_table_entry->variable_list.at(next_var_i); | | |
| 6031 | assert(variable->src_arg_index != SIZE_MAX); | | |
| 6032 | next_var_i += 1; | | |
| 6033 | | | |
| 6034 | assert(variable); | | |
| 6035 | assert(variable->value_ref); | | |
| 6036 | | | |
| 6037 | if (!handle_is_ptr(variable->value->type)) { | | |
| 6038 | clear_debug_source_node(g); | | |
| 6039 | gen_store_untyped(g, LLVMGetParam(fn, (unsigned)variable->gen_arg_index), variable->value_ref, | | |
| 6040 | variable->align_bytes, false); | | |
| 6041 | } | | |
| 6042 | | | |
| 6043 | if (variable->decl_node) { | | |
| 6044 | gen_var_debug_decl(g, variable); | | |
| 6045 | } | | |
| 6046 | } | | |
| 6047 | | 6368 | |
| 6048 | ir_render(g, fn_table_entry); | 6369 | ir_render(g, fn_table_entry); |
| 6049 | | 6370 | |