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 2ab2c23ad0..bfde645cad 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 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 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.
These types are closely related to {#link|Arrays#} and {#link|Slices#}:
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.
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; diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index ec953dfa13..5234cc1784 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); 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); +}