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

Merge branch 'c-abi'

closes #1411 closes #1264

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

src/all_types.hpp+49
......@@ -3284,4 +3284,53 @@ enum FloatMode {
32843284 FloatModeStrict,
32853285};
32863286
3287enum FnWalkId {
3288 FnWalkIdAttrs,
3289 FnWalkIdCall,
3290 FnWalkIdTypes,
3291 FnWalkIdVars,
3292 FnWalkIdInits,
3293};
3294
3295struct FnWalkAttrs {
3296 ZigFn *fn;
3297 unsigned gen_i;
3298};
3299
3300struct FnWalkCall {
3301 ZigList<LLVMValueRef> *gen_param_values;
3302 IrInstructionCall *inst;
3303 bool is_var_args;
3304};
3305
3306struct FnWalkTypes {
3307 ZigList<ZigLLVMDIType *> *param_di_types;
3308 ZigList<LLVMTypeRef> *gen_param_types;
3309};
3310
3311struct FnWalkVars {
3312 ImportTableEntry *import;
3313 LLVMValueRef llvm_fn;
3314 ZigFn *fn;
3315 ZigVar *var;
3316 unsigned gen_i;
3317};
3318
3319struct FnWalkInits {
3320 LLVMValueRef llvm_fn;
3321 ZigFn *fn;
3322 unsigned gen_i;
3323};
3324
3325struct FnWalk {
3326 FnWalkId id;
3327 union {
3328 FnWalkAttrs attrs;
3329 FnWalkCall call;
3330 FnWalkTypes types;
3331 FnWalkVars vars;
3332 FnWalkInits inits;
3333 } data;
3334};
3335
32873336#endif
src/analyze.cpp+29-29
......@@ -1119,18 +1119,18 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
11191119 bool first_arg_return = calling_convention_does_first_arg_return(fn_type_id->cc) &&
11201120 handle_is_ptr(fn_type_id->return_type);
11211121 bool is_async = fn_type_id->cc == CallingConventionAsync;
1122 bool is_c_abi = fn_type_id->cc == CallingConventionC;
11221123 bool prefix_arg_error_return_trace = g->have_err_ret_tracing && fn_type_can_fail(fn_type_id);
11231124 // +1 for maybe making the first argument the return value
11241125 // +1 for maybe first argument the error return trace
11251126 // +2 for maybe arguments async allocator and error code pointer
1126 LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(4 + fn_type_id->param_count);
1127 ZigList<LLVMTypeRef> gen_param_types = {};
11271128 // +1 because 0 is the return type and
11281129 // +1 for maybe making first arg ret val and
11291130 // +1 for maybe first argument the error return trace
11301131 // +2 for maybe arguments async allocator and error code pointer
1131 ZigLLVMDIType **param_di_types = allocate<ZigLLVMDIType*>(5 + fn_type_id->param_count);
1132 param_di_types[0] = fn_type_id->return_type->di_type;
1133 size_t gen_param_index = 0;
1132 ZigList<ZigLLVMDIType *> param_di_types = {};
1133 param_di_types.append(fn_type_id->return_type->di_type);
11341134 ZigType *gen_return_type;
11351135 if (is_async) {
11361136 gen_return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
......@@ -1138,10 +1138,8 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
11381138 gen_return_type = g->builtin_types.entry_void;
11391139 } else if (first_arg_return) {
11401140 ZigType *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false);
1141 gen_param_types[gen_param_index] = gen_type->type_ref;
1142 gen_param_index += 1;
1143 // after the gen_param_index += 1 because 0 is the return type
1144 param_di_types[gen_param_index] = gen_type->di_type;
1141 gen_param_types.append(gen_type->type_ref);
1142 param_di_types.append(gen_type->di_type);
11451143 gen_return_type = g->builtin_types.entry_void;
11461144 } else {
11471145 gen_return_type = fn_type_id->return_type;
......@@ -1150,28 +1148,22 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
11501148
11511149 if (prefix_arg_error_return_trace) {
11521150 ZigType *gen_type = get_ptr_to_stack_trace_type(g);
1153 gen_param_types[gen_param_index] = gen_type->type_ref;
1154 gen_param_index += 1;
1155 // after the gen_param_index += 1 because 0 is the return type
1156 param_di_types[gen_param_index] = gen_type->di_type;
1151 gen_param_types.append(gen_type->type_ref);
1152 param_di_types.append(gen_type->di_type);
11571153 }
11581154 if (is_async) {
11591155 {
11601156 // async allocator param
11611157 ZigType *gen_type = fn_type_id->async_allocator_type;
1162 gen_param_types[gen_param_index] = gen_type->type_ref;
1163 gen_param_index += 1;
1164 // after the gen_param_index += 1 because 0 is the return type
1165 param_di_types[gen_param_index] = gen_type->di_type;
1158 gen_param_types.append(gen_type->type_ref);
1159 param_di_types.append(gen_type->di_type);
11661160 }
11671161
11681162 {
11691163 // error code pointer
11701164 ZigType *gen_type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false);
1171 gen_param_types[gen_param_index] = gen_type->type_ref;
1172 gen_param_index += 1;
1173 // after the gen_param_index += 1 because 0 is the return type
1174 param_di_types[gen_param_index] = gen_type->di_type;
1165 gen_param_types.append(gen_type->type_ref);
1166 param_di_types.append(gen_type->di_type);
11751167 }
11761168 }
11771169
......@@ -1187,6 +1179,9 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
11871179 if ((err = ensure_complete_type(g, type_entry)))
11881180 return g->builtin_types.entry_invalid;
11891181
1182 if (is_c_abi)
1183 continue;
1184
11901185 if (type_has_bits(type_entry)) {
11911186 ZigType *gen_type;
11921187 if (handle_is_ptr(type_entry)) {
......@@ -1195,23 +1190,28 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
11951190 } else {
11961191 gen_type = type_entry;
11971192 }
1198 gen_param_types[gen_param_index] = gen_type->type_ref;
1199 gen_param_info->gen_index = gen_param_index;
1193 gen_param_info->gen_index = gen_param_types.length;
12001194 gen_param_info->type = gen_type;
1195 gen_param_types.append(gen_type->type_ref);
12011196
1202 gen_param_index += 1;
1203
1204 // after the gen_param_index += 1 because 0 is the return type
1205 param_di_types[gen_param_index] = gen_type->di_type;
1197 param_di_types.append(gen_type->di_type);
12061198 }
12071199 }
12081200
1209 fn_type->data.fn.gen_param_count = gen_param_index;
1201 if (is_c_abi) {
1202 FnWalk fn_walk = {};
1203 fn_walk.id = FnWalkIdTypes;
1204 fn_walk.data.types.param_di_types = &param_di_types;
1205 fn_walk.data.types.gen_param_types = &gen_param_types;
1206 walk_function_params(g, fn_type, &fn_walk);
1207 }
1208
1209 fn_type->data.fn.gen_param_count = gen_param_types.length;
12101210
12111211 fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref,
1212 gen_param_types, (unsigned int)gen_param_index, fn_type_id->is_var_args);
1212 gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args);
12131213 fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0);
1214 fn_type->di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types, (int)(gen_param_index + 1), 0);
1214 fn_type->di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0);
12151215 }
12161216
12171217 g->fn_type_table.put(&fn_type->data.fn.fn_type_id, fn_type);
src/analyze.hpp+3
......@@ -210,4 +210,7 @@ ZigType *get_primitive_type(CodeGen *g, Buf *name);
210210bool calling_convention_allows_zig_types(CallingConvention cc);
211211const char *calling_convention_name(CallingConvention cc);
212212
213void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk);
214
215
213216#endif
src/codegen.cpp+420-99
......@@ -466,7 +466,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
466466 }
467467
468468 bool external_linkage = linkage != GlobalLinkageIdInternal;
469 if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionStdcall && external_linkage &&
469 CallingConvention cc = fn_table_entry->type_entry->data.fn.fn_type_id.cc;
470 if (cc == CallingConventionStdcall && external_linkage &&
470471 g->zig_target.arch.arch == ZigLLVM_x86)
471472 {
472473 // prevent llvm name mangling
......@@ -510,17 +511,17 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
510511 break;
511512 }
512513
513 if (fn_type->data.fn.fn_type_id.cc == CallingConventionNaked) {
514 if (cc == CallingConventionNaked) {
514515 addLLVMFnAttr(fn_table_entry->llvm_value, "naked");
515516 } else {
516517 LLVMSetFunctionCallConv(fn_table_entry->llvm_value, get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc));
517518 }
518 if (fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) {
519 if (cc == CallingConventionAsync) {
519520 addLLVMFnAttr(fn_table_entry->llvm_value, "optnone");
520521 addLLVMFnAttr(fn_table_entry->llvm_value, "noinline");
521522 }
522523
523 bool want_cold = fn_table_entry->is_cold || fn_type->data.fn.fn_type_id.cc == CallingConventionCold;
524 bool want_cold = fn_table_entry->is_cold || cc == CallingConventionCold;
524525 if (want_cold) {
525526 ZigLLVMAddFunctionAttrCold(fn_table_entry->llvm_value);
526527 }
......@@ -576,37 +577,16 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
576577 // nothing to do
577578 } else if (type_is_codegen_pointer(return_type)) {
578579 addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");
579 } else if (handle_is_ptr(return_type) &&
580 calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc))
581 {
580 } else if (handle_is_ptr(return_type) && calling_convention_does_first_arg_return(cc)) {
582581 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
583582 addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull");
584583 }
585584
586
587585 // set parameter attributes
588 for (size_t param_i = 0; param_i < fn_type->data.fn.fn_type_id.param_count; param_i += 1) {
589 FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
590 size_t gen_index = gen_info->gen_index;
591 bool is_byval = gen_info->is_byval;
592
593 if (gen_index == SIZE_MAX) {
594 continue;
595 }
596
597 FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[param_i];
598
599 ZigType *param_type = gen_info->type;
600 if (param_info->is_noalias) {
601 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "noalias");
602 }
603 if ((param_type->id == ZigTypeIdPointer && param_type->data.pointer.is_const) || is_byval) {
604 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "readonly");
605 }
606 if (param_type->id == ZigTypeIdPointer) {
607 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "nonnull");
608 }
609 }
586 FnWalk fn_walk = {};
587 fn_walk.id = FnWalkIdAttrs;
588 fn_walk.data.attrs.fn = fn_table_entry;
589 walk_function_params(g, fn_type, &fn_walk);
610590
611591 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
612592 if (err_ret_trace_arg_index != UINT32_MAX) {
......@@ -1858,6 +1838,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty
18581838}
18591839
18601840static void gen_var_debug_decl(CodeGen *g, ZigVar *var) {
1841 assert(var->di_loc_var != nullptr);
18611842 AstNode *source_node = var->decl_node;
18621843 ZigLLVMDILocation *debug_loc = ZigLLVMGetDebugLoc((unsigned)source_node->line + 1,
18631844 (unsigned)source_node->column + 1, get_di_scope(g, var->parent_scope));
......@@ -1888,6 +1869,381 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
18881869 return instruction->llvm_value;
18891870}
18901871
1872ATTRIBUTE_NORETURN
1873static void report_errors_and_exit(CodeGen *g) {
1874 assert(g->errors.length != 0);
1875 for (size_t i = 0; i < g->errors.length; i += 1) {
1876 ErrorMsg *err = g->errors.at(i);
1877 print_err_msg(err, g->err_color);
1878 }
1879 exit(1);
1880}
1881
1882static void report_errors_and_maybe_exit(CodeGen *g) {
1883 if (g->errors.length != 0) {
1884 report_errors_and_exit(g);
1885 }
1886}
1887
1888ATTRIBUTE_NORETURN
1889static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) {
1890 ErrorMsg *msg = add_node_error(g, source_node,
1891 buf_sprintf("TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481"));
1892 add_error_note(g, msg, source_node,
1893 buf_sprintf("pointers, integers, floats, bools, and enums work on all targets"));
1894 report_errors_and_exit(g);
1895}
1896
1897static bool type_is_c_abi_int(CodeGen *g, ZigType *ty) {
1898 size_t ty_size = type_size(g, ty);
1899 if (ty_size > g->pointer_size_bytes)
1900 return false;
1901 return (ty->id == ZigTypeIdInt ||
1902 ty->id == ZigTypeIdFloat ||
1903 ty->id == ZigTypeIdBool ||
1904 ty->id == ZigTypeIdEnum ||
1905 get_codegen_ptr_type(ty) != nullptr);
1906}
1907
1908static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) {
1909 assert(alignment > 0);
1910 LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name);
1911 LLVMSetAlignment(result, alignment);
1912 return result;
1913}
1914
1915static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk, size_t src_i) {
1916 // Initialized from the type for some walks, but because of C var args,
1917 // initialized based on callsite instructions for that one.
1918 FnTypeParamInfo *param_info = nullptr;
1919 ZigType *ty;
1920 ZigType *dest_ty = nullptr;
1921 AstNode *source_node = nullptr;
1922 LLVMValueRef val;
1923 LLVMValueRef llvm_fn;
1924 unsigned di_arg_index;
1925 ZigVar *var;
1926 switch (fn_walk->id) {
1927 case FnWalkIdAttrs:
1928 if (src_i >= fn_type->data.fn.fn_type_id.param_count)
1929 return false;
1930 param_info = &fn_type->data.fn.fn_type_id.param_info[src_i];
1931 ty = param_info->type;
1932 source_node = fn_walk->data.attrs.fn->proto_node;
1933 llvm_fn = fn_walk->data.attrs.fn->llvm_value;
1934 break;
1935 case FnWalkIdCall: {
1936 if (src_i >= fn_walk->data.call.inst->arg_count)
1937 return false;
1938 IrInstruction *arg = fn_walk->data.call.inst->args[src_i];
1939 ty = arg->value.type;
1940 source_node = arg->source_node;
1941 val = ir_llvm_value(g, arg);
1942 break;
1943 }
1944 case FnWalkIdTypes:
1945 if (src_i >= fn_type->data.fn.fn_type_id.param_count)
1946 return false;
1947 param_info = &fn_type->data.fn.fn_type_id.param_info[src_i];
1948 ty = param_info->type;
1949 break;
1950 case FnWalkIdVars:
1951 assert(src_i < fn_type->data.fn.fn_type_id.param_count);
1952 param_info = &fn_type->data.fn.fn_type_id.param_info[src_i];
1953 ty = param_info->type;
1954 var = fn_walk->data.vars.var;
1955 source_node = var->decl_node;
1956 llvm_fn = fn_walk->data.vars.llvm_fn;
1957 break;
1958 case FnWalkIdInits:
1959 if (src_i >= fn_type->data.fn.fn_type_id.param_count)
1960 return false;
1961 param_info = &fn_type->data.fn.fn_type_id.param_info[src_i];
1962 ty = param_info->type;
1963 var = fn_walk->data.inits.fn->variable_list.at(src_i);
1964 source_node = fn_walk->data.inits.fn->proto_node;
1965 llvm_fn = fn_walk->data.inits.llvm_fn;
1966 break;
1967 }
1968
1969 if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat ||
1970 ty->id == ZigTypeIdInt // TODO investigate if we need to change this
1971 ) {
1972 switch (fn_walk->id) {
1973 case FnWalkIdAttrs: {
1974 ZigType *ptr_type = get_codegen_ptr_type(ty);
1975 if (ptr_type != nullptr) {
1976 if (ty->id != ZigTypeIdOptional) {
1977 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
1978 }
1979 if (ptr_type->data.pointer.is_const) {
1980 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "readonly");
1981 }
1982 if (param_info->is_noalias) {
1983 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "noalias");
1984 }
1985 }
1986 fn_walk->data.attrs.gen_i += 1;
1987 break;
1988 }
1989 case FnWalkIdCall:
1990 fn_walk->data.call.gen_param_values->append(val);
1991 break;
1992 case FnWalkIdTypes:
1993 fn_walk->data.types.gen_param_types->append(ty->type_ref);
1994 fn_walk->data.types.param_di_types->append(ty->di_type);
1995 break;
1996 case FnWalkIdVars: {
1997 var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes);
1998 di_arg_index = fn_walk->data.vars.gen_i;
1999 fn_walk->data.vars.gen_i += 1;
2000 dest_ty = ty;
2001 goto var_ok;
2002 }
2003 case FnWalkIdInits:
2004 clear_debug_source_node(g);
2005 gen_store_untyped(g, LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i), var->value_ref, var->align_bytes, false);
2006 if (var->decl_node) {
2007 gen_var_debug_decl(g, var);
2008 }
2009 fn_walk->data.inits.gen_i += 1;
2010 break;
2011 }
2012 return true;
2013 }
2014
2015 // Arrays are just pointers
2016 if (ty->id == ZigTypeIdArray) {
2017 assert(handle_is_ptr(ty));
2018 switch (fn_walk->id) {
2019 case FnWalkIdAttrs:
2020 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
2021 fn_walk->data.attrs.gen_i += 1;
2022 break;
2023 case FnWalkIdCall:
2024 fn_walk->data.call.gen_param_values->append(val);
2025 break;
2026 case FnWalkIdTypes: {
2027 ZigType *gen_type = get_pointer_to_type(g, ty, true);
2028 fn_walk->data.types.gen_param_types->append(gen_type->type_ref);
2029 fn_walk->data.types.param_di_types->append(gen_type->di_type);
2030 break;
2031 }
2032 case FnWalkIdVars: {
2033 var->value_ref = LLVMGetParam(llvm_fn, fn_walk->data.vars.gen_i);
2034 di_arg_index = fn_walk->data.vars.gen_i;
2035 dest_ty = get_pointer_to_type(g, ty, false);
2036 fn_walk->data.vars.gen_i += 1;
2037 goto var_ok;
2038 }
2039 case FnWalkIdInits:
2040 if (var->decl_node) {
2041 gen_var_debug_decl(g, var);
2042 }
2043 fn_walk->data.inits.gen_i += 1;
2044 break;
2045 }
2046 return true;
2047 }
2048
2049 if (g->zig_target.arch.arch == ZigLLVM_x86_64) {
2050 size_t ty_size = type_size(g, ty);
2051 if (ty->id == ZigTypeIdStruct || ty->id == ZigTypeIdUnion) {
2052 assert(handle_is_ptr(ty));
2053
2054 // "If the size of an object is larger than four eightbytes, or it contains unaligned
2055 // fields, it has class MEMORY"
2056 if (ty_size > 32) {
2057 switch (fn_walk->id) {
2058 case FnWalkIdAttrs:
2059 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "byval");
2060 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
2061 fn_walk->data.attrs.gen_i += 1;
2062 break;
2063 case FnWalkIdCall:
2064 fn_walk->data.call.gen_param_values->append(val);
2065 break;
2066 case FnWalkIdTypes: {
2067 ZigType *gen_type = get_pointer_to_type(g, ty, true);
2068 fn_walk->data.types.gen_param_types->append(gen_type->type_ref);
2069 fn_walk->data.types.param_di_types->append(gen_type->di_type);
2070 break;
2071 }
2072 case FnWalkIdVars: {
2073 di_arg_index = fn_walk->data.vars.gen_i;
2074 var->value_ref = LLVMGetParam(llvm_fn, fn_walk->data.vars.gen_i);
2075 dest_ty = get_pointer_to_type(g, ty, false);
2076 fn_walk->data.vars.gen_i += 1;
2077 goto var_ok;
2078 }
2079 case FnWalkIdInits:
2080 if (var->decl_node) {
2081 gen_var_debug_decl(g, var);
2082 }
2083 fn_walk->data.inits.gen_i += 1;
2084 break;
2085 }
2086 return true;
2087 }
2088 }
2089 if (ty->id == ZigTypeIdStruct) {
2090 assert(handle_is_ptr(ty));
2091 // "If the size of the aggregate exceeds a single eightbyte, each is classified
2092 // separately. Each eightbyte gets initialized to class NO_CLASS."
2093 if (ty_size <= 8) {
2094 bool contains_int = false;
2095 for (size_t i = 0; i < ty->data.structure.src_field_count; i += 1) {
2096 if (type_is_c_abi_int(g, ty->data.structure.fields[i].type_entry)) {
2097 contains_int = true;
2098 break;
2099 }
2100 }
2101 if (contains_int) {
2102 switch (fn_walk->id) {
2103 case FnWalkIdAttrs:
2104 fn_walk->data.attrs.gen_i += 1;
2105 break;
2106 case FnWalkIdCall: {
2107 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
2108 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, val, ptr_to_int_type_ref, "");
2109 LLVMValueRef loaded = LLVMBuildLoad(g->builder, bitcasted, "");
2110 fn_walk->data.call.gen_param_values->append(loaded);
2111 break;
2112 }
2113 case FnWalkIdTypes: {
2114 ZigType *gen_type = get_int_type(g, false, ty_size * 8);
2115 fn_walk->data.types.gen_param_types->append(gen_type->type_ref);
2116 fn_walk->data.types.param_di_types->append(gen_type->di_type);
2117 break;
2118 }
2119 case FnWalkIdVars: {
2120 di_arg_index = fn_walk->data.vars.gen_i;
2121 var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes);
2122 fn_walk->data.vars.gen_i += 1;
2123 dest_ty = ty;
2124 goto var_ok;
2125 }
2126 case FnWalkIdInits: {
2127 clear_debug_source_node(g);
2128 LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i);
2129 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
2130 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, "");
2131 gen_store_untyped(g, arg, bitcasted, var->align_bytes, false);
2132 if (var->decl_node) {
2133 gen_var_debug_decl(g, var);
2134 }
2135 fn_walk->data.inits.gen_i += 1;
2136 break;
2137 }
2138 }
2139 return true;
2140 }
2141 }
2142 }
2143 }
2144 if (source_node != nullptr) {
2145 give_up_with_c_abi_error(g, source_node);
2146 }
2147 // otherwise allow codegen code to report a compile error
2148 return false;
2149
2150var_ok:
2151 if (dest_ty != nullptr && var->decl_node) {
2152 // arg index + 1 because the 0 index is return value
2153 var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
2154 buf_ptr(&var->name), fn_walk->data.vars.import->di_file,
2155 (unsigned)(var->decl_node->line + 1),
2156 dest_ty->di_type, !g->strip_debug_symbols, 0, di_arg_index + 1);
2157 }
2158 return true;
2159}
2160
2161void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
2162 CallingConvention cc = fn_type->data.fn.fn_type_id.cc;
2163 if (cc == CallingConventionC) {
2164 size_t src_i = 0;
2165 for (;;) {
2166 if (!iter_function_params_c_abi(g, fn_type, fn_walk, src_i))
2167 break;
2168 src_i += 1;
2169 }
2170 return;
2171 }
2172 if (fn_walk->id == FnWalkIdCall) {
2173 IrInstructionCall *instruction = fn_walk->data.call.inst;
2174 bool is_var_args = fn_walk->data.call.is_var_args;
2175 for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) {
2176 IrInstruction *param_instruction = instruction->args[call_i];
2177 ZigType *param_type = param_instruction->value.type;
2178 if (is_var_args || type_has_bits(param_type)) {
2179 LLVMValueRef param_value = ir_llvm_value(g, param_instruction);
2180 assert(param_value);
2181 fn_walk->data.call.gen_param_values->append(param_value);
2182 }
2183 }
2184 return;
2185 }
2186 size_t next_var_i = 0;
2187 for (size_t param_i = 0; param_i < fn_type->data.fn.fn_type_id.param_count; param_i += 1) {
2188 FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
2189 size_t gen_index = gen_info->gen_index;
2190
2191 if (gen_index == SIZE_MAX) {
2192 continue;
2193 }
2194
2195 switch (fn_walk->id) {
2196 case FnWalkIdAttrs: {
2197 LLVMValueRef llvm_fn = fn_walk->data.attrs.fn->llvm_value;
2198 bool is_byval = gen_info->is_byval;
2199 FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[param_i];
2200
2201 ZigType *param_type = gen_info->type;
2202 if (param_info->is_noalias) {
2203 addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "noalias");
2204 }
2205 if ((param_type->id == ZigTypeIdPointer && param_type->data.pointer.is_const) || is_byval) {
2206 addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "readonly");
2207 }
2208 if (param_type->id == ZigTypeIdPointer) {
2209 addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "nonnull");
2210 }
2211 break;
2212 }
2213 case FnWalkIdInits: {
2214 ZigFn *fn_table_entry = fn_walk->data.inits.fn;
2215 LLVMValueRef llvm_fn = fn_table_entry->llvm_value;
2216 ZigVar *variable = fn_table_entry->variable_list.at(next_var_i);
2217 assert(variable->src_arg_index != SIZE_MAX);
2218 next_var_i += 1;
2219
2220 assert(variable);
2221 assert(variable->value_ref);
2222
2223 if (!handle_is_ptr(variable->value->type)) {
2224 clear_debug_source_node(g);
2225 gen_store_untyped(g, LLVMGetParam(llvm_fn, (unsigned)variable->gen_arg_index), variable->value_ref,
2226 variable->align_bytes, false);
2227 }
2228
2229 if (variable->decl_node) {
2230 gen_var_debug_decl(g, variable);
2231 }
2232 break;
2233 }
2234 case FnWalkIdCall:
2235 // handled before for loop
2236 zig_unreachable();
2237 case FnWalkIdTypes:
2238 // Not called for non-c-abi
2239 zig_unreachable();
2240 case FnWalkIdVars:
2241 // iter_function_params_c_abi is called directly for this one
2242 zig_unreachable();
2243 }
2244 }
2245}
2246
18912247static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable,
18922248 IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction)
18932249{
......@@ -3128,40 +3484,31 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
31283484 ZigType *src_return_type = fn_type_id->return_type;
31293485 bool ret_has_bits = type_has_bits(src_return_type);
31303486
3487 CallingConvention cc = fn_type->data.fn.fn_type_id.cc;
3488
31313489 bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type) &&
3132 calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc);
3490 calling_convention_does_first_arg_return(cc);
31333491 bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id);
3134 // +2 for the async args
3135 size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0) + (prefix_arg_err_ret_stack ? 1 : 0) + 2;
31363492 bool is_var_args = fn_type_id->is_var_args;
3137 LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
3138 size_t gen_param_index = 0;
3493 ZigList<LLVMValueRef> gen_param_values = {};
31393494 if (first_arg_ret) {
3140 gen_param_values[gen_param_index] = instruction->tmp_ptr;
3141 gen_param_index += 1;
3495 gen_param_values.append(instruction->tmp_ptr);
31423496 }
31433497 if (prefix_arg_err_ret_stack) {
3144 gen_param_values[gen_param_index] = get_cur_err_ret_trace_val(g, instruction->base.scope);
3145 gen_param_index += 1;
3498 gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope));
31463499 }
31473500 if (instruction->is_async) {
3148 gen_param_values[gen_param_index] = ir_llvm_value(g, instruction->async_allocator);
3149 gen_param_index += 1;
3501 gen_param_values.append(ir_llvm_value(g, instruction->async_allocator));
31503502
31513503 LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, "");
3152 gen_param_values[gen_param_index] = err_val_ptr;
3153 gen_param_index += 1;
3154 }
3155 for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) {
3156 IrInstruction *param_instruction = instruction->args[call_i];
3157 ZigType *param_type = param_instruction->value.type;
3158 if (is_var_args || type_has_bits(param_type)) {
3159 LLVMValueRef param_value = ir_llvm_value(g, param_instruction);
3160 assert(param_value);
3161 gen_param_values[gen_param_index] = param_value;
3162 gen_param_index += 1;
3163 }
3504 gen_param_values.append(err_val_ptr);
31643505 }
3506 FnWalk fn_walk = {};
3507 fn_walk.id = FnWalkIdCall;
3508 fn_walk.data.call.inst = instruction;
3509 fn_walk.data.call.is_var_args = is_var_args;
3510 fn_walk.data.call.gen_param_values = &gen_param_values;
3511 walk_function_params(g, fn_type, &fn_walk);
31653512
31663513 ZigLLVM_FnInline fn_inline;
31673514 switch (instruction->fn_inline) {
......@@ -3176,12 +3523,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
31763523 break;
31773524 }
31783525
3179 LLVMCallConv llvm_cc = get_llvm_cc(g, fn_type->data.fn.fn_type_id.cc);
3526 LLVMCallConv llvm_cc = get_llvm_cc(g, cc);
31803527 LLVMValueRef result;
31813528
31823529 if (instruction->new_stack == nullptr) {
31833530 result = ZigLLVMBuildCall(g->builder, fn_val,
3184 gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
3531 gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, "");
31853532 } else {
31863533 LLVMValueRef stacksave_fn_val = get_stacksave_fn_val(g);
31873534 LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g);
......@@ -3190,7 +3537,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
31903537 LLVMValueRef old_stack_ref = LLVMBuildCall(g->builder, stacksave_fn_val, nullptr, 0, "");
31913538 gen_set_stack_pointer(g, new_stack_addr);
31923539 result = ZigLLVMBuildCall(g->builder, fn_val,
3193 gen_param_values, (unsigned)gen_param_index, llvm_cc, fn_inline, "");
3540 gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, "");
31943541 LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, "");
31953542 }
31963543
......@@ -5721,13 +6068,6 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,
57216068 // TODO ^^ make an actual global variable
57226069}
57236070
5724static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) {
5725 assert(alignment > 0);
5726 LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name);
5727 LLVMSetAlignment(result, alignment);
5728 return result;
5729}
5730
57316071static void ensure_cache_dir(CodeGen *g) {
57326072 int err;
57336073 if ((err = os_make_path(&g->cache_dir))) {
......@@ -5735,16 +6075,6 @@ static void ensure_cache_dir(CodeGen *g) {
57356075 }
57366076}
57376077
5738static void report_errors_and_maybe_exit(CodeGen *g) {
5739 if (g->errors.length != 0) {
5740 for (size_t i = 0; i < g->errors.length; i += 1) {
5741 ErrorMsg *err = g->errors.at(i);
5742 print_err_msg(err, g->err_color);
5743 }
5744 exit(1);
5745 }
5746}
5747
57486078static void validate_inline_fns(CodeGen *g) {
57496079 for (size_t i = 0; i < g->inline_fns.length; i += 1) {
57506080 ZigFn *fn_entry = g->inline_fns.at(i);
......@@ -5865,6 +6195,8 @@ static void do_code_gen(CodeGen *g) {
58656195 // Generate function definitions.
58666196 for (size_t fn_i = 0; fn_i < g->fn_defs.length; fn_i += 1) {
58676197 ZigFn *fn_table_entry = g->fn_defs.at(fn_i);
6198 CallingConvention cc = fn_table_entry->type_entry->data.fn.fn_type_id.cc;
6199 bool is_c_abi = cc == CallingConventionC;
58686200
58696201 LLVMValueRef fn = fn_llvm_value(g, fn_table_entry);
58706202 g->cur_fn = fn_table_entry;
......@@ -5888,7 +6220,7 @@ static void do_code_gen(CodeGen *g) {
58886220 }
58896221
58906222 // error return tracing setup
5891 bool is_async = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
6223 bool is_async = cc == CallingConventionAsync;
58926224 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;
58936225 LLVMValueRef err_ret_array_val = nullptr;
58946226 if (have_err_ret_trace_stack) {
......@@ -5948,6 +6280,12 @@ static void do_code_gen(CodeGen *g) {
59486280 ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base);
59496281
59506282 // create debug variable declarations for variables and allocate all local variables
6283 FnWalk fn_walk_var = {};
6284 fn_walk_var.id = FnWalkIdVars;
6285 fn_walk_var.data.vars.import = import;
6286 fn_walk_var.data.vars.fn = fn_table_entry;
6287 fn_walk_var.data.vars.llvm_fn = fn;
6288 fn_walk_var.data.vars.gen_i = 0;
59516289 for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) {
59526290 ZigVar *var = fn_table_entry->variable_list.at(var_i);
59536291
......@@ -5966,6 +6304,9 @@ static void do_code_gen(CodeGen *g) {
59666304 buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1),
59676305 var->value->type->di_type, !g->strip_debug_symbols, 0);
59686306
6307 } else if (is_c_abi) {
6308 fn_walk_var.data.vars.var = var;
6309 iter_function_params_c_abi(g, fn_table_entry->type_entry, &fn_walk_var, var->src_arg_index);
59696310 } else {
59706311 assert(var->gen_arg_index != SIZE_MAX);
59716312 ZigType *gen_type;
......@@ -6017,33 +6358,13 @@ static void do_code_gen(CodeGen *g) {
60176358 gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
60186359 }
60196360
6020 FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;
6021
60226361 // create debug variable declarations for parameters
60236362 // rely on the first variables in the variable_list being parameters.
6024 size_t next_var_i = 0;
6025 for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
6026 FnGenParamInfo *info = &fn_table_entry->type_entry->data.fn.gen_param_info[param_i];
6027 if (info->gen_index == SIZE_MAX)
6028 continue;
6029
6030 ZigVar *variable = fn_table_entry->variable_list.at(next_var_i);
6031 assert(variable->src_arg_index != SIZE_MAX);
6032 next_var_i += 1;
6033
6034 assert(variable);
6035 assert(variable->value_ref);
6036
6037 if (!handle_is_ptr(variable->value->type)) {
6038 clear_debug_source_node(g);
6039 gen_store_untyped(g, LLVMGetParam(fn, (unsigned)variable->gen_arg_index), variable->value_ref,
6040 variable->align_bytes, false);
6041 }
6042
6043 if (variable->decl_node) {
6044 gen_var_debug_decl(g, variable);
6045 }
6046 }
6363 FnWalk fn_walk_init = {};
6364 fn_walk_init.id = FnWalkIdInits;
6365 fn_walk_init.data.inits.fn = fn_table_entry;
6366 fn_walk_init.data.inits.llvm_fn = fn;
6367 walk_function_params(g, fn_table_entry->type_entry, &fn_walk_init);
60476368
60486369 ir_render(g, fn_table_entry);
60496370
src/codegen.hpp-1
......@@ -61,5 +61,4 @@ void codegen_translate_c(CodeGen *g, Buf *path);
6161
6262Buf *codegen_generate_builtin_source(CodeGen *g);
6363
64
6564#endif
std/build.zig+27
......@@ -48,6 +48,12 @@ pub const Builder = struct {
4848 cache_root: []const u8,
4949 release_mode: ?builtin.Mode,
5050
51 pub const CStd = enum {
52 C89,
53 C99,
54 C11,
55 };
56
5157 const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8);
5258 const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8);
5359
......@@ -817,6 +823,7 @@ pub const LibExeObjStep = struct {
817823 frameworks: BufSet,
818824 verbose_link: bool,
819825 no_rosegment: bool,
826 c_std: Builder.CStd,
820827
821828 // zig only stuff
822829 root_src: ?[]const u8,
......@@ -918,6 +925,7 @@ pub const LibExeObjStep = struct {
918925 .object_src = undefined,
919926 .disable_libc = true,
920927 .build_options_contents = std.Buffer.initSize(builder.allocator, 0) catch unreachable,
928 .c_std = Builder.CStd.C99,
921929 };
922930 self.computeOutFileNames();
923931 return self;
......@@ -952,6 +960,7 @@ pub const LibExeObjStep = struct {
952960 .disable_libc = false,
953961 .is_zig = false,
954962 .linker_script = null,
963 .c_std = Builder.CStd.C99,
955964
956965 .root_src = undefined,
957966 .verbose_link = false,
......@@ -1392,6 +1401,13 @@ pub const LibExeObjStep = struct {
13921401
13931402 const is_darwin = self.target.isDarwin();
13941403
1404 const c_std_arg = switch (self.c_std) {
1405 Builder.CStd.C89 => "-std=c89",
1406 Builder.CStd.C99 => "-std=c99",
1407 Builder.CStd.C11 => "-std=c11",
1408 };
1409 try cc_args.append(c_std_arg);
1410
13951411 switch (self.kind) {
13961412 Kind.Obj => {
13971413 cc_args.append("-c") catch unreachable;
......@@ -1678,6 +1694,17 @@ pub const TestStep = struct {
16781694 self.filter = text;
16791695 }
16801696
1697 pub fn addObject(self: *TestStep, obj: *LibExeObjStep) void {
1698 assert(obj.kind == LibExeObjStep.Kind.Obj);
1699
1700 self.step.dependOn(&obj.step);
1701
1702 self.object_files.append(obj.getOutputPath()) catch unreachable;
1703
1704 // TODO should be some kind of isolated directory that only has this header in it
1705 self.include_dirs.append(self.builder.cache_root) catch unreachable;
1706 }
1707
16811708 pub fn addObjectFile(self: *TestStep, path: []const u8) void {
16821709 self.object_files.append(path) catch unreachable;
16831710 }
test/build_examples.zig+6
......@@ -28,4 +28,10 @@ pub fn addCases(cases: *tests.BuildExamplesContext) void {
2828 // TODO figure out how to make this work on darwin - probably libSystem has dlopen/dlsym in it
2929 cases.addBuildFile("test/standalone/load_dynamic_library/build.zig");
3030 }
31
32 if (!is_windows // TODO support compiling C files on windows with zig build system
33 and builtin.arch == builtin.Arch.x86_64 // TODO add C ABI support for other architectures
34 ) {
35 cases.addBuildFile("test/stage1/c_abi/build.zig");
36 }
3137}
test/gen_h.zig+24-4
......@@ -20,6 +20,9 @@ pub fn addCases(cases: *tests.GenHContext) void {
2020 \\ A: i32,
2121 \\ B: f32,
2222 \\ C: bool,
23 \\ D: u64,
24 \\ E: u64,
25 \\ F: u64,
2326 \\};
2427 \\export fn entry(foo: Foo) void { }
2528 ,
......@@ -27,6 +30,9 @@ pub fn addCases(cases: *tests.GenHContext) void {
2730 \\ int32_t A;
2831 \\ float B;
2932 \\ bool C;
33 \\ uint64_t D;
34 \\ uint64_t E;
35 \\ uint64_t F;
3036 \\};
3137 \\
3238 \\TEST_EXPORT void entry(struct Foo foo);
......@@ -34,17 +40,34 @@ pub fn addCases(cases: *tests.GenHContext) void {
3440 );
3541
3642 cases.add("declare union",
43 \\const Big = extern struct {
44 \\ A: u64,
45 \\ B: u64,
46 \\ C: u64,
47 \\ D: u64,
48 \\ E: u64,
49 \\};
3750 \\const Foo = extern union {
3851 \\ A: i32,
3952 \\ B: f32,
4053 \\ C: bool,
54 \\ D: Big,
4155 \\};
42 \\export fn entry(foo: Foo) void { }
56 \\export fn entry(foo: Foo) void {}
4357 ,
58 \\struct Big {
59 \\ uint64_t A;
60 \\ uint64_t B;
61 \\ uint64_t C;
62 \\ uint64_t D;
63 \\ uint64_t E;
64 \\};
65 \\
4466 \\union Foo {
4567 \\ int32_t A;
4668 \\ float B;
4769 \\ bool C;
70 \\ struct Big D;
4871 \\};
4972 \\
5073 \\TEST_EXPORT void entry(union Foo foo);
......@@ -85,7 +108,6 @@ pub fn addCases(cases: *tests.GenHContext) void {
85108 \\export fn a(s: *S) u8 {
86109 \\ return s.a;
87110 \\}
88
89111 ,
90112 \\struct S;
91113 \\TEST_EXPORT uint8_t a(struct S * s);
......@@ -101,7 +123,6 @@ pub fn addCases(cases: *tests.GenHContext) void {
101123 \\export fn a(s: *U) u8 {
102124 \\ return s.A;
103125 \\}
104
105126 ,
106127 \\union U;
107128 \\TEST_EXPORT uint8_t a(union U * s);
......@@ -117,7 +138,6 @@ pub fn addCases(cases: *tests.GenHContext) void {
117138 \\export fn a(s: *E) u8 {
118139 \\ return @enumToInt(s.*);
119140 \\}
120
121141 ,
122142 \\enum E;
123143 \\TEST_EXPORT uint8_t a(enum E * s);
test/stage1/c_abi/build.zig created+17
......@@ -0,0 +1,17 @@
1const Builder = @import("std").build.Builder;
2
3pub fn build(b: *Builder) void {
4 const rel_opts = b.standardReleaseOptions();
5
6 const c_obj = b.addCObject("cfuncs", "cfuncs.c");
7 c_obj.setBuildMode(rel_opts);
8
9 const main = b.addTest("main.zig");
10 main.setBuildMode(rel_opts);
11 main.addObject(c_obj);
12
13 const test_step = b.step("test", "Test the program");
14 test_step.dependOn(&main.step);
15
16 b.default_step.dependOn(test_step);
17}
test/stage1/c_abi/cfuncs.c created+169
......@@ -0,0 +1,169 @@
1#include <inttypes.h>
2#include <stdlib.h>
3#include <stdbool.h>
4
5void zig_panic();
6
7static void assert_or_panic(bool ok) {
8 if (!ok) {
9 zig_panic();
10 }
11}
12
13void zig_u8(uint8_t);
14void zig_u16(uint16_t);
15void zig_u32(uint32_t);
16void zig_u64(uint64_t);
17void zig_i8(int8_t);
18void zig_i16(int16_t);
19void zig_i32(int32_t);
20void zig_i64(int64_t);
21
22void zig_f32(float);
23void zig_f64(double);
24
25void zig_ptr(void *);
26
27void zig_bool(bool);
28
29void zig_array(uint8_t[10]);
30
31struct BigStruct {
32 uint64_t a;
33 uint64_t b;
34 uint64_t c;
35 uint64_t d;
36 uint8_t e;
37};
38
39void zig_big_struct(struct BigStruct);
40
41union BigUnion {
42 struct BigStruct a;
43};
44
45void zig_big_union(union BigUnion);
46
47struct SmallStructInts {
48 uint8_t a;
49 uint8_t b;
50 uint8_t c;
51 uint8_t d;
52};
53void zig_small_struct_ints(struct SmallStructInts);
54
55void run_c_tests(void) {
56 zig_u8(0xff);
57 zig_u16(0xfffe);
58 zig_u32(0xfffffffd);
59 zig_u64(0xfffffffffffffffc);
60
61 zig_i8(-1);
62 zig_i16(-2);
63 zig_i32(-3);
64 zig_i64(-4);
65
66 zig_f32(12.34f);
67 zig_f64(56.78);
68
69 zig_ptr((void*)0xdeadbeefL);
70
71 zig_bool(true);
72
73 // TODO making this non-static crashes for some reason
74 static uint8_t array[10] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
75 zig_array(array);
76
77 {
78 struct BigStruct s = {1, 2, 3, 4, 5};
79 zig_big_struct(s);
80 }
81
82 {
83 struct SmallStructInts s = {1, 2, 3, 4};
84 zig_small_struct_ints(s);
85 }
86}
87
88void c_u8(uint8_t x) {
89 assert_or_panic(x == 0xff);
90}
91
92void c_u16(uint16_t x) {
93 assert_or_panic(x == 0xfffe);
94}
95
96void c_u32(uint32_t x) {
97 assert_or_panic(x == 0xfffffffd);
98}
99
100void c_u64(uint64_t x) {
101 assert_or_panic(x == 0xfffffffffffffffcULL);
102}
103
104void c_i8(int8_t x) {
105 assert_or_panic(x == -1);
106}
107
108void c_i16(int16_t x) {
109 assert_or_panic(x == -2);
110}
111
112void c_i32(int32_t x) {
113 assert_or_panic(x == -3);
114}
115
116void c_i64(int64_t x) {
117 assert_or_panic(x == -4);
118}
119
120void c_f32(float x) {
121 assert_or_panic(x == 12.34f);
122}
123
124void c_f64(double x) {
125 assert_or_panic(x == 56.78);
126}
127
128void c_ptr(void *x) {
129 assert_or_panic(x == (void*)0xdeadbeefL);
130}
131
132void c_bool(bool x) {
133 assert_or_panic(x);
134}
135
136void c_array(uint8_t x[10]) {
137 assert_or_panic(x[0] == '1');
138 assert_or_panic(x[1] == '2');
139 assert_or_panic(x[2] == '3');
140 assert_or_panic(x[3] == '4');
141 assert_or_panic(x[4] == '5');
142 assert_or_panic(x[5] == '6');
143 assert_or_panic(x[6] == '7');
144 assert_or_panic(x[7] == '8');
145 assert_or_panic(x[8] == '9');
146 assert_or_panic(x[9] == '0');
147}
148
149void c_big_struct(struct BigStruct x) {
150 assert_or_panic(x.a == 1);
151 assert_or_panic(x.b == 2);
152 assert_or_panic(x.c == 3);
153 assert_or_panic(x.d == 4);
154 assert_or_panic(x.e == 5);
155}
156
157void c_big_union(union BigUnion x) {
158 assert_or_panic(x.a.a == 1);
159 assert_or_panic(x.a.b == 2);
160 assert_or_panic(x.a.c == 3);
161 assert_or_panic(x.a.d == 4);
162}
163
164void c_small_struct_ints(struct SmallStructInts x) {
165 assert_or_panic(x.a == 1);
166 assert_or_panic(x.b == 2);
167 assert_or_panic(x.c == 3);
168 assert_or_panic(x.d == 4);
169}
test/stage1/c_abi/main.zig created+183
......@@ -0,0 +1,183 @@
1const std = @import("std");
2const assertOrPanic = std.debug.assertOrPanic;
3
4extern fn run_c_tests() void;
5
6export fn zig_panic() noreturn {
7 @panic("zig_panic called from C");
8}
9
10test "C importing Zig ABI Tests" {
11 run_c_tests();
12}
13
14extern fn c_u8(u8) void;
15extern fn c_u16(u16) void;
16extern fn c_u32(u32) void;
17extern fn c_u64(u64) void;
18extern fn c_i8(i8) void;
19extern fn c_i16(i16) void;
20extern fn c_i32(i32) void;
21extern fn c_i64(i64) void;
22
23test "C ABI integers" {
24 c_u8(0xff);
25 c_u16(0xfffe);
26 c_u32(0xfffffffd);
27 c_u64(0xfffffffffffffffc);
28
29 c_i8(-1);
30 c_i16(-2);
31 c_i32(-3);
32 c_i64(-4);
33}
34
35export fn zig_u8(x: u8) void {
36 assertOrPanic(x == 0xff);
37}
38export fn zig_u16(x: u16) void {
39 assertOrPanic(x == 0xfffe);
40}
41export fn zig_u32(x: u32) void {
42 assertOrPanic(x == 0xfffffffd);
43}
44export fn zig_u64(x: u64) void {
45 assertOrPanic(x == 0xfffffffffffffffc);
46}
47export fn zig_i8(x: i8) void {
48 assertOrPanic(x == -1);
49}
50export fn zig_i16(x: i16) void {
51 assertOrPanic(x == -2);
52}
53export fn zig_i32(x: i32) void {
54 assertOrPanic(x == -3);
55}
56export fn zig_i64(x: i64) void {
57 assertOrPanic(x == -4);
58}
59
60extern fn c_f32(f32) void;
61extern fn c_f64(f64) void;
62
63test "C ABI floats" {
64 c_f32(12.34);
65 c_f64(56.78);
66}
67
68export fn zig_f32(x: f32) void {
69 assertOrPanic(x == 12.34);
70}
71export fn zig_f64(x: f64) void {
72 assertOrPanic(x == 56.78);
73}
74
75extern fn c_ptr(*c_void) void;
76
77test "C ABI pointer" {
78 c_ptr(@intToPtr(*c_void, 0xdeadbeef));
79}
80
81export fn zig_ptr(x: *c_void) void {
82 assertOrPanic(@ptrToInt(x) == 0xdeadbeef);
83}
84
85extern fn c_bool(bool) void;
86
87test "C ABI bool" {
88 c_bool(true);
89}
90
91export fn zig_bool(x: bool) void {
92 assertOrPanic(x);
93}
94
95extern fn c_array([10]u8) void;
96
97test "C ABI array" {
98 var array: [10]u8 = "1234567890";
99 c_array(array);
100}
101
102export fn zig_array(x: [10]u8) void {
103 assertOrPanic(std.mem.eql(u8, x, "1234567890"));
104}
105
106const BigStruct = extern struct {
107 a: u64,
108 b: u64,
109 c: u64,
110 d: u64,
111 e: u8,
112};
113extern fn c_big_struct(BigStruct) void;
114
115test "C ABI big struct" {
116 var s = BigStruct{
117 .a = 1,
118 .b = 2,
119 .c = 3,
120 .d = 4,
121 .e = 5,
122 };
123 c_big_struct(s);
124}
125
126export fn zig_big_struct(x: BigStruct) void {
127 assertOrPanic(x.a == 1);
128 assertOrPanic(x.b == 2);
129 assertOrPanic(x.c == 3);
130 assertOrPanic(x.d == 4);
131 assertOrPanic(x.e == 5);
132}
133
134const BigUnion = extern union {
135 a: BigStruct,
136};
137extern fn c_big_union(BigUnion) void;
138
139test "C ABI big union" {
140 var x = BigUnion{
141 .a = BigStruct{
142 .a = 1,
143 .b = 2,
144 .c = 3,
145 .d = 4,
146 .e = 5,
147 },
148 };
149 c_big_union(x);
150}
151
152export fn zig_big_union(x: BigUnion) void {
153 assertOrPanic(x.a.a == 1);
154 assertOrPanic(x.a.b == 2);
155 assertOrPanic(x.a.c == 3);
156 assertOrPanic(x.a.d == 4);
157 assertOrPanic(x.a.e == 5);
158}
159
160const SmallStructInts = extern struct {
161 a: u8,
162 b: u8,
163 c: u8,
164 d: u8,
165};
166extern fn c_small_struct_ints(SmallStructInts) void;
167
168test "C ABI small struct of ints" {
169 var s = SmallStructInts{
170 .a = 1,
171 .b = 2,
172 .c = 3,
173 .d = 4,
174 };
175 c_small_struct_ints(s);
176}
177
178export fn zig_small_struct_ints(x: SmallStructInts) void {
179 assertOrPanic(x.a == 1);
180 assertOrPanic(x.b == 2);
181 assertOrPanic(x.c == 3);
182 assertOrPanic(x.d == 4);
183}