| author | |
| committer | |
| log | 4af844732a88393b172d33676732580b056910f6 |
| tree | 32a05bfbf51e9f8fc0339ca44658e04c21345788 |
| parent | 67735c6f1557092efe6e8c1712445c30655fe283 |
| parent | 7dd3c3814de0caf808bc112aa07044cdd8bba135 |
| signature | Commit is signed but in an unrecognized format. |
22 files changed, 1309 insertions(+), 204 deletions(-)
build.zig+5-1| ... | @@ -76,7 +76,11 @@ pub fn build(b: *Builder) !void { | ... | @@ -76,7 +76,11 @@ pub fn build(b: *Builder) !void { |
| 76 | 76 | ||
| 77 | const test_stage2_step = b.step("test-stage2", "Run the stage2 compiler tests"); | 77 | const test_stage2_step = b.step("test-stage2", "Run the stage2 compiler tests"); |
| 78 | test_stage2_step.dependOn(&test_stage2.step); | 78 | 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 | } | ||
| 80 | 84 | ||
| 81 | const all_modes = []builtin.Mode{ | 85 | const all_modes = []builtin.Mode{ |
| 82 | builtin.Mode.Debug, | 86 | builtin.Mode.Debug, |
src/all_types.hpp+56| ... | @@ -41,6 +41,13 @@ struct Tld; | ... | @@ -41,6 +41,13 @@ struct Tld; |
| 41 | struct TldExport; | 41 | struct TldExport; |
| 42 | struct IrAnalyze; | 42 | struct IrAnalyze; |
| 43 | 43 | ||
| 44 | enum X64CABIClass { | ||
| 45 | X64CABIClass_Unknown, | ||
| 46 | X64CABIClass_MEMORY, | ||
| 47 | X64CABIClass_INTEGER, | ||
| 48 | X64CABIClass_SSE, | ||
| 49 | }; | ||
| 50 | |||
| 44 | struct IrExecutable { | 51 | struct IrExecutable { |
| 45 | ZigList<IrBasicBlock *> basic_block_list; | 52 | ZigList<IrBasicBlock *> basic_block_list; |
| 46 | Buf *name; | 53 | Buf *name; |
| ... | @@ -3282,4 +3289,53 @@ enum FloatMode { | ... | @@ -3282,4 +3289,53 @@ enum FloatMode { |
| 3282 | FloatModeStrict, | 3289 | FloatModeStrict, |
| 3283 | }; | 3290 | }; |
| 3284 | 3291 | ||
| 3292 | enum FnWalkId { | ||
| 3293 | FnWalkIdAttrs, | ||
| 3294 | FnWalkIdCall, | ||
| 3295 | FnWalkIdTypes, | ||
| 3296 | FnWalkIdVars, | ||
| 3297 | FnWalkIdInits, | ||
| 3298 | }; | ||
| 3299 | |||
| 3300 | struct FnWalkAttrs { | ||
| 3301 | ZigFn *fn; | ||
| 3302 | unsigned gen_i; | ||
| 3303 | }; | ||
| 3304 | |||
| 3305 | struct FnWalkCall { | ||
| 3306 | ZigList<LLVMValueRef> *gen_param_values; | ||
| 3307 | IrInstructionCall *inst; | ||
| 3308 | bool is_var_args; | ||
| 3309 | }; | ||
| 3310 | |||
| 3311 | struct FnWalkTypes { | ||
| 3312 | ZigList<ZigLLVMDIType *> *param_di_types; | ||
| 3313 | ZigList<LLVMTypeRef> *gen_param_types; | ||
| 3314 | }; | ||
| 3315 | |||
| 3316 | struct FnWalkVars { | ||
| 3317 | ImportTableEntry *import; | ||
| 3318 | LLVMValueRef llvm_fn; | ||
| 3319 | ZigFn *fn; | ||
| 3320 | ZigVar *var; | ||
| 3321 | unsigned gen_i; | ||
| 3322 | }; | ||
| 3323 | |||
| 3324 | struct FnWalkInits { | ||
| 3325 | LLVMValueRef llvm_fn; | ||
| 3326 | ZigFn *fn; | ||
| 3327 | unsigned gen_i; | ||
| 3328 | }; | ||
| 3329 | |||
| 3330 | struct 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 | |||
| 3285 | #endif | 3341 | #endif |
src/analyze.cpp+148-37| ... | @@ -1009,10 +1009,6 @@ ZigType *get_bound_fn_type(CodeGen *g, ZigFn *fn_entry) { | ... | @@ -1009,10 +1009,6 @@ ZigType *get_bound_fn_type(CodeGen *g, ZigFn *fn_entry) { |
| 1009 | return bound_fn_type; | 1009 | return bound_fn_type; |
| 1010 | } | 1010 | } |
| 1011 | 1011 | ||
| 1012 | bool calling_convention_does_first_arg_return(CallingConvention cc) { | ||
| 1013 | return cc == CallingConventionUnspecified; | ||
| 1014 | } | ||
| 1015 | |||
| 1016 | const char *calling_convention_name(CallingConvention cc) { | 1012 | const char *calling_convention_name(CallingConvention cc) { |
| 1017 | switch (cc) { | 1013 | switch (cc) { |
| 1018 | case CallingConventionUnspecified: return "undefined"; | 1014 | case CallingConventionUnspecified: return "undefined"; |
| ... | @@ -1061,6 +1057,27 @@ ZigType *get_ptr_to_stack_trace_type(CodeGen *g) { | ... | @@ -1061,6 +1057,27 @@ ZigType *get_ptr_to_stack_trace_type(CodeGen *g) { |
| 1061 | return g->ptr_to_stack_trace_type; | 1057 | return g->ptr_to_stack_trace_type; |
| 1062 | } | 1058 | } |
| 1063 | 1059 | ||
| 1060 | bool 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 | |||
| 1064 | ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { | 1081 | ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 1065 | Error err; | 1082 | Error err; |
| 1066 | auto table_entry = g->fn_type_table.maybe_get(fn_type_id); | 1083 | 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) { | ... | @@ -1116,21 +1133,20 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 1116 | // next, loop over the parameters again and compute debug information | 1133 | // next, loop over the parameters again and compute debug information |
| 1117 | // and codegen information | 1134 | // and codegen information |
| 1118 | if (!skip_debug_info) { | 1135 | if (!skip_debug_info) { |
| 1119 | bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) && | 1136 | bool first_arg_return = want_first_arg_sret(g, fn_type_id); |
| 1120 | handle_is_ptr(fn_type_id->return_type); | ||
| 1121 | bool is_async = fn_type_id->cc == CallingConventionAsync; | 1137 | bool is_async = fn_type_id->cc == CallingConventionAsync; |
| 1138 | 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); | 1139 | 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 value | 1140 | // +1 for maybe making the first argument the return value |
| 1124 | // +1 for maybe first argument the error return trace | 1141 | // +1 for maybe first argument the error return trace |
| 1125 | // +2 for maybe arguments async allocator and error code pointer | 1142 | // +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 = {}; |
| 1127 | // +1 because 0 is the return type and | 1144 | // +1 because 0 is the return type and |
| 1128 | // +1 for maybe making first arg ret val and | 1145 | // +1 for maybe making first arg ret val and |
| 1129 | // +1 for maybe first argument the error return trace | 1146 | // +1 for maybe first argument the error return trace |
| 1130 | // +2 for maybe arguments async allocator and error code pointer | 1147 | // +2 for maybe arguments async allocator and error code pointer |
| 1131 | ZigLLVMDIType **param_di_types = allocate<ZigLLVMDIType*>(5 + fn_type_id->param_count); | 1148 | ZigList<ZigLLVMDIType *> param_di_types = {}; |
| 1132 | param_di_types[0] = fn_type_id->return_type->di_type; | 1149 | param_di_types.append(fn_type_id->return_type->di_type); |
| 1133 | size_t gen_param_index = 0; | ||
| 1134 | ZigType *gen_return_type; | 1150 | ZigType *gen_return_type; |
| 1135 | if (is_async) { | 1151 | if (is_async) { |
| 1136 | gen_return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false); | 1152 | 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) { | ... | @@ -1138,10 +1154,8 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 1138 | gen_return_type = g->builtin_types.entry_void; | 1154 | gen_return_type = g->builtin_types.entry_void; |
| 1139 | } else if (first_arg_return) { | 1155 | } else if (first_arg_return) { |
| 1140 | ZigType *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false); | 1156 | 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; | 1157 | gen_param_types.append(gen_type->type_ref); |
| 1142 | gen_param_index += 1; | 1158 | 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; | 1159 | gen_return_type = g->builtin_types.entry_void; |
| 1146 | } else { | 1160 | } else { |
| 1147 | gen_return_type = fn_type_id->return_type; | 1161 | gen_return_type = fn_type_id->return_type; |
| ... | @@ -1150,28 +1164,22 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { | ... | @@ -1150,28 +1164,22 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 1150 | 1164 | ||
| 1151 | if (prefix_arg_error_return_trace) { | 1165 | if (prefix_arg_error_return_trace) { |
| 1152 | ZigType *gen_type = get_ptr_to_stack_trace_type(g); | 1166 | ZigType *gen_type = get_ptr_to_stack_trace_type(g); |
| 1153 | gen_param_types[gen_param_index] = gen_type->type_ref; | 1167 | gen_param_types.append(gen_type->type_ref); |
| 1154 | gen_param_index += 1; | 1168 | 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 | } | 1169 | } |
| 1158 | if (is_async) { | 1170 | if (is_async) { |
| 1159 | { | 1171 | { |
| 1160 | // async allocator param | 1172 | // async allocator param |
| 1161 | ZigType *gen_type = fn_type_id->async_allocator_type; | 1173 | ZigType *gen_type = fn_type_id->async_allocator_type; |
| 1162 | gen_param_types[gen_param_index] = gen_type->type_ref; | 1174 | gen_param_types.append(gen_type->type_ref); |
| 1163 | gen_param_index += 1; | 1175 | 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 | } | 1176 | } |
| 1167 | 1177 | ||
| 1168 | { | 1178 | { |
| 1169 | // error code pointer | 1179 | // error code pointer |
| 1170 | ZigType *gen_type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false); | 1180 | 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; | 1181 | gen_param_types.append(gen_type->type_ref); |
| 1172 | gen_param_index += 1; | 1182 | 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 | } | 1183 | } |
| 1176 | } | 1184 | } |
| 1177 | 1185 | ||
| ... | @@ -1187,6 +1195,9 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { | ... | @@ -1187,6 +1195,9 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 1187 | if ((err = ensure_complete_type(g, type_entry))) | 1195 | if ((err = ensure_complete_type(g, type_entry))) |
| 1188 | return g->builtin_types.entry_invalid; | 1196 | return g->builtin_types.entry_invalid; |
| 1189 | 1197 | ||
| 1198 | if (is_c_abi) | ||
| 1199 | continue; | ||
| 1200 | |||
| 1190 | if (type_has_bits(type_entry)) { | 1201 | if (type_has_bits(type_entry)) { |
| 1191 | ZigType *gen_type; | 1202 | ZigType *gen_type; |
| 1192 | if (handle_is_ptr(type_entry)) { | 1203 | if (handle_is_ptr(type_entry)) { |
| ... | @@ -1195,23 +1206,31 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { | ... | @@ -1195,23 +1206,31 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 1195 | } else { | 1206 | } else { |
| 1196 | gen_type = type_entry; | 1207 | gen_type = type_entry; |
| 1197 | } | 1208 | } |
| 1198 | gen_param_types[gen_param_index] = gen_type->type_ref; | 1209 | 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; | 1210 | gen_param_info->type = gen_type; |
| 1211 | gen_param_types.append(gen_type->type_ref); | ||
| 1201 | 1212 | ||
| 1202 | gen_param_index += 1; | 1213 | 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 | } | 1214 | } |
| 1207 | } | 1215 | } |
| 1208 | 1216 | ||
| 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; | ||
| 1210 | 1226 | ||
| 1227 | for (size_t i = 0; i < gen_param_types.length; i += 1) { | ||
| 1228 | assert(gen_param_types.items[i] != nullptr); | ||
| 1229 | } | ||
| 1211 | fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref, | 1230 | 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); |
| 1213 | fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0); | 1232 | 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); |
| 1215 | } | 1234 | } |
| 1216 | 1235 | ||
| 1217 | g->fn_type_table.put(&fn_type->data.fn.fn_type_id, fn_type); | 1236 | 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) { | ... | @@ -5863,12 +5882,23 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 5863 | } | 5882 | } |
| 5864 | case ZigTypeIdErrorUnion: | 5883 | case ZigTypeIdErrorUnion: |
| 5865 | { | 5884 | { |
| 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, ")"); | ||
| 5867 | return; | 5893 | return; |
| 5868 | } | 5894 | } |
| 5869 | case ZigTypeIdUnion: | 5895 | case ZigTypeIdUnion: |
| 5870 | { | 5896 | { |
| 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, "}"); | ||
| 5872 | return; | 5902 | return; |
| 5873 | } | 5903 | } |
| 5874 | case ZigTypeIdErrorSet: | 5904 | case ZigTypeIdErrorSet: |
| ... | @@ -6375,3 +6405,84 @@ Error file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents) { | ... | @@ -6375,3 +6405,84 @@ Error file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents) { |
| 6375 | return os_fetch_file_path(resolved_path, contents, false); | 6405 | return os_fetch_file_path(resolved_path, contents, false); |
| 6376 | } | 6406 | } |
| 6377 | } | 6407 | } |
| 6408 | |||
| 6409 | X64CABIClass 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 | ||
| 6480 | bool 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); | ... | @@ -182,7 +182,6 @@ size_t type_id_index(ZigType *entry); |
| 182 | ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id); | 182 | ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id); |
| 183 | Result<bool> type_is_copyable(CodeGen *g, ZigType *type_entry); | 183 | Result<bool> type_is_copyable(CodeGen *g, ZigType *type_entry); |
| 184 | LinkLib *create_link_lib(Buf *name); | 184 | LinkLib *create_link_lib(Buf *name); |
| 185 | bool calling_convention_does_first_arg_return(CallingConvention cc); | ||
| 186 | LinkLib *add_link_lib(CodeGen *codegen, Buf *lib); | 185 | LinkLib *add_link_lib(CodeGen *codegen, Buf *lib); |
| 187 | 186 | ||
| 188 | uint32_t get_abi_alignment(CodeGen *g, ZigType *type_entry); | 187 | uint32_t get_abi_alignment(CodeGen *g, ZigType *type_entry); |
| ... | @@ -210,7 +209,11 @@ ZigType *get_primitive_type(CodeGen *g, Buf *name); | ... | @@ -210,7 +209,11 @@ ZigType *get_primitive_type(CodeGen *g, Buf *name); |
| 210 | bool calling_convention_allows_zig_types(CallingConvention cc); | 209 | bool calling_convention_allows_zig_types(CallingConvention cc); |
| 211 | const char *calling_convention_name(CallingConvention cc); | 210 | const char *calling_convention_name(CallingConvention cc); |
| 212 | 211 | ||
| 213 | |||
| 214 | Error ATTRIBUTE_MUST_USE file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents); | 212 | Error ATTRIBUTE_MUST_USE file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents); |
| 215 | 213 | ||
| 214 | void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk); | ||
| 215 | X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty); | ||
| 216 | bool type_is_c_abi_int(CodeGen *g, ZigType *ty); | ||
| 217 | bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id); | ||
| 218 | |||
| 216 | #endif | 219 | #endif |
src/codegen.cpp+453-120| ... | @@ -350,8 +350,12 @@ static void addLLVMFnAttrInt(LLVMValueRef fn_val, const char *attr_name, uint64_ | ... | @@ -350,8 +350,12 @@ static void addLLVMFnAttrInt(LLVMValueRef fn_val, const char *attr_name, uint64_ |
| 350 | return addLLVMAttrInt(fn_val, -1, attr_name, attr_val); | 350 | return addLLVMAttrInt(fn_val, -1, attr_name, attr_val); |
| 351 | } | 351 | } |
| 352 | 352 | ||
| 353 | static void addLLVMArgAttr(LLVMValueRef arg_val, unsigned param_index, const char *attr_name) { | 353 | static void addLLVMArgAttr(LLVMValueRef fn_val, unsigned param_index, const char *attr_name) { |
| 354 | return addLLVMAttr(arg_val, param_index + 1, attr_name); | 354 | return addLLVMAttr(fn_val, param_index + 1, attr_name); |
| 355 | } | ||
| 356 | |||
| 357 | static 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); | ||
| 355 | } | 359 | } |
| 356 | 360 | ||
| 357 | static bool is_symbol_available(CodeGen *g, Buf *name) { | 361 | static bool is_symbol_available(CodeGen *g, Buf *name) { |
| ... | @@ -462,7 +466,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { | ... | @@ -462,7 +466,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { |
| 462 | } | 466 | } |
| 463 | 467 | ||
| 464 | bool external_linkage = linkage != GlobalLinkageIdInternal; | 468 | 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 && | ||
| 466 | g->zig_target.arch.arch == ZigLLVM_x86) | 471 | g->zig_target.arch.arch == ZigLLVM_x86) |
| 467 | { | 472 | { |
| 468 | // prevent llvm name mangling | 473 | // prevent llvm name mangling |
| ... | @@ -506,17 +511,17 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { | ... | @@ -506,17 +511,17 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { |
| 506 | break; | 511 | break; |
| 507 | } | 512 | } |
| 508 | 513 | ||
| 509 | if (fn_type->data.fn.fn_type_id.cc == CallingConventionNaked) { | 514 | if (cc == CallingConventionNaked) { |
| 510 | addLLVMFnAttr(fn_table_entry->llvm_value, "naked"); | 515 | addLLVMFnAttr(fn_table_entry->llvm_value, "naked"); |
| 511 | } else { | 516 | } else { |
| 512 | 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)); |
| 513 | } | 518 | } |
| 514 | if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) { | 519 | if (cc == CallingConventionAsync) { |
| 515 | addLLVMFnAttr(fn_table_entry->llvm_value, "optnone"); | 520 | addLLVMFnAttr(fn_table_entry->llvm_value, "optnone"); |
| 516 | addLLVMFnAttr(fn_table_entry->llvm_value, "noinline"); | 521 | addLLVMFnAttr(fn_table_entry->llvm_value, "noinline"); |
| 517 | } | 522 | } |
| 518 | 523 | ||
| 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; |
| 520 | if (want_cold) { | 525 | if (want_cold) { |
| 521 | ZigLLVMAddFunctionAttrCold(fn_table_entry->llvm_value); | 526 | ZigLLVMAddFunctionAttrCold(fn_table_entry->llvm_value); |
| 522 | } | 527 | } |
| ... | @@ -568,41 +573,26 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { | ... | @@ -568,41 +573,26 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { |
| 568 | // use the ABI alignment, which is fine. | 573 | // use the ABI alignment, which is fine. |
| 569 | } | 574 | } |
| 570 | 575 | ||
| 576 | unsigned init_gen_i = 0; | ||
| 571 | if (!type_has_bits(return_type)) { | 577 | if (!type_has_bits(return_type)) { |
| 572 | // nothing to do | 578 | // nothing to do |
| 573 | } else if (type_is_codegen_pointer(return_type)) { | 579 | } else if (type_is_codegen_pointer(return_type)) { |
| 574 | addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull"); | 580 | addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull"); |
| 575 | } else if (handle_is_ptr(return_type) && | 581 | } else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) { |
| 576 | calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc)) | ||
| 577 | { | ||
| 578 | addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret"); | 582 | addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret"); |
| 579 | addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull"); | 583 | 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; | ||
| 580 | } | 588 | } |
| 581 | 589 | ||
| 582 | |||
| 583 | // set parameter attributes | 590 | // set parameter attributes |
| 584 | for (size_t param_i = 0; param_i < fn_type->data.fn.fn_type_id.param_count; param_i += 1) { | 591 | FnWalk fn_walk = {}; |
| 585 | FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i]; | 592 | fn_walk.id = FnWalkIdAttrs; |
| 586 | size_t gen_index = gen_info->gen_index; | 593 | fn_walk.data.attrs.fn = fn_table_entry; |
| 587 | bool is_byval = gen_info->is_byval; | 594 | fn_walk.data.attrs.gen_i = init_gen_i; |
| 588 | 595 | walk_function_params(g, fn_type, &fn_walk); | |
| 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 | } | ||
| 606 | 596 | ||
| 607 | uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); | 597 | uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); |
| 608 | if (err_ret_trace_arg_index != UINT32_MAX) { | 598 | if (err_ret_trace_arg_index != UINT32_MAX) { |
| ... | @@ -1854,6 +1844,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty | ... | @@ -1854,6 +1844,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty |
| 1854 | } | 1844 | } |
| 1855 | 1845 | ||
| 1856 | static void gen_var_debug_decl(CodeGen *g, ZigVar *var) { | 1846 | static void gen_var_debug_decl(CodeGen *g, ZigVar *var) { |
| 1847 | assert(var->di_loc_var != nullptr); | ||
| 1857 | AstNode *source_node = var->decl_node; | 1848 | AstNode *source_node = var->decl_node; |
| 1858 | ZigLLVMDILocation *debug_loc = ZigLLVMGetDebugLoc((unsigned)source_node->line + 1, | 1849 | ZigLLVMDILocation *debug_loc = ZigLLVMGetDebugLoc((unsigned)source_node->line + 1, |
| 1859 | (unsigned)source_node->column + 1, get_di_scope(g, var->parent_scope)); | 1850 | (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) { | ... | @@ -1884,6 +1875,353 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) { |
| 1884 | return instruction->llvm_value; | 1875 | return instruction->llvm_value; |
| 1885 | } | 1876 | } |
| 1886 | 1877 | ||
| 1878 | ATTRIBUTE_NORETURN | ||
| 1879 | static 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 | |||
| 1888 | static void report_errors_and_maybe_exit(CodeGen *g) { | ||
| 1889 | if (g->errors.length != 0) { | ||
| 1890 | report_errors_and_exit(g); | ||
| 1891 | } | ||
| 1892 | } | ||
| 1893 | |||
| 1894 | ATTRIBUTE_NORETURN | ||
| 1895 | static 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 | |||
| 1903 | static 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 | |||
| 1910 | static 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 | |||
| 2128 | var_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 | |||
| 2139 | void 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 | |||
| 1887 | static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable, | 2225 | static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable, |
| 1888 | IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction) | 2226 | IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction) |
| 1889 | { | 2227 | { |
| ... | @@ -1902,15 +2240,13 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns | ... | @@ -1902,15 +2240,13 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns |
| 1902 | LLVMValueRef value = ir_llvm_value(g, return_instruction->value); | 2240 | LLVMValueRef value = ir_llvm_value(g, return_instruction->value); |
| 1903 | ZigType *return_type = return_instruction->value->value.type; | 2241 | ZigType *return_type = return_instruction->value->value.type; |
| 1904 | 2242 | ||
| 1905 | if (handle_is_ptr(return_type)) { | 2243 | if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) { |
| 1906 | if (calling_convention_does_first_arg_return(g->cur_fn->type_entry->data.fn.fn_type_id.cc)) { | 2244 | assert(g->cur_ret_ptr); |
| 1907 | assert(g->cur_ret_ptr); | 2245 | gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); |
| 1908 | gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); | 2246 | LLVMBuildRetVoid(g->builder); |
| 1909 | LLVMBuildRetVoid(g->builder); | 2247 | } else if (handle_is_ptr(return_type)) { |
| 1910 | } else { | 2248 | LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, ""); |
| 1911 | LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, ""); | 2249 | LLVMBuildRet(g->builder, by_val_value); |
| 1912 | LLVMBuildRet(g->builder, by_val_value); | ||
| 1913 | } | ||
| 1914 | } else { | 2250 | } else { |
| 1915 | LLVMBuildRet(g->builder, value); | 2251 | LLVMBuildRet(g->builder, value); |
| 1916 | } | 2252 | } |
| ... | @@ -2878,7 +3214,8 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, | ... | @@ -2878,7 +3214,8 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, |
| 2878 | assert(var->value->type == init_value->value.type); | 3214 | assert(var->value->type == init_value->value.type); |
| 2879 | ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->value->type, false, false, | 3215 | ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->value->type, false, false, |
| 2880 | PtrLenSingle, var->align_bytes, 0, 0); | 3216 | 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); | ||
| 2882 | } else { | 3219 | } else { |
| 2883 | bool want_safe = ir_want_runtime_safety(g, &decl_var_instruction->base); | 3220 | bool want_safe = ir_want_runtime_safety(g, &decl_var_instruction->base); |
| 2884 | if (want_safe) { | 3221 | if (want_safe) { |
| ... | @@ -3124,40 +3461,30 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr | ... | @@ -3124,40 +3461,30 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3124 | ZigType *src_return_type = fn_type_id->return_type; | 3461 | ZigType *src_return_type = fn_type_id->return_type; |
| 3125 | bool ret_has_bits = type_has_bits(src_return_type); | 3462 | bool ret_has_bits = type_has_bits(src_return_type); |
| 3126 | 3463 | ||
| 3127 | bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type) && | 3464 | CallingConvention cc = fn_type->data.fn.fn_type_id.cc; |
| 3128 | calling_convention_does_first_arg_return(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); | ||
| 3129 | bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id); | 3467 | 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; | ||
| 3132 | bool is_var_args = fn_type_id->is_var_args; | 3468 | bool is_var_args = fn_type_id->is_var_args; |
| 3133 | LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count); | 3469 | ZigList<LLVMValueRef> gen_param_values = {}; |
| 3134 | size_t gen_param_index = 0; | ||
| 3135 | if (first_arg_ret) { | 3470 | if (first_arg_ret) { |
| 3136 | gen_param_values[gen_param_index] = instruction->tmp_ptr; | 3471 | gen_param_values.append(instruction->tmp_ptr); |
| 3137 | gen_param_index += 1; | ||
| 3138 | } | 3472 | } |
| 3139 | if (prefix_arg_err_ret_stack) { | 3473 | if (prefix_arg_err_ret_stack) { |
| 3140 | gen_param_values[gen_param_index] = get_cur_err_ret_trace_val(g, instruction->base.scope); | 3474 | gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope)); |
| 3141 | gen_param_index += 1; | ||
| 3142 | } | 3475 | } |
| 3143 | if (instruction->is_async) { | 3476 | if (instruction->is_async) { |
| 3144 | gen_param_values[gen_param_index] = ir_llvm_value(g, instruction->async_allocator); | 3477 | gen_param_values.append(ir_llvm_value(g, instruction->async_allocator)); |
| 3145 | gen_param_index += 1; | ||
| 3146 | 3478 | ||
| 3147 | LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, ""); | 3479 | LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, ""); |
| 3148 | gen_param_values[gen_param_index] = err_val_ptr; | 3480 | gen_param_values.append(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 | } | ||
| 3160 | } | 3481 | } |
| 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); | ||
| 3161 | 3488 | ||
| 3162 | ZigLLVM_FnInline fn_inline; | 3489 | ZigLLVM_FnInline fn_inline; |
| 3163 | switch (instruction->fn_inline) { | 3490 | switch (instruction->fn_inline) { |
| ... | @@ -3172,12 +3499,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr | ... | @@ -3172,12 +3499,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3172 | break; | 3499 | break; |
| 3173 | } | 3500 | } |
| 3174 | 3501 | ||
| 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); |
| 3176 | LLVMValueRef result; | 3503 | LLVMValueRef result; |
| 3177 | 3504 | ||
| 3178 | if (instruction->new_stack == nullptr) { | 3505 | if (instruction->new_stack == nullptr) { |
| 3179 | result = ZigLLVMBuildCall(g->builder, fn_val, | 3506 | 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, ""); |
| 3181 | } else { | 3508 | } else { |
| 3182 | LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g); | 3509 | LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g); |
| 3183 | LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g); | 3510 | LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g); |
| ... | @@ -3186,7 +3513,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr | ... | @@ -3186,7 +3513,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3186 | LLVMValueRef old_stack_ref = LLVMBuildCall(g->builder, stacksave_fn_val, nullptr, 0, ""); | 3513 | LLVMValueRef old_stack_ref = LLVMBuildCall(g->builder, stacksave_fn_val, nullptr, 0, ""); |
| 3187 | gen_set_stack_pointer(g, new_stack_addr); | 3514 | gen_set_stack_pointer(g, new_stack_addr); |
| 3188 | result = ZigLLVMBuildCall(g->builder, fn_val, | 3515 | 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, ""); |
| 3190 | LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, ""); | 3517 | LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, ""); |
| 3191 | } | 3518 | } |
| 3192 | 3519 | ||
| ... | @@ -5533,12 +5860,24 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c | ... | @@ -5533,12 +5860,24 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c |
| 5533 | LLVMValueRef tag_value = bigint_to_llvm_const(type_entry->data.unionation.tag_type->type_ref, | 5860 | LLVMValueRef tag_value = bigint_to_llvm_const(type_entry->data.unionation.tag_type->type_ref, |
| 5534 | &const_val->data.x_union.tag); | 5861 | &const_val->data.x_union.tag); |
| 5535 | 5862 | ||
| 5536 | LLVMValueRef fields[2]; | 5863 | LLVMValueRef fields[3]; |
| 5537 | fields[type_entry->data.unionation.gen_union_index] = union_value_ref; | 5864 | fields[type_entry->data.unionation.gen_union_index] = union_value_ref; |
| 5538 | fields[type_entry->data.unionation.gen_tag_index] = tag_value; | 5865 | fields[type_entry->data.unionation.gen_tag_index] = tag_value; |
| 5539 | 5866 | ||
| 5540 | if (make_unnamed_struct) { | 5867 | 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; | ||
| 5542 | } else { | 5881 | } else { |
| 5543 | return LLVMConstNamedStruct(type_entry->type_ref, fields, 2); | 5882 | return LLVMConstNamedStruct(type_entry->type_ref, fields, 2); |
| 5544 | } | 5883 | } |
| ... | @@ -5578,13 +5917,29 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c | ... | @@ -5578,13 +5917,29 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c |
| 5578 | err_payload_value = gen_const_val(g, payload_val, ""); | 5917 | err_payload_value = gen_const_val(g, payload_val, ""); |
| 5579 | make_unnamed_struct = is_llvm_value_unnamed_type(payload_val->type, err_payload_value); | 5918 | make_unnamed_struct = is_llvm_value_unnamed_type(payload_val->type, err_payload_value); |
| 5580 | } | 5919 | } |
| 5581 | LLVMValueRef fields[] = { | ||
| 5582 | err_tag_value, | ||
| 5583 | err_payload_value, | ||
| 5584 | }; | ||
| 5585 | if (make_unnamed_struct) { | 5920 | 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 | } | ||
| 5587 | } else { | 5938 | } else { |
| 5939 | LLVMValueRef fields[] = { | ||
| 5940 | err_tag_value, | ||
| 5941 | err_payload_value, | ||
| 5942 | }; | ||
| 5588 | return LLVMConstNamedStruct(type_entry->type_ref, fields, 2); | 5943 | return LLVMConstNamedStruct(type_entry->type_ref, fields, 2); |
| 5589 | } | 5944 | } |
| 5590 | } | 5945 | } |
| ... | @@ -5717,23 +6072,6 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val, | ... | @@ -5717,23 +6072,6 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val, |
| 5717 | // TODO ^^ make an actual global variable | 6072 | // TODO ^^ make an actual global variable |
| 5718 | } | 6073 | } |
| 5719 | 6074 | ||
| 5720 | static 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 | |||
| 5727 | static 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 | |||
| 5737 | static void validate_inline_fns(CodeGen *g) { | 6075 | static void validate_inline_fns(CodeGen *g) { |
| 5738 | for (size_t i = 0; i < g->inline_fns.length; i += 1) { | 6076 | for (size_t i = 0; i < g->inline_fns.length; i += 1) { |
| 5739 | ZigFn *fn_entry = g->inline_fns.at(i); | 6077 | ZigFn *fn_entry = g->inline_fns.at(i); |
| ... | @@ -5852,11 +6190,14 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -5852,11 +6190,14 @@ static void do_code_gen(CodeGen *g) { |
| 5852 | // Generate function definitions. | 6190 | // Generate function definitions. |
| 5853 | for (size_t fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) { | 6191 | for (size_t fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) { |
| 5854 | ZigFn *fn_table_entry = g->fn_defs.at(fn_i); | 6192 | 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; | ||
| 5855 | 6196 | ||
| 5856 | LLVMValueRef fn = fn_llvm_value(g, fn_table_entry); | 6197 | LLVMValueRef fn = fn_llvm_value(g, fn_table_entry); |
| 5857 | g->cur_fn = fn_table_entry; | 6198 | g->cur_fn = fn_table_entry; |
| 5858 | g->cur_fn_val = fn; | 6199 | 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; |
| 5860 | if (handle_is_ptr(return_type)) { | 6201 | if (handle_is_ptr(return_type)) { |
| 5861 | g->cur_ret_ptr = LLVMGetParam(fn, 0); | 6202 | g->cur_ret_ptr = LLVMGetParam(fn, 0); |
| 5862 | } else { | 6203 | } else { |
| ... | @@ -5875,7 +6216,7 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -5875,7 +6216,7 @@ static void do_code_gen(CodeGen *g) { |
| 5875 | } | 6216 | } |
| 5876 | 6217 | ||
| 5877 | // error return tracing setup | 6218 | // 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; |
| 5879 | 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; | 6220 | 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; |
| 5880 | LLVMValueRef err_ret_array_val = nullptr; | 6221 | LLVMValueRef err_ret_array_val = nullptr; |
| 5881 | if (have_err_ret_trace_stack) { | 6222 | if (have_err_ret_trace_stack) { |
| ... | @@ -5934,7 +6275,15 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -5934,7 +6275,15 @@ static void do_code_gen(CodeGen *g) { |
| 5934 | 6275 | ||
| 5935 | ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base); | 6276 | ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base); |
| 5936 | 6277 | ||
| 6278 | unsigned gen_i_init = want_first_arg_sret(g, fn_type_id) ? 1 : 0; | ||
| 6279 | |||
| 5937 | // create debug variable declarations for variables and allocate all local variables | 6280 | // 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; | ||
| 5938 | for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) { | 6287 | for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) { |
| 5939 | ZigVar *var = fn_table_entry->variable_list.at(var_i); | 6288 | ZigVar *var = fn_table_entry->variable_list.at(var_i); |
| 5940 | 6289 | ||
| ... | @@ -5953,6 +6302,9 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -5953,6 +6302,9 @@ static void do_code_gen(CodeGen *g) { |
| 5953 | buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1), | 6302 | buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1), |
| 5954 | var->value->type->di_type, !g->strip_debug_symbols, 0); | 6303 | var->value->type->di_type, !g->strip_debug_symbols, 0); |
| 5955 | 6304 | ||
| 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); | ||
| 5956 | } else { | 6308 | } else { |
| 5957 | assert(var->gen_arg_index != SIZE_MAX); | 6309 | assert(var->gen_arg_index != SIZE_MAX); |
| 5958 | ZigType *gen_type; | 6310 | ZigType *gen_type; |
| ... | @@ -6004,33 +6356,14 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -6004,33 +6356,14 @@ static void do_code_gen(CodeGen *g) { |
| 6004 | gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false)); | 6356 | gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false)); |
| 6005 | } | 6357 | } |
| 6006 | 6358 | ||
| 6007 | FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; | ||
| 6008 | |||
| 6009 | // create debug variable declarations for parameters | 6359 | // create debug variable declarations for parameters |
| 6010 | // rely on the first variables in the variable_list being parameters. | 6360 | // rely on the first variables in the variable_list being parameters. |
| 6011 | size_t next_var_i = 0; | 6361 | FnWalk fn_walk_init = {}; |
| 6012 | for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) { | 6362 | fn_walk_init.id = FnWalkIdInits; |
| 6013 | FnGenParamInfo *info = &fn_table_entry->type_entry->data.fn.gen_param_info[param_i]; | 6363 | fn_walk_init.data.inits.fn = fn_table_entry; |
| 6014 | if (info->gen_index == SIZE_MAX) | 6364 | fn_walk_init.data.inits.llvm_fn = fn; |
| 6015 | continue; | 6365 | fn_walk_init.data.inits.gen_i = gen_i_init; |
| 6016 | 6366 | walk_function_params(g, fn_table_entry->type_entry, &fn_walk_init); | |
| 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 | } | ||
| 6034 | 6367 | ||
| 6035 | ir_render(g, fn_table_entry); | 6368 | ir_render(g, fn_table_entry); |
| 6036 | 6369 |
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); |
| 61 | 61 | ||
| 62 | Buf *codegen_generate_builtin_source(CodeGen *g); | 62 | Buf *codegen_generate_builtin_source(CodeGen *g); |
| 63 | 63 | ||
| 64 | |||
| 65 | #endif | 64 | #endif |
src/ir.cpp+8-3| ... | @@ -13107,8 +13107,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, | ... | @@ -13107,8 +13107,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 13107 | assert(ira->codegen->errors.length != 0); | 13107 | assert(ira->codegen->errors.length != 0); |
| 13108 | return ira->codegen->invalid_instruction; | 13108 | return ira->codegen->invalid_instruction; |
| 13109 | } | 13109 | } |
| 13110 | assert(var->value->type); | 13110 | if (var->value->type == nullptr || type_is_invalid(var->value->type)) |
| 13111 | if (type_is_invalid(var->value->type)) | ||
| 13112 | return ira->codegen->invalid_instruction; | 13111 | return ira->codegen->invalid_instruction; |
| 13113 | 13112 | ||
| 13114 | bool comptime_var_mem = ir_get_var_is_comptime(var); | 13113 | bool comptime_var_mem = ir_get_var_is_comptime(var); |
| ... | @@ -19643,7 +19642,7 @@ static ZigType *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnP | ... | @@ -19643,7 +19642,7 @@ static ZigType *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnP |
| 19643 | return ira->codegen->builtin_types.entry_invalid; | 19642 | return ira->codegen->builtin_types.entry_invalid; |
| 19644 | if (type_requires_comptime(param_type)) { | 19643 | if (type_requires_comptime(param_type)) { |
| 19645 | if (!calling_convention_allows_zig_types(fn_type_id.cc)) { | 19644 | 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, |
| 19647 | buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'", | 19646 | buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'", |
| 19648 | buf_ptr(&param_type->name), calling_convention_name(fn_type_id.cc))); | 19647 | buf_ptr(&param_type->name), calling_convention_name(fn_type_id.cc))); |
| 19649 | return ira->codegen->builtin_types.entry_invalid; | 19648 | return ira->codegen->builtin_types.entry_invalid; |
| ... | @@ -19654,6 +19653,12 @@ static ZigType *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnP | ... | @@ -19654,6 +19653,12 @@ static ZigType *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnP |
| 19654 | out_val->data.x_type = get_generic_fn_type(ira->codegen, &fn_type_id); | 19653 | out_val->data.x_type = get_generic_fn_type(ira->codegen, &fn_type_id); |
| 19655 | return ira->codegen->builtin_types.entry_type; | 19654 | return ira->codegen->builtin_types.entry_type; |
| 19656 | } | 19655 | } |
| 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 | } | ||
| 19657 | param_info->type = param_type; | 19662 | param_info->type = param_type; |
| 19658 | } | 19663 | } |
| 19659 | 19664 |
src/os.cpp+1-1| ... | @@ -445,7 +445,7 @@ static Buf os_path_resolve_windows(Buf **paths_ptr, size_t paths_len) { | ... | @@ -445,7 +445,7 @@ static Buf os_path_resolve_windows(Buf **paths_ptr, size_t paths_len) { |
| 445 | } | 445 | } |
| 446 | 446 | ||
| 447 | // determine which disk designator we will result with, if any | 447 | // 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 |
| 449 | Slice<uint8_t> result_disk_designator = str(""); | 449 | Slice<uint8_t> result_disk_designator = str(""); |
| 450 | WindowsPathKind have_drive_kind = WindowsPathKindNone; | 450 | WindowsPathKind have_drive_kind = WindowsPathKindNone; |
| 451 | bool have_abs_path = false; | 451 | 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 { | ... | @@ -62,6 +62,10 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { |
| 62 | return self.len; | 62 | return self.len; |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | pub fn capacity(self: Self) usize { | ||
| 66 | return self.items.len; | ||
| 67 | } | ||
| 68 | |||
| 65 | /// ArrayList takes ownership of the passed in slice. The slice must have been | 69 | /// ArrayList takes ownership of the passed in slice. The slice must have been |
| 66 | /// allocated with `allocator`. | 70 | /// allocated with `allocator`. |
| 67 | /// Deinitialize with `deinit` or use `toOwnedSlice`. | 71 | /// Deinitialize with `deinit` or use `toOwnedSlice`. |
| ... | @@ -102,6 +106,11 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { | ... | @@ -102,6 +106,11 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { |
| 102 | new_item_ptr.* = item; | 106 | new_item_ptr.* = item; |
| 103 | } | 107 | } |
| 104 | 108 | ||
| 109 | pub fn appendAssumeCapacity(self: *Self, item: T) void { | ||
| 110 | const new_item_ptr = self.addOneAssumeCapacity(); | ||
| 111 | new_item_ptr.* = item; | ||
| 112 | } | ||
| 113 | |||
| 105 | /// Removes the element at the specified index and returns it. | 114 | /// Removes the element at the specified index and returns it. |
| 106 | /// The empty slot is filled from the end of the list. | 115 | /// The empty slot is filled from the end of the list. |
| 107 | pub fn swapRemove(self: *Self, i: usize) T { | 116 | pub fn swapRemove(self: *Self, i: usize) T { |
| ... | @@ -138,7 +147,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { | ... | @@ -138,7 +147,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { |
| 138 | } | 147 | } |
| 139 | 148 | ||
| 140 | pub fn ensureCapacity(self: *Self, new_capacity: usize) !void { | 149 | pub fn ensureCapacity(self: *Self, new_capacity: usize) !void { |
| 141 | var better_capacity = self.items.len; | 150 | var better_capacity = self.capacity(); |
| 142 | if (better_capacity >= new_capacity) return; | 151 | if (better_capacity >= new_capacity) return; |
| 143 | while (true) { | 152 | while (true) { |
| 144 | better_capacity += better_capacity / 2 + 8; | 153 | better_capacity += better_capacity / 2 + 8; |
| ... | @@ -150,8 +159,13 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { | ... | @@ -150,8 +159,13 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { |
| 150 | pub fn addOne(self: *Self) !*T { | 159 | pub fn addOne(self: *Self) !*T { |
| 151 | const new_length = self.len + 1; | 160 | const new_length = self.len + 1; |
| 152 | try self.ensureCapacity(new_length); | 161 | try self.ensureCapacity(new_length); |
| 162 | return self.addOneAssumeCapacity(); | ||
| 163 | } | ||
| 164 | |||
| 165 | pub fn addOneAssumeCapacity(self: *Self) *T { | ||
| 166 | assert(self.count() < self.capacity()); | ||
| 153 | const result = &self.items[self.len]; | 167 | const result = &self.items[self.len]; |
| 154 | self.len = new_length; | 168 | self.len += 1; |
| 155 | return result; | 169 | return result; |
| 156 | } | 170 | } |
| 157 | 171 | ||
| ... | @@ -191,6 +205,17 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { | ... | @@ -191,6 +205,17 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { |
| 191 | }; | 205 | }; |
| 192 | } | 206 | } |
| 193 | 207 | ||
| 208 | test "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 | |||
| 194 | test "std.ArrayList.basic" { | 219 | test "std.ArrayList.basic" { |
| 195 | var bytes: [1024]u8 = undefined; | 220 | var bytes: [1024]u8 = undefined; |
| 196 | const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator; | 221 | const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator; |
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, |
| 50 | 50 | ||
| 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); |
| 53 | 59 | ||
| ... | @@ -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, | ||
| 820 | 827 | ||
| 821 | // zig only stuff | 828 | // 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, | ||
| 955 | 964 | ||
| 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 { |
| 1392 | 1401 | ||
| 1393 | const is_darwin = self.target.isDarwin(); | 1402 | const is_darwin = self.target.isDarwin(); |
| 1394 | 1403 | ||
| 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 | } |
| 1680 | 1696 | ||
| 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 | } |
std/crypto/x25519.zig+12-1| ... | @@ -4,6 +4,7 @@ | ... | @@ -4,6 +4,7 @@ |
| 4 | 4 | ||
| 5 | const std = @import("../index.zig"); | 5 | const std = @import("../index.zig"); |
| 6 | const builtin = @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 7 | const fmt = std.fmt; | ||
| 7 | 8 | ||
| 8 | const Endian = builtin.Endian; | 9 | const Endian = builtin.Endian; |
| 9 | const readInt = std.mem.readInt; | 10 | const readInt = std.mem.readInt; |
| ... | @@ -114,7 +115,7 @@ pub const X25519 = struct { | ... | @@ -114,7 +115,7 @@ pub const X25519 = struct { |
| 114 | return !zerocmp(u8, out); | 115 | return !zerocmp(u8, out); |
| 115 | } | 116 | } |
| 116 | 117 | ||
| 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 { |
| 118 | var base_point = []u8{9} ++ []u8{0} ** 31; | 119 | var base_point = []u8{9} ++ []u8{0} ** 31; |
| 119 | return create(public_key, private_key, base_point); | 120 | return create(public_key, private_key, base_point); |
| 120 | } | 121 | } |
| ... | @@ -573,6 +574,16 @@ const Fe = struct { | ... | @@ -573,6 +574,16 @@ const Fe = struct { |
| 573 | } | 574 | } |
| 574 | }; | 575 | }; |
| 575 | 576 | ||
| 577 | test "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 | |||
| 576 | test "x25519 rfc7748 vector1" { | 587 | test "x25519 rfc7748 vector1" { |
| 577 | 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"; | 588 | 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"; |
| 578 | 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"; | 589 | 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 { | ... | @@ -343,23 +343,25 @@ pub fn posixWrite(fd: i32, bytes: []const u8) !void { |
| 343 | const amt_to_write = math.min(bytes.len - index, usize(max_bytes_len)); | 343 | const amt_to_write = math.min(bytes.len - index, usize(max_bytes_len)); |
| 344 | const rc = posix.write(fd, bytes.ptr + index, amt_to_write); | 344 | const rc = posix.write(fd, bytes.ptr + index, amt_to_write); |
| 345 | const write_err = posix.getErrno(rc); | 345 | const write_err = posix.getErrno(rc); |
| 346 | if (write_err > 0) { | 346 | switch (write_err) { |
| 347 | return switch (write_err) { | 347 | 0 => { |
| 348 | posix.EINTR => continue, | 348 | index += rc; |
| 349 | posix.EINVAL, posix.EFAULT => unreachable, | 349 | continue; |
| 350 | posix.EAGAIN => PosixWriteError.WouldBlock, | 350 | }, |
| 351 | posix.EBADF => PosixWriteError.FileClosed, | 351 | posix.EINTR => continue, |
| 352 | posix.EDESTADDRREQ => PosixWriteError.DestinationAddressRequired, | 352 | posix.EINVAL => unreachable, |
| 353 | posix.EDQUOT => PosixWriteError.DiskQuota, | 353 | posix.EFAULT => unreachable, |
| 354 | posix.EFBIG => PosixWriteError.FileTooBig, | 354 | posix.EAGAIN => return PosixWriteError.WouldBlock, |
| 355 | posix.EIO => PosixWriteError.InputOutput, | 355 | posix.EBADF => return PosixWriteError.FileClosed, |
| 356 | posix.ENOSPC => PosixWriteError.NoSpaceLeft, | 356 | posix.EDESTADDRREQ => return PosixWriteError.DestinationAddressRequired, |
| 357 | posix.EPERM => PosixWriteError.AccessDenied, | 357 | posix.EDQUOT => return PosixWriteError.DiskQuota, |
| 358 | posix.EPIPE => PosixWriteError.BrokenPipe, | 358 | posix.EFBIG => return PosixWriteError.FileTooBig, |
| 359 | else => unexpectedErrorPosix(write_err), | 359 | posix.EIO => return PosixWriteError.InputOutput, |
| 360 | }; | 360 | posix.ENOSPC => return PosixWriteError.NoSpaceLeft, |
| 361 | posix.EPERM => return PosixWriteError.AccessDenied, | ||
| 362 | posix.EPIPE => return PosixWriteError.BrokenPipe, | ||
| 363 | else => return unexpectedErrorPosix(write_err), | ||
| 361 | } | 364 | } |
| 362 | index += rc; | ||
| 363 | } | 365 | } |
| 364 | } | 366 | } |
| 365 | 367 | ||
| ... | @@ -1614,7 +1616,7 @@ pub const Dir = struct { | ... | @@ -1614,7 +1616,7 @@ pub const Dir = struct { |
| 1614 | return null; | 1616 | return null; |
| 1615 | } | 1617 | } |
| 1616 | const name_utf16le = mem.toSlice(u16, self.handle.find_file_data.cFileName[0..].ptr); | 1618 | 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{ '.', '.' })) |
| 1618 | continue; | 1620 | continue; |
| 1619 | // Trust that Windows gives us valid UTF-16LE | 1621 | // Trust that Windows gives us valid UTF-16LE |
| 1620 | const name_utf8_len = std.unicode.utf16leToUtf8(self.handle.name_data[0..], name_utf16le) catch unreachable; | 1622 | 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 { | ... | @@ -9,9 +9,10 @@ comptime { |
| 9 | _ = @import("cases/bitcast.zig"); | 9 | _ = @import("cases/bitcast.zig"); |
| 10 | _ = @import("cases/bool.zig"); | 10 | _ = @import("cases/bool.zig"); |
| 11 | _ = @import("cases/bugs/1111.zig"); | 11 | _ = @import("cases/bugs/1111.zig"); |
| 12 | _ = @import("cases/bugs/1230.zig"); | ||
| 13 | _ = @import("cases/bugs/1277.zig"); | 12 | _ = @import("cases/bugs/1277.zig"); |
| 13 | _ = @import("cases/bugs/1381.zig"); | ||
| 14 | _ = @import("cases/bugs/1421.zig"); | 14 | _ = @import("cases/bugs/1421.zig"); |
| 15 | _ = @import("cases/bugs/1442.zig"); | ||
| 15 | _ = @import("cases/bugs/394.zig"); | 16 | _ = @import("cases/bugs/394.zig"); |
| 16 | _ = @import("cases/bugs/655.zig"); | 17 | _ = @import("cases/bugs/655.zig"); |
| 17 | _ = @import("cases/bugs/656.zig"); | 18 | _ = @import("cases/bugs/656.zig"); |
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 it | 28 | // 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/cases/bugs/1230.zig deleted-14| ... | @@ -1,14 +0,0 @@ | ||
| 1 | const assert = @import("std").debug.assert; | ||
| 2 | |||
| 3 | const S = extern struct { | ||
| 4 | x: i32, | ||
| 5 | }; | ||
| 6 | |||
| 7 | extern fn ret_struct() S { | ||
| 8 | return S{ .x = 42 }; | ||
| 9 | } | ||
| 10 | |||
| 11 | test "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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const B = union(enum) { | ||
| 4 | D: u8, | ||
| 5 | E: u16, | ||
| 6 | }; | ||
| 7 | |||
| 8 | const A = union(enum) { | ||
| 9 | B: B, | ||
| 10 | C: u8, | ||
| 11 | }; | ||
| 12 | |||
| 13 | test "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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | const Union = union(enum) { | ||
| 4 | Text: []const u8, | ||
| 5 | Color: u32, | ||
| 6 | }; | ||
| 7 | |||
| 8 | test "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 @@ | ... | @@ -1,6 +1,24 @@ |
| 1 | const tests = @import("tests.zig"); | 1 | const tests = @import("tests.zig"); |
| 2 | 2 | ||
| 3 | pub fn addCases(cases: *tests.CompileErrorContext) void { | 3 | pub 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 | |||
| 4 | cases.add( | 22 | cases.add( |
| 5 | "refer to the type of a generic function", | 23 | "refer to the type of a generic function", |
| 6 | \\export fn entry() void { | 24 | \\export fn entry() void { |
| ... | @@ -1273,6 +1291,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -1273,6 +1291,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1273 | \\ | 1291 | \\ |
| 1274 | \\extern fn bar(x: *void) void { } | 1292 | \\extern fn bar(x: *void) void { } |
| 1275 | , | 1293 | , |
| 1294 | ".tmp_source.zig:1:30: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'ccc'", | ||
| 1276 | ".tmp_source.zig:7:18: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'ccc'", | 1295 | ".tmp_source.zig:7:18: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'ccc'", |
| 1277 | ); | 1296 | ); |
| 1278 | 1297 |
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 | ); |
| 35 | 41 | ||
| 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+18| ... | @@ -0,0 +1,18 @@ | ||
| 1 | const Builder = @import("std").build.Builder; | ||
| 2 | |||
| 3 | pub 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 | |||
| 5 | void zig_panic(); | ||
| 6 | |||
| 7 | static void assert_or_panic(bool ok) { | ||
| 8 | if (!ok) { | ||
| 9 | zig_panic(); | ||
| 10 | } | ||
| 11 | } | ||
| 12 | |||
| 13 | void zig_u8(uint8_t); | ||
| 14 | void zig_u16(uint16_t); | ||
| 15 | void zig_u32(uint32_t); | ||
| 16 | void zig_u64(uint64_t); | ||
| 17 | void zig_i8(int8_t); | ||
| 18 | void zig_i16(int16_t); | ||
| 19 | void zig_i32(int32_t); | ||
| 20 | void zig_i64(int64_t); | ||
| 21 | |||
| 22 | void zig_f32(float); | ||
| 23 | void zig_f64(double); | ||
| 24 | |||
| 25 | void zig_ptr(void *); | ||
| 26 | |||
| 27 | void zig_bool(bool); | ||
| 28 | |||
| 29 | void zig_array(uint8_t[10]); | ||
| 30 | |||
| 31 | struct BigStruct { | ||
| 32 | uint64_t a; | ||
| 33 | uint64_t b; | ||
| 34 | uint64_t c; | ||
| 35 | uint64_t d; | ||
| 36 | uint8_t e; | ||
| 37 | }; | ||
| 38 | |||
| 39 | void zig_big_struct(struct BigStruct); | ||
| 40 | |||
| 41 | union BigUnion { | ||
| 42 | struct BigStruct a; | ||
| 43 | }; | ||
| 44 | |||
| 45 | void zig_big_union(union BigUnion); | ||
| 46 | |||
| 47 | struct SmallStructInts { | ||
| 48 | uint8_t a; | ||
| 49 | uint8_t b; | ||
| 50 | uint8_t c; | ||
| 51 | uint8_t d; | ||
| 52 | }; | ||
| 53 | void zig_small_struct_ints(struct SmallStructInts); | ||
| 54 | |||
| 55 | struct SplitStructInts { | ||
| 56 | uint64_t a; | ||
| 57 | uint8_t b; | ||
| 58 | uint32_t c; | ||
| 59 | }; | ||
| 60 | void zig_split_struct_ints(struct SplitStructInts); | ||
| 61 | |||
| 62 | struct BigStruct zig_big_struct_both(struct BigStruct); | ||
| 63 | |||
| 64 | void 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 | |||
| 111 | void c_u8(uint8_t x) { | ||
| 112 | assert_or_panic(x == 0xff); | ||
| 113 | } | ||
| 114 | |||
| 115 | void c_u16(uint16_t x) { | ||
| 116 | assert_or_panic(x == 0xfffe); | ||
| 117 | } | ||
| 118 | |||
| 119 | void c_u32(uint32_t x) { | ||
| 120 | assert_or_panic(x == 0xfffffffd); | ||
| 121 | } | ||
| 122 | |||
| 123 | void c_u64(uint64_t x) { | ||
| 124 | assert_or_panic(x == 0xfffffffffffffffcULL); | ||
| 125 | } | ||
| 126 | |||
| 127 | void c_i8(int8_t x) { | ||
| 128 | assert_or_panic(x == -1); | ||
| 129 | } | ||
| 130 | |||
| 131 | void c_i16(int16_t x) { | ||
| 132 | assert_or_panic(x == -2); | ||
| 133 | } | ||
| 134 | |||
| 135 | void c_i32(int32_t x) { | ||
| 136 | assert_or_panic(x == -3); | ||
| 137 | } | ||
| 138 | |||
| 139 | void c_i64(int64_t x) { | ||
| 140 | assert_or_panic(x == -4); | ||
| 141 | } | ||
| 142 | |||
| 143 | void c_f32(float x) { | ||
| 144 | assert_or_panic(x == 12.34f); | ||
| 145 | } | ||
| 146 | |||
| 147 | void c_f64(double x) { | ||
| 148 | assert_or_panic(x == 56.78); | ||
| 149 | } | ||
| 150 | |||
| 151 | void c_ptr(void *x) { | ||
| 152 | assert_or_panic(x == (void*)0xdeadbeefL); | ||
| 153 | } | ||
| 154 | |||
| 155 | void c_bool(bool x) { | ||
| 156 | assert_or_panic(x); | ||
| 157 | } | ||
| 158 | |||
| 159 | void 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 | |||
| 172 | void 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 | |||
| 180 | void 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 | |||
| 187 | void 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 | |||
| 194 | void 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 | |||
| 200 | struct 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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const assertOrPanic = std.debug.assertOrPanic; | ||
| 3 | |||
| 4 | extern fn run_c_tests() void; | ||
| 5 | |||
| 6 | export fn zig_panic() noreturn { | ||
| 7 | @panic("zig_panic called from C"); | ||
| 8 | } | ||
| 9 | |||
| 10 | test "C importing Zig ABI Tests" { | ||
| 11 | run_c_tests(); | ||
| 12 | } | ||
| 13 | |||
| 14 | extern fn c_u8(u8) void; | ||
| 15 | extern fn c_u16(u16) void; | ||
| 16 | extern fn c_u32(u32) void; | ||
| 17 | extern fn c_u64(u64) void; | ||
| 18 | extern fn c_i8(i8) void; | ||
| 19 | extern fn c_i16(i16) void; | ||
| 20 | extern fn c_i32(i32) void; | ||
| 21 | extern fn c_i64(i64) void; | ||
| 22 | |||
| 23 | test "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 | |||
| 35 | export fn zig_u8(x: u8) void { | ||
| 36 | assertOrPanic(x == 0xff); | ||
| 37 | } | ||
| 38 | export fn zig_u16(x: u16) void { | ||
| 39 | assertOrPanic(x == 0xfffe); | ||
| 40 | } | ||
| 41 | export fn zig_u32(x: u32) void { | ||
| 42 | assertOrPanic(x == 0xfffffffd); | ||
| 43 | } | ||
| 44 | export fn zig_u64(x: u64) void { | ||
| 45 | assertOrPanic(x == 0xfffffffffffffffc); | ||
| 46 | } | ||
| 47 | export fn zig_i8(x: i8) void { | ||
| 48 | assertOrPanic(x == -1); | ||
| 49 | } | ||
| 50 | export fn zig_i16(x: i16) void { | ||
| 51 | assertOrPanic(x == -2); | ||
| 52 | } | ||
| 53 | export fn zig_i32(x: i32) void { | ||
| 54 | assertOrPanic(x == -3); | ||
| 55 | } | ||
| 56 | export fn zig_i64(x: i64) void { | ||
| 57 | assertOrPanic(x == -4); | ||
| 58 | } | ||
| 59 | |||
| 60 | extern fn c_f32(f32) void; | ||
| 61 | extern fn c_f64(f64) void; | ||
| 62 | |||
| 63 | test "C ABI floats" { | ||
| 64 | c_f32(12.34); | ||
| 65 | c_f64(56.78); | ||
| 66 | } | ||
| 67 | |||
| 68 | export fn zig_f32(x: f32) void { | ||
| 69 | assertOrPanic(x == 12.34); | ||
| 70 | } | ||
| 71 | export fn zig_f64(x: f64) void { | ||
| 72 | assertOrPanic(x == 56.78); | ||
| 73 | } | ||
| 74 | |||
| 75 | extern fn c_ptr(*c_void) void; | ||
| 76 | |||
| 77 | test "C ABI pointer" { | ||
| 78 | c_ptr(@intToPtr(*c_void, 0xdeadbeef)); | ||
| 79 | } | ||
| 80 | |||
| 81 | export fn zig_ptr(x: *c_void) void { | ||
| 82 | assertOrPanic(@ptrToInt(x) == 0xdeadbeef); | ||
| 83 | } | ||
| 84 | |||
| 85 | extern fn c_bool(bool) void; | ||
| 86 | |||
| 87 | test "C ABI bool" { | ||
| 88 | c_bool(true); | ||
| 89 | } | ||
| 90 | |||
| 91 | export fn zig_bool(x: bool) void { | ||
| 92 | assertOrPanic(x); | ||
| 93 | } | ||
| 94 | |||
| 95 | extern fn c_array([10]u8) void; | ||
| 96 | |||
| 97 | test "C ABI array" { | ||
| 98 | var array: [10]u8 = "1234567890"; | ||
| 99 | c_array(array); | ||
| 100 | } | ||
| 101 | |||
| 102 | export fn zig_array(x: [10]u8) void { | ||
| 103 | assertOrPanic(std.mem.eql(u8, x, "1234567890")); | ||
| 104 | } | ||
| 105 | |||
| 106 | const BigStruct = extern struct { | ||
| 107 | a: u64, | ||
| 108 | b: u64, | ||
| 109 | c: u64, | ||
| 110 | d: u64, | ||
| 111 | e: u8, | ||
| 112 | }; | ||
| 113 | extern fn c_big_struct(BigStruct) void; | ||
| 114 | |||
| 115 | test "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 | |||
| 126 | export 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 | |||
| 134 | const BigUnion = extern union { | ||
| 135 | a: BigStruct, | ||
| 136 | }; | ||
| 137 | extern fn c_big_union(BigUnion) void; | ||
| 138 | |||
| 139 | test "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 | |||
| 152 | export 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 | |||
| 160 | const SmallStructInts = extern struct { | ||
| 161 | a: u8, | ||
| 162 | b: u8, | ||
| 163 | c: u8, | ||
| 164 | d: u8, | ||
| 165 | }; | ||
| 166 | extern fn c_small_struct_ints(SmallStructInts) void; | ||
| 167 | |||
| 168 | test "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 | |||
| 178 | export 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 | |||
| 185 | const SplitStructInt = extern struct { | ||
| 186 | a: u64, | ||
| 187 | b: u8, | ||
| 188 | c: u32, | ||
| 189 | }; | ||
| 190 | extern fn c_split_struct_ints(SplitStructInt) void; | ||
| 191 | |||
| 192 | test "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 | |||
| 201 | export 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 | |||
| 207 | extern fn c_big_struct_both(BigStruct) BigStruct; | ||
| 208 | |||
| 209 | test "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 | |||
| 225 | export 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 | } | ||