authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-11 15:54:38-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-11 15:56:04-04:00
log4af844732a88393b172d33676732580b056910f6
tree32a05bfbf51e9f8fc0339ca44658e04c21345788
parent67735c6f1557092efe6e8c1712445c30655fe283
parent7dd3c3814de0caf808bc112aa07044cdd8bba135
signaturelock-open Commit is signed but in an unrecognized format.

Merge remote-tracking branch 'origin/master' into stage1-caching


22 files changed, 1309 insertions(+), 204 deletions(-)

build.zig+5-1
......@@ -76,7 +76,11 @@ pub fn build(b: *Builder) !void {
7676
7777 const test_stage2_step = b.step("test-stage2", "Run the stage2 compiler tests");
7878 test_stage2_step.dependOn(&test_stage2.step);
79 test_step.dependOn(test_stage2_step);
79
80 // TODO see https://github.com/ziglang/zig/issues/1364
81 if (false) {
82 test_step.dependOn(test_stage2_step);
83 }
8084
8185 const all_modes = []builtin.Mode{
8286 builtin.Mode.Debug,
src/all_types.hpp+56
......@@ -41,6 +41,13 @@ struct Tld;
4141struct TldExport;
4242struct IrAnalyze;
4343
44enum X64CABIClass {
45 X64CABIClass_Unknown,
46 X64CABIClass_MEMORY,
47 X64CABIClass_INTEGER,
48 X64CABIClass_SSE,
49};
50
4451struct IrExecutable {
4552 ZigList<IrBasicBlock *> basic_block_list;
4653 Buf *name;
......@@ -3282,4 +3289,53 @@ enum FloatMode {
32823289 FloatModeStrict,
32833290};
32843291
3292enum FnWalkId {
3293 FnWalkIdAttrs,
3294 FnWalkIdCall,
3295 FnWalkIdTypes,
3296 FnWalkIdVars,
3297 FnWalkIdInits,
3298};
3299
3300struct FnWalkAttrs {
3301 ZigFn *fn;
3302 unsigned gen_i;
3303};
3304
3305struct FnWalkCall {
3306 ZigList<LLVMValueRef> *gen_param_values;
3307 IrInstructionCall *inst;
3308 bool is_var_args;
3309};
3310
3311struct FnWalkTypes {
3312 ZigList<ZigLLVMDIType *> *param_di_types;
3313 ZigList<LLVMTypeRef> *gen_param_types;
3314};
3315
3316struct FnWalkVars {
3317 ImportTableEntry *import;
3318 LLVMValueRef llvm_fn;
3319 ZigFn *fn;
3320 ZigVar *var;
3321 unsigned gen_i;
3322};
3323
3324struct FnWalkInits {
3325 LLVMValueRef llvm_fn;
3326 ZigFn *fn;
3327 unsigned gen_i;
3328};
3329
3330struct FnWalk {
3331 FnWalkId id;
3332 union {
3333 FnWalkAttrs attrs;
3334 FnWalkCall call;
3335 FnWalkTypes types;
3336 FnWalkVars vars;
3337 FnWalkInits inits;
3338 } data;
3339};
3340
32853341#endif
src/analyze.cpp+148-37
......@@ -1009,10 +1009,6 @@ ZigType *get_bound_fn_type(CodeGen *g, ZigFn *fn_entry) {
10091009 return bound_fn_type;
10101010}
10111011
1012bool calling_convention_does_first_arg_return(CallingConvention cc) {
1013 return cc == CallingConventionUnspecified;
1014}
1015
10161012const char *calling_convention_name(CallingConvention cc) {
10171013 switch (cc) {
10181014 case CallingConventionUnspecified: return "undefined";
......@@ -1061,6 +1057,27 @@ ZigType *get_ptr_to_stack_trace_type(CodeGen *g) {
10611057 return g->ptr_to_stack_trace_type;
10621058}
10631059
1060bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) {
1061 if (fn_type_id->cc == CallingConventionUnspecified) {
1062 return handle_is_ptr(fn_type_id->return_type);
1063 }
1064 if (fn_type_id->cc != CallingConventionC) {
1065 return false;
1066 }
1067 if (type_is_c_abi_int(g, fn_type_id->return_type)) {
1068 return false;
1069 }
1070 if (g->zig_target.arch.arch == ZigLLVM_x86_64) {
1071 X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type);
1072 if (abi_class == X64CABIClass_MEMORY) {
1073 return true;
1074 }
1075 zig_panic("TODO implement C ABI for x86_64 return types. type '%s'\nSee https://github.com/ziglang/zig/issues/1481",
1076 buf_ptr(&fn_type_id->return_type->name));
1077 }
1078 zig_panic("TODO implement C ABI for this architecture. See https://github.com/ziglang/zig/issues/1481");
1079}
1080
10641081ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
10651082 Error err;
10661083 auto table_entry = g->fn_type_table.maybe_get(fn_type_id);
......@@ -1116,21 +1133,20 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
11161133 // next, loop over the parameters again and compute debug information
11171134 // and codegen information
11181135 if (!skip_debug_info) {
1119 bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) &&
1120 handle_is_ptr(fn_type_id->return_type);
1136 bool first_arg_return = want_first_arg_sret(g, fn_type_id);
11211137 bool is_async = fn_type_id->cc == CallingConventionAsync;
1138 bool is_c_abi = fn_type_id->cc == CallingConventionC;
11221139 bool prefix_arg_error_return_trace = g->have_err_ret_tracing && fn_type_can_fail(fn_type_id);
11231140 // +1 for maybe making the first argument the return value
11241141 // +1 for maybe first argument the error return trace
11251142 // +2 for maybe arguments async allocator and error code pointer
1126 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(4 + fn_type_id->param_count);
1143 ZigList<LLVMTypeRef> gen_param_types = {};
11271144 // +1 because 0 is the return type and
11281145 // +1 for maybe making first arg ret val and
11291146 // +1 for maybe first argument the error return trace
11301147 // +2 for maybe arguments async allocator and error code pointer
1131 ZigLLVMDIType **param_di_types = allocate<ZigLLVMDIType*>(5 + fn_type_id->param_count);
1132 param_di_types[0] = fn_type_id->return_type->di_type;
1133 size_t gen_param_index = 0;
1148 ZigList<ZigLLVMDIType *> param_di_types = {};
1149 param_di_types.append(fn_type_id->return_type->di_type);
11341150 ZigType *gen_return_type;
11351151 if (is_async) {
11361152 gen_return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
......@@ -1138,10 +1154,8 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
11381154 gen_return_type = g->builtin_types.entry_void;
11391155 } else if (first_arg_return) {
11401156 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;
1142 gen_param_index += 1;
1143 // after the gen_param_index += 1 because 0 is the return type
1144 param_di_types[gen_param_index] = gen_type->di_type;
1157 gen_param_types.append(gen_type->type_ref);
1158 param_di_types.append(gen_type->di_type);
11451159 gen_return_type = g->builtin_types.entry_void;
11461160 } else {
11471161 gen_return_type = fn_type_id->return_type;
......@@ -1150,28 +1164,22 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
11501164
11511165 if (prefix_arg_error_return_trace) {
11521166 ZigType *gen_type = get_ptr_to_stack_trace_type(g);
1153 gen_param_types[gen_param_index] = gen_type->type_ref;
1154 gen_param_index += 1;
1155 // after the gen_param_index += 1 because 0 is the return type
1156 param_di_types[gen_param_index] = gen_type->di_type;
1167 gen_param_types.append(gen_type->type_ref);
1168 param_di_types.append(gen_type->di_type);
11571169 }
11581170 if (is_async) {
11591171 {
11601172 // async allocator param
11611173 ZigType *gen_type = fn_type_id->async_allocator_type;
1162 gen_param_types[gen_param_index] = gen_type->type_ref;
1163 gen_param_index += 1;
1164 // after the gen_param_index += 1 because 0 is the return type
1165 param_di_types[gen_param_index] = gen_type->di_type;
1174 gen_param_types.append(gen_type->type_ref);
1175 param_di_types.append(gen_type->di_type);
11661176 }
11671177
11681178 {
11691179 // error code pointer
11701180 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;
1172 gen_param_index += 1;
1173 // after the gen_param_index += 1 because 0 is the return type
1174 param_di_types[gen_param_index] = gen_type->di_type;
1181 gen_param_types.append(gen_type->type_ref);
1182 param_di_types.append(gen_type->di_type);
11751183 }
11761184 }
11771185
......@@ -1187,6 +1195,9 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
11871195 if ((err = ensure_complete_type(g, type_entry)))
11881196 return g->builtin_types.entry_invalid;
11891197
1198 if (is_c_abi)
1199 continue;
1200
11901201 if (type_has_bits(type_entry)) {
11911202 ZigType *gen_type;
11921203 if (handle_is_ptr(type_entry)) {
......@@ -1195,23 +1206,31 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
11951206 } else {
11961207 gen_type = type_entry;
11971208 }
1198 gen_param_types[gen_param_index] = gen_type->type_ref;
1199 gen_param_info->gen_index = gen_param_index;
1209 gen_param_info->gen_index = gen_param_types.length;
12001210 gen_param_info->type = gen_type;
1211 gen_param_types.append(gen_type->type_ref);
12011212
1202 gen_param_index += 1;
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;
1213 param_di_types.append(gen_type->di_type);
12061214 }
12071215 }
12081216
1209 fn_type->data.fn.gen_param_count = gen_param_index;
1217 if (is_c_abi) {
1218 FnWalk fn_walk = {};
1219 fn_walk.id = FnWalkIdTypes;
1220 fn_walk.data.types.param_di_types = &param_di_types;
1221 fn_walk.data.types.gen_param_types = &gen_param_types;
1222 walk_function_params(g, fn_type, &fn_walk);
1223 }
1224
1225 fn_type->data.fn.gen_param_count = gen_param_types.length;
12101226
1227 for (size_t i = 0; i < gen_param_types.length; i += 1) {
1228 assert(gen_param_types.items[i] != nullptr);
1229 }
12111230 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);
1231 gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args);
12131232 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);
1233 fn_type->di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0);
12151234 }
12161235
12171236 g->fn_type_table.put(&fn_type->data.fn.fn_type_id, fn_type);
......@@ -5863,12 +5882,23 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
58635882 }
58645883 case ZigTypeIdErrorUnion:
58655884 {
5866 buf_appendf(buf, "(error union %s constant)", buf_ptr(&type_entry->name));
5885 buf_appendf(buf, "%s(", buf_ptr(&type_entry->name));
5886 if (const_val->data.x_err_union.err == nullptr) {
5887 render_const_value(g, buf, const_val->data.x_err_union.payload);
5888 } else {
5889 buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->data.error_union.err_set_type->name),
5890 buf_ptr(&const_val->data.x_err_union.err->name));
5891 }
5892 buf_appendf(buf, ")");
58675893 return;
58685894 }
58695895 case ZigTypeIdUnion:
58705896 {
5871 buf_appendf(buf, "(union %s constant)", buf_ptr(&type_entry->name));
5897 uint64_t tag = bigint_as_unsigned(&const_val->data.x_union.tag);
5898 TypeUnionField *field = &type_entry->data.unionation.fields[tag];
5899 buf_appendf(buf, "%s { .%s = ", buf_ptr(&type_entry->name), buf_ptr(field->name));
5900 render_const_value(g, buf, const_val->data.x_union.payload);
5901 buf_append_str(buf, "}");
58725902 return;
58735903 }
58745904 case ZigTypeIdErrorSet:
......@@ -6375,3 +6405,84 @@ Error file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents) {
63756405 return os_fetch_file_path(resolved_path, contents, false);
63766406 }
63776407}
6408
6409X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) {
6410 size_t ty_size = type_size(g, ty);
6411 if (get_codegen_ptr_type(ty) != nullptr)
6412 return X64CABIClass_INTEGER;
6413 switch (ty->id) {
6414 case ZigTypeIdEnum:
6415 case ZigTypeIdInt:
6416 case ZigTypeIdBool:
6417 return X64CABIClass_INTEGER;
6418 case ZigTypeIdFloat:
6419 return X64CABIClass_SSE;
6420 case ZigTypeIdStruct: {
6421 // "If the size of an object is larger than four eightbytes, or it contains unaligned
6422 // fields, it has class MEMORY"
6423 if (ty_size > 32)
6424 return X64CABIClass_MEMORY;
6425 if (ty->data.structure.layout != ContainerLayoutExtern) {
6426 // TODO determine whether packed structs have any unaligned fields
6427 return X64CABIClass_Unknown;
6428 }
6429 // "If the size of the aggregate exceeds two eightbytes and the first eight-
6430 // byte isn’t SSE or any other eightbyte isn’t SSEUP, the whole argument
6431 // is passed in memory."
6432 if (ty_size > 16) {
6433 // Zig doesn't support vectors and large fp registers yet, so this will always
6434 // be memory.
6435 return X64CABIClass_MEMORY;
6436 }
6437 X64CABIClass working_class = X64CABIClass_Unknown;
6438 for (uint32_t i = 0; i < ty->data.structure.src_field_count; i += 1) {
6439 X64CABIClass field_class = type_c_abi_x86_64_class(g, ty->data.structure.fields->type_entry);
6440 if (field_class == X64CABIClass_Unknown)
6441 return X64CABIClass_Unknown;
6442 if (i == 0 || field_class == X64CABIClass_MEMORY || working_class == X64CABIClass_SSE) {
6443 working_class = field_class;
6444 }
6445 }
6446 return working_class;
6447 }
6448 case ZigTypeIdUnion: {
6449 // "If the size of an object is larger than four eightbytes, or it contains unaligned
6450 // fields, it has class MEMORY"
6451 if (ty_size > 32)
6452 return X64CABIClass_MEMORY;
6453 if (ty->data.unionation.layout != ContainerLayoutExtern)
6454 return X64CABIClass_MEMORY;
6455 // "If the size of the aggregate exceeds two eightbytes and the first eight-
6456 // byte isn’t SSE or any other eightbyte isn’t SSEUP, the whole argument
6457 // is passed in memory."
6458 if (ty_size > 16) {
6459 // Zig doesn't support vectors and large fp registers yet, so this will always
6460 // be memory.
6461 return X64CABIClass_MEMORY;
6462 }
6463 X64CABIClass working_class = X64CABIClass_Unknown;
6464 for (uint32_t i = 0; i < ty->data.unionation.src_field_count; i += 1) {
6465 X64CABIClass field_class = type_c_abi_x86_64_class(g, ty->data.unionation.fields->type_entry);
6466 if (field_class == X64CABIClass_Unknown)
6467 return X64CABIClass_Unknown;
6468 if (i == 0 || field_class == X64CABIClass_MEMORY || working_class == X64CABIClass_SSE) {
6469 working_class = field_class;
6470 }
6471 }
6472 return working_class;
6473 }
6474 default:
6475 return X64CABIClass_Unknown;
6476 }
6477}
6478
6479// NOTE this does not depend on x86_64
6480bool type_is_c_abi_int(CodeGen *g, ZigType *ty) {
6481 return (ty->id == ZigTypeIdInt ||
6482 ty->id == ZigTypeIdFloat ||
6483 ty->id == ZigTypeIdBool ||
6484 ty->id == ZigTypeIdEnum ||
6485 ty->id == ZigTypeIdVoid ||
6486 ty->id == ZigTypeIdUnreachable ||
6487 get_codegen_ptr_type(ty) != nullptr);
6488}
src/analyze.hpp+5-2
......@@ -182,7 +182,6 @@ size_t type_id_index(ZigType *entry);
182182ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id);
183183Result<bool> type_is_copyable(CodeGen *g, ZigType *type_entry);
184184LinkLib *create_link_lib(Buf *name);
185bool calling_convention_does_first_arg_return(CallingConvention cc);
186185LinkLib *add_link_lib(CodeGen *codegen, Buf *lib);
187186
188187uint32_t get_abi_alignment(CodeGen *g, ZigType *type_entry);
......@@ -210,7 +209,11 @@ ZigType *get_primitive_type(CodeGen *g, Buf *name);
210209bool calling_convention_allows_zig_types(CallingConvention cc);
211210const char *calling_convention_name(CallingConvention cc);
212211
213
214212Error ATTRIBUTE_MUST_USE file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents);
215213
214void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk);
215X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty);
216bool type_is_c_abi_int(CodeGen *g, ZigType *ty);
217bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id);
218
216219#endif
src/codegen.cpp+453-120
......@@ -350,8 +350,12 @@ static void addLLVMFnAttrInt(LLVMValueRef fn_val, const char *attr_name, uint64_
350350 return addLLVMAttrInt(fn_val, -1, attr_name, attr_val);
351351}
352352
353static void addLLVMArgAttr(LLVMValueRef arg_val, unsigned param_index, const char *attr_name) {
354 return addLLVMAttr(arg_val, param_index + 1, attr_name);
353static void addLLVMArgAttr(LLVMValueRef fn_val, unsigned param_index, const char *attr_name) {
354 return addLLVMAttr(fn_val, param_index + 1, attr_name);
355}
356
357static void addLLVMArgAttrInt(LLVMValueRef fn_val, unsigned param_index, const char *attr_name, uint64_t attr_val) {
358 return addLLVMAttrInt(fn_val, param_index + 1, attr_name, attr_val);
355359}
356360
357361static bool is_symbol_available(CodeGen *g, Buf *name) {
......@@ -462,7 +466,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
462466 }
463467
464468 bool external_linkage = linkage != GlobalLinkageIdInternal;
465 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 &&
466471 g->zig_target.arch.arch == ZigLLVM_x86)
467472 {
468473 // prevent llvm name mangling
......@@ -506,17 +511,17 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
506511 break;
507512 }
508513
509 if (fn_type->data.fn.fn_type_id.cc == CallingConventionNaked) {
514 if (cc == CallingConventionNaked) {
510515 addLLVMFnAttr(fn_table_entry->llvm_value, "naked");
511516 } else {
512517 LLVMSetFunctionCallConv(fn_table_entry->llvm_value, get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc));
513518 }
514 if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) {
519 if (cc == CallingConventionAsync) {
515520 addLLVMFnAttr(fn_table_entry->llvm_value, "optnone");
516521 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");
517522 }
518523
519 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;
520525 if (want_cold) {
521526 ZigLLVMAddFunctionAttrCold(fn_table_entry->llvm_value);
522527 }
......@@ -568,41 +573,26 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
568573 // use the ABI alignment, which is fine.
569574 }
570575
576 unsigned init_gen_i = 0;
571577 if (!type_has_bits(return_type)) {
572578 // nothing to do
573579 } else if (type_is_codegen_pointer(return_type)) {
574580 addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");
575 } else if (handle_is_ptr(return_type) &&
576 calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc))
577 {
581 } else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) {
578582 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
579583 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull");
584 if (cc == CallingConventionC) {
585 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "noalias");
586 }
587 init_gen_i = 1;
580588 }
581589
582
583590 // set parameter attributes
584 for (size_t param_i = 0; param_i < fn_type->data.fn.fn_type_id.param_count; param_i += 1) {
585 FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
586 size_t gen_index = gen_info->gen_index;
587 bool is_byval = gen_info->is_byval;
588
589 if (gen_index == SIZE_MAX) {
590 continue;
591 }
592
593 FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[param_i];
594
595 ZigType *param_type = gen_info->type;
596 if (param_info->is_noalias) {
597 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "noalias");
598 }
599 if ((param_type->id == ZigTypeIdPointer && param_type->data.pointer.is_const) || is_byval) {
600 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "readonly");
601 }
602 if (param_type->id == ZigTypeIdPointer) {
603 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "nonnull");
604 }
605 }
591 FnWalk fn_walk = {};
592 fn_walk.id = FnWalkIdAttrs;
593 fn_walk.data.attrs.fn = fn_table_entry;
594 fn_walk.data.attrs.gen_i = init_gen_i;
595 walk_function_params(g, fn_type, &fn_walk);
606596
607597 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
608598 if (err_ret_trace_arg_index != UINT32_MAX) {
......@@ -1854,6 +1844,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty
18541844}
18551845
18561846static void gen_var_debug_decl(CodeGen *g, ZigVar *var) {
1847 assert(var->di_loc_var != nullptr);
18571848 AstNode *source_node = var->decl_node;
18581849 ZigLLVMDILocation *debug_loc = ZigLLVMGetDebugLoc((unsigned)source_node->line + 1,
18591850 (unsigned)source_node->column + 1, get_di_scope(g, var->parent_scope));
......@@ -1884,6 +1875,353 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
18841875 return instruction->llvm_value;
18851876}
18861877
1878ATTRIBUTE_NORETURN
1879static void report_errors_and_exit(CodeGen *g) {
1880 assert(g->errors.length != 0);
1881 for (size_t i = 0; i < g->errors.length; i += 1) {
1882 ErrorMsg *err = g->errors.at(i);
1883 print_err_msg(err, g->err_color);
1884 }
1885 exit(1);
1886}
1887
1888static void report_errors_and_maybe_exit(CodeGen *g) {
1889 if (g->errors.length != 0) {
1890 report_errors_and_exit(g);
1891 }
1892}
1893
1894ATTRIBUTE_NORETURN
1895static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) {
1896 ErrorMsg *msg = add_node_error(g, source_node,
1897 buf_sprintf("TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481"));
1898 add_error_note(g, msg, source_node,
1899 buf_sprintf("pointers, integers, floats, bools, and enums work on all targets"));
1900 report_errors_and_exit(g);
1901}
1902
1903static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) {
1904 assert(alignment > 0);
1905 LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name);
1906 LLVMSetAlignment(result, alignment);
1907 return result;
1908}
1909
1910static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk, size_t src_i) {
1911 // Initialized from the type for some walks, but because of C var args,
1912 // initialized based on callsite instructions for that one.
1913 FnTypeParamInfo *param_info = nullptr;
1914 ZigType *ty;
1915 ZigType *dest_ty = nullptr;
1916 AstNode *source_node = nullptr;
1917 LLVMValueRef val;
1918 LLVMValueRef llvm_fn;
1919 unsigned di_arg_index;
1920 ZigVar *var;
1921 switch (fn_walk->id) {
1922 case FnWalkIdAttrs:
1923 if (src_i >= fn_type->data.fn.fn_type_id.param_count)
1924 return false;
1925 param_info = &fn_type->data.fn.fn_type_id.param_info[src_i];
1926 ty = param_info->type;
1927 source_node = fn_walk->data.attrs.fn->proto_node;
1928 llvm_fn = fn_walk->data.attrs.fn->llvm_value;
1929 break;
1930 case FnWalkIdCall: {
1931 if (src_i >= fn_walk->data.call.inst->arg_count)
1932 return false;
1933 IrInstruction *arg = fn_walk->data.call.inst->args[src_i];
1934 ty = arg->value.type;
1935 source_node = arg->source_node;
1936 val = ir_llvm_value(g, arg);
1937 break;
1938 }
1939 case FnWalkIdTypes:
1940 if (src_i >= fn_type->data.fn.fn_type_id.param_count)
1941 return false;
1942 param_info = &fn_type->data.fn.fn_type_id.param_info[src_i];
1943 ty = param_info->type;
1944 break;
1945 case FnWalkIdVars:
1946 assert(src_i < fn_type->data.fn.fn_type_id.param_count);
1947 param_info = &fn_type->data.fn.fn_type_id.param_info[src_i];
1948 ty = param_info->type;
1949 var = fn_walk->data.vars.var;
1950 source_node = var->decl_node;
1951 llvm_fn = fn_walk->data.vars.llvm_fn;
1952 break;
1953 case FnWalkIdInits:
1954 if (src_i >= fn_type->data.fn.fn_type_id.param_count)
1955 return false;
1956 param_info = &fn_type->data.fn.fn_type_id.param_info[src_i];
1957 ty = param_info->type;
1958 var = fn_walk->data.inits.fn->variable_list.at(src_i);
1959 source_node = fn_walk->data.inits.fn->proto_node;
1960 llvm_fn = fn_walk->data.inits.llvm_fn;
1961 break;
1962 }
1963
1964 if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat ||
1965 ty->id == ZigTypeIdInt // TODO investigate if we need to change this
1966 ) {
1967 switch (fn_walk->id) {
1968 case FnWalkIdAttrs: {
1969 ZigType *ptr_type = get_codegen_ptr_type(ty);
1970 if (ptr_type != nullptr) {
1971 if (ty->id != ZigTypeIdOptional) {
1972 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
1973 }
1974 if (ptr_type->data.pointer.is_const) {
1975 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "readonly");
1976 }
1977 if (param_info->is_noalias) {
1978 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "noalias");
1979 }
1980 }
1981 fn_walk->data.attrs.gen_i += 1;
1982 break;
1983 }
1984 case FnWalkIdCall:
1985 fn_walk->data.call.gen_param_values->append(val);
1986 break;
1987 case FnWalkIdTypes:
1988 fn_walk->data.types.gen_param_types->append(ty->type_ref);
1989 fn_walk->data.types.param_di_types->append(ty->di_type);
1990 break;
1991 case FnWalkIdVars: {
1992 var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes);
1993 di_arg_index = fn_walk->data.vars.gen_i;
1994 fn_walk->data.vars.gen_i += 1;
1995 dest_ty = ty;
1996 goto var_ok;
1997 }
1998 case FnWalkIdInits:
1999 clear_debug_source_node(g);
2000 gen_store_untyped(g, LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i), var->value_ref, var->align_bytes, false);
2001 if (var->decl_node) {
2002 gen_var_debug_decl(g, var);
2003 }
2004 fn_walk->data.inits.gen_i += 1;
2005 break;
2006 }
2007 return true;
2008 }
2009
2010 // Arrays are just pointers
2011 if (ty->id == ZigTypeIdArray) {
2012 assert(handle_is_ptr(ty));
2013 switch (fn_walk->id) {
2014 case FnWalkIdAttrs:
2015 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
2016 addLLVMArgAttrInt(llvm_fn, fn_walk->data.attrs.gen_i, "align", get_abi_alignment(g, ty));
2017 fn_walk->data.attrs.gen_i += 1;
2018 break;
2019 case FnWalkIdCall:
2020 fn_walk->data.call.gen_param_values->append(val);
2021 break;
2022 case FnWalkIdTypes: {
2023 ZigType *gen_type = get_pointer_to_type(g, ty, true);
2024 fn_walk->data.types.gen_param_types->append(gen_type->type_ref);
2025 fn_walk->data.types.param_di_types->append(gen_type->di_type);
2026 break;
2027 }
2028 case FnWalkIdVars: {
2029 var->value_ref = LLVMGetParam(llvm_fn, fn_walk->data.vars.gen_i);
2030 di_arg_index = fn_walk->data.vars.gen_i;
2031 dest_ty = get_pointer_to_type(g, ty, false);
2032 fn_walk->data.vars.gen_i += 1;
2033 goto var_ok;
2034 }
2035 case FnWalkIdInits:
2036 if (var->decl_node) {
2037 gen_var_debug_decl(g, var);
2038 }
2039 fn_walk->data.inits.gen_i += 1;
2040 break;
2041 }
2042 return true;
2043 }
2044
2045 if (g->zig_target.arch.arch == ZigLLVM_x86_64) {
2046 X64CABIClass abi_class = type_c_abi_x86_64_class(g, ty);
2047 size_t ty_size = type_size(g, ty);
2048 if (abi_class == X64CABIClass_MEMORY) {
2049 assert(handle_is_ptr(ty));
2050 switch (fn_walk->id) {
2051 case FnWalkIdAttrs:
2052 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "byval");
2053 addLLVMArgAttrInt(llvm_fn, fn_walk->data.attrs.gen_i, "align", get_abi_alignment(g, ty));
2054 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
2055 fn_walk->data.attrs.gen_i += 1;
2056 break;
2057 case FnWalkIdCall:
2058 fn_walk->data.call.gen_param_values->append(val);
2059 break;
2060 case FnWalkIdTypes: {
2061 ZigType *gen_type = get_pointer_to_type(g, ty, true);
2062 fn_walk->data.types.gen_param_types->append(gen_type->type_ref);
2063 fn_walk->data.types.param_di_types->append(gen_type->di_type);
2064 break;
2065 }
2066 case FnWalkIdVars: {
2067 di_arg_index = fn_walk->data.vars.gen_i;
2068 var->value_ref = LLVMGetParam(llvm_fn, fn_walk->data.vars.gen_i);
2069 dest_ty = get_pointer_to_type(g, ty, false);
2070 fn_walk->data.vars.gen_i += 1;
2071 goto var_ok;
2072 }
2073 case FnWalkIdInits:
2074 if (var->decl_node) {
2075 gen_var_debug_decl(g, var);
2076 }
2077 fn_walk->data.inits.gen_i += 1;
2078 break;
2079 }
2080 return true;
2081 } else if (abi_class == X64CABIClass_INTEGER) {
2082 switch (fn_walk->id) {
2083 case FnWalkIdAttrs:
2084 fn_walk->data.attrs.gen_i += 1;
2085 break;
2086 case FnWalkIdCall: {
2087 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
2088 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, val, ptr_to_int_type_ref, "");
2089 LLVMValueRef loaded = LLVMBuildLoad(g->builder, bitcasted, "");
2090 fn_walk->data.call.gen_param_values->append(loaded);
2091 break;
2092 }
2093 case FnWalkIdTypes: {
2094 ZigType *gen_type = get_int_type(g, false, ty_size * 8);
2095 fn_walk->data.types.gen_param_types->append(gen_type->type_ref);
2096 fn_walk->data.types.param_di_types->append(gen_type->di_type);
2097 break;
2098 }
2099 case FnWalkIdVars: {
2100 di_arg_index = fn_walk->data.vars.gen_i;
2101 var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes);
2102 fn_walk->data.vars.gen_i += 1;
2103 dest_ty = ty;
2104 goto var_ok;
2105 }
2106 case FnWalkIdInits: {
2107 clear_debug_source_node(g);
2108 LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i);
2109 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
2110 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, "");
2111 gen_store_untyped(g, arg, bitcasted, var->align_bytes, false);
2112 if (var->decl_node) {
2113 gen_var_debug_decl(g, var);
2114 }
2115 fn_walk->data.inits.gen_i += 1;
2116 break;
2117 }
2118 }
2119 return true;
2120 }
2121 }
2122 if (source_node != nullptr) {
2123 give_up_with_c_abi_error(g, source_node);
2124 }
2125 // otherwise allow codegen code to report a compile error
2126 return false;
2127
2128var_ok:
2129 if (dest_ty != nullptr && var->decl_node) {
2130 // arg index + 1 because the 0 index is return value
2131 var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
2132 buf_ptr(&var->name), fn_walk->data.vars.import->di_file,
2133 (unsigned)(var->decl_node->line + 1),
2134 dest_ty->di_type, !g->strip_debug_symbols, 0, di_arg_index + 1);
2135 }
2136 return true;
2137}
2138
2139void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
2140 CallingConvention cc = fn_type->data.fn.fn_type_id.cc;
2141 if (cc == CallingConventionC) {
2142 size_t src_i = 0;
2143 for (;;) {
2144 if (!iter_function_params_c_abi(g, fn_type, fn_walk, src_i))
2145 break;
2146 src_i += 1;
2147 }
2148 return;
2149 }
2150 if (fn_walk->id == FnWalkIdCall) {
2151 IrInstructionCall *instruction = fn_walk->data.call.inst;
2152 bool is_var_args = fn_walk->data.call.is_var_args;
2153 for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) {
2154 IrInstruction *param_instruction = instruction->args[call_i];
2155 ZigType *param_type = param_instruction->value.type;
2156 if (is_var_args || type_has_bits(param_type)) {
2157 LLVMValueRef param_value = ir_llvm_value(g, param_instruction);
2158 assert(param_value);
2159 fn_walk->data.call.gen_param_values->append(param_value);
2160 }
2161 }
2162 return;
2163 }
2164 size_t next_var_i = 0;
2165 for (size_t param_i = 0; param_i < fn_type->data.fn.fn_type_id.param_count; param_i += 1) {
2166 FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
2167 size_t gen_index = gen_info->gen_index;
2168
2169 if (gen_index == SIZE_MAX) {
2170 continue;
2171 }
2172
2173 switch (fn_walk->id) {
2174 case FnWalkIdAttrs: {
2175 LLVMValueRef llvm_fn = fn_walk->data.attrs.fn->llvm_value;
2176 bool is_byval = gen_info->is_byval;
2177 FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[param_i];
2178
2179 ZigType *param_type = gen_info->type;
2180 if (param_info->is_noalias) {
2181 addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "noalias");
2182 }
2183 if ((param_type->id == ZigTypeIdPointer && param_type->data.pointer.is_const) || is_byval) {
2184 addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "readonly");
2185 }
2186 if (param_type->id == ZigTypeIdPointer) {
2187 addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "nonnull");
2188 }
2189 break;
2190 }
2191 case FnWalkIdInits: {
2192 ZigFn *fn_table_entry = fn_walk->data.inits.fn;
2193 LLVMValueRef llvm_fn = fn_table_entry->llvm_value;
2194 ZigVar *variable = fn_table_entry->variable_list.at(next_var_i);
2195 assert(variable->src_arg_index != SIZE_MAX);
2196 next_var_i += 1;
2197
2198 assert(variable);
2199 assert(variable->value_ref);
2200
2201 if (!handle_is_ptr(variable->value->type)) {
2202 clear_debug_source_node(g);
2203 gen_store_untyped(g, LLVMGetParam(llvm_fn, (unsigned)variable->gen_arg_index), variable->value_ref,
2204 variable->align_bytes, false);
2205 }
2206
2207 if (variable->decl_node) {
2208 gen_var_debug_decl(g, variable);
2209 }
2210 break;
2211 }
2212 case FnWalkIdCall:
2213 // handled before for loop
2214 zig_unreachable();
2215 case FnWalkIdTypes:
2216 // Not called for non-c-abi
2217 zig_unreachable();
2218 case FnWalkIdVars:
2219 // iter_function_params_c_abi is called directly for this one
2220 zig_unreachable();
2221 }
2222 }
2223}
2224
18872225static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable,
18882226 IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction)
18892227{
......@@ -1902,15 +2240,13 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
19022240 LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
19032241 ZigType *return_type = return_instruction->value->value.type;
19042242
1905 if (handle_is_ptr(return_type)) {
1906 if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) {
1907 assert(g->cur_ret_ptr);
1908 gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);
1909 LLVMBuildRetVoid(g->builder);
1910 } else {
1911 LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, "");
1912 LLVMBuildRet(g->builder, by_val_value);
1913 }
2243 if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) {
2244 assert(g->cur_ret_ptr);
2245 gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);
2246 LLVMBuildRetVoid(g->builder);
2247 } else if (handle_is_ptr(return_type)) {
2248 LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, "");
2249 LLVMBuildRet(g->builder, by_val_value);
19142250 } else {
19152251 LLVMBuildRet(g->builder, value);
19162252 }
......@@ -2878,7 +3214,8 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
28783214 assert(var->value->type == init_value->value.type);
28793215 ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->value->type, false, false,
28803216 PtrLenSingle, var->align_bytes, 0, 0);
2881 gen_assign_raw(g, var->value_ref, var_ptr_type, ir_llvm_value(g, init_value));
3217 LLVMValueRef llvm_init_val = ir_llvm_value(g, init_value);
3218 gen_assign_raw(g, var->value_ref, var_ptr_type, llvm_init_val);
28823219 } else {
28833220 bool want_safe = ir_want_runtime_safety(g, &decl_var_instruction->base);
28843221 if (want_safe) {
......@@ -3124,40 +3461,30 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
31243461 ZigType *src_return_type = fn_type_id->return_type;
31253462 bool ret_has_bits = type_has_bits(src_return_type);
31263463
3127 bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type) &&
3128 calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc);
3464 CallingConvention cc = fn_type->data.fn.fn_type_id.cc;
3465
3466 bool first_arg_ret = ret_has_bits && want_first_arg_sret(g, fn_type_id);
31293467 bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id);
3130 // +2 for the async args
3131 size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0) + 2;
31323468 bool is_var_args = fn_type_id->is_var_args;
3133 LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
3134 size_t gen_param_index = 0;
3469 ZigList<LLVMValueRef> gen_param_values = {};
31353470 if (first_arg_ret) {
3136 gen_param_values[gen_param_index] = instruction->tmp_ptr;
3137 gen_param_index += 1;
3471 gen_param_values.append(instruction->tmp_ptr);
31383472 }
31393473 if (prefix_arg_err_ret_stack) {
3140 gen_param_values[gen_param_index] = get_cur_err_ret_trace_val(g, instruction->base.scope);
3141 gen_param_index += 1;
3474 gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope));
31423475 }
31433476 if (instruction->is_async) {
3144 gen_param_values[gen_param_index] = ir_llvm_value(g, instruction->async_allocator);
3145 gen_param_index += 1;
3477 gen_param_values.append(ir_llvm_value(g, instruction->async_allocator));
31463478
31473479 LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, "");
3148 gen_param_values[gen_param_index] = err_val_ptr;
3149 gen_param_index += 1;
3150 }
3151 for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) {
3152 IrInstruction *param_instruction = instruction->args[call_i];
3153 ZigType *param_type = param_instruction->value.type;
3154 if (is_var_args || type_has_bits(param_type)) {
3155 LLVMValueRef param_value = ir_llvm_value(g, param_instruction);
3156 assert(param_value);
3157 gen_param_values[gen_param_index] = param_value;
3158 gen_param_index += 1;
3159 }
3480 gen_param_values.append(err_val_ptr);
31603481 }
3482 FnWalk fn_walk = {};
3483 fn_walk.id = FnWalkIdCall;
3484 fn_walk.data.call.inst = instruction;
3485 fn_walk.data.call.is_var_args = is_var_args;
3486 fn_walk.data.call.gen_param_values = &gen_param_values;
3487 walk_function_params(g, fn_type, &fn_walk);
31613488
31623489 ZigLLVM_FnInline fn_inline;
31633490 switch (instruction->fn_inline) {
......@@ -3172,12 +3499,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
31723499 break;
31733500 }
31743501
3175 LLVMCallConv llvm_cc = get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc);
3502 LLVMCallConv llvm_cc = get_llvm_cc(g, cc);
31763503 LLVMValueRef result;
31773504
31783505 if (instruction->new_stack == nullptr) {
31793506 result = ZigLLVMBuildCall(g->builder, fn_val,
3180 gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
3507 gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, "");
31813508 } else {
31823509 LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g);
31833510 LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g);
......@@ -3186,7 +3513,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
31863513 LLVMValueRef old_stack_ref = LLVMBuildCall(g->builder, stacksave_fn_val, nullptr, 0, "");
31873514 gen_set_stack_pointer(g, new_stack_addr);
31883515 result = ZigLLVMBuildCall(g->builder, fn_val,
3189 gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
3516 gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, "");
31903517 LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, "");
31913518 }
31923519
......@@ -5533,12 +5860,24 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
55335860 LLVMValueRef tag_value = bigint_to_llvm_const(type_entry->data.unionation.tag_type->type_ref,
55345861 &const_val->data.x_union.tag);
55355862
5536 LLVMValueRef fields[2];
5863 LLVMValueRef fields[3];
55375864 fields[type_entry->data.unionation.gen_union_index] = union_value_ref;
55385865 fields[type_entry->data.unionation.gen_tag_index] = tag_value;
55395866
55405867 if (make_unnamed_struct) {
5541 return LLVMConstStruct(fields, 2, false);
5868 LLVMValueRef result = LLVMConstStruct(fields, 2, false);
5869 uint64_t last_field_offset = LLVMOffsetOfElement(g->target_data_ref, LLVMTypeOf(result), 1);
5870 uint64_t end_offset = last_field_offset +
5871 LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(fields[1]));
5872 uint64_t expected_sz = LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref);
5873 unsigned pad_sz = expected_sz - end_offset;
5874 if (pad_sz != 0) {
5875 fields[2] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_sz));
5876 result = LLVMConstStruct(fields, 3, false);
5877 }
5878 uint64_t actual_sz = LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(result));
5879 assert(actual_sz == expected_sz);
5880 return result;
55425881 } else {
55435882 return LLVMConstNamedStruct(type_entry->type_ref, fields, 2);
55445883 }
......@@ -5578,13 +5917,29 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
55785917 err_payload_value = gen_const_val(g, payload_val, "");
55795918 make_unnamed_struct = is_llvm_value_unnamed_type(payload_val->type, err_payload_value);
55805919 }
5581 LLVMValueRef fields[] = {
5582 err_tag_value,
5583 err_payload_value,
5584 };
55855920 if (make_unnamed_struct) {
5586 return LLVMConstStruct(fields, 2, false);
5921 uint64_t payload_off = LLVMOffsetOfElement(g->target_data_ref, type_entry->type_ref, 1);
5922 uint64_t err_sz = LLVMStoreSizeOfType(g->target_data_ref, LLVMTypeOf(err_tag_value));
5923 unsigned pad_sz = payload_off - err_sz;
5924 if (pad_sz == 0) {
5925 LLVMValueRef fields[] = {
5926 err_tag_value,
5927 err_payload_value,
5928 };
5929 return LLVMConstStruct(fields, 2, false);
5930 } else {
5931 LLVMValueRef fields[] = {
5932 err_tag_value,
5933 LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), pad_sz)),
5934 err_payload_value,
5935 };
5936 return LLVMConstStruct(fields, 3, false);
5937 }
55875938 } else {
5939 LLVMValueRef fields[] = {
5940 err_tag_value,
5941 err_payload_value,
5942 };
55885943 return LLVMConstNamedStruct(type_entry->type_ref, fields, 2);
55895944 }
55905945 }
......@@ -5717,23 +6072,6 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,
57176072 // TODO ^^ make an actual global variable
57186073}
57196074
5720static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) {
5721 assert(alignment > 0);
5722 LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name);
5723 LLVMSetAlignment(result, alignment);
5724 return result;
5725}
5726
5727static void report_errors_and_maybe_exit(CodeGen *g) {
5728 if (g->errors.length != 0) {
5729 for (size_t i = 0; i < g->errors.length; i += 1) {
5730 ErrorMsg *err = g->errors.at(i);
5731 print_err_msg(err, g->err_color);
5732 }
5733 exit(1);
5734 }
5735}
5736
57376075static void validate_inline_fns(CodeGen *g) {
57386076 for (size_t i = 0; i < g->inline_fns.length; i += 1) {
57396077 ZigFn *fn_entry = g->inline_fns.at(i);
......@@ -5852,11 +6190,14 @@ static void do_code_gen(CodeGen *g) {
58526190 // Generate function definitions.
58536191 for (size_t fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) {
58546192 ZigFn *fn_table_entry = g->fn_defs.at(fn_i);
6193 FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;
6194 CallingConvention cc = fn_type_id->cc;
6195 bool is_c_abi = cc == CallingConventionC;
58556196
58566197 LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);
58576198 g->cur_fn = fn_table_entry;
58586199 g->cur_fn_val = fn;
5859 ZigType *return_type = fn_table_entry->type_entry->data.fn.fn_type_id.return_type;
6200 ZigType *return_type = fn_type_id->return_type;
58606201 if (handle_is_ptr(return_type)) {
58616202 g->cur_ret_ptr = LLVMGetParam(fn, 0);
58626203 } else {
......@@ -5875,7 +6216,7 @@ static void do_code_gen(CodeGen *g) {
58756216 }
58766217
58776218 // error return tracing setup
5878 bool is_async = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
6219 bool is_async = cc == CallingConventionAsync;
58796220 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;
58806221 LLVMValueRef err_ret_array_val = nullptr;
58816222 if (have_err_ret_trace_stack) {
......@@ -5934,7 +6275,15 @@ static void do_code_gen(CodeGen *g) {
59346275
59356276 ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base);
59366277
6278 unsigned gen_i_init = want_first_arg_sret(g, fn_type_id) ? 1 : 0;
6279
59376280 // create debug variable declarations for variables and allocate all local variables
6281 FnWalk fn_walk_var = {};
6282 fn_walk_var.id = FnWalkIdVars;
6283 fn_walk_var.data.vars.import = import;
6284 fn_walk_var.data.vars.fn = fn_table_entry;
6285 fn_walk_var.data.vars.llvm_fn = fn;
6286 fn_walk_var.data.vars.gen_i = gen_i_init;
59386287 for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) {
59396288 ZigVar *var = fn_table_entry->variable_list.at(var_i);
59406289
......@@ -5953,6 +6302,9 @@ static void do_code_gen(CodeGen *g) {
59536302 buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1),
59546303 var->value->type->di_type, !g->strip_debug_symbols, 0);
59556304
6305 } else if (is_c_abi) {
6306 fn_walk_var.data.vars.var = var;
6307 iter_function_params_c_abi(g, fn_table_entry->type_entry, &fn_walk_var, var->src_arg_index);
59566308 } else {
59576309 assert(var->gen_arg_index != SIZE_MAX);
59586310 ZigType *gen_type;
......@@ -6004,33 +6356,14 @@ static void do_code_gen(CodeGen *g) {
60046356 gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
60056357 }
60066358
6007 FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;
6008
60096359 // create debug variable declarations for parameters
60106360 // rely on the first variables in the variable_list being parameters.
6011 size_t next_var_i = 0;
6012 for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
6013 FnGenParamInfo *info = &fn_table_entry->type_entry->data.fn.gen_param_info[param_i];
6014 if (info->gen_index == SIZE_MAX)
6015 continue;
6016
6017 ZigVar *variable = fn_table_entry->variable_list.at(next_var_i);
6018 assert(variable->src_arg_index != SIZE_MAX);
6019 next_var_i += 1;
6020
6021 assert(variable);
6022 assert(variable->value_ref);
6023
6024 if (!handle_is_ptr(variable->value->type)) {
6025 clear_debug_source_node(g);
6026 gen_store_untyped(g, LLVMGetParam(fn, (unsigned)variable->gen_arg_index), variable->value_ref,
6027 variable->align_bytes, false);
6028 }
6029
6030 if (variable->decl_node) {
6031 gen_var_debug_decl(g, variable);
6032 }
6033 }
6361 FnWalk fn_walk_init = {};
6362 fn_walk_init.id = FnWalkIdInits;
6363 fn_walk_init.data.inits.fn = fn_table_entry;
6364 fn_walk_init.data.inits.llvm_fn = fn;
6365 fn_walk_init.data.inits.gen_i = gen_i_init;
6366 walk_function_params(g, fn_table_entry->type_entry, &fn_walk_init);
60346367
60356368 ir_render(g, fn_table_entry);
60366369
src/codegen.hpp-1
......@@ -61,5 +61,4 @@ void codegen_translate_c(CodeGen *g, Buf *path);
6161
6262Buf *codegen_generate_builtin_source(CodeGen *g);
6363
64
6564#endif
src/ir.cpp+8-3
......@@ -13107,8 +13107,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
1310713107 assert(ira->codegen->errors.length != 0);
1310813108 return ira->codegen->invalid_instruction;
1310913109 }
13110 assert(var->value->type);
13111 if (type_is_invalid(var->value->type))
13110 if (var->value->type == nullptr || type_is_invalid(var->value->type))
1311213111 return ira->codegen->invalid_instruction;
1311313112
1311413113 bool comptime_var_mem = ir_get_var_is_comptime(var);
......@@ -19643,7 +19642,7 @@ static ZigType *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnP
1964319642 return ira->codegen->builtin_types.entry_invalid;
1964419643 if (type_requires_comptime(param_type)) {
1964519644 if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
19646 ir_add_error(ira, &instruction->base,
19645 ir_add_error(ira, param_type_value,
1964719646 buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'",
1964819647 buf_ptr(&param_type->name), calling_convention_name(fn_type_id.cc)));
1964919648 return ira->codegen->builtin_types.entry_invalid;
......@@ -19654,6 +19653,12 @@ static ZigType *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnP
1965419653 out_val->data.x_type = get_generic_fn_type(ira->codegen, &fn_type_id);
1965519654 return ira->codegen->builtin_types.entry_type;
1965619655 }
19656 if (!type_has_bits(param_type) && !calling_convention_allows_zig_types(fn_type_id.cc)) {
19657 ir_add_error(ira, param_type_value,
19658 buf_sprintf("parameter of type '%s' has 0 bits; not allowed in function with calling convention '%s'",
19659 buf_ptr(&param_type->name), calling_convention_name(fn_type_id.cc)));
19660 return ira->codegen->builtin_types.entry_invalid;
19661 }
1965719662 param_info->type = param_type;
1965819663 }
1965919664
src/os.cpp+1-1
......@@ -445,7 +445,7 @@ static Buf os_path_resolve_windows(Buf **paths_ptr, size_t paths_len) {
445445 }
446446
447447 // determine which disk designator we will result with, if any
448 char result_drive_buf[2] = {'_', ':'};
448 char result_drive_buf[3] = {'_', ':', '\0'}; // 0 needed for strlen later
449449 Slice<uint8_t> result_disk_designator = str("");
450450 WindowsPathKind have_drive_kind = WindowsPathKindNone;
451451 bool have_abs_path = false;
std/array_list.zig+27-2
......@@ -62,6 +62,10 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
6262 return self.len;
6363 }
6464
65 pub fn capacity(self: Self) usize {
66 return self.items.len;
67 }
68
6569 /// ArrayList takes ownership of the passed in slice. The slice must have been
6670 /// allocated with `allocator`.
6771 /// Deinitialize with `deinit` or use `toOwnedSlice`.
......@@ -102,6 +106,11 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
102106 new_item_ptr.* = item;
103107 }
104108
109 pub fn appendAssumeCapacity(self: *Self, item: T) void {
110 const new_item_ptr = self.addOneAssumeCapacity();
111 new_item_ptr.* = item;
112 }
113
105114 /// Removes the element at the specified index and returns it.
106115 /// The empty slot is filled from the end of the list.
107116 pub fn swapRemove(self: *Self, i: usize) T {
......@@ -138,7 +147,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
138147 }
139148
140149 pub fn ensureCapacity(self: *Self, new_capacity: usize) !void {
141 var better_capacity = self.items.len;
150 var better_capacity = self.capacity();
142151 if (better_capacity >= new_capacity) return;
143152 while (true) {
144153 better_capacity += better_capacity / 2 + 8;
......@@ -150,8 +159,13 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
150159 pub fn addOne(self: *Self) !*T {
151160 const new_length = self.len + 1;
152161 try self.ensureCapacity(new_length);
162 return self.addOneAssumeCapacity();
163 }
164
165 pub fn addOneAssumeCapacity(self: *Self) *T {
166 assert(self.count() < self.capacity());
153167 const result = &self.items[self.len];
154 self.len = new_length;
168 self.len += 1;
155169 return result;
156170 }
157171
......@@ -191,6 +205,17 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
191205 };
192206}
193207
208test "std.ArrayList.init" {
209 var bytes: [1024]u8 = undefined;
210 const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
211
212 var list = ArrayList(i32).init(allocator);
213 defer list.deinit();
214
215 assert(list.count() == 0);
216 assert(list.capacity() == 0);
217}
218
194219test "std.ArrayList.basic" {
195220 var bytes: [1024]u8 = undefined;
196221 const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
std/build.zig+27
......@@ -48,6 +48,12 @@ pub const Builder = struct {
4848 cache_root: []const u8,
4949 release_mode: ?builtin.Mode,
5050
51 pub const CStd = enum {
52 C89,
53 C99,
54 C11,
55 };
56
5157 const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8);
5258 const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8);
5359
......@@ -817,6 +823,7 @@ pub const LibExeObjStep = struct {
817823 frameworks: BufSet,
818824 verbose_link: bool,
819825 no_rosegment: bool,
826 c_std: Builder.CStd,
820827
821828 // zig only stuff
822829 root_src: ?[]const u8,
......@@ -918,6 +925,7 @@ pub const LibExeObjStep = struct {
918925 .object_src = undefined,
919926 .disable_libc = true,
920927 .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable,
928 .c_std = Builder.CStd.C99,
921929 };
922930 self.computeOutFileNames();
923931 return self;
......@@ -952,6 +960,7 @@ pub const LibExeObjStep = struct {
952960 .disable_libc = false,
953961 .is_zig = false,
954962 .linker_script = null,
963 .c_std = Builder.CStd.C99,
955964
956965 .root_src = undefined,
957966 .verbose_link = false,
......@@ -1392,6 +1401,13 @@ pub const LibExeObjStep = struct {
13921401
13931402 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
13951411 switch (self.kind) {
13961412 Kind.Obj => {
13971413 cc_args.append("-c") catch unreachable;
......@@ -1678,6 +1694,17 @@ pub const TestStep = struct {
16781694 self.filter = text;
16791695 }
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
16811708 pub fn addObjectFile(self: *TestStep, path: []const u8) void {
16821709 self.object_files.append(path) catch unreachable;
16831710 }
std/crypto/x25519.zig+12-1
......@@ -4,6 +4,7 @@
44
55const std = @import("../index.zig");
66const builtin = @import("builtin");
7const fmt = std.fmt;
78
89const Endian = builtin.Endian;
910const readInt = std.mem.readInt;
......@@ -114,7 +115,7 @@ pub const X25519 = struct {
114115 return !zerocmp(u8, out);
115116 }
116117
117 pub fn createPublicKey(public_key: []const u8, private_key: []const u8) bool {
118 pub fn createPublicKey(public_key: [] u8, private_key: []const u8) bool {
118119 var base_point = []u8{9} ++ []u8{0} ** 31;
119120 return create(public_key, private_key, base_point);
120121 }
......@@ -573,6 +574,16 @@ const Fe = struct {
573574 }
574575};
575576
577test "x25519 public key calculation from secret key" {
578 var sk: [32]u8 = undefined;
579 var pk_expected: [32]u8 = undefined;
580 var pk_calculated: [32]u8 = undefined;
581 try fmt.hexToBytes(sk[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
582 try fmt.hexToBytes(pk_expected[0..], "f1814f0e8ff1043d8a44d25babff3cedcae6c22c3edaa48f857ae70de2baae50");
583 std.debug.assert(X25519.createPublicKey(pk_calculated[0..], sk));
584 std.debug.assert(std.mem.eql(u8, pk_calculated, pk_expected));
585}
586
576587test "x25519 rfc7748 vector1" {
577588 const secret_key = "\xa5\x46\xe3\x6b\xf0\x52\x7c\x9d\x3b\x16\x15\x4b\x82\x46\x5e\xdd\x62\x14\x4c\x0a\xc1\xfc\x5a\x18\x50\x6a\x22\x44\xba\x44\x9a\xc4";
578589 const public_key = "\xe6\xdb\x68\x67\x58\x30\x30\xdb\x35\x94\xc1\xa4\x24\xb1\x5f\x7c\x72\x66\x24\xec\x26\xb3\x35\x3b\x10\xa9\x03\xa6\xd0\xab\x1c\x4c";
std/os/index.zig+19-17
......@@ -343,23 +343,25 @@ pub fn posixWrite(fd: i32, bytes: []const u8) !void {
343343 const amt_to_write = math.min(bytes.len - index, usize(max_bytes_len));
344344 const rc = posix.write(fd, bytes.ptr + index, amt_to_write);
345345 const write_err = posix.getErrno(rc);
346 if (write_err > 0) {
347 return switch (write_err) {
348 posix.EINTR => continue,
349 posix.EINVAL, posix.EFAULT => unreachable,
350 posix.EAGAIN => PosixWriteError.WouldBlock,
351 posix.EBADF => PosixWriteError.FileClosed,
352 posix.EDESTADDRREQ => PosixWriteError.DestinationAddressRequired,
353 posix.EDQUOT => PosixWriteError.DiskQuota,
354 posix.EFBIG => PosixWriteError.FileTooBig,
355 posix.EIO => PosixWriteError.InputOutput,
356 posix.ENOSPC => PosixWriteError.NoSpaceLeft,
357 posix.EPERM => PosixWriteError.AccessDenied,
358 posix.EPIPE => PosixWriteError.BrokenPipe,
359 else => unexpectedErrorPosix(write_err),
360 };
346 switch (write_err) {
347 0 => {
348 index += rc;
349 continue;
350 },
351 posix.EINTR => continue,
352 posix.EINVAL => unreachable,
353 posix.EFAULT => unreachable,
354 posix.EAGAIN => return PosixWriteError.WouldBlock,
355 posix.EBADF => return PosixWriteError.FileClosed,
356 posix.EDESTADDRREQ => return PosixWriteError.DestinationAddressRequired,
357 posix.EDQUOT => return PosixWriteError.DiskQuota,
358 posix.EFBIG => return PosixWriteError.FileTooBig,
359 posix.EIO => return PosixWriteError.InputOutput,
360 posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
361 posix.EPERM => return PosixWriteError.AccessDenied,
362 posix.EPIPE => return PosixWriteError.BrokenPipe,
363 else => return unexpectedErrorPosix(write_err),
361364 }
362 index += rc;
363365 }
364366}
365367
......@@ -1614,7 +1616,7 @@ pub const Dir = struct {
16141616 return null;
16151617 }
16161618 const name_utf16le = mem.toSlice(u16, self.handle.find_file_data.cFileName[0..].ptr);
1617 if (mem.eql(u16, name_utf16le, []u16{'.'}) or mem.eql(u16, name_utf16le, []u16{'.', '.'}))
1619 if (mem.eql(u16, name_utf16le, []u16{'.'}) or mem.eql(u16, name_utf16le, []u16{ '.', '.' }))
16181620 continue;
16191621 // Trust that Windows gives us valid UTF-16LE
16201622 const name_utf8_len = std.unicode.utf16leToUtf8(self.handle.name_data[0..], name_utf16le) catch unreachable;
test/behavior.zig+2-1
......@@ -9,9 +9,10 @@ comptime {
99 _ = @import("cases/bitcast.zig");
1010 _ = @import("cases/bool.zig");
1111 _ = @import("cases/bugs/1111.zig");
12 _ = @import("cases/bugs/1230.zig");
1312 _ = @import("cases/bugs/1277.zig");
13 _ = @import("cases/bugs/1381.zig");
1414 _ = @import("cases/bugs/1421.zig");
15 _ = @import("cases/bugs/1442.zig");
1516 _ = @import("cases/bugs/394.zig");
1617 _ = @import("cases/bugs/655.zig");
1718 _ = @import("cases/bugs/656.zig");
test/build_examples.zig+6
......@@ -28,4 +28,10 @@ pub fn addCases(cases: *tests.BuildExamplesContext) void {
2828 // TODO figure out how to make this work on darwin - probably libSystem has dlopen/dlsym in it
2929 cases.addBuildFile("test/standalone/load_dynamic_library/build.zig");
3030 }
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 }
3137}
test/cases/bugs/1230.zig deleted-14
......@@ -1,14 +0,0 @@
1const assert = @import("std").debug.assert;
2
3const S = extern struct {
4 x: i32,
5};
6
7extern fn ret_struct() S {
8 return S{ .x = 42 };
9}
10
11test "extern return small struct (bug 1230)" {
12 const s = ret_struct();
13 assert(s.x == 42);
14}
test/cases/bugs/1381.zig created+21
......@@ -0,0 +1,21 @@
1const std = @import("std");
2
3const B = union(enum) {
4 D: u8,
5 E: u16,
6};
7
8const A = union(enum) {
9 B: B,
10 C: u8,
11};
12
13test "union that needs padding bytes inside an array" {
14 var as = []A{
15 A{ .B = B{ .D = 1 } },
16 A{ .B = B{ .D = 1 } },
17 };
18
19 const a = as[0].B;
20 std.debug.assertOrPanic(a.D == 1);
21}
test/cases/bugs/1442.zig created+11
......@@ -0,0 +1,11 @@
1const std = @import("std");
2
3const Union = union(enum) {
4 Text: []const u8,
5 Color: u32,
6};
7
8test "const error union field alignment" {
9 var union_or_err: error!Union = Union{ .Color = 1234 };
10 std.debug.assertOrPanic((union_or_err catch unreachable).Color == 1234);
11}
test/compile_errors.zig+19
......@@ -1,6 +1,24 @@
11const tests = @import("tests.zig");
22
33pub fn addCases(cases: *tests.CompileErrorContext) void {
4 cases.add(
5 "variable initialization compile error then referenced",
6 \\fn Undeclared() type {
7 \\ return T;
8 \\}
9 \\fn Gen() type {
10 \\ const X = Undeclared();
11 \\ return struct {
12 \\ x: X,
13 \\ };
14 \\}
15 \\export fn entry() void {
16 \\ const S = Gen();
17 \\}
18 ,
19 ".tmp_source.zig:2:12: error: use of undeclared identifier 'T'",
20 );
21
422 cases.add(
523 "refer to the type of a generic function",
624 \\export fn entry() void {
......@@ -1273,6 +1291,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
12731291 \\
12741292 \\extern fn bar(x: *void) void { }
12751293 ,
1294 ".tmp_source.zig:1:30: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'ccc'",
12761295 ".tmp_source.zig:7:18: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'ccc'",
12771296 );
12781297
test/gen_h.zig+24-4
......@@ -20,6 +20,9 @@ pub fn addCases(cases: *tests.GenHContext) void {
2020 \\ A: i32,
2121 \\ B: f32,
2222 \\ C: bool,
23 \\ D: u64,
24 \\ E: u64,
25 \\ F: u64,
2326 \\};
2427 \\export fn entry(foo: Foo) void { }
2528 ,
......@@ -27,6 +30,9 @@ pub fn addCases(cases: *tests.GenHContext) void {
2730 \\ int32_t A;
2831 \\ float B;
2932 \\ bool C;
33 \\ uint64_t D;
34 \\ uint64_t E;
35 \\ uint64_t F;
3036 \\};
3137 \\
3238 \\TEST_EXPORT void entry(struct Foo foo);
......@@ -34,17 +40,34 @@ pub fn addCases(cases: *tests.GenHContext) void {
3440 );
3541
3642 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 \\};
3750 \\const Foo = extern union {
3851 \\ A: i32,
3952 \\ B: f32,
4053 \\ C: bool,
54 \\ D: Big,
4155 \\};
42 \\export fn entry(foo: Foo) void { }
56 \\export fn entry(foo: Foo) void {}
4357 ,
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 \\
4466 \\union Foo {
4567 \\ int32_t A;
4668 \\ float B;
4769 \\ bool C;
70 \\ struct Big D;
4871 \\};
4972 \\
5073 \\TEST_EXPORT void entry(union Foo foo);
......@@ -85,7 +108,6 @@ pub fn addCases(cases: *tests.GenHContext) void {
85108 \\export fn a(s: *S) u8 {
86109 \\ return s.a;
87110 \\}
88
89111 ,
90112 \\struct S;
91113 \\TEST_EXPORT uint8_t a(struct S * s);
......@@ -101,7 +123,6 @@ pub fn addCases(cases: *tests.GenHContext) void {
101123 \\export fn a(s: *U) u8 {
102124 \\ return s.A;
103125 \\}
104
105126 ,
106127 \\union U;
107128 \\TEST_EXPORT uint8_t a(union U * s);
......@@ -117,7 +138,6 @@ pub fn addCases(cases: *tests.GenHContext) void {
117138 \\export fn a(s: *E) u8 {
118139 \\ return @enumToInt(s.*);
119140 \\}
120
121141 ,
122142 \\enum E;
123143 \\TEST_EXPORT uint8_t a(enum E * s);
test/stage1/c_abi/build.zig created+18
......@@ -0,0 +1,18 @@
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 c_obj.setNoStdLib(true);
9
10 const main = b.addTest("main.zig");
11 main.setBuildMode(rel_opts);
12 main.addObject(c_obj);
13
14 const test_step = b.step("test", "Test the program");
15 test_step.dependOn(&main.step);
16
17 b.default_step.dependOn(test_step);
18}
test/stage1/c_abi/cfuncs.c created+208
......@@ -0,0 +1,208 @@
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
55struct SplitStructInts {
56 uint64_t a;
57 uint8_t b;
58 uint32_t c;
59};
60void zig_split_struct_ints(struct SplitStructInts);
61
62struct BigStruct zig_big_struct_both(struct BigStruct);
63
64void run_c_tests(void) {
65 zig_u8(0xff);
66 zig_u16(0xfffe);
67 zig_u32(0xfffffffd);
68 zig_u64(0xfffffffffffffffc);
69
70 zig_i8(-1);
71 zig_i16(-2);
72 zig_i32(-3);
73 zig_i64(-4);
74
75 zig_f32(12.34f);
76 zig_f64(56.78);
77
78 zig_ptr((void*)0xdeadbeefL);
79
80 zig_bool(true);
81
82 uint8_t array[10] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
83 zig_array(array);
84
85 {
86 struct BigStruct s = {1, 2, 3, 4, 5};
87 zig_big_struct(s);
88 }
89
90 {
91 struct SmallStructInts s = {1, 2, 3, 4};
92 zig_small_struct_ints(s);
93 }
94
95 {
96 struct SplitStructInts s = {1234, 100, 1337};
97 zig_split_struct_ints(s);
98 }
99
100 {
101 struct BigStruct s = {30, 31, 32, 33, 34};
102 struct BigStruct res = zig_big_struct_both(s);
103 assert_or_panic(res.a == 20);
104 assert_or_panic(res.b == 21);
105 assert_or_panic(res.c == 22);
106 assert_or_panic(res.d == 23);
107 assert_or_panic(res.e == 24);
108 }
109}
110
111void c_u8(uint8_t x) {
112 assert_or_panic(x == 0xff);
113}
114
115void c_u16(uint16_t x) {
116 assert_or_panic(x == 0xfffe);
117}
118
119void c_u32(uint32_t x) {
120 assert_or_panic(x == 0xfffffffd);
121}
122
123void c_u64(uint64_t x) {
124 assert_or_panic(x == 0xfffffffffffffffcULL);
125}
126
127void c_i8(int8_t x) {
128 assert_or_panic(x == -1);
129}
130
131void c_i16(int16_t x) {
132 assert_or_panic(x == -2);
133}
134
135void c_i32(int32_t x) {
136 assert_or_panic(x == -3);
137}
138
139void c_i64(int64_t x) {
140 assert_or_panic(x == -4);
141}
142
143void c_f32(float x) {
144 assert_or_panic(x == 12.34f);
145}
146
147void c_f64(double x) {
148 assert_or_panic(x == 56.78);
149}
150
151void c_ptr(void *x) {
152 assert_or_panic(x == (void*)0xdeadbeefL);
153}
154
155void c_bool(bool x) {
156 assert_or_panic(x);
157}
158
159void c_array(uint8_t x[10]) {
160 assert_or_panic(x[0] == '1');
161 assert_or_panic(x[1] == '2');
162 assert_or_panic(x[2] == '3');
163 assert_or_panic(x[3] == '4');
164 assert_or_panic(x[4] == '5');
165 assert_or_panic(x[5] == '6');
166 assert_or_panic(x[6] == '7');
167 assert_or_panic(x[7] == '8');
168 assert_or_panic(x[8] == '9');
169 assert_or_panic(x[9] == '0');
170}
171
172void c_big_struct(struct BigStruct x) {
173 assert_or_panic(x.a == 1);
174 assert_or_panic(x.b == 2);
175 assert_or_panic(x.c == 3);
176 assert_or_panic(x.d == 4);
177 assert_or_panic(x.e == 5);
178}
179
180void c_big_union(union BigUnion x) {
181 assert_or_panic(x.a.a == 1);
182 assert_or_panic(x.a.b == 2);
183 assert_or_panic(x.a.c == 3);
184 assert_or_panic(x.a.d == 4);
185}
186
187void c_small_struct_ints(struct SmallStructInts x) {
188 assert_or_panic(x.a == 1);
189 assert_or_panic(x.b == 2);
190 assert_or_panic(x.c == 3);
191 assert_or_panic(x.d == 4);
192}
193
194void c_split_struct_ints(struct SplitStructInts x) {
195 assert_or_panic(x.a == 1234);
196 assert_or_panic(x.b == 100);
197 assert_or_panic(x.c == 1337);
198}
199
200struct BigStruct c_big_struct_both(struct BigStruct x) {
201 assert_or_panic(x.a == 1);
202 assert_or_panic(x.b == 2);
203 assert_or_panic(x.c == 3);
204 assert_or_panic(x.d == 4);
205 assert_or_panic(x.e == 5);
206 struct BigStruct y = {10, 11, 12, 13, 14};
207 return y;
208}
test/stage1/c_abi/main.zig created+239
......@@ -0,0 +1,239 @@
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}
184
185const SplitStructInt = extern struct {
186 a: u64,
187 b: u8,
188 c: u32,
189};
190extern fn c_split_struct_ints(SplitStructInt) void;
191
192test "C ABI split struct of ints" {
193 var s = SplitStructInt{
194 .a = 1234,
195 .b = 100,
196 .c = 1337,
197 };
198 c_split_struct_ints(s);
199}
200
201export fn zig_split_struct_ints(x: SplitStructInt) void {
202 assertOrPanic(x.a == 1234);
203 assertOrPanic(x.b == 100);
204 assertOrPanic(x.c == 1337);
205}
206
207extern fn c_big_struct_both(BigStruct) BigStruct;
208
209test "C ABI sret and byval together" {
210 var s = BigStruct{
211 .a = 1,
212 .b = 2,
213 .c = 3,
214 .d = 4,
215 .e = 5,
216 };
217 var y = c_big_struct_both(s);
218 assertOrPanic(y.a == 10);
219 assertOrPanic(y.b == 11);
220 assertOrPanic(y.c == 12);
221 assertOrPanic(y.d == 13);
222 assertOrPanic(y.e == 14);
223}
224
225export fn zig_big_struct_both(x: BigStruct) BigStruct {
226 assertOrPanic(x.a == 30);
227 assertOrPanic(x.b == 31);
228 assertOrPanic(x.c == 32);
229 assertOrPanic(x.d == 33);
230 assertOrPanic(x.e == 34);
231 var s = BigStruct{
232 .a = 20,
233 .b = 21,
234 .c = 22,
235 .d = 23,
236 .e = 24,
237 };
238 return s;
239}