authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-07 11:52:57-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-07 11:52:57-04:00
logbe6cccb3a51512dea011326d9ad30ad495e7c716
tree439f53f2dd82e0e97b6c89db1ca05aefbfdf7170
parenta9a925e500c66b8eb57d619b9b6828c70a13d4c5
signaturelock-open Commit is signed but in an unrecognized format.

stage1: c abi for big struct works


6 files changed, 396 insertions(+), 132 deletions(-)

src/all_types.hpp+24
......@@ -3284,4 +3284,28 @@ enum FloatMode {
32843284 FloatModeStrict,
32853285};
32863286
3287enum FnWalkId {
3288 FnWalkIdAttrs,
3289 FnWalkIdCall,
3290};
3291
3292struct FnWalkAttrs {
3293 ZigFn *fn;
3294 unsigned gen_i;
3295};
3296
3297struct FnWalkCall {
3298 ZigList<LLVMValueRef> *gen_param_values;
3299 IrInstructionCall *inst;
3300 bool is_var_args;
3301};
3302
3303struct FnWalk {
3304 FnWalkId id;
3305 union {
3306 FnWalkAttrs attrs;
3307 FnWalkCall call;
3308 } data;
3309};
3310
32873311#endif
src/analyze.cpp-1
......@@ -1073,7 +1073,6 @@ bool type_is_c_abi_int(CodeGen *g, ZigType *ty) {
10731073}
10741074
10751075// If you edit this function you have to edit the corresponding code:
1076// codegen.cpp:gen_c_abi_param
10771076// analyze.cpp:gen_c_abi_param_type
10781077// codegen.cpp:gen_c_abi_param_var
10791078// codegen.cpp:gen_c_abi_param_var_init
src/codegen.cpp+226-131
......@@ -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) {
......@@ -1888,6 +1868,216 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) {
18881868 return instruction->llvm_value;
18891869}
18901870
1871ATTRIBUTE_NORETURN
1872static void report_errors_and_exit(CodeGen *g) {
1873 assert(g->errors.length != 0);
1874 for (size_t i = 0; i < g->errors.length; i += 1) {
1875 ErrorMsg *err = g->errors.at(i);
1876 print_err_msg(err, g->err_color);
1877 }
1878 exit(1);
1879}
1880
1881static void report_errors_and_maybe_exit(CodeGen *g) {
1882 if (g->errors.length != 0) {
1883 report_errors_and_exit(g);
1884 }
1885}
1886
1887ATTRIBUTE_NORETURN
1888static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) {
1889 ErrorMsg *msg = add_node_error(g, source_node,
1890 buf_sprintf("TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481"));
1891 add_error_note(g, msg, source_node,
1892 buf_sprintf("pointers, integers, floats, bools, and enums work on all targets"));
1893 report_errors_and_exit(g);
1894}
1895
1896static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk, size_t src_i) {
1897 // Initialized from the type for some walks, but because of C var args,
1898 // initialized based on callsite instructions for that one.
1899 FnTypeParamInfo *param_info = nullptr;
1900 ZigType *ty;
1901 AstNode *source_node = nullptr;
1902 LLVMValueRef val;
1903 LLVMValueRef llvm_fn;
1904 switch (fn_walk->id) {
1905 case FnWalkIdAttrs:
1906 if (src_i >= fn_type->data.fn.fn_type_id.param_count)
1907 return false;
1908 param_info = &fn_type->data.fn.fn_type_id.param_info[src_i];
1909 ty = param_info->type;
1910 source_node = fn_walk->data.attrs.fn->proto_node;
1911 llvm_fn = fn_walk->data.attrs.fn->llvm_value;
1912 break;
1913 case FnWalkIdCall: {
1914 if (src_i >= fn_walk->data.call.inst->arg_count)
1915 return false;
1916 IrInstruction *arg = fn_walk->data.call.inst->args[src_i];
1917 ty = arg->value.type;
1918 source_node = arg->source_node;
1919 val = ir_llvm_value(g, arg);
1920 break;
1921 }
1922 }
1923 if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat ||
1924 ty->id == ZigTypeIdInt // TODO investigate if we need to change this
1925 ) {
1926 switch (fn_walk->id) {
1927 case FnWalkIdAttrs: {
1928 ZigType *ptr_type = get_codegen_ptr_type(ty);
1929 if (ptr_type != nullptr) {
1930 if (ty->id != ZigTypeIdOptional) {
1931 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
1932 }
1933 if (ptr_type->data.pointer.is_const) {
1934 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "readonly");
1935 }
1936 if (param_info->is_noalias) {
1937 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "noalias");
1938 }
1939 }
1940 fn_walk->data.attrs.gen_i += 1;
1941 break;
1942 }
1943 case FnWalkIdCall:
1944 fn_walk->data.call.gen_param_values->append(val);
1945 break;
1946 }
1947 return true;
1948 }
1949
1950 // Arrays are just pointers
1951 if (ty->id == ZigTypeIdArray) {
1952 assert(handle_is_ptr(ty));
1953 switch (fn_walk->id) {
1954 case FnWalkIdAttrs:
1955 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
1956 fn_walk->data.attrs.gen_i += 1;
1957 break;
1958 case FnWalkIdCall:
1959 fn_walk->data.call.gen_param_values->append(val);
1960 break;
1961 }
1962 return true;
1963 }
1964
1965 if (g->zig_target.arch.arch == ZigLLVM_x86_64) {
1966 size_t ty_size = type_size(g, ty);
1967 if (ty->id == ZigTypeIdStruct || ty->id == ZigTypeIdUnion) {
1968 assert(handle_is_ptr(ty));
1969
1970 // "If the size of an object is larger than four eightbytes, or it contains unaligned
1971 // fields, it has class MEMORY"
1972 if (ty_size > 32) {
1973 switch (fn_walk->id) {
1974 case FnWalkIdAttrs:
1975 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "byval");
1976 addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
1977 fn_walk->data.attrs.gen_i += 1;
1978 break;
1979 case FnWalkIdCall:
1980 fn_walk->data.call.gen_param_values->append(val);
1981 break;
1982 }
1983 return true;
1984 }
1985 }
1986 if (ty->id == ZigTypeIdStruct) {
1987 assert(handle_is_ptr(ty));
1988 // "If the size of the aggregate exceeds a single eightbyte, each is classified
1989 // separately. Each eightbyte gets initialized to class NO_CLASS."
1990 if (ty_size <= 8) {
1991 bool contains_int = false;
1992 for (size_t i = 0; i < ty->data.structure.src_field_count; i += 1) {
1993 if (type_is_c_abi_int(g, ty->data.structure.fields[i].type_entry)) {
1994 contains_int = true;
1995 break;
1996 }
1997 }
1998 if (contains_int) {
1999 switch (fn_walk->id) {
2000 case FnWalkIdAttrs:
2001 fn_walk->data.attrs.gen_i += 1;
2002 break;
2003 case FnWalkIdCall: {
2004 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
2005 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, val, ptr_to_int_type_ref, "");
2006 LLVMValueRef loaded = LLVMBuildLoad(g->builder, bitcasted, "");
2007 fn_walk->data.call.gen_param_values->append(loaded);
2008 break;
2009 }
2010 }
2011 return true;
2012 }
2013 }
2014 }
2015 }
2016 if (source_node != nullptr) {
2017 give_up_with_c_abi_error(g, source_node);
2018 }
2019 // otherwise allow codegen code to report a compile error
2020 return false;
2021}
2022
2023void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
2024 CallingConvention cc = fn_type->data.fn.fn_type_id.cc;
2025 if (cc == CallingConventionC) {
2026 size_t src_i = 0;
2027 for (;;) {
2028 if (!iter_function_params_c_abi(g, fn_type, fn_walk, src_i))
2029 break;
2030 src_i += 1;
2031 }
2032 return;
2033 }
2034 if (fn_walk->id == FnWalkIdCall) {
2035 IrInstructionCall *instruction = fn_walk->data.call.inst;
2036 bool is_var_args = fn_walk->data.call.is_var_args;
2037 for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) {
2038 IrInstruction *param_instruction = instruction->args[call_i];
2039 ZigType *param_type = param_instruction->value.type;
2040 if (is_var_args || type_has_bits(param_type)) {
2041 LLVMValueRef param_value = ir_llvm_value(g, param_instruction);
2042 assert(param_value);
2043 fn_walk->data.call.gen_param_values->append(param_value);
2044 }
2045 }
2046 return;
2047 }
2048 for (size_t param_i = 0; param_i < fn_type->data.fn.fn_type_id.param_count; param_i += 1) {
2049 FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
2050 size_t gen_index = gen_info->gen_index;
2051
2052 if (gen_index == SIZE_MAX) {
2053 continue;
2054 }
2055
2056 switch (fn_walk->id) {
2057 case FnWalkIdAttrs: {
2058 LLVMValueRef llvm_fn = fn_walk->data.attrs.fn->llvm_value;
2059 bool is_byval = gen_info->is_byval;
2060 FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[param_i];
2061
2062 ZigType *param_type = gen_info->type;
2063 if (param_info->is_noalias) {
2064 addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "noalias");
2065 }
2066 if ((param_type->id == ZigTypeIdPointer && param_type->data.pointer.is_const) || is_byval) {
2067 addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "readonly");
2068 }
2069 if (param_type->id == ZigTypeIdPointer) {
2070 addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "nonnull");
2071 }
2072 break;
2073 }
2074 case FnWalkIdCall:
2075 // handled before for loop
2076 zig_unreachable();
2077 }
2078 }
2079}
2080
18912081static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *executable,
18922082 IrInstructionSaveErrRetAddr *save_err_ret_addr_instruction)
18932083{
......@@ -3111,31 +3301,6 @@ static void set_call_instr_sret(CodeGen *g, LLVMValueRef call_instr) {
31113301 LLVMAddCallSiteAttribute(call_instr, 1, sret_attr);
31123302}
31133303
3114ATTRIBUTE_NORETURN
3115static void report_errors_and_exit(CodeGen *g) {
3116 assert(g->errors.length != 0);
3117 for (size_t i = 0; i < g->errors.length; i += 1) {
3118 ErrorMsg *err = g->errors.at(i);
3119 print_err_msg(err, g->err_color);
3120 }
3121 exit(1);
3122}
3123
3124static void report_errors_and_maybe_exit(CodeGen *g) {
3125 if (g->errors.length != 0) {
3126 report_errors_and_exit(g);
3127 }
3128}
3129
3130ATTRIBUTE_NORETURN
3131static void give_up_with_c_abi_error(CodeGen *g, AstNode *source_node) {
3132 ErrorMsg *msg = add_node_error(g, source_node,
3133 buf_sprintf("TODO: support C ABI for more targets. https://github.com/ziglang/zig/issues/1481"));
3134 add_error_note(g, msg, source_node,
3135 buf_sprintf("pointers, integers, floats, bools, and enums work on all targets"));
3136 report_errors_and_exit(g);
3137}
3138
31393304static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *name, uint32_t alignment) {
31403305 assert(alignment > 0);
31413306 LLVMValueRef result = LLVMBuildAlloca(g->builder, type_entry->type_ref, name);
......@@ -3144,67 +3309,6 @@ static LLVMValueRef build_alloca(CodeGen *g, ZigType *type_entry, const char *na
31443309}
31453310
31463311// 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
3151static void gen_c_abi_param(CodeGen *g, ZigList<LLVMValueRef> *gen_param_values, LLVMValueRef val,
3152 ZigType *ty, AstNode *source_node)
3153{
3154 if (type_is_c_abi_int(g, ty) || ty->id == ZigTypeIdFloat ||
3155 ty->id == ZigTypeIdInt // TODO investigate if we need to change this
3156 ) {
3157 gen_param_values->append(val);
3158 return;
3159 }
3160
3161 // Arrays are just pointers
3162 if (ty->id == ZigTypeIdArray) {
3163 assert(handle_is_ptr(ty));
3164 gen_param_values->append(val);
3165 return;
3166 }
3167
3168 if (g->zig_target.arch.arch == ZigLLVM_x86_64) {
3169 // This code all assumes that val is a pointer.
3170 assert(handle_is_ptr(ty));
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
32083312// analyze.cpp:gen_c_abi_param_type
32093313// codegen.cpp:gen_c_abi_param_var
32103314// codegen.cpp:gen_c_abi_param_var_init
......@@ -3283,7 +3387,6 @@ ok:
32833387}
32843388
32853389// If you edit this function you have to edit the corresponding code:
3286// codegen.cpp:gen_c_abi_param
32873390// analyze.cpp:gen_c_abi_param_type
32883391// codegen.cpp:gen_c_abi_param_var
32893392// codegen.cpp:gen_c_abi_param_var_init
......@@ -3376,7 +3479,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
33763479 bool ret_has_bits = type_has_bits(src_return_type);
33773480
33783481 CallingConvention cc = fn_type->data.fn.fn_type_id.cc;
3379 bool is_c_abi = cc == CallingConventionC;
33803482
33813483 bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type) &&
33823484 calling_convention_does_first_arg_return(cc);
......@@ -3395,19 +3497,12 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
33953497 LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, "");
33963498 gen_param_values.append(err_val_ptr);
33973499 }
3398 for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) {
3399 IrInstruction *param_instruction = instruction->args[call_i];
3400 ZigType *param_type = param_instruction->value.type;
3401 if (is_var_args || type_has_bits(param_type)) {
3402 LLVMValueRef param_value = ir_llvm_value(g, param_instruction);
3403 assert(param_value);
3404 if (is_c_abi) {
3405 gen_c_abi_param(g, &gen_param_values, param_value, param_type, param_instruction->source_node);
3406 } else {
3407 gen_param_values.append(param_value);
3408 }
3409 }
3410 }
3500 FnWalk fn_walk = {};
3501 fn_walk.id = FnWalkIdCall;
3502 fn_walk.data.call.inst = instruction;
3503 fn_walk.data.call.is_var_args = is_var_args;
3504 fn_walk.data.call.gen_param_values = &gen_param_values;
3505 walk_function_params(g, fn_type, &fn_walk);
34113506
34123507 ZigLLVM_FnInline fn_inline;
34133508 switch (instruction->fn_inline) {
src/codegen.hpp+1
......@@ -61,5 +61,6 @@ void codegen_translate_c(CodeGen *g, Buf *path);
6161
6262Buf *codegen_generate_builtin_source(CodeGen *g);
6363
64void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk);
6465
6566#endif
test/stage1/c_abi/cfuncs.c+71
......@@ -19,6 +19,29 @@ void zig_i16(int16_t);
1919void zig_i32(int32_t);
2020void zig_i64(int64_t);
2121
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
31static uint8_t array[10] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
32
33struct BigStruct {
34 uint64_t a;
35 uint64_t b;
36 uint64_t c;
37 uint64_t d;
38 uint8_t e;
39};
40
41void zig_big_struct(struct BigStruct);
42
43static struct BigStruct s = {1, 2, 3, 4, 5};
44
2245void run_c_tests(void) {
2346 zig_u8(0xff);
2447 zig_u16(0xfffe);
......@@ -29,6 +52,17 @@ void run_c_tests(void) {
2952 zig_i16(-2);
3053 zig_i32(-3);
3154 zig_i64(-4);
55
56 zig_f32(12.34f);
57 zig_f64(56.78);
58
59 zig_ptr((void*)0xdeadbeefL);
60
61 zig_bool(true);
62
63 zig_array(array);
64
65 zig_big_struct(s);
3266}
3367
3468void c_u8(uint8_t x) {
......@@ -62,3 +96,40 @@ void c_i32(int32_t x) {
6296void c_i64(int64_t x) {
6397 assert_or_panic(x == -4);
6498}
99
100void c_f32(float x) {
101 assert_or_panic(x == 12.34f);
102}
103
104void c_f64(double x) {
105 assert_or_panic(x == 56.78);
106}
107
108void c_ptr(void *x) {
109 assert_or_panic(x == (void*)0xdeadbeefL);
110}
111
112void c_bool(bool x) {
113 assert_or_panic(x);
114}
115
116void c_array(uint8_t x[10]) {
117 assert_or_panic(x[0] == '1');
118 assert_or_panic(x[1] == '2');
119 assert_or_panic(x[2] == '3');
120 assert_or_panic(x[3] == '4');
121 assert_or_panic(x[4] == '5');
122 assert_or_panic(x[5] == '6');
123 assert_or_panic(x[6] == '7');
124 assert_or_panic(x[7] == '8');
125 assert_or_panic(x[8] == '9');
126 assert_or_panic(x[9] == '0');
127}
128
129void c_big_struct(struct BigStruct x) {
130 assert_or_panic(x.a == 1);
131 assert_or_panic(x.b == 2);
132 assert_or_panic(x.c == 3);
133 assert_or_panic(x.d == 4);
134 assert_or_panic(x.e == 5);
135}
test/stage1/c_abi/main.zig+74
......@@ -56,3 +56,77 @@ export fn zig_i32(x: i32) void {
5656export fn zig_i64(x: i64) void {
5757 assertOrPanic(x == -4);
5858}
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}