From 7813068e218457b074576d3dac8926b7923f97ba Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 5 Mar 2021 12:37:49 +0100 Subject: [PATCH 1/5] stage1: Follow the C ABI for return types The current implementation of the target C ABI rules is hopelessly bad, let's tack some more rules on top in order to prevent some miscompilations. Truth to be told the same rule should be applied also to parameters, but I really can't stand stage1. --- src/stage1/codegen.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index 97daf249b1..5c37a1247b 100644 --- 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); From 36c4037144bdc3d80530205c0e2e9c31bee0f114 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 12 Mar 2021 11:20:37 +0100 Subject: [PATCH 2/5] stage1: Add tests for C ABI integer return types --- test/stage1/c_abi/cfuncs.c | 52 ++++++++++++++++++++++++++++++++++++++ test/stage1/c_abi/main.zig | 52 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/test/stage1/c_abi/cfuncs.c b/test/stage1/c_abi/cfuncs.c index 0e8204779a..05ae78d290 100644 --- 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 index 18e9858da4..51fcc406ee 100644 --- 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); +} From 95eb711ca8c0843ede117f61025c5eda0102f845 Mon Sep 17 00:00:00 2001 From: Dave Gauer Date: Fri, 12 Mar 2021 20:10:55 -0500 Subject: [PATCH 3/5] langref: Use "single-item pointer" and "many-item pointer" (#8217) These terms give short, descriptive names for the two pointer types which reflect the names used in src/type.zig. --- doc/langref.html.in | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 645c03dcbb..aca09c55fe 100644 --- 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#}

- 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#}

- Zig has two kinds of pointers: + Zig has two kinds of pointers: single-item and many-item.

    -
  • {#syntax#}*T{#endsyntax#} - pointer to exactly one item. +
  • {#syntax#}*T{#endsyntax#} - single-item pointer to exactly one item.
    • Supports deref syntax: {#syntax#}ptr.*{#endsyntax#}
  • -
  • {#syntax#}[*]T{#endsyntax#} - pointer to unknown number of items. +
  • {#syntax#}[*]T{#endsyntax#} - many-item pointer to unknown number of items.
    • Supports index syntax: {#syntax#}ptr[i]{#endsyntax#}
    • Supports slice syntax: {#syntax#}ptr[start..end]{#endsyntax#}
    • @@ -2009,7 +2009,7 @@ test "null terminated array" {

    These types are closely related to {#link|Arrays#} and {#link|Slices#}:

      -
    • {#syntax#}*[N]T{#endsyntax#} - pointer to N items, same as single-item pointer to array. +
    • {#syntax#}*[N]T{#endsyntax#} - pointer to N items, same as single-item pointer to an array.
      • Supports index syntax: {#syntax#}array_ptr[i]{#endsyntax#}
      • Supports slice syntax: {#syntax#}array_ptr[start..end]{#endsyntax#}
      • @@ -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({

        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.

        {#syntax#}[*c]T{#endsyntax#} - C pointer.

        From cc650abf09d98ff241cc28b50b2519a9c4919dd0 Mon Sep 17 00:00:00 2001 From: Michael Dusan Date: Fri, 12 Mar 2021 18:58:04 -0500 Subject: [PATCH 4/5] lld: handle error instead of abort closes #6675 --- src/link/MachO.zig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 0f76925618..fe8fcd6281 100644 --- 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; From 4e9894cfc4c8e2e1d3e01aa2e3400b295b0ee2df Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 13 Mar 2021 14:30:56 -0700 Subject: [PATCH 5/5] cmake build: allow overriding whether to use llvm-config Previously, there was an option ZIG_PREFER_LLVM_CONFIG which would override the default of not using llvm-config when cross compiling. That option is now removed in favor of the more powerful ZIG_USE_LLVM_CONFIG which defaults to OFF for cross compiling and ON for native compilation. The option overrides the default. This will be used in zig-bootstrap to improve support for native builds. --- CMakeLists.txt | 7 ++++++- cmake/Findllvm.cmake | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c0218e305..55198f3581 100644 --- 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 index 02f22037b8..4984723ec2 100644 --- a/cmake/Findllvm.cmake +++ b/cmake/Findllvm.cmake @@ -63,7 +63,7 @@ if(ZIG_PREFER_CLANG_CPP_DYLIB) if("${LLVM_CONFIG_VERSION}" VERSION_GREATER 12) message(FATAL_ERROR "expected LLVM 11.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-11 llvm-config-11.0 llvm-config110 llvm-config11 llvm-config PATHS