| author | |
| committer | |
| log | a4316d5505d3af1e868a3506787f31a9ae90085a |
| tree | 197b3e2b3da083de2494c85a29fbf938f314fba9 |
| parent | 1f34c03ac14ac352ec03267ca8592dadfbd5e4bc |
| parent | 4e9894cfc4c8e2e1d3e01aa2e3400b295b0ee2df |
7 files changed, 174 insertions(+), 16 deletions(-)
CMakeLists.txt+6-1| ... | @@ -87,10 +87,15 @@ option(ZIG_TEST_COVERAGE "Build Zig with test coverage instrumentation" OFF) | ... | @@ -87,10 +87,15 @@ option(ZIG_TEST_COVERAGE "Build Zig with test coverage instrumentation" OFF) |
| 87 | set(ZIG_TARGET_TRIPLE "native" CACHE STRING "arch-os-abi to output binaries for") | 87 | set(ZIG_TARGET_TRIPLE "native" CACHE STRING "arch-os-abi to output binaries for") |
| 88 | set(ZIG_TARGET_MCPU "baseline" CACHE STRING "-mcpu parameter to output binaries for") | 88 | set(ZIG_TARGET_MCPU "baseline" CACHE STRING "-mcpu parameter to output binaries for") |
| 89 | set(ZIG_EXECUTABLE "" CACHE STRING "(when cross compiling) path to already-built zig binary") | 89 | set(ZIG_EXECUTABLE "" CACHE STRING "(when cross compiling) path to already-built zig binary") |
| 90 | set(ZIG_PREFER_LLVM_CONFIG off CACHE BOOL "(when cross compiling) use llvm-config to find target llvm dependencies if needed") | ||
| 91 | set(ZIG_SINGLE_THREADED off CACHE BOOL "limit the zig compiler to use only 1 thread") | 90 | set(ZIG_SINGLE_THREADED off CACHE BOOL "limit the zig compiler to use only 1 thread") |
| 92 | set(ZIG_OMIT_STAGE2 off CACHE BOOL "omit the stage2 backend from stage1") | 91 | set(ZIG_OMIT_STAGE2 off CACHE BOOL "omit the stage2 backend from stage1") |
| 93 | 92 | ||
| 93 | if("${ZIG_TARGET_TRIPLE}" STREQUAL "native") | ||
| 94 | set(ZIG_USE_LLVM_CONFIG ON CACHE BOOL "use llvm-config to find LLVM libraries") | ||
| 95 | else() | ||
| 96 | set(ZIG_USE_LLVM_CONFIG OFF CACHE BOOL "use llvm-config to find LLVM libraries") | ||
| 97 | endif() | ||
| 98 | |||
| 94 | find_package(llvm) | 99 | find_package(llvm) |
| 95 | find_package(clang) | 100 | find_package(clang) |
| 96 | find_package(lld) | 101 | find_package(lld) |
cmake/Findllvm.cmake+1-1| ... | @@ -63,7 +63,7 @@ if(ZIG_PREFER_CLANG_CPP_DYLIB) | ... | @@ -63,7 +63,7 @@ if(ZIG_PREFER_CLANG_CPP_DYLIB) |
| 63 | if("${LLVM_CONFIG_VERSION}" VERSION_GREATER 13) | 63 | if("${LLVM_CONFIG_VERSION}" VERSION_GREATER 13) |
| 64 | message(FATAL_ERROR "expected LLVM 12.x but found ${LLVM_CONFIG_VERSION} using ${LLVM_CONFIG_EXE}") | 64 | message(FATAL_ERROR "expected LLVM 12.x but found ${LLVM_CONFIG_VERSION} using ${LLVM_CONFIG_EXE}") |
| 65 | endif() | 65 | endif() |
| 66 | elseif(("${ZIG_TARGET_TRIPLE}" STREQUAL "native") OR ZIG_PREFER_LLVM_CONFIG) | 66 | elseif(ZIG_USE_LLVM_CONFIG) |
| 67 | find_program(LLVM_CONFIG_EXE | 67 | find_program(LLVM_CONFIG_EXE |
| 68 | NAMES llvm-config-12 llvm-config-12.0 llvm-config120 llvm-config12 llvm-config | 68 | NAMES llvm-config-12 llvm-config-12.0 llvm-config120 llvm-config12 llvm-config |
| 69 | PATHS | 69 | PATHS |
doc/langref.html.in+12-13| ... | @@ -684,7 +684,7 @@ pub fn main() void { | ... | @@ -684,7 +684,7 @@ pub fn main() void { |
| 684 | {#header_close#} | 684 | {#header_close#} |
| 685 | {#header_open|String Literals and Unicode Code Point Literals#} | 685 | {#header_open|String Literals and Unicode Code Point Literals#} |
| 686 | <p> | 686 | <p> |
| 687 | String literals are single-item constant {#link|Pointers#} to null-terminated byte arrays. | 687 | String literals are constant single-item {#link|Pointers#} to null-terminated byte arrays. |
| 688 | The type of string literals encodes both the length, and the fact that they are null-terminated, | 688 | The type of string literals encodes both the length, and the fact that they are null-terminated, |
| 689 | and thus they can be {#link|coerced|Type Coercion#} to both {#link|Slices#} and | 689 | and thus they can be {#link|coerced|Type Coercion#} to both {#link|Slices#} and |
| 690 | {#link|Null-Terminated Pointers|Sentinel-Terminated Pointers#}. | 690 | {#link|Null-Terminated Pointers|Sentinel-Terminated Pointers#}. |
| ... | @@ -1783,7 +1783,7 @@ comptime { | ... | @@ -1783,7 +1783,7 @@ comptime { |
| 1783 | expect(message.len == 5); | 1783 | expect(message.len == 5); |
| 1784 | } | 1784 | } |
| 1785 | 1785 | ||
| 1786 | // A string literal is a pointer to an array literal. | 1786 | // A string literal is a single-item pointer to an array literal. |
| 1787 | const same_message = "hello"; | 1787 | const same_message = "hello"; |
| 1788 | 1788 | ||
| 1789 | comptime { | 1789 | comptime { |
| ... | @@ -1989,15 +1989,15 @@ test "null terminated array" { | ... | @@ -1989,15 +1989,15 @@ test "null terminated array" { |
| 1989 | 1989 | ||
| 1990 | {#header_open|Pointers#} | 1990 | {#header_open|Pointers#} |
| 1991 | <p> | 1991 | <p> |
| 1992 | Zig has two kinds of pointers: | 1992 | Zig has two kinds of pointers: single-item and many-item. |
| 1993 | </p> | 1993 | </p> |
| 1994 | <ul> | 1994 | <ul> |
| 1995 | <li>{#syntax#}*T{#endsyntax#} - pointer to exactly one item. | 1995 | <li>{#syntax#}*T{#endsyntax#} - single-item pointer to exactly one item. |
| 1996 | <ul> | 1996 | <ul> |
| 1997 | <li>Supports deref syntax: {#syntax#}ptr.*{#endsyntax#}</li> | 1997 | <li>Supports deref syntax: {#syntax#}ptr.*{#endsyntax#}</li> |
| 1998 | </ul> | 1998 | </ul> |
| 1999 | </li> | 1999 | </li> |
| 2000 | <li>{#syntax#}[*]T{#endsyntax#} - pointer to unknown number of items. | 2000 | <li>{#syntax#}[*]T{#endsyntax#} - many-item pointer to unknown number of items. |
| 2001 | <ul> | 2001 | <ul> |
| 2002 | <li>Supports index syntax: {#syntax#}ptr[i]{#endsyntax#}</li> | 2002 | <li>Supports index syntax: {#syntax#}ptr[i]{#endsyntax#}</li> |
| 2003 | <li>Supports slice syntax: {#syntax#}ptr[start..end]{#endsyntax#}</li> | 2003 | <li>Supports slice syntax: {#syntax#}ptr[start..end]{#endsyntax#}</li> |
| ... | @@ -2009,7 +2009,7 @@ test "null terminated array" { | ... | @@ -2009,7 +2009,7 @@ test "null terminated array" { |
| 2009 | </ul> | 2009 | </ul> |
| 2010 | <p>These types are closely related to {#link|Arrays#} and {#link|Slices#}:</p> | 2010 | <p>These types are closely related to {#link|Arrays#} and {#link|Slices#}:</p> |
| 2011 | <ul> | 2011 | <ul> |
| 2012 | <li>{#syntax#}*[N]T{#endsyntax#} - pointer to N items, same as single-item pointer to array. | 2012 | <li>{#syntax#}*[N]T{#endsyntax#} - pointer to N items, same as single-item pointer to an array. |
| 2013 | <ul> | 2013 | <ul> |
| 2014 | <li>Supports index syntax: {#syntax#}array_ptr[i]{#endsyntax#}</li> | 2014 | <li>Supports index syntax: {#syntax#}array_ptr[i]{#endsyntax#}</li> |
| 2015 | <li>Supports slice syntax: {#syntax#}array_ptr[start..end]{#endsyntax#}</li> | 2015 | <li>Supports slice syntax: {#syntax#}array_ptr[start..end]{#endsyntax#}</li> |
| ... | @@ -2038,7 +2038,7 @@ test "address of syntax" { | ... | @@ -2038,7 +2038,7 @@ test "address of syntax" { |
| 2038 | // Dereference a pointer: | 2038 | // Dereference a pointer: |
| 2039 | expect(x_ptr.* == 1234); | 2039 | expect(x_ptr.* == 1234); |
| 2040 | 2040 | ||
| 2041 | // When you get the address of a const variable, you get a const pointer to a single item. | 2041 | // When you get the address of a const variable, you get a const single-item pointer. |
| 2042 | expect(@TypeOf(x_ptr) == *const i32); | 2042 | expect(@TypeOf(x_ptr) == *const i32); |
| 2043 | 2043 | ||
| 2044 | // If you want to mutate the value, you'd need an address of a mutable variable: | 2044 | // If you want to mutate the value, you'd need an address of a mutable variable: |
| ... | @@ -2051,7 +2051,7 @@ test "address of syntax" { | ... | @@ -2051,7 +2051,7 @@ test "address of syntax" { |
| 2051 | 2051 | ||
| 2052 | test "pointer array access" { | 2052 | test "pointer array access" { |
| 2053 | // Taking an address of an individual element gives a | 2053 | // Taking an address of an individual element gives a |
| 2054 | // pointer to a single item. This kind of pointer | 2054 | // single-item pointer. This kind of pointer |
| 2055 | // does not support pointer arithmetic. | 2055 | // does not support pointer arithmetic. |
| 2056 | var array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; | 2056 | var array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; |
| 2057 | const ptr = &array[2]; | 2057 | const ptr = &array[2]; |
| ... | @@ -2320,8 +2320,8 @@ test "basic slices" { | ... | @@ -2320,8 +2320,8 @@ test "basic slices" { |
| 2320 | expect(&slice[0] == &array[0]); | 2320 | expect(&slice[0] == &array[0]); |
| 2321 | expect(slice.len == array.len); | 2321 | expect(slice.len == array.len); |
| 2322 | 2322 | ||
| 2323 | // Using the address-of operator on a slice gives a pointer to a single | 2323 | // Using the address-of operator on a slice gives a single-item pointer, |
| 2324 | // item, while using the `ptr` field gives an unknown length pointer. | 2324 | // while using the `ptr` field gives a many-item pointer. |
| 2325 | expect(@TypeOf(slice.ptr) == [*]i32); | 2325 | expect(@TypeOf(slice.ptr) == [*]i32); |
| 2326 | expect(@TypeOf(&slice[0]) == *i32); | 2326 | expect(@TypeOf(&slice[0]) == *i32); |
| 2327 | expect(@ptrToInt(slice.ptr) == @ptrToInt(&slice[0])); | 2327 | expect(@ptrToInt(slice.ptr) == @ptrToInt(&slice[0])); |
| ... | @@ -5244,8 +5244,7 @@ test "*[N]T to []T" { | ... | @@ -5244,8 +5244,7 @@ test "*[N]T to []T" { |
| 5244 | expect(std.mem.eql(f32, x2, &[2]f32{ 1.2, 3.4 })); | 5244 | expect(std.mem.eql(f32, x2, &[2]f32{ 1.2, 3.4 })); |
| 5245 | } | 5245 | } |
| 5246 | 5246 | ||
| 5247 | // Single-item pointers to arrays can be coerced to | 5247 | // Single-item pointers to arrays can be coerced to many-item pointers. |
| 5248 | // unknown length pointers. | ||
| 5249 | test "*[N]T to [*]T" { | 5248 | test "*[N]T to [*]T" { |
| 5250 | var buf: [5]u8 = "hello".*; | 5249 | var buf: [5]u8 = "hello".*; |
| 5251 | const x: [*]u8 = &buf; | 5250 | const x: [*]u8 = &buf; |
| ... | @@ -9853,7 +9852,7 @@ const c = @cImport({ | ... | @@ -9853,7 +9852,7 @@ const c = @cImport({ |
| 9853 | </p> | 9852 | </p> |
| 9854 | <p> | 9853 | <p> |
| 9855 | When importing C header files, it is ambiguous whether pointers should be translated as | 9854 | When importing C header files, it is ambiguous whether pointers should be translated as |
| 9856 | single-item pointers ({#syntax#}*T{#endsyntax#}) or unknown-length pointers ({#syntax#}[*]T{#endsyntax#}). | 9855 | single-item pointers ({#syntax#}*T{#endsyntax#}) or many-item pointers ({#syntax#}[*]T{#endsyntax#}). |
| 9857 | C pointers are a compromise so that Zig code can utilize translated header files directly. | 9856 | C pointers are a compromise so that Zig code can utilize translated header files directly. |
| 9858 | </p> | 9857 | </p> |
| 9859 | <p>{#syntax#}[*c]T{#endsyntax#} - C pointer.</p> | 9858 | <p>{#syntax#}[*c]T{#endsyntax#} - C pointer.</p> |
src/link/MachO.zig+4-1| ... | @@ -835,7 +835,10 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { | ... | @@ -835,7 +835,10 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 835 | std.process.exit(1); | 835 | std.process.exit(1); |
| 836 | } | 836 | } |
| 837 | }, | 837 | }, |
| 838 | else => std.process.abort(), | 838 | else => { |
| 839 | log.err("{s} terminated", .{ argv.items[0] }); | ||
| 840 | return error.LLDCrashed; | ||
| 841 | }, | ||
| 839 | } | 842 | } |
| 840 | } else { | 843 | } else { |
| 841 | child.stdin_behavior = .Ignore; | 844 | child.stdin_behavior = .Ignore; |
src/stage1/codegen.cpp+47| ... | @@ -487,6 +487,53 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { | ... | @@ -487,6 +487,53 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { |
| 487 | addLLVMFnAttr(llvm_fn, "noreturn"); | 487 | addLLVMFnAttr(llvm_fn, "noreturn"); |
| 488 | } | 488 | } |
| 489 | 489 | ||
| 490 | if (!calling_convention_allows_zig_types(cc)) { | ||
| 491 | // A simplistic and desperate attempt at making the compiler respect the | ||
| 492 | // target ABI for return types. | ||
| 493 | // This is just enough to avoid miscompiling the test suite, it will be | ||
| 494 | // better in stage2. | ||
| 495 | ZigType *int_type = return_type->id == ZigTypeIdInt ? return_type : | ||
| 496 | return_type->id == ZigTypeIdEnum ? return_type->data.enumeration.tag_int_type : | ||
| 497 | nullptr; | ||
| 498 | |||
| 499 | if (int_type != nullptr) { | ||
| 500 | const bool is_signed = int_type->data.integral.is_signed; | ||
| 501 | const uint32_t bit_width = int_type->data.integral.bit_count; | ||
| 502 | bool should_extend = false; | ||
| 503 | |||
| 504 | // Rough equivalent of Clang's isPromotableIntegerType. | ||
| 505 | switch (bit_width) { | ||
| 506 | case 1: // bool | ||
| 507 | case 8: // {un,}signed char | ||
| 508 | case 16: // {un,}signed short | ||
| 509 | should_extend = true; | ||
| 510 | break; | ||
| 511 | default: | ||
| 512 | break; | ||
| 513 | } | ||
| 514 | |||
| 515 | switch (g->zig_target->arch) { | ||
| 516 | case ZigLLVM_sparcv9: | ||
| 517 | case ZigLLVM_riscv64: | ||
| 518 | case ZigLLVM_ppc64: | ||
| 519 | case ZigLLVM_ppc64le: | ||
| 520 | // Always extend to the register width. | ||
| 521 | should_extend = bit_width < 64; | ||
| 522 | break; | ||
| 523 | default: | ||
| 524 | break; | ||
| 525 | } | ||
| 526 | |||
| 527 | // {zero,sign}-extend the result. | ||
| 528 | if (should_extend) { | ||
| 529 | if (is_signed) | ||
| 530 | addLLVMAttr(llvm_fn, 0, "signext"); | ||
| 531 | else | ||
| 532 | addLLVMAttr(llvm_fn, 0, "zeroext"); | ||
| 533 | } | ||
| 534 | } | ||
| 535 | } | ||
| 536 | |||
| 490 | if (fn->body_node != nullptr) { | 537 | if (fn->body_node != nullptr) { |
| 491 | maybe_export_dll(g, llvm_fn, linkage); | 538 | maybe_export_dll(g, llvm_fn, linkage); |
| 492 | 539 |
test/stage1/c_abi/cfuncs.c+52| ... | @@ -24,6 +24,16 @@ void zig_f32(float); | ... | @@ -24,6 +24,16 @@ void zig_f32(float); |
| 24 | void zig_f64(double); | 24 | void zig_f64(double); |
| 25 | void zig_five_floats(float, float, float, float, float); | 25 | void zig_five_floats(float, float, float, float, float); |
| 26 | 26 | ||
| 27 | bool zig_ret_bool(); | ||
| 28 | uint8_t zig_ret_u8(); | ||
| 29 | uint16_t zig_ret_u16(); | ||
| 30 | uint32_t zig_ret_u32(); | ||
| 31 | uint64_t zig_ret_u64(); | ||
| 32 | int8_t zig_ret_i8(); | ||
| 33 | int16_t zig_ret_i16(); | ||
| 34 | int32_t zig_ret_i32(); | ||
| 35 | int64_t zig_ret_i64(); | ||
| 36 | |||
| 27 | void zig_ptr(void *); | 37 | void zig_ptr(void *); |
| 28 | 38 | ||
| 29 | void zig_bool(bool); | 39 | void zig_bool(bool); |
| ... | @@ -119,6 +129,20 @@ void run_c_tests(void) { | ... | @@ -119,6 +129,20 @@ void run_c_tests(void) { |
| 119 | assert_or_panic(res.d == 23); | 129 | assert_or_panic(res.d == 23); |
| 120 | assert_or_panic(res.e == 24); | 130 | assert_or_panic(res.e == 24); |
| 121 | } | 131 | } |
| 132 | |||
| 133 | { | ||
| 134 | assert_or_panic(zig_ret_bool() == 1); | ||
| 135 | |||
| 136 | assert_or_panic(zig_ret_u8() == 0xff); | ||
| 137 | assert_or_panic(zig_ret_u16() == 0xffff); | ||
| 138 | assert_or_panic(zig_ret_u32() == 0xffffffff); | ||
| 139 | assert_or_panic(zig_ret_u64() == 0xffffffffffffffff); | ||
| 140 | |||
| 141 | assert_or_panic(zig_ret_i8() == -1); | ||
| 142 | assert_or_panic(zig_ret_i16() == -1); | ||
| 143 | assert_or_panic(zig_ret_i32() == -1); | ||
| 144 | assert_or_panic(zig_ret_i64() == -1); | ||
| 145 | } | ||
| 122 | } | 146 | } |
| 123 | 147 | ||
| 124 | void c_u8(uint8_t x) { | 148 | void c_u8(uint8_t x) { |
| ... | @@ -236,3 +260,31 @@ void c_big_struct_floats(Vector5 vec) { | ... | @@ -236,3 +260,31 @@ void c_big_struct_floats(Vector5 vec) { |
| 236 | assert_or_panic(vec.w == 69); | 260 | assert_or_panic(vec.w == 69); |
| 237 | assert_or_panic(vec.q == 55); | 261 | assert_or_panic(vec.q == 55); |
| 238 | } | 262 | } |
| 263 | |||
| 264 | bool c_ret_bool() { | ||
| 265 | return 1; | ||
| 266 | } | ||
| 267 | uint8_t c_ret_u8() { | ||
| 268 | return 0xff; | ||
| 269 | } | ||
| 270 | uint16_t c_ret_u16() { | ||
| 271 | return 0xffff; | ||
| 272 | } | ||
| 273 | uint32_t c_ret_u32() { | ||
| 274 | return 0xffffffff; | ||
| 275 | } | ||
| 276 | uint64_t c_ret_u64() { | ||
| 277 | return 0xffffffffffffffff; | ||
| 278 | } | ||
| 279 | int8_t c_ret_i8() { | ||
| 280 | return -1; | ||
| 281 | } | ||
| 282 | int16_t c_ret_i16() { | ||
| 283 | return -1; | ||
| 284 | } | ||
| 285 | int32_t c_ret_i32() { | ||
| 286 | return -1; | ||
| 287 | } | ||
| 288 | int64_t c_ret_i64() { | ||
| 289 | return -1; | ||
| 290 | } |
test/stage1/c_abi/main.zig+52| ... | @@ -284,3 +284,55 @@ test "C ABI structs of floats as parameter" { | ... | @@ -284,3 +284,55 @@ test "C ABI structs of floats as parameter" { |
| 284 | }; | 284 | }; |
| 285 | c_big_struct_floats(v5); | 285 | c_big_struct_floats(v5); |
| 286 | } | 286 | } |
| 287 | |||
| 288 | export fn zig_ret_bool() bool { | ||
| 289 | return true; | ||
| 290 | } | ||
| 291 | export fn zig_ret_u8() u8 { | ||
| 292 | return 0xff; | ||
| 293 | } | ||
| 294 | export fn zig_ret_u16() u16 { | ||
| 295 | return 0xffff; | ||
| 296 | } | ||
| 297 | export fn zig_ret_u32() u32 { | ||
| 298 | return 0xffffffff; | ||
| 299 | } | ||
| 300 | export fn zig_ret_u64() u64 { | ||
| 301 | return 0xffffffffffffffff; | ||
| 302 | } | ||
| 303 | export fn zig_ret_i8() i8 { | ||
| 304 | return -1; | ||
| 305 | } | ||
| 306 | export fn zig_ret_i16() i16 { | ||
| 307 | return -1; | ||
| 308 | } | ||
| 309 | export fn zig_ret_i32() i32 { | ||
| 310 | return -1; | ||
| 311 | } | ||
| 312 | export fn zig_ret_i64() i64 { | ||
| 313 | return -1; | ||
| 314 | } | ||
| 315 | |||
| 316 | extern fn c_ret_bool() bool; | ||
| 317 | extern fn c_ret_u8() u8; | ||
| 318 | extern fn c_ret_u16() u16; | ||
| 319 | extern fn c_ret_u32() u32; | ||
| 320 | extern fn c_ret_u64() u64; | ||
| 321 | extern fn c_ret_i8() i8; | ||
| 322 | extern fn c_ret_i16() i16; | ||
| 323 | extern fn c_ret_i32() i32; | ||
| 324 | extern fn c_ret_i64() i64; | ||
| 325 | |||
| 326 | test "C ABI integer return types" { | ||
| 327 | expect(c_ret_bool() == true); | ||
| 328 | |||
| 329 | expect(c_ret_u8() == 0xff); | ||
| 330 | expect(c_ret_u16() == 0xffff); | ||
| 331 | expect(c_ret_u32() == 0xffffffff); | ||
| 332 | expect(c_ret_u64() == 0xffffffffffffffff); | ||
| 333 | |||
| 334 | expect(c_ret_i8() == -1); | ||
| 335 | expect(c_ret_i16() == -1); | ||
| 336 | expect(c_ret_i32() == -1); | ||
| 337 | expect(c_ret_i64() == -1); | ||
| 338 | } |