authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-06 16:29:35-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-06 16:29:35-04:00
loga9a925e500c66b8eb57d619b9b6828c70a13d4c5
treeb118496e115a04c5b49fa77bf3478d2821d82024
parenta375bd0d9f5c7773598a8ea31af8c963d6a79706
signaturelock-open Commit is signed but in an unrecognized format.

add C ABI tests


9 files changed, 515 insertions(+), 51 deletions(-)

src/analyze.cpp+92-30
...@@ -1061,6 +1061,77 @@ ZigType *get_ptr_to_stack_trace_type(CodeGen *g) {...@@ -1061,6 +1061,77 @@ ZigType *get_ptr_to_stack_trace_type(CodeGen *g) {
1061 return g->ptr_to_stack_trace_type;1061 return g->ptr_to_stack_trace_type;
1062}1062}
10631063
1064bool type_is_c_abi_int(CodeGen *g, ZigType *ty) {
1065 size_t ty_size = type_size(g, ty);
1066 if (ty_size > g->pointer_size_bytes)
1067 return false;
1068 return (ty->id == ZigTypeIdInt ||
1069 ty->id == ZigTypeIdFloat ||
1070 ty->id == ZigTypeIdBool ||
1071 ty->id == ZigTypeIdEnum ||
1072 get_codegen_ptr_type(ty) != nullptr);
1073}
1074
1075// If you edit this function you have to edit the corresponding code:
1076// codegen.cpp:gen_c_abi_param
1077// analyze.cpp:gen_c_abi_param_type
1078// codegen.cpp:gen_c_abi_param_var
1079// codegen.cpp:gen_c_abi_param_var_init
1080static void gen_c_abi_param_type(CodeGen *g, ZigList<LLVMTypeRef> *gen_param_types,
1081 ZigList<ZigLLVMDIType *> *param_di_types, ZigType *ty)
1082{
1083 if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat ||
1084 ty->id == ZigTypeIdInt // TODO investigate if we need to change this
1085 ) {
1086 gen_param_types->append(ty->type_ref);
1087 param_di_types->append(ty->di_type);
1088 return;
1089 }
1090
1091 // Arrays are just pointers
1092 if (ty->id == ZigTypeIdArray) {
1093 ZigType *gen_type = get_pointer_to_type(g, ty, true);
1094 gen_param_types->append(gen_type->type_ref);
1095 param_di_types->append(gen_type->di_type);
1096 return;
1097 }
1098
1099 if (g->zig_target.arch.arch == ZigLLVM_x86_64) {
1100 size_t ty_size = type_size(g, ty);
1101 if (ty->id == ZigTypeIdStruct || ty->id == ZigTypeIdUnion) {
1102 // "If the size of an object is larger than four eightbytes, or it contains unaligned
1103 // fields, it has class MEMORY"
1104 if (ty_size > 32) {
1105 ZigType *gen_type = get_pointer_to_type(g, ty, true);
1106 gen_param_types->append(gen_type->type_ref);
1107 param_di_types->append(gen_type->di_type);
1108 return;
1109 }
1110 }
1111 if (ty->id == ZigTypeIdStruct) {
1112 // "If the size of the aggregate exceeds a single eightbyte, each is classified
1113 // separately. Each eightbyte gets initialized to class NO_CLASS."
1114 if (ty_size <= 8) {
1115 bool contains_int = false;
1116 for (size_t i = 0; i < ty->data.structure.src_field_count; i += 1) {
1117 if (type_is_c_abi_int(g, ty->data.structure.fields[i].type_entry)) {
1118 contains_int = true;
1119 break;
1120 }
1121 }
1122 if (contains_int) {
1123 ZigType *gen_type = get_int_type(g, false, ty_size * 8);
1124 gen_param_types->append(gen_type->type_ref);
1125 param_di_types->append(gen_type->di_type);
1126 return;
1127 }
1128 }
1129 }
1130 }
1131
1132 // allow codegen code to report a compile error
1133}
1134
1064ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {1135ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
1065 Error err;1136 Error err;
1066 auto table_entry = g->fn_type_table.maybe_get(fn_type_id);1137 auto table_entry = g->fn_type_table.maybe_get(fn_type_id);
...@@ -1119,18 +1190,18 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -1119,18 +1190,18 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
1119 bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) &&1190 bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) &&
1120 handle_is_ptr(fn_type_id->return_type);1191 handle_is_ptr(fn_type_id->return_type);
1121 bool is_async = fn_type_id->cc == CallingConventionAsync;1192 bool is_async = fn_type_id->cc == CallingConventionAsync;
1193 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);1194 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 value1195 // +1 for maybe making the first argument the return value
1124 // +1 for maybe first argument the error return trace1196 // +1 for maybe first argument the error return trace
1125 // +2 for maybe arguments async allocator and error code pointer1197 // +2 for maybe arguments async allocator and error code pointer
1126 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(4 + fn_type_id->param_count);1198 ZigList<LLVMTypeRef> gen_param_types = {};
1127 // +1 because 0 is the return type and1199 // +1 because 0 is the return type and
1128 // +1 for maybe making first arg ret val and1200 // +1 for maybe making first arg ret val and
1129 // +1 for maybe first argument the error return trace1201 // +1 for maybe first argument the error return trace
1130 // +2 for maybe arguments async allocator and error code pointer1202 // +2 for maybe arguments async allocator and error code pointer
1131 ZigLLVMDIType **param_di_types = allocate<ZigLLVMDIType*>(5 + fn_type_id->param_count);1203 ZigList<ZigLLVMDIType *> param_di_types = {};
1132 param_di_types[0] = fn_type_id->return_type->di_type;1204 param_di_types.append(fn_type_id->return_type->di_type);
1133 size_t gen_param_index = 0;
1134 ZigType *gen_return_type;1205 ZigType *gen_return_type;
1135 if (is_async) {1206 if (is_async) {
1136 gen_return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);1207 gen_return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
...@@ -1138,10 +1209,8 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -1138,10 +1209,8 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
1138 gen_return_type = g->builtin_types.entry_void;1209 gen_return_type = g->builtin_types.entry_void;
1139 } else if (first_arg_return) {1210 } else if (first_arg_return) {
1140 ZigType *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false);1211 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;1212 gen_param_types.append(gen_type->type_ref);
1142 gen_param_index += 1;1213 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;1214 gen_return_type = g->builtin_types.entry_void;
1146 } else {1215 } else {
1147 gen_return_type = fn_type_id->return_type;1216 gen_return_type = fn_type_id->return_type;
...@@ -1150,28 +1219,22 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -1150,28 +1219,22 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
11501219
1151 if (prefix_arg_error_return_trace) {1220 if (prefix_arg_error_return_trace) {
1152 ZigType *gen_type = get_ptr_to_stack_trace_type(g);1221 ZigType *gen_type = get_ptr_to_stack_trace_type(g);
1153 gen_param_types[gen_param_index] = gen_type->type_ref;1222 gen_param_types.append(gen_type->type_ref);
1154 gen_param_index += 1;1223 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 }1224 }
1158 if (is_async) {1225 if (is_async) {
1159 {1226 {
1160 // async allocator param1227 // async allocator param
1161 ZigType *gen_type = fn_type_id->async_allocator_type;1228 ZigType *gen_type = fn_type_id->async_allocator_type;
1162 gen_param_types[gen_param_index] = gen_type->type_ref;1229 gen_param_types.append(gen_type->type_ref);
1163 gen_param_index += 1;1230 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 }1231 }
11671232
1168 {1233 {
1169 // error code pointer1234 // error code pointer
1170 ZigType *gen_type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false);1235 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;1236 gen_param_types.append(gen_type->type_ref);
1172 gen_param_index += 1;1237 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 }1238 }
1176 }1239 }
11771240
...@@ -1187,7 +1250,9 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -1187,7 +1250,9 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
1187 if ((err = ensure_complete_type(g, type_entry)))1250 if ((err = ensure_complete_type(g, type_entry)))
1188 return g->builtin_types.entry_invalid;1251 return g->builtin_types.entry_invalid;
11891252
1190 if (type_has_bits(type_entry)) {1253 if (is_c_abi) {
1254 gen_c_abi_param_type(g, &gen_param_types, &param_di_types, type_entry);
1255 } else if (type_has_bits(type_entry)) {
1191 ZigType *gen_type;1256 ZigType *gen_type;
1192 if (handle_is_ptr(type_entry)) {1257 if (handle_is_ptr(type_entry)) {
1193 gen_type = get_pointer_to_type(g, type_entry, true);1258 gen_type = get_pointer_to_type(g, type_entry, true);
...@@ -1195,23 +1260,20 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {...@@ -1195,23 +1260,20 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
1195 } else {1260 } else {
1196 gen_type = type_entry;1261 gen_type = type_entry;
1197 }1262 }
1198 gen_param_types[gen_param_index] = gen_type->type_ref;1263 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;1264 gen_param_info->type = gen_type;
1265 gen_param_types.append(gen_type->type_ref);
12011266
1202 gen_param_index += 1;1267 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 }1268 }
1207 }1269 }
12081270
1209 fn_type->data.fn.gen_param_count = gen_param_index;1271 fn_type->data.fn.gen_param_count = gen_param_types.length;
12101272
1211 fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref,1273 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);1274 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);1275 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);1276 fn_type->di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0);
1215 }1277 }
12161278
1217 g->fn_type_table.put(&fn_type->data.fn.fn_type_id, fn_type);1279 g->fn_type_table.put(&fn_type->data.fn.fn_type_id, fn_type);
src/analyze.hpp+2
...@@ -210,4 +210,6 @@ ZigType *get_primitive_type(CodeGen *g, Buf *name);...@@ -210,4 +210,6 @@ ZigType *get_primitive_type(CodeGen *g, Buf *name);
210bool calling_convention_allows_zig_types(CallingConvention cc);210bool calling_convention_allows_zig_types(CallingConvention cc);
211const char *calling_convention_name(CallingConvention cc);211const char *calling_convention_name(CallingConvention cc);
212212
213bool type_is_c_abi_int(CodeGen *g, ZigType *ty);
214
213#endif215#endif
src/codegen.cpp+225-17
...@@ -3136,24 +3136,226 @@ static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) {...@@ -3136,24 +3136,226 @@ static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) {
3136 report_errors_and_exit(g);3136 report_errors_and_exit(g);
3137}3137}
31383138
3139static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) {
3140 assert(alignment > 0);
3141 LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name);
3142 LLVMSetAlignment(result, alignment);
3143 return result;
3144}
3145
3146// If you edit this function you have to edit the corresponding code:
3147// codegen.cpp:gen_c_abi_param
3148// analyze.cpp:gen_c_abi_param_type
3149// codegen.cpp:gen_c_abi_param_var
3150// codegen.cpp:gen_c_abi_param_var_init
3139static void gen_c_abi_param(CodeGen *g, ZigList<LLVMValueRef> *gen_param_values, LLVMValueRef val,3151static void gen_c_abi_param(CodeGen *g, ZigList<LLVMValueRef> *gen_param_values, LLVMValueRef val,
3140 ZigType *ty, AstNode *source_node)3152 ZigType *ty, AstNode *source_node)
3141{3153{
3142 if (ty->id == ZigTypeIdInt ||3154 if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat ||
3143 ty->id == ZigTypeIdFloat ||3155 ty->id == ZigTypeIdInt // TODO investigate if we need to change this
3144 ty->id == ZigTypeIdBool ||3156 ) {
3145 ty->id == ZigTypeIdEnum ||3157 gen_param_values->append(val);
3146 get_codegen_ptr_type(ty) != nullptr)3158 return;
3147 {3159 }
3160
3161 // Arrays are just pointers
3162 if (ty->id == ZigTypeIdArray) {
3163 assert(handle_is_ptr(ty));
3148 gen_param_values->append(val);3164 gen_param_values->append(val);
3149 return;3165 return;
3150 }3166 }
31513167
3152 if (g->zig_target.arch.arch == ZigLLVM_x86_64) {3168 if (g->zig_target.arch.arch == ZigLLVM_x86_64) {
3153 give_up_with_c_abi_error(g, source_node);3169 // This code all assumes that val is a pointer.
3154 } else {3170 assert(handle_is_ptr(ty));
3155 give_up_with_c_abi_error(g, source_node);3171
3172 size_t ty_size = type_size(g, ty);
3173 if (ty->id == ZigTypeIdStruct || ty->id == ZigTypeIdUnion) {
3174 // "If the size of an object is larger than four eightbytes, or it contains unaligned
3175 // fields, it has class MEMORY"
3176 if (ty_size > 32) {
3177 gen_param_values->append(val);
3178 return;
3179 }
3180 }
3181 if (ty->id == ZigTypeIdStruct) {
3182 // "If the size of the aggregate exceeds a single eightbyte, each is classified
3183 // separately. Each eightbyte gets initialized to class NO_CLASS."
3184 if (ty_size <= 8) {
3185 bool contains_int = false;
3186 for (size_t i = 0; i < ty->data.structure.src_field_count; i += 1) {
3187 if (type_is_c_abi_int(g, ty->data.structure.fields[i].type_entry)) {
3188 contains_int = true;
3189 break;
3190 }
3191 }
3192 if (contains_int) {
3193 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
3194 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, val, ptr_to_int_type_ref, "");
3195 LLVMValueRef loaded = LLVMBuildLoad(g->builder, bitcasted, "");
3196 gen_param_values->append(loaded);
3197 return;
3198 }
3199 }
3200 }
3201 }
3202
3203 give_up_with_c_abi_error(g, source_node);
3204}
3205
3206// If you edit this function you have to edit the corresponding code:
3207// codegen.cpp:gen_c_abi_param
3208// analyze.cpp:gen_c_abi_param_type
3209// codegen.cpp:gen_c_abi_param_var
3210// codegen.cpp:gen_c_abi_param_var_init
3211static void gen_c_abi_param_var(CodeGen *g, ImportTableEntry *import, LLVMValueRef llvm_fn, ZigFn *fn,
3212 ZigVar *var, unsigned *arg_index)
3213{
3214 ZigType *ty = var->value->type;
3215
3216 ZigType *dest_ty = nullptr;
3217 unsigned di_arg_index;
3218
3219 if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat ||
3220 ty->id == ZigTypeIdInt // TODO investigate if we need to change this
3221 ) {
3222 var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes);
3223 di_arg_index = *arg_index;
3224 *arg_index += 1;
3225 dest_ty = ty;
3226 goto ok;
3227 }
3228
3229 // Arrays are just pointers
3230 if (ty->id == ZigTypeIdArray) {
3231 di_arg_index = *arg_index;
3232 var->value_ref = LLVMGetParam(llvm_fn, *arg_index);
3233 dest_ty = get_pointer_to_type(g, ty, false);
3234 *arg_index += 1;
3235 goto ok;
3236 }
3237
3238 if (g->zig_target.arch.arch == ZigLLVM_x86_64) {
3239 assert(handle_is_ptr(ty));
3240 size_t ty_size = type_size(g, ty);
3241
3242 if (ty->id == ZigTypeIdStruct || ty->id == ZigTypeIdUnion) {
3243 // "If the size of an object is larger than four eightbytes, or it contains unaligned
3244 // fields, it has class MEMORY"
3245 if (ty_size > 32) {
3246 di_arg_index = *arg_index;
3247 var->value_ref = LLVMGetParam(llvm_fn, *arg_index);
3248 dest_ty = get_pointer_to_type(g, ty, false);
3249 *arg_index += 1;
3250 goto ok;
3251 }
3252 }
3253 if (ty->id == ZigTypeIdStruct) {
3254 // "If the size of the aggregate exceeds a single eightbyte, each is classified
3255 // separately. Each eightbyte gets initialized to class NO_CLASS."
3256 if (ty_size <= 8) {
3257 bool contains_int = false;
3258 for (size_t i = 0; i < ty->data.structure.src_field_count; i += 1) {
3259 if (type_is_c_abi_int(g, ty->data.structure.fields[i].type_entry)) {
3260 contains_int = true;
3261 break;
3262 }
3263 }
3264 if (contains_int) {
3265 var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes);
3266 *arg_index += 1;
3267 goto ok;
3268 }
3269 }
3270 }
3271 }
3272
3273 give_up_with_c_abi_error(g, fn->proto_node);
3274
3275ok:
3276 if (dest_ty != nullptr && var->decl_node) {
3277 // arg index + 1 because the 0 index is return value
3278 var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
3279 buf_ptr(&var->name), import->di_file,
3280 (unsigned)(var->decl_node->line + 1),
3281 dest_ty->di_type, !g->strip_debug_symbols, 0, di_arg_index + 1);
3282 }
3283}
3284
3285// If you edit this function you have to edit the corresponding code:
3286// codegen.cpp:gen_c_abi_param
3287// analyze.cpp:gen_c_abi_param_type
3288// codegen.cpp:gen_c_abi_param_var
3289// codegen.cpp:gen_c_abi_param_var_init
3290static void gen_c_abi_param_var_init(CodeGen *g, ImportTableEntry *import, LLVMValueRef llvm_fn, ZigFn *fn,
3291 ZigVar *var, unsigned *arg_index)
3292{
3293 ZigType *ty = var->value->type;
3294
3295 if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat ||
3296 ty->id == ZigTypeIdInt // TODO investigate if we need to change this
3297 ) {
3298 clear_debug_source_node(g);
3299 gen_store_untyped(g, LLVMGetParam(llvm_fn, *arg_index), var->value_ref, var->align_bytes, false);
3300 if (var->decl_node) {
3301 gen_var_debug_decl(g, var);
3302 }
3303 *arg_index += 1;
3304 return;
3305 }
3306
3307 // Arrays are just pointers
3308 if (ty->id == ZigTypeIdArray) {
3309 if (var->decl_node) {
3310 gen_var_debug_decl(g, var);
3311 }
3312 *arg_index += 1;
3313 return;
3314 }
3315
3316 if (g->zig_target.arch.arch == ZigLLVM_x86_64) {
3317 assert(handle_is_ptr(ty));
3318 size_t ty_size = type_size(g, ty);
3319
3320 if (ty->id == ZigTypeIdStruct || ty->id == ZigTypeIdUnion) {
3321 // "If the size of an object is larger than four eightbytes, or it contains unaligned
3322 // fields, it has class MEMORY"
3323 if (ty_size > 32) {
3324 if (var->decl_node) {
3325 gen_var_debug_decl(g, var);
3326 }
3327 *arg_index += 1;
3328 return;
3329 }
3330 }
3331 if (ty->id == ZigTypeIdStruct) {
3332 // "If the size of the aggregate exceeds a single eightbyte, each is classified
3333 // separately. Each eightbyte gets initialized to class NO_CLASS."
3334 if (ty_size <= 8) {
3335 bool contains_int = false;
3336 for (size_t i = 0; i < ty->data.structure.src_field_count; i += 1) {
3337 if (type_is_c_abi_int(g, ty->data.structure.fields[i].type_entry)) {
3338 contains_int = true;
3339 break;
3340 }
3341 }
3342 if (contains_int) {
3343 clear_debug_source_node(g);
3344 LLVMValueRef arg = LLVMGetParam(llvm_fn, *arg_index);
3345 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
3346 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, "");
3347 gen_store_untyped(g, arg, bitcasted, var->align_bytes, false);
3348 if (var->decl_node) {
3349 gen_var_debug_decl(g, var);
3350 }
3351 *arg_index += 1;
3352 return;
3353 }
3354 }
3355 }
3156 }3356 }
3357
3358 give_up_with_c_abi_error(g, fn->proto_node);
3157}3359}
31583360
3159static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) {3361static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) {
...@@ -5765,13 +5967,6 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,...@@ -5765,13 +5967,6 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,
5765 // TODO ^^ make an actual global variable5967 // TODO ^^ make an actual global variable
5766}5968}
57675969
5768static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) {
5769 assert(alignment > 0);
5770 LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name);
5771 LLVMSetAlignment(result, alignment);
5772 return result;
5773}
5774
5775static void ensure_cache_dir(CodeGen *g) {5970static void ensure_cache_dir(CodeGen *g) {
5776 int err;5971 int err;
5777 if ((err = os_make_path(&g->cache_dir))) {5972 if ((err = os_make_path(&g->cache_dir))) {
...@@ -5899,6 +6094,8 @@ static void do_code_gen(CodeGen *g) {...@@ -5899,6 +6094,8 @@ static void do_code_gen(CodeGen *g) {
5899 // Generate function definitions.6094 // Generate function definitions.
5900 for (size_t fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) {6095 for (size_t fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) {
5901 ZigFn *fn_table_entry = g->fn_defs.at(fn_i);6096 ZigFn *fn_table_entry = g->fn_defs.at(fn_i);
6097 CallingConvention cc = fn_table_entry->type_entry->data.fn.fn_type_id.cc;
6098 bool is_c_abi = cc == CallingConventionC;
59026099
5903 LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);6100 LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);
5904 g->cur_fn = fn_table_entry;6101 g->cur_fn = fn_table_entry;
...@@ -5922,7 +6119,7 @@ static void do_code_gen(CodeGen *g) {...@@ -5922,7 +6119,7 @@ static void do_code_gen(CodeGen *g) {
5922 }6119 }
59236120
5924 // error return tracing setup6121 // error return tracing setup
5925 bool is_async = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;6122 bool is_async = cc == CallingConventionAsync;
5926 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;6123 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;
5927 LLVMValueRef err_ret_array_val = nullptr;6124 LLVMValueRef err_ret_array_val = nullptr;
5928 if (have_err_ret_trace_stack) {6125 if (have_err_ret_trace_stack) {
...@@ -5982,6 +6179,7 @@ static void do_code_gen(CodeGen *g) {...@@ -5982,6 +6179,7 @@ static void do_code_gen(CodeGen *g) {
5982 ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base);6179 ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base);
59836180
5984 // create debug variable declarations for variables and allocate all local variables6181 // create debug variable declarations for variables and allocate all local variables
6182 unsigned c_abi_arg_index = 0;
5985 for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) {6183 for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) {
5986 ZigVar *var = fn_table_entry->variable_list.at(var_i);6184 ZigVar *var = fn_table_entry->variable_list.at(var_i);
59876185
...@@ -6000,6 +6198,8 @@ static void do_code_gen(CodeGen *g) {...@@ -6000,6 +6198,8 @@ static void do_code_gen(CodeGen *g) {
6000 buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1),6198 buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1),
6001 var->value->type->di_type, !g->strip_debug_symbols, 0);6199 var->value->type->di_type, !g->strip_debug_symbols, 0);
60026200
6201 } else if (is_c_abi) {
6202 gen_c_abi_param_var(g, import, fn, fn_table_entry, var, &c_abi_arg_index);
6003 } else {6203 } else {
6004 assert(var->gen_arg_index != SIZE_MAX);6204 assert(var->gen_arg_index != SIZE_MAX);
6005 ZigType *gen_type;6205 ZigType *gen_type;
...@@ -6056,7 +6256,14 @@ static void do_code_gen(CodeGen *g) {...@@ -6056,7 +6256,14 @@ static void do_code_gen(CodeGen *g) {
6056 // create debug variable declarations for parameters6256 // create debug variable declarations for parameters
6057 // rely on the first variables in the variable_list being parameters.6257 // rely on the first variables in the variable_list being parameters.
6058 size_t next_var_i = 0;6258 size_t next_var_i = 0;
6259 unsigned c_abi_arg_init_index = 0;
6059 for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {6260 for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
6261 if (is_c_abi) {
6262 ZigVar *var = fn_table_entry->variable_list.at(param_i);
6263 gen_c_abi_param_var_init(g, import, fn, fn_table_entry, var, &c_abi_arg_init_index);
6264 continue;
6265 }
6266
6060 FnGenParamInfo *info = &fn_table_entry->type_entry->data.fn.gen_param_info[param_i];6267 FnGenParamInfo *info = &fn_table_entry->type_entry->data.fn.gen_param_info[param_i];
6061 if (info->gen_index == SIZE_MAX)6268 if (info->gen_index == SIZE_MAX)
6062 continue;6269 continue;
...@@ -6078,6 +6285,7 @@ static void do_code_gen(CodeGen *g) {...@@ -6078,6 +6285,7 @@ static void do_code_gen(CodeGen *g) {
6078 gen_var_debug_decl(g, variable);6285 gen_var_debug_decl(g, variable);
6079 }6286 }
6080 }6287 }
6288 assert(c_abi_arg_index == c_abi_arg_init_index);
60816289
6082 ir_render(g, fn_table_entry);6290 ir_render(g, fn_table_entry);
60836291
std/build.zig+27
...@@ -48,6 +48,12 @@ pub const Builder = struct {...@@ -48,6 +48,12 @@ pub const Builder = struct {
48 cache_root: []const u8,48 cache_root: []const u8,
49 release_mode: ?builtin.Mode,49 release_mode: ?builtin.Mode,
5050
51 pub const CStd = enum {
52 C89,
53 C99,
54 C11,
55 };
56
51 const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8);57 const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8);
52 const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8);58 const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8);
5359
...@@ -817,6 +823,7 @@ pub const LibExeObjStep = struct {...@@ -817,6 +823,7 @@ pub const LibExeObjStep = struct {
817 frameworks: BufSet,823 frameworks: BufSet,
818 verbose_link: bool,824 verbose_link: bool,
819 no_rosegment: bool,825 no_rosegment: bool,
826 c_std: Builder.CStd,
820827
821 // zig only stuff828 // zig only stuff
822 root_src: ?[]const u8,829 root_src: ?[]const u8,
...@@ -918,6 +925,7 @@ pub const LibExeObjStep = struct {...@@ -918,6 +925,7 @@ pub const LibExeObjStep = struct {
918 .object_src = undefined,925 .object_src = undefined,
919 .disable_libc = true,926 .disable_libc = true,
920 .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable,927 .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable,
928 .c_std = Builder.CStd.C99,
921 };929 };
922 self.computeOutFileNames();930 self.computeOutFileNames();
923 return self;931 return self;
...@@ -952,6 +960,7 @@ pub const LibExeObjStep = struct {...@@ -952,6 +960,7 @@ pub const LibExeObjStep = struct {
952 .disable_libc = false,960 .disable_libc = false,
953 .is_zig = false,961 .is_zig = false,
954 .linker_script = null,962 .linker_script = null,
963 .c_std = Builder.CStd.C99,
955964
956 .root_src = undefined,965 .root_src = undefined,
957 .verbose_link = false,966 .verbose_link = false,
...@@ -1392,6 +1401,13 @@ pub const LibExeObjStep = struct {...@@ -1392,6 +1401,13 @@ pub const LibExeObjStep = struct {
13921401
1393 const is_darwin = self.target.isDarwin();1402 const is_darwin = self.target.isDarwin();
13941403
1404 const c_std_arg = switch (self.c_std) {
1405 Builder.CStd.C89 => "-std=c89",
1406 Builder.CStd.C99 => "-std=c99",
1407 Builder.CStd.C11 => "-std=c11",
1408 };
1409 try cc_args.append(c_std_arg);
1410
1395 switch (self.kind) {1411 switch (self.kind) {
1396 Kind.Obj => {1412 Kind.Obj => {
1397 cc_args.append("-c") catch unreachable;1413 cc_args.append("-c") catch unreachable;
...@@ -1678,6 +1694,17 @@ pub const TestStep = struct {...@@ -1678,6 +1694,17 @@ pub const TestStep = struct {
1678 self.filter = text;1694 self.filter = text;
1679 }1695 }
16801696
1697 pub fn addObject(self: *TestStep, obj: *LibExeObjStep) void {
1698 assert(obj.kind == LibExeObjStep.Kind.Obj);
1699
1700 self.step.dependOn(&obj.step);
1701
1702 self.object_files.append(obj.getOutputPath()) catch unreachable;
1703
1704 // TODO should be some kind of isolated directory that only has this header in it
1705 self.include_dirs.append(self.builder.cache_root) catch unreachable;
1706 }
1707
1681 pub fn addObjectFile(self: *TestStep, path: []const u8) void {1708 pub fn addObjectFile(self: *TestStep, path: []const u8) void {
1682 self.object_files.append(path) catch unreachable;1709 self.object_files.append(path) catch unreachable;
1683 }1710 }
test/build_examples.zig+6
...@@ -28,4 +28,10 @@ pub fn addCases(cases: *tests.BuildExamplesContext) void {...@@ -28,4 +28,10 @@ pub fn addCases(cases: *tests.BuildExamplesContext) void {
28 // TODO figure out how to make this work on darwin - probably libSystem has dlopen/dlsym in it28 // TODO figure out how to make this work on darwin - probably libSystem has dlopen/dlsym in it
29 cases.addBuildFile("test/standalone/load_dynamic_library/build.zig");29 cases.addBuildFile("test/standalone/load_dynamic_library/build.zig");
30 }30 }
31
32 if (!is_windows // TODO support compiling C files on windows with zig build system
33 and builtin.arch == builtin.Arch.x86_64 // TODO add C ABI support for other architectures
34 ) {
35 cases.addBuildFile("test/stage1/c_abi/build.zig");
36 }
31}37}
test/gen_h.zig+24-4
...@@ -20,6 +20,9 @@ pub fn addCases(cases: *tests.GenHContext) void {...@@ -20,6 +20,9 @@ pub fn addCases(cases: *tests.GenHContext) void {
20 \\ A: i32,20 \\ A: i32,
21 \\ B: f32,21 \\ B: f32,
22 \\ C: bool,22 \\ C: bool,
23 \\ D: u64,
24 \\ E: u64,
25 \\ F: u64,
23 \\};26 \\};
24 \\export fn entry(foo: Foo) void { }27 \\export fn entry(foo: Foo) void { }
25 ,28 ,
...@@ -27,6 +30,9 @@ pub fn addCases(cases: *tests.GenHContext) void {...@@ -27,6 +30,9 @@ pub fn addCases(cases: *tests.GenHContext) void {
27 \\ int32_t A;30 \\ int32_t A;
28 \\ float B;31 \\ float B;
29 \\ bool C;32 \\ bool C;
33 \\ uint64_t D;
34 \\ uint64_t E;
35 \\ uint64_t F;
30 \\};36 \\};
31 \\37 \\
32 \\TEST_EXPORT void entry(struct Foo foo);38 \\TEST_EXPORT void entry(struct Foo foo);
...@@ -34,17 +40,34 @@ pub fn addCases(cases: *tests.GenHContext) void {...@@ -34,17 +40,34 @@ pub fn addCases(cases: *tests.GenHContext) void {
34 );40 );
3541
36 cases.add("declare union",42 cases.add("declare union",
43 \\const Big = extern struct {
44 \\ A: u64,
45 \\ B: u64,
46 \\ C: u64,
47 \\ D: u64,
48 \\ E: u64,
49 \\};
37 \\const Foo = extern union {50 \\const Foo = extern union {
38 \\ A: i32,51 \\ A: i32,
39 \\ B: f32,52 \\ B: f32,
40 \\ C: bool,53 \\ C: bool,
54 \\ D: Big,
41 \\};55 \\};
42 \\export fn entry(foo: Foo) void { }56 \\export fn entry(foo: Foo) void {}
43 ,57 ,
58 \\struct Big {
59 \\ uint64_t A;
60 \\ uint64_t B;
61 \\ uint64_t C;
62 \\ uint64_t D;
63 \\ uint64_t E;
64 \\};
65 \\
44 \\union Foo {66 \\union Foo {
45 \\ int32_t A;67 \\ int32_t A;
46 \\ float B;68 \\ float B;
47 \\ bool C;69 \\ bool C;
70 \\ struct Big D;
48 \\};71 \\};
49 \\72 \\
50 \\TEST_EXPORT void entry(union Foo foo);73 \\TEST_EXPORT void entry(union Foo foo);
...@@ -85,7 +108,6 @@ pub fn addCases(cases: *tests.GenHContext) void {...@@ -85,7 +108,6 @@ pub fn addCases(cases: *tests.GenHContext) void {
85 \\export fn a(s: *S) u8 {108 \\export fn a(s: *S) u8 {
86 \\ return s.a;109 \\ return s.a;
87 \\}110 \\}
88
89 ,111 ,
90 \\struct S;112 \\struct S;
91 \\TEST_EXPORT uint8_t a(struct S * s);113 \\TEST_EXPORT uint8_t a(struct S * s);
...@@ -101,7 +123,6 @@ pub fn addCases(cases: *tests.GenHContext) void {...@@ -101,7 +123,6 @@ pub fn addCases(cases: *tests.GenHContext) void {
101 \\export fn a(s: *U) u8 {123 \\export fn a(s: *U) u8 {
102 \\ return s.A;124 \\ return s.A;
103 \\}125 \\}
104
105 ,126 ,
106 \\union U;127 \\union U;
107 \\TEST_EXPORT uint8_t a(union U * s);128 \\TEST_EXPORT uint8_t a(union U * s);
...@@ -117,7 +138,6 @@ pub fn addCases(cases: *tests.GenHContext) void {...@@ -117,7 +138,6 @@ pub fn addCases(cases: *tests.GenHContext) void {
117 \\export fn a(s: *E) u8 {138 \\export fn a(s: *E) u8 {
118 \\ return @enumToInt(s.*);139 \\ return @enumToInt(s.*);
119 \\}140 \\}
120
121 ,141 ,
122 \\enum E;142 \\enum E;
123 \\TEST_EXPORT uint8_t a(enum E * s);143 \\TEST_EXPORT uint8_t a(enum E * s);
test/stage1/c_abi/build.zig created+17
...@@ -0,0 +1,17 @@
1const Builder = @import("std").build.Builder;
2
3pub fn build(b: *Builder) void {
4 const rel_opts = b.standardReleaseOptions();
5
6 const c_obj = b.addCObject("cfuncs", "cfuncs.c");
7 c_obj.setBuildMode(rel_opts);
8
9 const main = b.addTest("main.zig");
10 main.setBuildMode(rel_opts);
11 main.addObject(c_obj);
12
13 const test_step = b.step("test", "Test the program");
14 test_step.dependOn(&main.step);
15
16 b.default_step.dependOn(test_step);
17}
test/stage1/c_abi/cfuncs.c created+64
...@@ -0,0 +1,64 @@
1#include <inttypes.h>
2#include <stdlib.h>
3#include <stdbool.h>
4
5void zig_panic();
6
7static void assert_or_panic(bool ok) {
8 if (!ok) {
9 zig_panic();
10 }
11}
12
13void zig_u8(uint8_t);
14void zig_u16(uint16_t);
15void zig_u32(uint32_t);
16void zig_u64(uint64_t);
17void zig_i8(int8_t);
18void zig_i16(int16_t);
19void zig_i32(int32_t);
20void zig_i64(int64_t);
21
22void run_c_tests(void) {
23 zig_u8(0xff);
24 zig_u16(0xfffe);
25 zig_u32(0xfffffffd);
26 zig_u64(0xfffffffffffffffc);
27
28 zig_i8(-1);
29 zig_i16(-2);
30 zig_i32(-3);
31 zig_i64(-4);
32}
33
34void c_u8(uint8_t x) {
35 assert_or_panic(x == 0xff);
36}
37
38void c_u16(uint16_t x) {
39 assert_or_panic(x == 0xfffe);
40}
41
42void c_u32(uint32_t x) {
43 assert_or_panic(x == 0xfffffffd);
44}
45
46void c_u64(uint64_t x) {
47 assert_or_panic(x == 0xfffffffffffffffcULL);
48}
49
50void c_i8(int8_t x) {
51 assert_or_panic(x == -1);
52}
53
54void c_i16(int16_t x) {
55 assert_or_panic(x == -2);
56}
57
58void c_i32(int32_t x) {
59 assert_or_panic(x == -3);
60}
61
62void c_i64(int64_t x) {
63 assert_or_panic(x == -4);
64}
test/stage1/c_abi/main.zig created+58
...@@ -0,0 +1,58 @@
1const std = @import("std");
2const assertOrPanic = std.debug.assertOrPanic;
3
4extern fn run_c_tests() void;
5
6export fn zig_panic() noreturn {
7 @panic("zig_panic called from C");
8}
9
10test "C importing Zig ABI Tests" {
11 run_c_tests();
12}
13
14extern fn c_u8(u8) void;
15extern fn c_u16(u16) void;
16extern fn c_u32(u32) void;
17extern fn c_u64(u64) void;
18extern fn c_i8(i8) void;
19extern fn c_i16(i16) void;
20extern fn c_i32(i32) void;
21extern fn c_i64(i64) void;
22
23test "C ABI integers" {
24 c_u8(0xff);
25 c_u16(0xfffe);
26 c_u32(0xfffffffd);
27 c_u64(0xfffffffffffffffc);
28
29 c_i8(-1);
30 c_i16(-2);
31 c_i32(-3);
32 c_i64(-4);
33}
34
35export fn zig_u8(x: u8) void {
36 assertOrPanic(x == 0xff);
37}
38export fn zig_u16(x: u16) void {
39 assertOrPanic(x == 0xfffe);
40}
41export fn zig_u32(x: u32) void {
42 assertOrPanic(x == 0xfffffffd);
43}
44export fn zig_u64(x: u64) void {
45 assertOrPanic(x == 0xfffffffffffffffc);
46}
47export fn zig_i8(x: i8) void {
48 assertOrPanic(x == -1);
49}
50export fn zig_i16(x: i16) void {
51 assertOrPanic(x == -2);
52}
53export fn zig_i32(x: i32) void {
54 assertOrPanic(x == -3);
55}
56export fn zig_i64(x: i64) void {
57 assertOrPanic(x == -4);
58}