authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-07 13:56:54-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-07 13:56:54-04:00
log7505529e448dc9e07e9220addc994dc5b4a524fd
tree60868daa6a79c9578a649c738df1aac2a15e9e35
parent29923efb954aa6e3297e6c2010eaf92fdb977c53
parent743b2e4afc72f436a73977f896b32e6041785795
signaturelock-open Commit is signed but in an unrecognized format.

Merge branch 'c-abi'

closes #1411 closes #1264

11 files changed, 927 insertions(+), 133 deletions(-)

src/all_types.hpp+49
...@@ -3284,4 +3284,53 @@ enum FloatMode {...@@ -3284,4 +3284,53 @@ enum FloatMode {
3284 FloatModeStrict,3284 FloatModeStrict,
3285};3285};
32863286
3287enum FnWalkId {
3288 FnWalkIdAttrs,
3289 FnWalkIdCall,
3290 FnWalkIdTypes,
3291 FnWalkIdVars,
3292 FnWalkIdInits,
3293};
3294
3295struct FnWalkAttrs {
3296 ZigFn *fn;
3297 unsigned gen_i;
3298};
3299
3300struct FnWalkCall {
3301 ZigList<LLVMValueRef> *gen_param_values;
3302 IrInstructionCall *inst;
3303 bool is_var_args;
3304};
3305
3306struct FnWalkTypes {
3307 ZigList<ZigLLVMDIType *> *param_di_types;
3308 ZigList<LLVMTypeRef> *gen_param_types;
3309};
3310
3311struct FnWalkVars {
3312 ImportTableEntry *import;
3313 LLVMValueRef llvm_fn;
3314 ZigFn *fn;
3315 ZigVar *var;
3316 unsigned gen_i;
3317};
3318
3319struct FnWalkInits {
3320 LLVMValueRef llvm_fn;
3321 ZigFn *fn;
3322 unsigned gen_i;
3323};
3324
3325struct FnWalk {
3326 FnWalkId id;
3327 union {
3328 FnWalkAttrs attrs;
3329 FnWalkCall call;
3330 FnWalkTypes types;
3331 FnWalkVars vars;
3332 FnWalkInits inits;
3333 } data;
3334};
3335
3287#endif3336#endif
src/analyze.cpp+29-29
...@@ -1119,18 +1119,18 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -1119,18 +1119,18 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
1119 bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) &&1119 bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) &&
1120 handle_is_ptr(fn_type_id->return_type);1120 handle_is_ptr(fn_type_id->return_type);
1121 bool is_async = fn_type_id->cc == CallingConventionAsync;1121 bool is_async = fn_type_id->cc == CallingConventionAsync;
1122 bool is_c_abi = fn_type_id->cc == CallingConventionC;
1122 bool prefix_arg_error_return_trace = g->have_err_ret_tracing && fn_type_can_fail(fn_type_id);1123 bool prefix_arg_error_return_trace = g->have_err_ret_tracing && fn_type_can_fail(fn_type_id);
1123 // +1 for maybe making the first argument the return value1124 // +1 for maybe making the first argument the return value
1124 // +1 for maybe first argument the error return trace1125 // +1 for maybe first argument the error return trace
1125 // +2 for maybe arguments async allocator and error code pointer1126 // +2 for maybe arguments async allocator and error code pointer
1126 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(4 + fn_type_id->param_count);1127 ZigList<LLVMTypeRef> gen_param_types = {};
1127 // +1 because 0 is the return type and1128 // +1 because 0 is the return type and
1128 // +1 for maybe making first arg ret val and1129 // +1 for maybe making first arg ret val and
1129 // +1 for maybe first argument the error return trace1130 // +1 for maybe first argument the error return trace
1130 // +2 for maybe arguments async allocator and error code pointer1131 // +2 for maybe arguments async allocator and error code pointer
1131 ZigLLVMDIType **param_di_types = allocate<ZigLLVMDIType*>(5 + fn_type_id->param_count);1132 ZigList<ZigLLVMDIType *> param_di_types = {};
1132 param_di_types[0] = fn_type_id->return_type->di_type;1133 param_di_types.append(fn_type_id->return_type->di_type);
1133 size_t gen_param_index = 0;
1134 ZigType *gen_return_type;1134 ZigType *gen_return_type;
1135 if (is_async) {1135 if (is_async) {
1136 gen_return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);1136 gen_return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
...@@ -1138,10 +1138,8 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -1138,10 +1138,8 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
1138 gen_return_type = g->builtin_types.entry_void;1138 gen_return_type = g->builtin_types.entry_void;
1139 } else if (first_arg_return) {1139 } else if (first_arg_return) {
1140 ZigType *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false);1140 ZigType *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false);
1141 gen_param_types[gen_param_index] = gen_type->type_ref;1141 gen_param_types.append(gen_type->type_ref);
1142 gen_param_index += 1;1142 param_di_types.append(gen_type->di_type);
1143 // after the gen_param_index += 1 because 0 is the return type
1144 param_di_types[gen_param_index] = gen_type->di_type;
1145 gen_return_type = g->builtin_types.entry_void;1143 gen_return_type = g->builtin_types.entry_void;
1146 } else {1144 } else {
1147 gen_return_type = fn_type_id->return_type;1145 gen_return_type = fn_type_id->return_type;
...@@ -1150,28 +1148,22 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -1150,28 +1148,22 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
11501148
1151 if (prefix_arg_error_return_trace) {1149 if (prefix_arg_error_return_trace) {
1152 ZigType *gen_type = get_ptr_to_stack_trace_type(g);1150 ZigType *gen_type = get_ptr_to_stack_trace_type(g);
1153 gen_param_types[gen_param_index] = gen_type->type_ref;1151 gen_param_types.append(gen_type->type_ref);
1154 gen_param_index += 1;1152 param_di_types.append(gen_type->di_type);
1155 // after the gen_param_index += 1 because 0 is the return type
1156 param_di_types[gen_param_index] = gen_type->di_type;
1157 }1153 }
1158 if (is_async) {1154 if (is_async) {
1159 {1155 {
1160 // async allocator param1156 // async allocator param
1161 ZigType *gen_type = fn_type_id->async_allocator_type;1157 ZigType *gen_type = fn_type_id->async_allocator_type;
1162 gen_param_types[gen_param_index] = gen_type->type_ref;1158 gen_param_types.append(gen_type->type_ref);
1163 gen_param_index += 1;1159 param_di_types.append(gen_type->di_type);
1164 // after the gen_param_index += 1 because 0 is the return type
1165 param_di_types[gen_param_index] = gen_type->di_type;
1166 }1160 }
11671161
1168 {1162 {
1169 // error code pointer1163 // error code pointer
1170 ZigType *gen_type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false);1164 ZigType *gen_type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false);
1171 gen_param_types[gen_param_index] = gen_type->type_ref;1165 gen_param_types.append(gen_type->type_ref);
1172 gen_param_index += 1;1166 param_di_types.append(gen_type->di_type);
1173 // after the gen_param_index += 1 because 0 is the return type
1174 param_di_types[gen_param_index] = gen_type->di_type;
1175 }1167 }
1176 }1168 }
11771169
...@@ -1187,6 +1179,9 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -1187,6 +1179,9 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
1187 if ((err = ensure_complete_type(g, type_entry)))1179 if ((err = ensure_complete_type(g, type_entry)))
1188 return g->builtin_types.entry_invalid;1180 return g->builtin_types.entry_invalid;
11891181
1182 if (is_c_abi)
1183 continue;
1184
1190 if (type_has_bits(type_entry)) {1185 if (type_has_bits(type_entry)) {
1191 ZigType *gen_type;1186 ZigType *gen_type;
1192 if (handle_is_ptr(type_entry)) {1187 if (handle_is_ptr(type_entry)) {
...@@ -1195,23 +1190,28 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -1195,23 +1190,28 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
1195 } else {1190 } else {
1196 gen_type = type_entry;1191 gen_type = type_entry;
1197 }1192 }
1198 gen_param_types[gen_param_index] = gen_type->type_ref;1193 gen_param_info->gen_index = gen_param_types.length;
1199 gen_param_info->gen_index = gen_param_index;
1200 gen_param_info->type = gen_type;1194 gen_param_info->type = gen_type;
1195 gen_param_types.append(gen_type->type_ref);
12011196
1202 gen_param_index += 1;1197 param_di_types.append(gen_type->di_type);
1203
1204 // after the gen_param_index += 1 because 0 is the return type
1205 param_di_types[gen_param_index] = gen_type->di_type;
1206 }1198 }
1207 }1199 }
12081200
1209 fn_type->data.fn.gen_param_count = gen_param_index;1201 if (is_c_abi) {
1202 FnWalk fn_walk = {};
1203 fn_walk.id = FnWalkIdTypes;
1204 fn_walk.data.types.param_di_types = &param_di_types;
1205 fn_walk.data.types.gen_param_types = &gen_param_types;
1206 walk_function_params(g, fn_type, &fn_walk);
1207 }
1208
1209 fn_type->data.fn.gen_param_count = gen_param_types.length;
12101210
1211 fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref,1211 fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref,
1212 gen_param_types, (unsigned int)gen_param_index, fn_type_id->is_var_args);1212 gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args);
1213 fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0);1213 fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0);
1214 fn_type->di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types, (int)(gen_param_index + 1), 0);1214 fn_type->di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0);
1215 }1215 }
12161216
1217 g->fn_type_table.put(&fn_type->data.fn.fn_type_id, fn_type);1217 g->fn_type_table.put(&fn_type->data.fn.fn_type_id, fn_type);
src/analyze.hpp+3
...@@ -210,4 +210,7 @@ ZigType *get_primitive_type(CodeGen *g, Buf *name);...@@ -210,4 +210,7 @@ ZigType *get_primitive_type(CodeGen *g, Buf *name);
210bool calling_convention_allows_zig_types(CallingConvention cc);210bool calling_convention_allows_zig_types(CallingConvention cc);
211const char *calling_convention_name(CallingConvention cc);211const char *calling_convention_name(CallingConvention cc);
212212
213void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk);
214
215
213#endif216#endif
src/codegen.cpp+420-99
...@@ -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 }
467467
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 mangling473 // 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 }
512513
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 }
522523
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 do577 // 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 }
585584
586
587 // set parameter attributes585 // 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 }
610590
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}
18591839
1860static void gen_var_debug_decl(CodeGen *g, ZigVar *var) {1840static 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}
18901871
1872ATTRIBUTE_NORETURN
1873static 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
1882static void report_errors_and_maybe_exit(CodeGen *g) {
1883 if (g->errors.length != 0) {
1884 report_errors_and_exit(g);
1885 }
1886}
1887
1888ATTRIBUTE_NORETURN
1889static 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
1897static 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
1908static 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
1915static 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
2150var_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
2161void 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
1891static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable,2247static 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);
31303486
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;
31503502
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);
31653512
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 }
31783525
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 }
31963543
...@@ -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 variable6068 // TODO ^^ make an actual global variable
5722}6069}
57236070
5724static 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
5731static void ensure_cache_dir(CodeGen *g) {6071static 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}
57376077
5738static 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
5748static void validate_inline_fns(CodeGen *g) {6078static 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;
58686200
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 }
58896221
5890 // error return tracing setup6222 // 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);
59496281
5950 // create debug variable declarations for variables and allocate all local variables6282 // 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);
59536291
...@@ -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);
59686306
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 }
60196360
6020 FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;
6021
6022 // create debug variable declarations for parameters6361 // 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 }
60476368
6048 ir_render(g, fn_table_entry);6369 ir_render(g, fn_table_entry);
60496370
src/codegen.hpp-1
...@@ -61,5 +61,4 @@ void codegen_translate_c(CodeGen *g, Buf *path);...@@ -61,5 +61,4 @@ void codegen_translate_c(CodeGen *g, Buf *path);
6161
62Buf *codegen_generate_builtin_source(CodeGen *g);62Buf *codegen_generate_builtin_source(CodeGen *g);
6363
64
65#endif64#endif
std/build.zig+27
...@@ -48,6 +48,12 @@ pub const Builder = struct {...@@ -48,6 +48,12 @@ pub const Builder = struct {
48 cache_root: []const u8,48 cache_root: []const u8,
49 release_mode: ?builtin.Mode,49 release_mode: ?builtin.Mode,
5050
51 pub const CStd = enum {
52 C89,
53 C99,
54 C11,
55 };
56
51 const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8);57 const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8);
52 const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8);58 const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8);
5359
...@@ -817,6 +823,7 @@ pub const LibExeObjStep = struct {...@@ -817,6 +823,7 @@ pub const LibExeObjStep = struct {
817 frameworks: BufSet,823 frameworks: BufSet,
818 verbose_link: bool,824 verbose_link: bool,
819 no_rosegment: bool,825 no_rosegment: bool,
826 c_std: Builder.CStd,
820827
821 // zig only stuff828 // zig only stuff
822 root_src: ?[]const u8,829 root_src: ?[]const u8,
...@@ -918,6 +925,7 @@ pub const LibExeObjStep = struct {...@@ -918,6 +925,7 @@ pub const LibExeObjStep = struct {
918 .object_src = undefined,925 .object_src = undefined,
919 .disable_libc = true,926 .disable_libc = true,
920 .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable,927 .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable,
928 .c_std = Builder.CStd.C99,
921 };929 };
922 self.computeOutFileNames();930 self.computeOutFileNames();
923 return self;931 return self;
...@@ -952,6 +960,7 @@ pub const LibExeObjStep = struct {...@@ -952,6 +960,7 @@ pub const LibExeObjStep = struct {
952 .disable_libc = false,960 .disable_libc = false,
953 .is_zig = false,961 .is_zig = false,
954 .linker_script = null,962 .linker_script = null,
963 .c_std = Builder.CStd.C99,
955964
956 .root_src = undefined,965 .root_src = undefined,
957 .verbose_link = false,966 .verbose_link = false,
...@@ -1392,6 +1401,13 @@ pub const LibExeObjStep = struct {...@@ -1392,6 +1401,13 @@ pub const LibExeObjStep = struct {
13921401
1393 const is_darwin = self.target.isDarwin();1402 const is_darwin = self.target.isDarwin();
13941403
1404 const c_std_arg = switch (self.c_std) {
1405 Builder.CStd.C89 => "-std=c89",
1406 Builder.CStd.C99 => "-std=c99",
1407 Builder.CStd.C11 => "-std=c11",
1408 };
1409 try cc_args.append(c_std_arg);
1410
1395 switch (self.kind) {1411 switch (self.kind) {
1396 Kind.Obj => {1412 Kind.Obj => {
1397 cc_args.append("-c") catch unreachable;1413 cc_args.append("-c") catch unreachable;
...@@ -1678,6 +1694,17 @@ pub const TestStep = struct {...@@ -1678,6 +1694,17 @@ pub const TestStep = struct {
1678 self.filter = text;1694 self.filter = text;
1679 }1695 }
16801696
1697 pub fn addObject(self: *TestStep, obj: *LibExeObjStep) void {
1698 assert(obj.kind == LibExeObjStep.Kind.Obj);
1699
1700 self.step.dependOn(&obj.step);
1701
1702 self.object_files.append(obj.getOutputPath()) catch unreachable;
1703
1704 // TODO should be some kind of isolated directory that only has this header in it
1705 self.include_dirs.append(self.builder.cache_root) catch unreachable;
1706 }
1707
1681 pub fn addObjectFile(self: *TestStep, path: []const u8) void {1708 pub fn addObjectFile(self: *TestStep, path: []const u8) void {
1682 self.object_files.append(path) catch unreachable;1709 self.object_files.append(path) catch unreachable;
1683 }1710 }
test/build_examples.zig+6
...@@ -28,4 +28,10 @@ pub fn addCases(cases: *tests.BuildExamplesContext) void {...@@ -28,4 +28,10 @@ pub fn addCases(cases: *tests.BuildExamplesContext) void {
28 // TODO figure out how to make this work on darwin - probably libSystem has dlopen/dlsym in it28 // TODO figure out how to make this work on darwin - probably libSystem has dlopen/dlsym in it
29 cases.addBuildFile("test/standalone/load_dynamic_library/build.zig");29 cases.addBuildFile("test/standalone/load_dynamic_library/build.zig");
30 }30 }
31
32 if (!is_windows // TODO support compiling C files on windows with zig build system
33 and builtin.arch == builtin.Arch.x86_64 // TODO add C ABI support for other architectures
34 ) {
35 cases.addBuildFile("test/stage1/c_abi/build.zig");
36 }
31}37}
test/gen_h.zig+24-4
...@@ -20,6 +20,9 @@ pub fn addCases(cases: *tests.GenHContext) void {...@@ -20,6 +20,9 @@ pub fn addCases(cases: *tests.GenHContext) void {
20 \\ A: i32,20 \\ A: i32,
21 \\ B: f32,21 \\ B: f32,
22 \\ C: bool,22 \\ C: bool,
23 \\ D: u64,
24 \\ E: u64,
25 \\ F: u64,
23 \\};26 \\};
24 \\export fn entry(foo: Foo) void { }27 \\export fn entry(foo: Foo) void { }
25 ,28 ,
...@@ -27,6 +30,9 @@ pub fn addCases(cases: *tests.GenHContext) void {...@@ -27,6 +30,9 @@ pub fn addCases(cases: *tests.GenHContext) void {
27 \\ int32_t A;30 \\ int32_t A;
28 \\ float B;31 \\ float B;
29 \\ bool C;32 \\ bool C;
33 \\ uint64_t D;
34 \\ uint64_t E;
35 \\ uint64_t F;
30 \\};36 \\};
31 \\37 \\
32 \\TEST_EXPORT void entry(struct Foo foo);38 \\TEST_EXPORT void entry(struct Foo foo);
...@@ -34,17 +40,34 @@ pub fn addCases(cases: *tests.GenHContext) void {...@@ -34,17 +40,34 @@ pub fn addCases(cases: *tests.GenHContext) void {
34 );40 );
3541
36 cases.add("declare union",42 cases.add("declare union",
43 \\const Big = extern struct {
44 \\ A: u64,
45 \\ B: u64,
46 \\ C: u64,
47 \\ D: u64,
48 \\ E: u64,
49 \\};
37 \\const Foo = extern union {50 \\const Foo = extern union {
38 \\ A: i32,51 \\ A: i32,
39 \\ B: f32,52 \\ B: f32,
40 \\ C: bool,53 \\ C: bool,
54 \\ D: Big,
41 \\};55 \\};
42 \\export fn entry(foo: Foo) void { }56 \\export fn entry(foo: Foo) void {}
43 ,57 ,
58 \\struct Big {
59 \\ uint64_t A;
60 \\ uint64_t B;
61 \\ uint64_t C;
62 \\ uint64_t D;
63 \\ uint64_t E;
64 \\};
65 \\
44 \\union Foo {66 \\union Foo {
45 \\ int32_t A;67 \\ int32_t A;
46 \\ float B;68 \\ float B;
47 \\ bool C;69 \\ bool C;
70 \\ struct Big D;
48 \\};71 \\};
49 \\72 \\
50 \\TEST_EXPORT void entry(union Foo foo);73 \\TEST_EXPORT void entry(union Foo foo);
...@@ -85,7 +108,6 @@ pub fn addCases(cases: *tests.GenHContext) void {...@@ -85,7 +108,6 @@ pub fn addCases(cases: *tests.GenHContext) void {
85 \\export fn a(s: *S) u8 {108 \\export fn a(s: *S) u8 {
86 \\ return s.a;109 \\ return s.a;
87 \\}110 \\}
88
89 ,111 ,
90 \\struct S;112 \\struct S;
91 \\TEST_EXPORT uint8_t a(struct S * s);113 \\TEST_EXPORT uint8_t a(struct S * s);
...@@ -101,7 +123,6 @@ pub fn addCases(cases: *tests.GenHContext) void {...@@ -101,7 +123,6 @@ pub fn addCases(cases: *tests.GenHContext) void {
101 \\export fn a(s: *U) u8 {123 \\export fn a(s: *U) u8 {
102 \\ return s.A;124 \\ return s.A;
103 \\}125 \\}
104
105 ,126 ,
106 \\union U;127 \\union U;
107 \\TEST_EXPORT uint8_t a(union U * s);128 \\TEST_EXPORT uint8_t a(union U * s);
...@@ -117,7 +138,6 @@ pub fn addCases(cases: *tests.GenHContext) void {...@@ -117,7 +138,6 @@ pub fn addCases(cases: *tests.GenHContext) void {
117 \\export fn a(s: *E) u8 {138 \\export fn a(s: *E) u8 {
118 \\ return @enumToInt(s.*);139 \\ return @enumToInt(s.*);
119 \\}140 \\}
120
121 ,141 ,
122 \\enum E;142 \\enum E;
123 \\TEST_EXPORT uint8_t a(enum E * s);143 \\TEST_EXPORT uint8_t a(enum E * s);
test/stage1/c_abi/build.zig created+17
...@@ -0,0 +1,17 @@
1const Builder = @import("std").build.Builder;
2
3pub fn build(b: *Builder) void {
4 const rel_opts = b.standardReleaseOptions();
5
6 const c_obj = b.addCObject("cfuncs", "cfuncs.c");
7 c_obj.setBuildMode(rel_opts);
8
9 const main = b.addTest("main.zig");
10 main.setBuildMode(rel_opts);
11 main.addObject(c_obj);
12
13 const test_step = b.step("test", "Test the program");
14 test_step.dependOn(&main.step);
15
16 b.default_step.dependOn(test_step);
17}
test/stage1/c_abi/cfuncs.c created+169
...@@ -0,0 +1,169 @@
1#include <inttypes.h>
2#include <stdlib.h>
3#include <stdbool.h>
4
5void zig_panic();
6
7static void assert_or_panic(bool ok) {
8 if (!ok) {
9 zig_panic();
10 }
11}
12
13void zig_u8(uint8_t);
14void zig_u16(uint16_t);
15void zig_u32(uint32_t);
16void zig_u64(uint64_t);
17void zig_i8(int8_t);
18void zig_i16(int16_t);
19void zig_i32(int32_t);
20void zig_i64(int64_t);
21
22void zig_f32(float);
23void zig_f64(double);
24
25void zig_ptr(void *);
26
27void zig_bool(bool);
28
29void zig_array(uint8_t[10]);
30
31struct BigStruct {
32 uint64_t a;
33 uint64_t b;
34 uint64_t c;
35 uint64_t d;
36 uint8_t e;
37};
38
39void zig_big_struct(struct BigStruct);
40
41union BigUnion {
42 struct BigStruct a;
43};
44
45void zig_big_union(union BigUnion);
46
47struct SmallStructInts {
48 uint8_t a;
49 uint8_t b;
50 uint8_t c;
51 uint8_t d;
52};
53void zig_small_struct_ints(struct SmallStructInts);
54
55void run_c_tests(void) {
56 zig_u8(0xff);
57 zig_u16(0xfffe);
58 zig_u32(0xfffffffd);
59 zig_u64(0xfffffffffffffffc);
60
61 zig_i8(-1);
62 zig_i16(-2);
63 zig_i32(-3);
64 zig_i64(-4);
65
66 zig_f32(12.34f);
67 zig_f64(56.78);
68
69 zig_ptr((void*)0xdeadbeefL);
70
71 zig_bool(true);
72
73 // TODO making this non-static crashes for some reason
74 static uint8_t array[10] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
75 zig_array(array);
76
77 {
78 struct BigStruct s = {1, 2, 3, 4, 5};
79 zig_big_struct(s);
80 }
81
82 {
83 struct SmallStructInts s = {1, 2, 3, 4};
84 zig_small_struct_ints(s);
85 }
86}
87
88void c_u8(uint8_t x) {
89 assert_or_panic(x == 0xff);
90}
91
92void c_u16(uint16_t x) {
93 assert_or_panic(x == 0xfffe);
94}
95
96void c_u32(uint32_t x) {
97 assert_or_panic(x == 0xfffffffd);
98}
99
100void c_u64(uint64_t x) {
101 assert_or_panic(x == 0xfffffffffffffffcULL);
102}
103
104void c_i8(int8_t x) {
105 assert_or_panic(x == -1);
106}
107
108void c_i16(int16_t x) {
109 assert_or_panic(x == -2);
110}
111
112void c_i32(int32_t x) {
113 assert_or_panic(x == -3);
114}
115
116void c_i64(int64_t x) {
117 assert_or_panic(x == -4);
118}
119
120void c_f32(float x) {
121 assert_or_panic(x == 12.34f);
122}
123
124void c_f64(double x) {
125 assert_or_panic(x == 56.78);
126}
127
128void c_ptr(void *x) {
129 assert_or_panic(x == (void*)0xdeadbeefL);
130}
131
132void c_bool(bool x) {
133 assert_or_panic(x);
134}
135
136void c_array(uint8_t x[10]) {
137 assert_or_panic(x[0] == '1');
138 assert_or_panic(x[1] == '2');
139 assert_or_panic(x[2] == '3');
140 assert_or_panic(x[3] == '4');
141 assert_or_panic(x[4] == '5');
142 assert_or_panic(x[5] == '6');
143 assert_or_panic(x[6] == '7');
144 assert_or_panic(x[7] == '8');
145 assert_or_panic(x[8] == '9');
146 assert_or_panic(x[9] == '0');
147}
148
149void c_big_struct(struct BigStruct x) {
150 assert_or_panic(x.a == 1);
151 assert_or_panic(x.b == 2);
152 assert_or_panic(x.c == 3);
153 assert_or_panic(x.d == 4);
154 assert_or_panic(x.e == 5);
155}
156
157void c_big_union(union BigUnion x) {
158 assert_or_panic(x.a.a == 1);
159 assert_or_panic(x.a.b == 2);
160 assert_or_panic(x.a.c == 3);
161 assert_or_panic(x.a.d == 4);
162}
163
164void c_small_struct_ints(struct SmallStructInts x) {
165 assert_or_panic(x.a == 1);
166 assert_or_panic(x.b == 2);
167 assert_or_panic(x.c == 3);
168 assert_or_panic(x.d == 4);
169}
test/stage1/c_abi/main.zig created+183
...@@ -0,0 +1,183 @@
1const std = @import("std");
2const assertOrPanic = std.debug.assertOrPanic;
3
4extern fn run_c_tests() void;
5
6export fn zig_panic() noreturn {
7 @panic("zig_panic called from C");
8}
9
10test "C importing Zig ABI Tests" {
11 run_c_tests();
12}
13
14extern fn c_u8(u8) void;
15extern fn c_u16(u16) void;
16extern fn c_u32(u32) void;
17extern fn c_u64(u64) void;
18extern fn c_i8(i8) void;
19extern fn c_i16(i16) void;
20extern fn c_i32(i32) void;
21extern fn c_i64(i64) void;
22
23test "C ABI integers" {
24 c_u8(0xff);
25 c_u16(0xfffe);
26 c_u32(0xfffffffd);
27 c_u64(0xfffffffffffffffc);
28
29 c_i8(-1);
30 c_i16(-2);
31 c_i32(-3);
32 c_i64(-4);
33}
34
35export fn zig_u8(x: u8) void {
36 assertOrPanic(x == 0xff);
37}
38export fn zig_u16(x: u16) void {
39 assertOrPanic(x == 0xfffe);
40}
41export fn zig_u32(x: u32) void {
42 assertOrPanic(x == 0xfffffffd);
43}
44export fn zig_u64(x: u64) void {
45 assertOrPanic(x == 0xfffffffffffffffc);
46}
47export fn zig_i8(x: i8) void {
48 assertOrPanic(x == -1);
49}
50export fn zig_i16(x: i16) void {
51 assertOrPanic(x == -2);
52}
53export fn zig_i32(x: i32) void {
54 assertOrPanic(x == -3);
55}
56export fn zig_i64(x: i64) void {
57 assertOrPanic(x == -4);
58}
59
60extern fn c_f32(f32) void;
61extern fn c_f64(f64) void;
62
63test "C ABI floats" {
64 c_f32(12.34);
65 c_f64(56.78);
66}
67
68export fn zig_f32(x: f32) void {
69 assertOrPanic(x == 12.34);
70}
71export fn zig_f64(x: f64) void {
72 assertOrPanic(x == 56.78);
73}
74
75extern fn c_ptr(*c_void) void;
76
77test "C ABI pointer" {
78 c_ptr(@intToPtr(*c_void, 0xdeadbeef));
79}
80
81export fn zig_ptr(x: *c_void) void {
82 assertOrPanic(@ptrToInt(x) == 0xdeadbeef);
83}
84
85extern fn c_bool(bool) void;
86
87test "C ABI bool" {
88 c_bool(true);
89}
90
91export fn zig_bool(x: bool) void {
92 assertOrPanic(x);
93}
94
95extern fn c_array([10]u8) void;
96
97test "C ABI array" {
98 var array: [10]u8 = "1234567890";
99 c_array(array);
100}
101
102export fn zig_array(x: [10]u8) void {
103 assertOrPanic(std.mem.eql(u8, x, "1234567890"));
104}
105
106const BigStruct = extern struct {
107 a: u64,
108 b: u64,
109 c: u64,
110 d: u64,
111 e: u8,
112};
113extern fn c_big_struct(BigStruct) void;
114
115test "C ABI big struct" {
116 var s = BigStruct{
117 .a = 1,
118 .b = 2,
119 .c = 3,
120 .d = 4,
121 .e = 5,
122 };
123 c_big_struct(s);
124}
125
126export fn zig_big_struct(x: BigStruct) void {
127 assertOrPanic(x.a == 1);
128 assertOrPanic(x.b == 2);
129 assertOrPanic(x.c == 3);
130 assertOrPanic(x.d == 4);
131 assertOrPanic(x.e == 5);
132}
133
134const BigUnion = extern union {
135 a: BigStruct,
136};
137extern fn c_big_union(BigUnion) void;
138
139test "C ABI big union" {
140 var x = BigUnion{
141 .a = BigStruct{
142 .a = 1,
143 .b = 2,
144 .c = 3,
145 .d = 4,
146 .e = 5,
147 },
148 };
149 c_big_union(x);
150}
151
152export fn zig_big_union(x: BigUnion) void {
153 assertOrPanic(x.a.a == 1);
154 assertOrPanic(x.a.b == 2);
155 assertOrPanic(x.a.c == 3);
156 assertOrPanic(x.a.d == 4);
157 assertOrPanic(x.a.e == 5);
158}
159
160const SmallStructInts = extern struct {
161 a: u8,
162 b: u8,
163 c: u8,
164 d: u8,
165};
166extern fn c_small_struct_ints(SmallStructInts) void;
167
168test "C ABI small struct of ints" {
169 var s = SmallStructInts{
170 .a = 1,
171 .b = 2,
172 .c = 3,
173 .d = 4,
174 };
175 c_small_struct_ints(s);
176}
177
178export fn zig_small_struct_ints(x: SmallStructInts) void {
179 assertOrPanic(x.a == 1);
180 assertOrPanic(x.b == 2);
181 assertOrPanic(x.c == 3);
182 assertOrPanic(x.d == 4);
183}