motiejus/zig

fork of https://codeberg.org/ziglang/zig
git clone https://git.jakstys.lt/motiejus/zig.git
Log | Tree | Refs | README | LICENSE

commit a4316d5505d3af1e868a3506787f31a9ae90085a (tree)
parent 1f34c03ac14ac352ec03267ca8592dadfbd5e4bc
Author: Andrew Kelley <andrew@ziglang.org>
Date:   Sat, 13 Mar 2021 14:35:03 -0700

Merge remote-tracking branch 'origin/master' into llvm12

Diffstat:
MCMakeLists.txt | 7++++++-
Mcmake/Findllvm.cmake | 2+-
Mdoc/langref.html.in | 25++++++++++++-------------
Msrc/link/MachO.zig | 5++++-
Msrc/stage1/codegen.cpp | 47+++++++++++++++++++++++++++++++++++++++++++++++
Mtest/stage1/c_abi/cfuncs.c | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtest/stage1/c_abi/main.zig | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 174 insertions(+), 16 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -87,10 +87,15 @@ option(ZIG_TEST_COVERAGE "Build Zig with test coverage instrumentation" OFF) set(ZIG_TARGET_TRIPLE "native" CACHE STRING "arch-os-abi to output binaries for") set(ZIG_TARGET_MCPU "baseline" CACHE STRING "-mcpu parameter to output binaries for") set(ZIG_EXECUTABLE "" CACHE STRING "(when cross compiling) path to already-built zig binary") -set(ZIG_PREFER_LLVM_CONFIG off CACHE BOOL "(when cross compiling) use llvm-config to find target llvm dependencies if needed") set(ZIG_SINGLE_THREADED off CACHE BOOL "limit the zig compiler to use only 1 thread") set(ZIG_OMIT_STAGE2 off CACHE BOOL "omit the stage2 backend from stage1") +if("${ZIG_TARGET_TRIPLE}" STREQUAL "native") + set(ZIG_USE_LLVM_CONFIG ON CACHE BOOL "use llvm-config to find LLVM libraries") +else() + set(ZIG_USE_LLVM_CONFIG OFF CACHE BOOL "use llvm-config to find LLVM libraries") +endif() + find_package(llvm) find_package(clang) find_package(lld) diff --git a/cmake/Findllvm.cmake b/cmake/Findllvm.cmake @@ -63,7 +63,7 @@ if(ZIG_PREFER_CLANG_CPP_DYLIB) if("${LLVM_CONFIG_VERSION}" VERSION_GREATER 13) message(FATAL_ERROR "expected LLVM 12.x but found ${LLVM_CONFIG_VERSION} using ${LLVM_CONFIG_EXE}") endif() -elseif(("${ZIG_TARGET_TRIPLE}" STREQUAL "native") OR ZIG_PREFER_LLVM_CONFIG) +elseif(ZIG_USE_LLVM_CONFIG) find_program(LLVM_CONFIG_EXE NAMES llvm-config-12 llvm-config-12.0 llvm-config120 llvm-config12 llvm-config PATHS diff --git a/doc/langref.html.in b/doc/langref.html.in @@ -684,7 +684,7 @@ pub fn main() void { {#header_close#} {#header_open|String Literals and Unicode Code Point Literals#} <p> - String literals are single-item constant {#link|Pointers#} to null-terminated byte arrays. + String literals are constant single-item {#link|Pointers#} to null-terminated byte arrays. The type of string literals encodes both the length, and the fact that they are null-terminated, and thus they can be {#link|coerced|Type Coercion#} to both {#link|Slices#} and {#link|Null-Terminated Pointers|Sentinel-Terminated Pointers#}. @@ -1783,7 +1783,7 @@ comptime { expect(message.len == 5); } -// A string literal is a pointer to an array literal. +// A string literal is a single-item pointer to an array literal. const same_message = "hello"; comptime { @@ -1989,15 +1989,15 @@ test "null terminated array" { {#header_open|Pointers#} <p> - Zig has two kinds of pointers: + Zig has two kinds of pointers: single-item and many-item. </p> <ul> - <li>{#syntax#}*T{#endsyntax#} - pointer to exactly one item. + <li>{#syntax#}*T{#endsyntax#} - single-item pointer to exactly one item. <ul> <li>Supports deref syntax: {#syntax#}ptr.*{#endsyntax#}</li> </ul> </li> - <li>{#syntax#}[*]T{#endsyntax#} - pointer to unknown number of items. + <li>{#syntax#}[*]T{#endsyntax#} - many-item pointer to unknown number of items. <ul> <li>Supports index syntax: {#syntax#}ptr[i]{#endsyntax#}</li> <li>Supports slice syntax: {#syntax#}ptr[start..end]{#endsyntax#}</li> @@ -2009,7 +2009,7 @@ test "null terminated array" { </ul> <p>These types are closely related to {#link|Arrays#} and {#link|Slices#}:</p> <ul> - <li>{#syntax#}*[N]T{#endsyntax#} - pointer to N items, same as single-item pointer to array. + <li>{#syntax#}*[N]T{#endsyntax#} - pointer to N items, same as single-item pointer to an array. <ul> <li>Supports index syntax: {#syntax#}array_ptr[i]{#endsyntax#}</li> <li>Supports slice syntax: {#syntax#}array_ptr[start..end]{#endsyntax#}</li> @@ -2038,7 +2038,7 @@ test "address of syntax" { // Dereference a pointer: expect(x_ptr.* == 1234); - // When you get the address of a const variable, you get a const pointer to a single item. + // When you get the address of a const variable, you get a const single-item pointer. expect(@TypeOf(x_ptr) == *const i32); // If you want to mutate the value, you'd need an address of a mutable variable: @@ -2051,7 +2051,7 @@ test "address of syntax" { test "pointer array access" { // Taking an address of an individual element gives a - // pointer to a single item. This kind of pointer + // single-item pointer. This kind of pointer // does not support pointer arithmetic. var array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; const ptr = &array[2]; @@ -2320,8 +2320,8 @@ test "basic slices" { expect(&slice[0] == &array[0]); expect(slice.len == array.len); - // Using the address-of operator on a slice gives a pointer to a single - // item, while using the `ptr` field gives an unknown length pointer. + // Using the address-of operator on a slice gives a single-item pointer, + // while using the `ptr` field gives a many-item pointer. expect(@TypeOf(slice.ptr) == [*]i32); expect(@TypeOf(&slice[0]) == *i32); expect(@ptrToInt(slice.ptr) == @ptrToInt(&slice[0])); @@ -5244,8 +5244,7 @@ test "*[N]T to []T" { expect(std.mem.eql(f32, x2, &[2]f32{ 1.2, 3.4 })); } -// Single-item pointers to arrays can be coerced to -// unknown length pointers. +// Single-item pointers to arrays can be coerced to many-item pointers. test "*[N]T to [*]T" { var buf: [5]u8 = "hello".*; const x: [*]u8 = &buf; @@ -9853,7 +9852,7 @@ const c = @cImport({ </p> <p> When importing C header files, it is ambiguous whether pointers should be translated as - single-item pointers ({#syntax#}*T{#endsyntax#}) or unknown-length pointers ({#syntax#}[*]T{#endsyntax#}). + single-item pointers ({#syntax#}*T{#endsyntax#}) or many-item pointers ({#syntax#}[*]T{#endsyntax#}). C pointers are a compromise so that Zig code can utilize translated header files directly. </p> <p>{#syntax#}[*c]T{#endsyntax#} - C pointer.</p> diff --git a/src/link/MachO.zig b/src/link/MachO.zig @@ -835,7 +835,10 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { std.process.exit(1); } }, - else => std.process.abort(), + else => { + log.err("{s} terminated", .{ argv.items[0] }); + return error.LLDCrashed; + }, } } else { child.stdin_behavior = .Ignore; diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp @@ -487,6 +487,53 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { addLLVMFnAttr(llvm_fn, "noreturn"); } + if (!calling_convention_allows_zig_types(cc)) { + // A simplistic and desperate attempt at making the compiler respect the + // target ABI for return types. + // This is just enough to avoid miscompiling the test suite, it will be + // better in stage2. + ZigType *int_type = return_type->id == ZigTypeIdInt ? return_type : + return_type->id == ZigTypeIdEnum ? return_type->data.enumeration.tag_int_type : + nullptr; + + if (int_type != nullptr) { + const bool is_signed = int_type->data.integral.is_signed; + const uint32_t bit_width = int_type->data.integral.bit_count; + bool should_extend = false; + + // Rough equivalent of Clang's isPromotableIntegerType. + switch (bit_width) { + case 1: // bool + case 8: // {un,}signed char + case 16: // {un,}signed short + should_extend = true; + break; + default: + break; + } + + switch (g->zig_target->arch) { + case ZigLLVM_sparcv9: + case ZigLLVM_riscv64: + case ZigLLVM_ppc64: + case ZigLLVM_ppc64le: + // Always extend to the register width. + should_extend = bit_width < 64; + break; + default: + break; + } + + // {zero,sign}-extend the result. + if (should_extend) { + if (is_signed) + addLLVMAttr(llvm_fn, 0, "signext"); + else + addLLVMAttr(llvm_fn, 0, "zeroext"); + } + } + } + if (fn->body_node != nullptr) { maybe_export_dll(g, llvm_fn, linkage); diff --git a/test/stage1/c_abi/cfuncs.c b/test/stage1/c_abi/cfuncs.c @@ -24,6 +24,16 @@ void zig_f32(float); void zig_f64(double); void zig_five_floats(float, float, float, float, float); +bool zig_ret_bool(); +uint8_t zig_ret_u8(); +uint16_t zig_ret_u16(); +uint32_t zig_ret_u32(); +uint64_t zig_ret_u64(); +int8_t zig_ret_i8(); +int16_t zig_ret_i16(); +int32_t zig_ret_i32(); +int64_t zig_ret_i64(); + void zig_ptr(void *); void zig_bool(bool); @@ -119,6 +129,20 @@ void run_c_tests(void) { assert_or_panic(res.d == 23); assert_or_panic(res.e == 24); } + + { + assert_or_panic(zig_ret_bool() == 1); + + assert_or_panic(zig_ret_u8() == 0xff); + assert_or_panic(zig_ret_u16() == 0xffff); + assert_or_panic(zig_ret_u32() == 0xffffffff); + assert_or_panic(zig_ret_u64() == 0xffffffffffffffff); + + assert_or_panic(zig_ret_i8() == -1); + assert_or_panic(zig_ret_i16() == -1); + assert_or_panic(zig_ret_i32() == -1); + assert_or_panic(zig_ret_i64() == -1); + } } void c_u8(uint8_t x) { @@ -236,3 +260,31 @@ void c_big_struct_floats(Vector5 vec) { assert_or_panic(vec.w == 69); assert_or_panic(vec.q == 55); } + +bool c_ret_bool() { + return 1; +} +uint8_t c_ret_u8() { + return 0xff; +} +uint16_t c_ret_u16() { + return 0xffff; +} +uint32_t c_ret_u32() { + return 0xffffffff; +} +uint64_t c_ret_u64() { + return 0xffffffffffffffff; +} +int8_t c_ret_i8() { + return -1; +} +int16_t c_ret_i16() { + return -1; +} +int32_t c_ret_i32() { + return -1; +} +int64_t c_ret_i64() { + return -1; +} diff --git a/test/stage1/c_abi/main.zig b/test/stage1/c_abi/main.zig @@ -284,3 +284,55 @@ test "C ABI structs of floats as parameter" { }; c_big_struct_floats(v5); } + +export fn zig_ret_bool() bool { + return true; +} +export fn zig_ret_u8() u8 { + return 0xff; +} +export fn zig_ret_u16() u16 { + return 0xffff; +} +export fn zig_ret_u32() u32 { + return 0xffffffff; +} +export fn zig_ret_u64() u64 { + return 0xffffffffffffffff; +} +export fn zig_ret_i8() i8 { + return -1; +} +export fn zig_ret_i16() i16 { + return -1; +} +export fn zig_ret_i32() i32 { + return -1; +} +export fn zig_ret_i64() i64 { + return -1; +} + +extern fn c_ret_bool() bool; +extern fn c_ret_u8() u8; +extern fn c_ret_u16() u16; +extern fn c_ret_u32() u32; +extern fn c_ret_u64() u64; +extern fn c_ret_i8() i8; +extern fn c_ret_i16() i16; +extern fn c_ret_i32() i32; +extern fn c_ret_i64() i64; + +test "C ABI integer return types" { + expect(c_ret_bool() == true); + + expect(c_ret_u8() == 0xff); + expect(c_ret_u16() == 0xffff); + expect(c_ret_u32() == 0xffffffff); + expect(c_ret_u64() == 0xffffffffffffffff); + + expect(c_ret_i8() == -1); + expect(c_ret_i16() == -1); + expect(c_ret_i32() == -1); + expect(c_ret_i64() == -1); +}