zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit f33bf48af7d9c99d532864f8a6c3f695ad5bbd21 (tree)
parent 64365bc5d7b1e2c507806ee8976acc3479ad7862
Author: Andrew Kelley <andrew@ziglang.org>
Date:   Tue, 25 Feb 2020 16:30:40 -0500

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

Diffstat:
MCMakeLists.txt | 98+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mbuild.zig | 29+----------------------------
Mci/srht/freebsd_script | 31+++++++------------------------
Mcmake/install.cmake | 12++++++------
Mdoc/langref.html.in | 176+++++++++++--------------------------------------------------------------------
Mlib/std/array_list.zig | 25+++++++++++++++++++++++++
Mlib/std/buffer.zig | 12++++++++++++
Mlib/std/build.zig | 193+++++++++++++++----------------------------------------------------------------
Mlib/std/builtin.zig | 7++-----
Mlib/std/c.zig | 3+++
Mlib/std/c/tokenizer.zig | 2++
Mlib/std/child_process.zig | 56++++++++++++++++++++++++++++++++++++++++----------------
Mlib/std/crypto.zig | 31+++++++++++++++++++++++++++++++
Mlib/std/crypto/blake2.zig | 4++--
Mlib/std/crypto/gimli.zig | 4++--
Mlib/std/crypto/md5.zig | 2+-
Mlib/std/crypto/sha1.zig | 2+-
Mlib/std/crypto/sha2.zig | 4++--
Mlib/std/cstr.zig | 2+-
Mlib/std/debug/leb128.zig | 12++++++------
Mlib/std/event.zig | 2++
Alib/std/event/batch.zig | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/std/event/group.zig | 5+++++
Mlib/std/event/loop.zig | 25+++++++++++++------------
Mlib/std/fifo.zig | 8++++----
Mlib/std/fmt.zig | 24++++++++++++------------
Mlib/std/fmt/parse_float.zig | 2+-
Mlib/std/fs.zig | 59++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mlib/std/fs/file.zig | 25-------------------------
Mlib/std/fs/watch.zig | 2+-
Mlib/std/hash/auto_hash.zig | 2+-
Mlib/std/hash/wyhash.zig | 2+-
Mlib/std/heap.zig | 8++++----
Mlib/std/io.zig | 313++++++++++++++++++++++++-------------------------------------------------------
Mlib/std/io/in_stream.zig | 2+-
Mlib/std/io/test.zig | 24+++++++++++++-----------
Mlib/std/json.zig | 825++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mlib/std/math.zig | 54++++++++++++++++++++++++++----------------------------
Mlib/std/math/big/int.zig | 17+++++++----------
Mlib/std/math/big/rational.zig | 15++++++---------
Mlib/std/math/cos.zig | 2+-
Mlib/std/math/ln.zig | 12+++++-------
Mlib/std/math/log.zig | 14++++++--------
Mlib/std/math/log10.zig | 12+++++-------
Mlib/std/math/log2.zig | 12+++++-------
Mlib/std/math/pow.zig | 2+-
Mlib/std/math/sin.zig | 2+-
Mlib/std/math/sqrt.zig | 6+++---
Mlib/std/math/tan.zig | 2+-
Mlib/std/mem.zig | 305++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mlib/std/meta.zig | 20+++++++++++++++-----
Mlib/std/meta/trait.zig | 28++++++++++++++++++++++------
Mlib/std/net.zig | 6+++---
Mlib/std/os.zig | 288++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Mlib/std/os/bits/linux.zig | 2+-
Mlib/std/os/linux/tls.zig | 2+-
Mlib/std/os/test.zig | 33+++++++++++++++++++++------------
Mlib/std/os/windows/bits.zig | 2+-
Mlib/std/os/windows/ntdll.zig | 6++++++
Mlib/std/packed_int_array.zig | 12++++++------
Mlib/std/process.zig | 134++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Mlib/std/rand.zig | 20++++++++++----------
Mlib/std/special/build_runner.zig | 25++++++++++++++-----------
Mlib/std/special/c.zig | 2+-
Mlib/std/special/compiler_rt/addXf3.zig | 14+++++++-------
Mlib/std/special/compiler_rt/compareXf2.zig | 6+++---
Mlib/std/special/compiler_rt/divdf3.zig | 8++++----
Mlib/std/special/compiler_rt/divsf3.zig | 6+++---
Mlib/std/special/compiler_rt/extendXfYf2.zig | 6+++---
Mlib/std/special/compiler_rt/fixint.zig | 2+-
Mlib/std/special/compiler_rt/fixuint.zig | 2+-
Mlib/std/special/compiler_rt/floatsiXf.zig | 4++--
Mlib/std/special/compiler_rt/mulXf3.zig | 6+++---
Mlib/std/special/compiler_rt/negXf2.zig | 2+-
Mlib/std/special/compiler_rt/truncXfYf2.zig | 4++--
Mlib/std/special/compiler_rt/udivmod.zig | 4++--
Mlib/std/start.zig | 10++++++++--
Mlib/std/target.zig | 1413+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mlib/std/target/aarch64.zig | 574++++++++++++++++++++++++++++---------------------------------------------------
Mlib/std/target/amdgpu.zig | 89++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mlib/std/target/arm.zig | 1527++++++++++++++++++++++++++++++++++++-------------------------------------------
Mlib/std/target/avr.zig | 525++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mlib/std/target/bpf.zig | 21+++++++++++----------
Mlib/std/target/hexagon.zig | 25+++++++++++++------------
Mlib/std/target/mips.zig | 49+++++++++++++++++++++++++------------------------
Mlib/std/target/msp430.zig | 17+++++++++--------
Mlib/std/target/nvptx.zig | 41+++++++++++++++++++++--------------------
Mlib/std/target/powerpc.zig | 87++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mlib/std/target/riscv.zig | 19++++++++++---------
Mlib/std/target/sparc.zig | 91++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mlib/std/target/systemz.zig | 37+++++++++++++++++++------------------
Mlib/std/target/wasm.zig | 17+++++++++--------
Mlib/std/target/x86.zig | 169++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mlib/std/thread.zig | 6+++---
Mlib/std/time.zig | 23++++++++++++++---------
Mlib/std/unicode.zig | 12++++++------
Mlib/std/zig.zig | 1+
Mlib/std/zig/ast.zig | 36+++++++++++++++++-------------------
Mlib/std/zig/parse.zig | 16++++++++++++++--
Mlib/std/zig/parser_test.zig | 13++++++++++++-
Mlib/std/zig/render.zig | 12+++++++++---
Alib/std/zig/system.zig | 163+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/std/zig/tokenizer.zig | 8++------
Msrc-self-hosted/c.zig | 1-
Msrc-self-hosted/introspect.zig | 8++++++++
Msrc-self-hosted/ir.zig | 39+++++++++++++++++----------------------
Msrc-self-hosted/libc_installation.zig | 792+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Msrc-self-hosted/print_targets.zig | 84++++++++++++++++++++++++++++++++-----------------------------------------------
Dsrc-self-hosted/stage1.zig | 832-------------------------------------------------------------------------------
Asrc-self-hosted/stage2.zig | 1064+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc-self-hosted/translate_c.zig | 10+++++-----
Msrc-self-hosted/type.zig | 2+-
Msrc-self-hosted/util.zig | 138-------------------------------------------------------------------------------
Asrc-self-hosted/windows_sdk.zig | 22++++++++++++++++++++++
Msrc/all_types.hpp | 105++++++++++++++++---------------------------------------------------------------
Msrc/analyze.cpp | 14++++++++++----
Msrc/cache_hash.cpp | 2+-
Msrc/codegen.cpp | 454++++++++++++++++++++++++++++---------------------------------------------------
Msrc/codegen.hpp | 8+++-----
Msrc/compiler.cpp | 34----------------------------------
Msrc/compiler.hpp | 1-
Msrc/error.cpp | 19++++++++++++++++++-
Msrc/error.hpp | 2+-
Msrc/glibc.cpp | 6++----
Msrc/ir.cpp | 832++++++++++++++++---------------------------------------------------------------
Msrc/ir_print.cpp | 102-------------------------------------------------------------------------------
Dsrc/libc_installation.cpp | 498-------------------------------------------------------------------------------
Dsrc/libc_installation.hpp | 35-----------------------------------
Msrc/link.cpp | 52++++++++++++++++++++++++++--------------------------
Msrc/main.cpp | 239++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/mem_list.hpp | 15+++++++++------
Msrc/mem_profile.cpp | 4++--
Msrc/os.cpp | 317+++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/os.hpp | 16++++++----------
Msrc/parser.cpp | 7+++++++
Asrc/stage2.cpp | 208+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/stage2.h | 319+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/target.cpp | 542++-----------------------------------------------------------------------------
Msrc/target.hpp | 86+++----------------------------------------------------------------------------
Dsrc/userland.cpp | 146-------------------------------------------------------------------------------
Dsrc/userland.h | 208-------------------------------------------------------------------------------
Msrc/util.cpp | 2+-
Msrc/windows_sdk.h | 4++++
Msrc/zig_clang.h | 2+-
Msrc/zig_llvm.cpp | 198++++++++++++++++++++++++-------------------------------------------------------
Msrc/zig_llvm.h | 53++++-------------------------------------------------
Mtest/compile_errors.zig | 179+++++++++++++++++--------------------------------------------------------------
Mtest/runtime_safety.zig | 16+++++++++-------
Mtest/stage1/behavior.zig | 2+-
Mtest/stage1/behavior/align.zig | 14--------------
Mtest/stage1/behavior/async_fn.zig | 54++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mtest/stage1/behavior/bit_shifting.zig | 4++--
Mtest/stage1/behavior/bugs/1851.zig | 2+-
Atest/stage1/behavior/bugs/3586.zig | 11+++++++++++
Mtest/stage1/behavior/bugs/3742.zig | 2+-
Mtest/stage1/behavior/cast.zig | 20--------------------
Mtest/stage1/behavior/enum.zig | 4++--
Mtest/stage1/behavior/error.zig | 7+++----
Mtest/stage1/behavior/eval.zig | 14++------------
Mtest/stage1/behavior/for.zig | 28++++++++++++++++++++++++++++
Mtest/stage1/behavior/if.zig | 19++++++++++++++++++-
Mtest/stage1/behavior/math.zig | 2+-
Mtest/stage1/behavior/misc.zig | 85-------------------------------------------------------------------------------
Mtest/stage1/behavior/reflection.zig | 36+++---------------------------------
Dtest/stage1/behavior/slicetobytes.zig | 29-----------------------------
Mtest/stage1/behavior/struct.zig | 4++--
Mtest/stage1/behavior/switch.zig | 22++++++++++++++++++++++
Mtest/stage1/behavior/type_info.zig | 11+++++++++++
Mtest/stage1/behavior/union.zig | 2+-
Mtest/stage1/behavior/while.zig | 18+++++++++++++++++-
Mtest/standalone/guess_number/main.zig | 14+++++++-------
Mtest/tests.zig | 89+++++++++++++++++++++++++++++--------------------------------------------------
Mtest/translate_c.zig | 42++++++++++++++++++++----------------------
173 files changed, 8079 insertions(+), 8445 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -240,8 +240,8 @@ find_package(Threads) # CMake doesn't let us create an empty executable, so we hang on to this one separately. set(ZIG_MAIN_SRC "${CMAKE_SOURCE_DIR}/src/main.cpp") -# This is our shim which will be replaced by libuserland written in Zig. -set(ZIG0_SHIM_SRC "${CMAKE_SOURCE_DIR}/src/userland.cpp") +# This is our shim which will be replaced by libstage2 written in Zig. +set(ZIG0_SHIM_SRC "${CMAKE_SOURCE_DIR}/src/stage2.cpp") if(ZIG_ENABLE_MEM_PROFILE) set(ZIG_SOURCES_MEM_PROFILE "${CMAKE_SOURCE_DIR}/src/mem_profile.cpp") @@ -263,7 +263,6 @@ set(ZIG_SOURCES "${CMAKE_SOURCE_DIR}/src/heap.cpp" "${CMAKE_SOURCE_DIR}/src/ir.cpp" "${CMAKE_SOURCE_DIR}/src/ir_print.cpp" - "${CMAKE_SOURCE_DIR}/src/libc_installation.cpp" "${CMAKE_SOURCE_DIR}/src/link.cpp" "${CMAKE_SOURCE_DIR}/src/mem.cpp" "${CMAKE_SOURCE_DIR}/src/os.cpp" @@ -377,27 +376,27 @@ set_target_properties(opt_c_util PROPERTIES COMPILE_FLAGS "${OPTIMIZED_C_FLAGS}" ) -add_library(compiler STATIC ${ZIG_SOURCES}) -set_target_properties(compiler PROPERTIES +add_library(zigcompiler STATIC ${ZIG_SOURCES}) +set_target_properties(zigcompiler PROPERTIES COMPILE_FLAGS ${EXE_CFLAGS} LINK_FLAGS ${EXE_LDFLAGS} ) -target_link_libraries(compiler LINK_PUBLIC +target_link_libraries(zigcompiler LINK_PUBLIC zig_cpp opt_c_util ${SOFTFLOAT_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ) if(NOT MSVC) - target_link_libraries(compiler LINK_PUBLIC ${LIBXML2}) + target_link_libraries(zigcompiler LINK_PUBLIC ${LIBXML2}) endif() if(ZIG_DIA_GUIDS_LIB) - target_link_libraries(compiler LINK_PUBLIC ${ZIG_DIA_GUIDS_LIB}) + target_link_libraries(zigcompiler LINK_PUBLIC ${ZIG_DIA_GUIDS_LIB}) endif() if(MSVC OR MINGW) - target_link_libraries(compiler LINK_PUBLIC version) + target_link_libraries(zigcompiler LINK_PUBLIC version) endif() add_executable(zig0 "${ZIG_MAIN_SRC}" "${ZIG0_SHIM_SRC}") @@ -405,40 +404,43 @@ set_target_properties(zig0 PROPERTIES COMPILE_FLAGS ${EXE_CFLAGS} LINK_FLAGS ${EXE_LDFLAGS} ) -target_link_libraries(zig0 compiler) +target_link_libraries(zig0 zigcompiler) if(MSVC) - set(LIBUSERLAND "${CMAKE_BINARY_DIR}/userland.lib") + set(LIBSTAGE2 "${CMAKE_BINARY_DIR}/zigstage2.lib") else() - set(LIBUSERLAND "${CMAKE_BINARY_DIR}/libuserland.a") + set(LIBSTAGE2 "${CMAKE_BINARY_DIR}/libzigstage2.a") endif() if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - set(LIBUSERLAND_RELEASE_MODE "false") + set(LIBSTAGE2_RELEASE_ARG "") else() - set(LIBUSERLAND_RELEASE_MODE "true") + set(LIBSTAGE2_RELEASE_ARG --release-fast --strip) +endif() +if(WIN32) + set(LIBSTAGE2_WINDOWS_ARGS "-lntdll") +else() + set(LIBSTAGE2_WINDOWS_ARGS "") endif() -set(BUILD_LIBUSERLAND_ARGS "build" +set(BUILD_LIBSTAGE2_ARGS "build-lib" + "src-self-hosted/stage2.zig" + -mcpu=baseline + --name zigstage2 --override-lib-dir "${CMAKE_SOURCE_DIR}/lib" - "-Doutput-dir=${CMAKE_BINARY_DIR}" - "-Drelease=${LIBUSERLAND_RELEASE_MODE}" - "-Dlib-files-only" - --prefix "${CMAKE_INSTALL_PREFIX}" - libuserland + --cache on + --output-dir "${CMAKE_BINARY_DIR}" + ${LIBSTAGE2_RELEASE_ARG} + --disable-gen-h + --bundle-compiler-rt + -fPIC + -lc + ${LIBSTAGE2_WINDOWS_ARGS} ) -# When using Visual Studio build system generator we default to libuserland install. -if(MSVC) - set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL "Disable copying lib/ files to install prefix") - if(NOT ZIG_SKIP_INSTALL_LIB_FILES) - set(BUILD_LIBUSERLAND_ARGS ${BUILD_LIBUSERLAND_ARGS} install) - endif() -endif() - -add_custom_target(zig_build_libuserland ALL - COMMAND zig0 ${BUILD_LIBUSERLAND_ARGS} +add_custom_target(zig_build_libstage2 ALL + COMMAND zig0 ${BUILD_LIBSTAGE2_ARGS} DEPENDS zig0 - BYPRODUCTS "${LIBUSERLAND}" + BYPRODUCTS "${LIBSTAGE2}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" ) add_executable(zig "${ZIG_MAIN_SRC}") @@ -447,22 +449,40 @@ set_target_properties(zig PROPERTIES COMPILE_FLAGS ${EXE_CFLAGS} LINK_FLAGS ${EXE_LDFLAGS} ) -target_link_libraries(zig compiler "${LIBUSERLAND}") +target_link_libraries(zig zigcompiler "${LIBSTAGE2}") if(MSVC) target_link_libraries(zig ntdll.lib) elseif(MINGW) target_link_libraries(zig ntdll) endif() -add_dependencies(zig zig_build_libuserland) +add_dependencies(zig zig_build_libstage2) install(TARGETS zig DESTINATION bin) -# CODE has no effect with Visual Studio build system generator. -if(NOT MSVC) - get_target_property(zig0_BINARY_DIR zig0 BINARY_DIR) - install(CODE "set(zig0_EXE \"${zig0_BINARY_DIR}/zig0\")") - install(CODE "set(INSTALL_LIBUSERLAND_ARGS \"${BUILD_LIBUSERLAND_ARGS}\" install)") - install(CODE "set(BUILD_LIBUSERLAND_ARGS \"${BUILD_LIBUSERLAND_ARGS}\")") +set(ZIG_INSTALL_ARGS "build" + --override-lib-dir "${CMAKE_SOURCE_DIR}/lib" + "-Dlib-files-only" + --prefix "${CMAKE_INSTALL_PREFIX}" + install +) + +# CODE has no effect with Visual Studio build system generator, therefore +# when using Visual Studio build system generator we resort to running +# `zig build install` during the build phase. +if(MSVC) + set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL + "Windows-only: Disable copying lib/ files to install prefix during the build phase") + if(NOT ZIG_SKIP_INSTALL_LIB_FILES) + add_custom_target(zig_install_lib_files ALL + COMMAND zig ${ZIG_INSTALL_ARGS} + DEPENDS zig + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + ) + endif() +else() + get_target_property(zig_BINARY_DIR zig BINARY_DIR) + install(CODE "set(zig_EXE \"${zig_BINARY_DIR}/zig\")") + install(CODE "set(ZIG_INSTALL_ARGS \"${ZIG_INSTALL_ARGS}\")") install(CODE "set(CMAKE_SOURCE_DIR \"${CMAKE_SOURCE_DIR}\")") install(SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/cmake/install.cmake) endif() diff --git a/build.zig b/build.zig @@ -65,8 +65,6 @@ pub fn build(b: *Builder) !void { try configureStage2(b, test_stage2, ctx); try configureStage2(b, exe, ctx); - addLibUserlandStep(b, mode); - const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false; const skip_release_small = b.option(bool, "skip-release-small", "Main test suite skips release-small builds") orelse skip_release; const skip_release_fast = b.option(bool, "skip-release-fast", "Main test suite skips release-fast builds") orelse skip_release; @@ -176,7 +174,7 @@ fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void { } fn fileExists(filename: []const u8) !bool { - fs.File.access(filename) catch |err| switch (err) { + fs.cwd().access(filename, .{}) catch |err| switch (err) { error.FileNotFound => return false, else => return err, }; @@ -379,28 +377,3 @@ const Context = struct { dia_guids_lib: []const u8, llvm: LibraryDep, }; - -fn addLibUserlandStep(b: *Builder, mode: builtin.Mode) void { - const artifact = b.addStaticLibrary("userland", "src-self-hosted/stage1.zig"); - artifact.disable_gen_h = true; - artifact.bundle_compiler_rt = true; - artifact.setTarget(builtin.arch, builtin.os, builtin.abi); - artifact.setBuildMode(mode); - artifact.force_pic = true; - if (mode != .Debug) { - artifact.strip = true; - } - artifact.linkSystemLibrary("c"); - if (builtin.os == .windows) { - artifact.linkSystemLibrary("ntdll"); - } - const libuserland_step = b.step("libuserland", "Build the userland compiler library for use in stage1"); - libuserland_step.dependOn(&artifact.step); - - const output_dir = b.option( - []const u8, - "output-dir", - "For libuserland step, where to put the output", - ) orelse return; - artifact.setOutputDir(output_dir); -} diff --git a/ci/srht/freebsd_script b/ci/srht/freebsd_script @@ -34,38 +34,21 @@ release/bin/zig build test-behavior # release/bin/zig build test-std release/bin/zig build test-compiler-rt - -# This test is disabled because it triggers "out of memory" on the sr.ht CI service. -# See https://github.com/ziglang/zig/issues/3210 -# release/bin/zig build test-compare-output - -# This test is disabled because it triggers "out of memory" on the sr.ht CI service. -# See https://github.com/ziglang/zig/issues/3210 -# release/bin/zig build test-standalone - +release/bin/zig build test-compare-output +release/bin/zig build test-standalone release/bin/zig build test-stack-traces release/bin/zig build test-cli release/bin/zig build test-asm-link release/bin/zig build test-runtime-safety - -# This test is disabled because it triggers "out of memory" on the sr.ht CI service. -# See https://github.com/ziglang/zig/issues/3210 -# release/bin/zig build test-translate-c - +release/bin/zig build test-translate-c +release/bin/zig build test-run-translated-c release/bin/zig build test-gen-h - -# This test is disabled because it triggers "out of memory" on the sr.ht CI service. -# See https://github.com/ziglang/zig/issues/3210 -# release/bin/zig build test-compile-errors - -# This test is disabled because it triggers "out of memory" on the sr.ht CI service. -# See https://github.com/ziglang/zig/issues/3210 -# release/bin/zig build docs +release/bin/zig build test-compile-errors +release/bin/zig build docs if [ -f ~/.s3cfg ]; then mv ../LICENSE release/ - # Enable when `release/bin/zig build docs` passes without "out of memory" or failures - #mv ../zig-cache/langref.html release/ + mv ../zig-cache/langref.html release/ mv release/bin/zig release/ rmdir release/bin diff --git a/cmake/install.cmake b/cmake/install.cmake @@ -1,16 +1,16 @@ message("-- Installing: ${CMAKE_INSTALL_PREFIX}/lib") -if(NOT EXISTS ${zig0_EXE}) +if(NOT EXISTS ${zig_EXE}) message("::") message(":: ERROR: Executable not found") message(":: (execute_process)") message("::") - message(":: executable: ${zig0_EXE}") + message(":: executable: ${zig_EXE}") message("::") message(FATAL_ERROR) endif() -execute_process(COMMAND ${zig0_EXE} ${INSTALL_LIBUSERLAND_ARGS} +execute_process(COMMAND ${zig_EXE} ${ZIG_INSTALL_ARGS} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} RESULT_VARIABLE _result ) @@ -19,11 +19,11 @@ if(_result) message(":: ERROR: ${_result}") message(":: (execute_process)") - string(REPLACE ";" " " s_INSTALL_LIBUSERLAND_ARGS "${INSTALL_LIBUSERLAND_ARGS}") + string(REPLACE ";" " " s_INSTALL_LIBSTAGE2_ARGS "${ZIG_INSTALL_ARGS}") message("::") - message(":: argv: ${zig0_EXE} ${s_INSTALL_LIBUSERLAND_ARGS} install") + message(":: argv: ${zig_EXE} ${s_INSTALL_LIBSTAGE2_ARGS}") - set(_args ${zig0_EXE} ${INSTALL_LIBUSERLAND_ARGS}) + set(_args ${zig_EXE} ${ZIG_INSTALL_ARGS}) list(LENGTH _args _len) math(EXPR _len "${_len} - 1") message("::") diff --git a/doc/langref.html.in b/doc/langref.html.in @@ -550,7 +550,7 @@ pub fn main() void { {#syntax#}i7{#endsyntax#} refers to a signed 7-bit integer. The maximum allowed bit-width of an integer type is {#syntax#}65535{#endsyntax#}. </p> - {#see_also|Integers|Floats|void|Errors|@IntType#} + {#see_also|Integers|Floats|void|Errors|@Type#} {#header_close#} {#header_open|Primitive Values#} <div class="table-wrapper"> @@ -2025,7 +2025,8 @@ test "volatile" { conversions are not possible. </p> {#code_begin|test#} -const assert = @import("std").debug.assert; +const std = @import("std"); +const assert = std.debug.assert; test "pointer casting" { const bytes align(@alignOf(u32)) = [_]u8{ 0x12, 0x12, 0x12, 0x12 }; @@ -2034,7 +2035,7 @@ test "pointer casting" { // Even this example is contrived - there are better ways to do the above than // pointer casting. For example, using a slice narrowing cast: - const u32_value = @bytesToSlice(u32, bytes[0..])[0]; + const u32_value = std.mem.bytesAsSlice(u32, bytes[0..])[0]; assert(u32_value == 0x12121212); // And even another way, the most straightforward way to do it: @@ -2114,16 +2115,16 @@ test "function alignment" { {#link|safety check|Incorrect Pointer Alignment#}: </p> {#code_begin|test_safety|incorrect alignment#} -const assert = @import("std").debug.assert; +const std = @import("std"); test "pointer alignment safety" { var array align(4) = [_]u32{ 0x11111111, 0x11111111 }; - const bytes = @sliceToBytes(array[0..]); - assert(foo(bytes) == 0x11111111); + const bytes = std.mem.sliceAsBytes(array[0..]); + std.debug.assert(foo(bytes) == 0x11111111); } fn foo(bytes: []u8) u32 { const slice4 = bytes[1..5]; - const int_slice = @bytesToSlice(u32, @alignCast(4, slice4)); + const int_slice = std.mem.bytesAsSlice(u32, @alignCast(4, slice4)); return int_slice[0]; } {#code_end#} @@ -2249,7 +2250,7 @@ test "slice widening" { // Zig supports slice widening and slice narrowing. Cast a slice of u8 // to a slice of anything else, and Zig will perform the length conversion. const array align(@alignOf(u32)) = [_]u8{ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13 }; - const slice = @bytesToSlice(u32, array[0..]); + const slice = mem.bytesAsSlice(u32, array[0..]); assert(slice.len == 2); assert(slice[0] == 0x12121212); assert(slice[1] == 0x13131313); @@ -2809,14 +2810,10 @@ test "@TagType" { assert(@TagType(Small) == u2); } -// @memberCount tells how many fields an enum has: -test "@memberCount" { - assert(@memberCount(Small) == 4); -} - -// @memberName tells the name of a field in an enum: -test "@memberName" { - assert(mem.eql(u8, @memberName(Small, 1), "Two")); +// @typeInfo tells us the field count and the fields names: +test "@typeInfo" { + assert(@typeInfo(Small).Enum.fields.len == 4); + assert(mem.eql(u8, @typeInfo(Small).Enum.fields[1].name, "Two")); } // @tagName gives a []const u8 representation of an enum value: @@ -2824,7 +2821,7 @@ test "@tagName" { assert(mem.eql(u8, @tagName(Small.Three), "Three")); } {#code_end#} - {#see_also|@memberName|@memberCount|@tagName|@sizeOf#} + {#see_also|@typeInfo|@tagName|@sizeOf#} {#header_open|extern enum#} <p> @@ -5186,7 +5183,6 @@ test "coercion of zero bit types" { <li>{#link|@bitCast#} - change type but maintain bit representation</li> <li>{#link|@alignCast#} - make a pointer have more alignment</li> <li>{#link|@boolToInt#} - convert true to 1 and false to 0</li> - <li>{#link|@bytesToSlice#} - convert a slice of bytes to a slice of another type</li> <li>{#link|@enumToInt#} - obtain the integer tag value of an enum or tagged union</li> <li>{#link|@errSetCast#} - convert to a smaller error set</li> <li>{#link|@errorToInt#} - obtain the integer value of an error code</li> @@ -5199,7 +5195,6 @@ test "coercion of zero bit types" { <li>{#link|@intToPtr#} - convert an address to a pointer</li> <li>{#link|@ptrCast#} - convert between pointer types</li> <li>{#link|@ptrToInt#} - obtain the address of a pointer</li> - <li>{#link|@sliceToBytes#} - convert a slice of anything to a slice of bytes</li> <li>{#link|@truncate#} - convert between integer types, chopping off bits</li> </ul> {#header_close#} @@ -6672,18 +6667,6 @@ comptime { </p> {#see_also|Alignment#} {#header_close#} - {#header_open|@ArgType#} - <pre>{#syntax#}@ArgType(comptime T: type, comptime n: usize) type{#endsyntax#}</pre> - <p> - This builtin function takes a function type and returns the type of the parameter at index {#syntax#}n{#endsyntax#}. - </p> - <p> - {#syntax#}T{#endsyntax#} must be a function type. - </p> - <p> - Note: This function is deprecated. Use {#link|@typeInfo#} instead. - </p> - {#header_close#} {#header_open|@as#} <pre>{#syntax#}@as(comptime T: type, expression) T{#endsyntax#}</pre> @@ -6817,7 +6800,7 @@ async fn func(y: *i32) void { Asserts that {#syntax#}@sizeOf(@TypeOf(value)) == @sizeOf(DestType){#endsyntax#}. </p> <p> - Asserts that {#syntax#}@typeId(DestType) != @import("builtin").TypeId.Pointer{#endsyntax#}. Use {#syntax#}@ptrCast{#endsyntax#} or {#syntax#}@intToPtr{#endsyntax#} if you need this. + Asserts that {#syntax#}@typeInfo(DestType) != .Pointer{#endsyntax#}. Use {#syntax#}@ptrCast{#endsyntax#} or {#syntax#}@intToPtr{#endsyntax#} if you need this. </p> <p> Can be used for these things for example: @@ -6929,18 +6912,6 @@ async fn func(y: *i32) void { {#see_also|@bitOffsetOf#} {#header_close#} - {#header_open|@bytesToSlice#} - <pre>{#syntax#}@bytesToSlice(comptime Element: type, bytes: []u8) []Element{#endsyntax#}</pre> - <p> - Converts a slice of bytes or array of bytes into a slice of {#syntax#}Element{#endsyntax#}. - The resulting slice has the same {#link|pointer|Pointers#} properties as the parameter. - </p> - <p> - Attempting to convert a number of bytes with a length that does not evenly divide into a slice of - elements results in safety-protected {#link|Undefined Behavior#}. - </p> - {#header_close#} - {#header_open|@call#} <pre>{#syntax#}@call(options: std.builtin.CallOptions, function: var, args: var) var{#endsyntax#}</pre> <p> @@ -7248,7 +7219,7 @@ test "main" { <p> Floored division. Rounds toward negative infinity. For unsigned integers it is the same as {#syntax#}numerator / denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator != 0{#endsyntax#} and - {#syntax#}!(@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == std.math.minInt(T) and denominator == -1){#endsyntax#}. + {#syntax#}!(@typeInfo(T) == .Int and T.is_signed and numerator == std.math.minInt(T) and denominator == -1){#endsyntax#}. </p> <ul> <li>{#syntax#}@divFloor(-5, 3) == -2{#endsyntax#}</li> @@ -7262,7 +7233,7 @@ test "main" { <p> Truncated division. Rounds toward zero. For unsigned integers it is the same as {#syntax#}numerator / denominator{#endsyntax#}. Caller guarantees {#syntax#}denominator != 0{#endsyntax#} and - {#syntax#}!(@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == std.math.minInt(T) and denominator == -1){#endsyntax#}. + {#syntax#}!(@typeInfo(T) == .Int and T.is_signed and numerator == std.math.minInt(T) and denominator == -1){#endsyntax#}. </p> <ul> <li>{#syntax#}@divTrunc(-5, 3) == -1{#endsyntax#}</li> @@ -7320,7 +7291,7 @@ test "main" { {#header_close#} {#header_open|@errorToInt#} - <pre>{#syntax#}@errorToInt(err: var) @IntType(false, @sizeOf(anyerror) * 8){#endsyntax#}</pre> + <pre>{#syntax#}@errorToInt(err: var) std.meta.IntType(false, @sizeOf(anyerror) * 8){#endsyntax#}</pre> <p> Supports the following types: </p> @@ -7365,7 +7336,7 @@ comptime { @export(internalName, .{ .name = "foo", .linkage = .Strong }); } -extern fn internalName() void {} +fn internalName() callconv(.C) void {} {#code_end#} <p>This is equivalent to:</p> {#code_begin|obj#} @@ -7614,7 +7585,7 @@ test "@hasDecl" { {#header_close#} {#header_open|@intToError#} - <pre>{#syntax#}@intToError(value: @IntType(false, @sizeOf(anyerror) * 8)) anyerror{#endsyntax#}</pre> + <pre>{#syntax#}@intToError(value: std.meta.IntType(false, @sizeOf(anyerror) * 8)) anyerror{#endsyntax#}</pre> <p> Converts from the integer representation of an error into {#link|The Global Error Set#} type. </p> @@ -7647,44 +7618,6 @@ test "@hasDecl" { </p> {#header_close#} - {#header_open|@IntType#} - <pre>{#syntax#}@IntType(comptime is_signed: bool, comptime bit_count: u16) type{#endsyntax#}</pre> - <p> - This function returns an integer type with the given signness and bit count. The maximum - bit count for an integer type is {#syntax#}65535{#endsyntax#}. - </p> - <p> - Deprecated. Use {#link|@Type#}. - </p> - {#header_close#} - - {#header_open|@memberCount#} - <pre>{#syntax#}@memberCount(comptime T: type) comptime_int{#endsyntax#}</pre> - <p> - This function returns the number of members in a struct, enum, or union type. - </p> - <p> - The result is a compile time constant. - </p> - <p> - It does not include functions, variables, or constants. - </p> - {#header_close#} - {#header_open|@memberName#} - <pre>{#syntax#}@memberName(comptime T: type, comptime index: usize) [N]u8{#endsyntax#}</pre> - <p>Returns the field name of a struct, union, or enum.</p> - <p> - The result is a compile time constant. - </p> - <p> - It does not include functions, variables, or constants. - </p> - {#header_close#} - {#header_open|@memberType#} - <pre>{#syntax#}@memberType(comptime T: type, comptime index: usize) type{#endsyntax#}</pre> - <p>Returns the field type of a struct or union.</p> - {#header_close#} - {#header_open|@memcpy#} <pre>{#syntax#}@memcpy(noalias dest: [*]u8, noalias source: [*]const u8, byte_count: usize){#endsyntax#}</pre> <p> @@ -8067,14 +8000,6 @@ test "@setRuntimeSafety" { {#see_also|@bitSizeOf|@typeInfo#} {#header_close#} - {#header_open|@sliceToBytes#} - <pre>{#syntax#}@sliceToBytes(value: var) []u8{#endsyntax#}</pre> - <p> - Converts a slice or array to a slice of {#syntax#}u8{#endsyntax#}. The resulting slice has the same - {#link|pointer|Pointers#} properties as the parameter. - </p> - {#header_close#} - {#header_open|@splat#} <pre>{#syntax#}@splat(comptime len: u32, scalar: var) @Vector(len, @TypeOf(scalar)){#endsyntax#}</pre> <p> @@ -8388,43 +8313,6 @@ test "integer truncation" { <li>{#link|struct#}</li> </ul> {#header_close#} - - {#header_open|@typeId#} - <pre>{#syntax#}@typeId(comptime T: type) @import("builtin").TypeId{#endsyntax#}</pre> - <p> - Returns which kind of type something is. Possible values: - </p> - {#code_begin|syntax#} -pub const TypeId = enum { - Type, - Void, - Bool, - NoReturn, - Int, - Float, - Pointer, - Array, - Struct, - ComptimeFloat, - ComptimeInt, - Undefined, - Null, - Optional, - ErrorUnion, - ErrorSet, - Enum, - Union, - Fn, - BoundFn, - Opaque, - Frame, - AnyFrame, - Vector, - EnumLiteral, -}; - {#code_end#} - {#header_close#} - {#header_open|@typeInfo#} <pre>{#syntax#}@typeInfo(comptime T: type) @import("std").builtin.TypeInfo{#endsyntax#}</pre> <p> @@ -8888,25 +8776,6 @@ pub fn main() void { } {#code_end#} {#header_close#} - {#header_open|Slice Widen Remainder#} - <p>At compile-time:</p> - {#code_begin|test_err|unable to convert#} -comptime { - var bytes = [5]u8{ 1, 2, 3, 4, 5 }; - var slice = @bytesToSlice(u32, bytes[0..]); -} - {#code_end#} - <p>At runtime:</p> - {#code_begin|exe_err#} -const std = @import("std"); - -pub fn main() void { - var bytes = [5]u8{ 1, 2, 3, 4, 5 }; - var slice = @bytesToSlice(u32, bytes[0..]); - std.debug.warn("value: {}\n", .{slice[0]}); -} - {#code_end#} - {#header_close#} {#header_open|Attempt to Unwrap Null#} <p>At compile-time:</p> {#code_begin|test_err|unable to unwrap null#} @@ -9085,14 +8954,15 @@ comptime { {#code_end#} <p>At runtime:</p> {#code_begin|exe_err#} +const mem = @import("std").mem; pub fn main() !void { var array align(4) = [_]u32{ 0x11111111, 0x11111111 }; - const bytes = @sliceToBytes(array[0..]); + const bytes = mem.sliceAsBytes(array[0..]); if (foo(bytes) != 0x11111111) return error.Wrong; } fn foo(bytes: []u8) u32 { const slice4 = bytes[1..5]; - const int_slice = @bytesToSlice(u32, @alignCast(4, slice4)); + const int_slice = mem.bytesAsSlice(u32, @alignCast(4, slice4)); return int_slice[0]; } {#code_end#} diff --git a/lib/std/array_list.zig b/lib/std/array_list.zig @@ -188,6 +188,14 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { self.len += items.len; } + /// Append a value to the list `n` times. Allocates more memory + /// as necessary. + pub fn appendNTimes(self: *Self, value: T, n: usize) !void { + const old_len = self.len; + try self.resize(self.len + n); + mem.set(T, self.items[old_len..self.len], value); + } + /// Adjust the list's length to `new_len`. Doesn't initialize /// added items if any. pub fn resize(self: *Self, new_len: usize) !void { @@ -311,6 +319,23 @@ test "std.ArrayList.basic" { testing.expect(list.pop() == 33); } +test "std.ArrayList.appendNTimes" { + var list = ArrayList(i32).init(testing.allocator); + defer list.deinit(); + + try list.appendNTimes(2, 10); + testing.expectEqual(@as(usize, 10), list.len); + for (list.toSlice()) |element| { + testing.expectEqual(@as(i32, 2), element); + } +} + +test "std.ArrayList.appendNTimes with failing allocator" { + var list = ArrayList(i32).init(testing.failing_allocator); + defer list.deinit(); + testing.expectError(error.OutOfMemory, list.appendNTimes(2, 10)); +} + test "std.ArrayList.orderedRemove" { var list = ArrayList(i32).init(testing.allocator); defer list.deinit(); diff --git a/lib/std/buffer.zig b/lib/std/buffer.zig @@ -147,6 +147,10 @@ pub const Buffer = struct { try self.resize(m.len); mem.copy(u8, self.list.toSlice(), m); } + + pub fn print(self: *Buffer, comptime fmt: []const u8, args: var) !void { + return std.fmt.format(self, error{OutOfMemory}, Buffer.append, fmt, args); + } }; test "simple Buffer" { @@ -190,3 +194,11 @@ test "Buffer.initCapacity" { testing.expect(buf.capacity() == old_cap); testing.expect(mem.eql(u8, buf.toSliceConst(), "hello")); } + +test "Buffer.print" { + var buf = try Buffer.init(testing.allocator, ""); + defer buf.deinit(); + + try buf.print("Hello {} the {}", .{ 2, "world" }); + testing.expect(buf.eql("Hello 2 the world")); +} diff --git a/lib/std/build.zig b/lib/std/build.zig @@ -27,9 +27,6 @@ pub const Builder = struct { install_tls: TopLevelStep, uninstall_tls: TopLevelStep, allocator: *Allocator, - native_system_lib_paths: ArrayList([]const u8), - native_system_include_dirs: ArrayList([]const u8), - native_system_rpaths: ArrayList([]const u8), user_input_options: UserInputOptionsMap, available_options_map: AvailableOptionsMap, available_options_list: ArrayList(AvailableOption), @@ -41,6 +38,7 @@ pub const Builder = struct { verbose_ir: bool, verbose_llvm_ir: bool, verbose_cimport: bool, + verbose_llvm_cpu_features: bool, invalid_user_input: bool, zig_exe: []const u8, default_step: *Step, @@ -137,11 +135,9 @@ pub const Builder = struct { .verbose_ir = false, .verbose_llvm_ir = false, .verbose_cimport = false, + .verbose_llvm_cpu_features = false, .invalid_user_input = false, .allocator = allocator, - .native_system_lib_paths = ArrayList([]const u8).init(allocator), - .native_system_include_dirs = ArrayList([]const u8).init(allocator), - .native_system_rpaths = ArrayList([]const u8).init(allocator), .user_input_options = UserInputOptionsMap.init(allocator), .available_options_map = AvailableOptionsMap.init(allocator), .available_options_list = ArrayList(AvailableOption).init(allocator), @@ -172,15 +168,11 @@ pub const Builder = struct { }; try self.top_level_steps.append(&self.install_tls); try self.top_level_steps.append(&self.uninstall_tls); - self.detectNativeSystemPaths(); self.default_step = &self.install_tls.step; return self; } pub fn destroy(self: *Builder) void { - self.native_system_lib_paths.deinit(); - self.native_system_include_dirs.deinit(); - self.native_system_rpaths.deinit(); self.env_map.deinit(); self.top_level_steps.deinit(); self.allocator.destroy(self); @@ -347,18 +339,6 @@ pub const Builder = struct { }; } - pub fn addNativeSystemIncludeDir(self: *Builder, path: []const u8) void { - self.native_system_include_dirs.append(path) catch unreachable; - } - - pub fn addNativeSystemRPath(self: *Builder, path: []const u8) void { - self.native_system_rpaths.append(path) catch unreachable; - } - - pub fn addNativeSystemLibPath(self: *Builder, path: []const u8) void { - self.native_system_lib_paths.append(path) catch unreachable; - } - pub fn make(self: *Builder, step_names: []const []const u8) !void { try self.makePath(self.cache_root); @@ -433,87 +413,6 @@ pub const Builder = struct { return error.InvalidStepName; } - fn detectNativeSystemPaths(self: *Builder) void { - var is_nixos = false; - if (process.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| { - is_nixos = true; - var it = mem.tokenize(nix_cflags_compile, " "); - while (true) { - const word = it.next() orelse break; - if (mem.eql(u8, word, "-isystem")) { - const include_path = it.next() orelse { - warn("Expected argument after -isystem in NIX_CFLAGS_COMPILE\n", .{}); - break; - }; - self.addNativeSystemIncludeDir(include_path); - } else { - warn("Unrecognized C flag from NIX_CFLAGS_COMPILE: {}\n", .{word}); - break; - } - } - } else |err| { - assert(err == error.EnvironmentVariableNotFound); - } - if (process.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| { - is_nixos = true; - var it = mem.tokenize(nix_ldflags, " "); - while (true) { - const word = it.next() orelse break; - if (mem.eql(u8, word, "-rpath")) { - const rpath = it.next() orelse { - warn("Expected argument after -rpath in NIX_LDFLAGS\n", .{}); - break; - }; - self.addNativeSystemRPath(rpath); - } else if (word.len > 2 and word[0] == '-' and word[1] == 'L') { - const lib_path = word[2..]; - self.addNativeSystemLibPath(lib_path); - } else { - warn("Unrecognized C flag from NIX_LDFLAGS: {}\n", .{word}); - break; - } - } - } else |err| { - assert(err == error.EnvironmentVariableNotFound); - } - if (is_nixos) return; - switch (builtin.os) { - .windows => {}, - else => { - const triple = (Target{ - .Cross = CrossTarget{ - .arch = builtin.arch, - .os = builtin.os, - .abi = builtin.abi, - .cpu_features = builtin.cpu_features, - }, - }).linuxTriple(self.allocator); - - // TODO: $ ld --verbose | grep SEARCH_DIR - // the output contains some paths that end with lib64, maybe include them too? - // also, what is the best possible order of things? - - self.addNativeSystemIncludeDir("/usr/local/include"); - self.addNativeSystemLibPath("/usr/local/lib"); - self.addNativeSystemLibPath("/usr/local/lib64"); - - self.addNativeSystemIncludeDir(self.fmt("/usr/include/{}", .{triple})); - self.addNativeSystemLibPath(self.fmt("/usr/lib/{}", .{triple})); - - self.addNativeSystemIncludeDir("/usr/include"); - self.addNativeSystemLibPath("/lib"); - self.addNativeSystemLibPath("/lib64"); - self.addNativeSystemLibPath("/usr/lib"); - self.addNativeSystemLibPath("/usr/lib64"); - - // example: on a 64-bit debian-based linux distro, with zlib installed from apt: - // zlib.h is in /usr/include (added above) - // libz.so.1 is in /lib/x86_64-linux-gnu (added here) - self.addNativeSystemLibPath(self.fmt("/lib/{}", .{triple})); - }, - } - } - pub fn option(self: *Builder, comptime T: type, name: []const u8, description: []const u8) ?T { const type_id = comptime typeToEnum(T); const available_option = AvailableOption{ @@ -638,7 +537,7 @@ pub const Builder = struct { return Target.Native; } else { const target_str = self.option([]const u8, "target", "the target to build for") orelse return Target.Native; - return Target.parse(target_str) catch unreachable; // TODO better error message for bad target + return Target.parse(.{ .arch_os_abi = target_str }) catch unreachable; // TODO better error message for bad target } } @@ -710,13 +609,13 @@ pub const Builder = struct { } fn typeToEnum(comptime T: type) TypeId { - return switch (@typeId(T)) { - builtin.TypeId.Int => TypeId.Int, - builtin.TypeId.Float => TypeId.Float, - builtin.TypeId.Bool => TypeId.Bool, + return switch (@typeInfo(T)) { + .Int => .Int, + .Float => .Float, + .Bool => .Bool, else => switch (T) { - []const u8 => TypeId.String, - []const []const u8 => TypeId.List, + []const u8 => .String, + []const []const u8 => .List, else => @compileError("Unsupported type: " ++ @typeName(T)), }, }; @@ -728,11 +627,11 @@ pub const Builder = struct { pub fn typeIdName(id: TypeId) []const u8 { return switch (id) { - TypeId.Bool => "bool", - TypeId.Int => "int", - TypeId.Float => "float", - TypeId.String => "string", - TypeId.List => "list", + .Bool => "bool", + .Int => "int", + .Float => "float", + .String => "string", + .List => "list", }; } @@ -1155,6 +1054,9 @@ pub const LibExeObjStep = struct { frameworks: BufSet, verbose_link: bool, verbose_cc: bool, + emit_llvm_ir: bool = false, + emit_asm: bool = false, + emit_bin: bool = true, disable_gen_h: bool, bundle_compiler_rt: bool, disable_stack_probing: bool, @@ -1182,7 +1084,6 @@ pub const LibExeObjStep = struct { include_dirs: ArrayList(IncludeDir), c_macros: ArrayList([]const u8), output_dir: ?[]const u8, - need_system_paths: bool, is_linking_libc: bool = false, vcpkg_bin_path: ?[]const u8 = null, @@ -1320,7 +1221,6 @@ pub const LibExeObjStep = struct { .disable_stack_probing = false, .disable_sanitize_c = false, .output_dir = null, - .need_system_paths = false, .single_threaded = false, .installed_path = null, .install_step = null, @@ -1496,7 +1396,6 @@ pub const LibExeObjStep = struct { /// Prefer to use `linkSystemLibrary` instead. pub fn linkSystemLibraryName(self: *LibExeObjStep, name: []const u8) void { self.link_objects.append(LinkObject{ .SystemLib = self.builder.dupe(name) }) catch unreachable; - self.need_system_paths = true; } /// This links against a system library, exclusively using pkg-config to find the library. @@ -1940,6 +1839,11 @@ pub const LibExeObjStep = struct { if (builder.verbose_llvm_ir) zig_args.append("--verbose-llvm-ir") catch unreachable; if (builder.verbose_link or self.verbose_link) zig_args.append("--verbose-link") catch unreachable; if (builder.verbose_cc or self.verbose_cc) zig_args.append("--verbose-cc") catch unreachable; + if (builder.verbose_llvm_cpu_features) zig_args.append("--verbose-llvm-cpu-features") catch unreachable; + + if (self.emit_llvm_ir) try zig_args.append("-femit-llvm-ir"); + if (self.emit_asm) try zig_args.append("-femit-asm"); + if (!self.emit_bin) try zig_args.append("-fno-emit-bin"); if (self.strip) { try zig_args.append("--strip"); @@ -2008,43 +1912,33 @@ pub const LibExeObjStep = struct { try zig_args.append(self.target.zigTriple(builder.allocator) catch unreachable); const all_features = self.target.getArch().allFeaturesList(); - var populated_cpu_features = cross.cpu_features.cpu.features; - if (self.target.getArch().subArchFeature()) |sub_arch_index| { - populated_cpu_features.addFeature(sub_arch_index); - } + var populated_cpu_features = cross.cpu.model.features; populated_cpu_features.populateDependencies(all_features); - if (populated_cpu_features.eql(cross.cpu_features.features)) { + if (populated_cpu_features.eql(cross.cpu.features)) { // The CPU name alone is sufficient. // If it is the baseline CPU, no command line args are required. - if (cross.cpu_features.cpu != self.target.getArch().getBaselineCpuFeatures().cpu) { - try zig_args.append("-target-cpu"); - try zig_args.append(cross.cpu_features.cpu.name); + if (cross.cpu.model != Target.Cpu.baseline(self.target.getArch()).model) { + try zig_args.append("-mcpu"); + try zig_args.append(cross.cpu.model.name); } } else { - try zig_args.append("-target-cpu"); - try zig_args.append(cross.cpu_features.cpu.name); + var mcpu_buffer = try std.Buffer.init(builder.allocator, "-mcpu="); + try mcpu_buffer.append(cross.cpu.model.name); - try zig_args.append("-target-feature"); - var feature_str_buffer = try std.Buffer.initSize(builder.allocator, 0); for (all_features) |feature, i_usize| { const i = @intCast(Target.Cpu.Feature.Set.Index, i_usize); const in_cpu_set = populated_cpu_features.isEnabled(i); - const in_actual_set = cross.cpu_features.features.isEnabled(i); + const in_actual_set = cross.cpu.features.isEnabled(i); if (in_cpu_set and !in_actual_set) { - try feature_str_buffer.appendByte('-'); - try feature_str_buffer.append(feature.name); - try feature_str_buffer.appendByte(','); + try mcpu_buffer.appendByte('-'); + try mcpu_buffer.append(feature.name); } else if (!in_cpu_set and in_actual_set) { - try feature_str_buffer.appendByte('+'); - try feature_str_buffer.append(feature.name); - try feature_str_buffer.appendByte(','); + try mcpu_buffer.appendByte('+'); + try mcpu_buffer.append(feature.name); } } - if (mem.endsWith(u8, feature_str_buffer.toSliceConst(), ",")) { - feature_str_buffer.shrink(feature_str_buffer.len() - 1); - } - try zig_args.append(feature_str_buffer.toSliceConst()); + try zig_args.append(mcpu_buffer.toSliceConst()); } }, } @@ -2152,23 +2046,6 @@ pub const LibExeObjStep = struct { try zig_args.append(lib_path); } - if (self.need_system_paths and self.target == Target.Native) { - for (builder.native_system_include_dirs.toSliceConst()) |include_path| { - zig_args.append("-isystem") catch unreachable; - zig_args.append(builder.pathFromRoot(include_path)) catch unreachable; - } - - for (builder.native_system_rpaths.toSliceConst()) |rpath| { - zig_args.append("-rpath") catch unreachable; - zig_args.append(rpath) catch unreachable; - } - - for (builder.native_system_lib_paths.toSliceConst()) |lib_path| { - zig_args.append("--library-path") catch unreachable; - zig_args.append(lib_path) catch unreachable; - } - } - for (self.c_macros.toSliceConst()) |c_macro| { try zig_args.append("-D"); try zig_args.append(c_macro); diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig @@ -6,8 +6,8 @@ pub const Target = std.Target; /// Deprecated: use `std.Target.Os`. pub const Os = std.Target.Os; -/// Deprecated: use `std.Target.Arch`. -pub const Arch = std.Target.Arch; +/// Deprecated: use `std.Target.Cpu.Arch`. +pub const Arch = std.Target.Cpu.Arch; /// Deprecated: use `std.Target.Abi`. pub const Abi = std.Target.Abi; @@ -18,9 +18,6 @@ pub const ObjectFormat = std.Target.ObjectFormat; /// Deprecated: use `std.Target.SubSystem`. pub const SubSystem = std.Target.SubSystem; -/// Deprecated: use `std.Target.CpuFeatures`. -pub const CpuFeatures = std.Target.CpuFeatures; - /// Deprecated: use `std.Target.Cpu`. pub const Cpu = std.Target.Cpu; diff --git a/lib/std/c.zig b/lib/std/c.zig @@ -62,6 +62,8 @@ pub fn versionCheck(glibc_version: builtin.Version) type { }; } +pub extern "c" var environ: [*:null]?[*:0]u8; + pub extern "c" fn fopen(filename: [*:0]const u8, modes: [*:0]const u8) ?*FILE; pub extern "c" fn fclose(stream: *FILE) c_int; pub extern "c" fn fwrite(ptr: [*]const u8, size_of_type: usize, item_count: usize, stream: *FILE) usize; @@ -96,6 +98,7 @@ pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8; pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_uint, options: c_uint) c_int; pub extern "c" fn fork() c_int; pub extern "c" fn access(path: [*:0]const u8, mode: c_uint) c_int; +pub extern "c" fn faccessat(dirfd: fd_t, path: [*:0]const u8, mode: c_uint, flags: c_uint) c_int; pub extern "c" fn pipe(fds: *[2]fd_t) c_int; pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int; pub extern "c" fn mkdir(path: [*:0]const u8, mode: c_uint) c_int; diff --git a/lib/std/c/tokenizer.zig b/lib/std/c/tokenizer.zig @@ -616,6 +616,7 @@ pub const Tokenizer = struct { }, .BackSlash => switch (c) { '\n' => { + result.start = self.index + 1; state = .Start; }, '\r' => { @@ -631,6 +632,7 @@ pub const Tokenizer = struct { }, .BackSlashCr => switch (c) { '\n' => { + result.start = self.index + 1; state = .Start; }, else => { diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig @@ -48,7 +48,10 @@ pub const ChildProcess = struct { cwd: ?[]const u8, err_pipe: if (builtin.os == .windows) void else [2]os.fd_t, - llnode: if (builtin.os == .windows) void else TailQueue(*ChildProcess).Node, + + expand_arg0: Arg0Expand, + + pub const Arg0Expand = os.Arg0Expand; pub const SpawnError = error{ OutOfMemory, @@ -90,7 +93,6 @@ pub const ChildProcess = struct { .handle = undefined, .thread_handle = undefined, .err_pipe = undefined, - .llnode = undefined, .term = null, .env_map = null, .cwd = null, @@ -102,6 +104,7 @@ pub const ChildProcess = struct { .stdin_behavior = StdIo.Inherit, .stdout_behavior = StdIo.Inherit, .stderr_behavior = StdIo.Inherit, + .expand_arg0 = .no_expand, }; errdefer allocator.destroy(child); return child; @@ -174,34 +177,56 @@ pub const ChildProcess = struct { /// Spawns a child process, waits for it, collecting stdout and stderr, and then returns. /// If it succeeds, the caller owns result.stdout and result.stderr memory. + /// TODO deprecate in favor of exec2 pub fn exec( allocator: *mem.Allocator, argv: []const []const u8, cwd: ?[]const u8, env_map: ?*const BufMap, - max_output_size: usize, + max_output_bytes: usize, ) !ExecResult { - const child = try ChildProcess.init(argv, allocator); + return exec2(.{ + .allocator = allocator, + .argv = argv, + .cwd = cwd, + .env_map = env_map, + .max_output_bytes = max_output_bytes, + }); + } + + /// Spawns a child process, waits for it, collecting stdout and stderr, and then returns. + /// If it succeeds, the caller owns result.stdout and result.stderr memory. + /// TODO rename to exec + pub fn exec2(args: struct { + allocator: *mem.Allocator, + argv: []const []const u8, + cwd: ?[]const u8 = null, + env_map: ?*const BufMap = null, + max_output_bytes: usize = 50 * 1024, + expand_arg0: Arg0Expand = .no_expand, + }) !ExecResult { + const child = try ChildProcess.init(args.argv, args.allocator); defer child.deinit(); - child.stdin_behavior = ChildProcess.StdIo.Ignore; - child.stdout_behavior = ChildProcess.StdIo.Pipe; - child.stderr_behavior = ChildProcess.StdIo.Pipe; - child.cwd = cwd; - child.env_map = env_map; + child.stdin_behavior = .Ignore; + child.stdout_behavior = .Pipe; + child.stderr_behavior = .Pipe; + child.cwd = args.cwd; + child.env_map = args.env_map; + child.expand_arg0 = args.expand_arg0; try child.spawn(); - var stdout = Buffer.initNull(allocator); - var stderr = Buffer.initNull(allocator); + var stdout = Buffer.initNull(args.allocator); + var stderr = Buffer.initNull(args.allocator); defer Buffer.deinit(&stdout); defer Buffer.deinit(&stderr); var stdout_file_in_stream = child.stdout.?.inStream(); var stderr_file_in_stream = child.stderr.?.inStream(); - try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size); - try stderr_file_in_stream.stream.readAllBuffer(&stderr, max_output_size); + try stdout_file_in_stream.stream.readAllBuffer(&stdout, args.max_output_bytes); + try stderr_file_in_stream.stream.readAllBuffer(&stderr, args.max_output_bytes); return ExecResult{ .term = try child.wait(), @@ -420,7 +445,7 @@ pub const ChildProcess = struct { os.setreuid(uid, uid) catch |err| forkChildErrReport(err_pipe[1], err); } - const err = os.execvpe(self.allocator, self.argv, env_map); + const err = os.execvpe_expandArg0(self.allocator, self.expand_arg0, self.argv, env_map); forkChildErrReport(err_pipe[1], err); } @@ -453,7 +478,6 @@ pub const ChildProcess = struct { self.pid = pid; self.err_pipe = err_pipe; - self.llnode = TailQueue(*ChildProcess).Node.init(self); self.term = null; if (self.stdin_behavior == StdIo.Pipe) { @@ -827,7 +851,7 @@ fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn { os.exit(1); } -const ErrInt = @IntType(false, @sizeOf(anyerror) * 8); +const ErrInt = std.meta.IntType(false, @sizeOf(anyerror) * 8); fn writeIntFd(fd: i32, value: ErrInt) !void { const file = File{ diff --git a/lib/std/crypto.zig b/lib/std/crypto.zig @@ -57,3 +57,34 @@ test "crypto" { _ = @import("crypto/sha3.zig"); _ = @import("crypto/x25519.zig"); } + +test "issue #4532: no index out of bounds" { + const types = [_]type{ + Md5, + Sha1, + Sha224, + Sha256, + Sha384, + Sha512, + Blake2s224, + Blake2s256, + Blake2b384, + Blake2b512, + }; + + inline for (types) |Hasher| { + var block = [_]u8{'#'} ** Hasher.block_length; + var out1: [Hasher.digest_length]u8 = undefined; + var out2: [Hasher.digest_length]u8 = undefined; + + var h = Hasher.init(); + h.update(block[0..]); + h.final(out1[0..]); + h.reset(); + h.update(block[0..1]); + h.update(block[1..]); + h.final(out2[0..]); + + std.testing.expectEqual(out1, out2); + } +} diff --git a/lib/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig @@ -94,7 +94,7 @@ fn Blake2s(comptime out_len: usize) type { var off: usize = 0; // Partial buffer exists from previous update. Copy into buffer then hash. - if (d.buf_len != 0 and d.buf_len + b.len > 64) { + if (d.buf_len != 0 and d.buf_len + b.len >= 64) { off += 64 - d.buf_len; mem.copy(u8, d.buf[d.buf_len..], b[0..off]); d.t += 64; @@ -331,7 +331,7 @@ fn Blake2b(comptime out_len: usize) type { var off: usize = 0; // Partial buffer exists from previous update. Copy into buffer then hash. - if (d.buf_len != 0 and d.buf_len + b.len > 128) { + if (d.buf_len != 0 and d.buf_len + b.len >= 128) { off += 128 - d.buf_len; mem.copy(u8, d.buf[d.buf_len..], b[0..off]); d.t += 128; diff --git a/lib/std/crypto/gimli.zig b/lib/std/crypto/gimli.zig @@ -24,11 +24,11 @@ pub const State = struct { const Self = @This(); pub fn toSlice(self: *Self) []u8 { - return @sliceToBytes(self.data[0..]); + return mem.sliceAsBytes(self.data[0..]); } pub fn toSliceConst(self: *Self) []const u8 { - return @sliceToBytes(self.data[0..]); + return mem.sliceAsBytes(self.data[0..]); } pub fn permute(self: *Self) void { diff --git a/lib/std/crypto/md5.zig b/lib/std/crypto/md5.zig @@ -63,7 +63,7 @@ pub const Md5 = struct { var off: usize = 0; // Partial buffer exists from previous update. Copy into buffer then hash. - if (d.buf_len != 0 and d.buf_len + b.len > 64) { + if (d.buf_len != 0 and d.buf_len + b.len >= 64) { off += 64 - d.buf_len; mem.copy(u8, d.buf[d.buf_len..], b[0..off]); diff --git a/lib/std/crypto/sha1.zig b/lib/std/crypto/sha1.zig @@ -61,7 +61,7 @@ pub const Sha1 = struct { var off: usize = 0; // Partial buffer exists from previous update. Copy into buffer then hash. - if (d.buf_len != 0 and d.buf_len + b.len > 64) { + if (d.buf_len != 0 and d.buf_len + b.len >= 64) { off += 64 - d.buf_len; mem.copy(u8, d.buf[d.buf_len..], b[0..off]); diff --git a/lib/std/crypto/sha2.zig b/lib/std/crypto/sha2.zig @@ -116,7 +116,7 @@ fn Sha2_32(comptime params: Sha2Params32) type { var off: usize = 0; // Partial buffer exists from previous update. Copy into buffer then hash. - if (d.buf_len != 0 and d.buf_len + b.len > 64) { + if (d.buf_len != 0 and d.buf_len + b.len >= 64) { off += 64 - d.buf_len; mem.copy(u8, d.buf[d.buf_len..], b[0..off]); @@ -458,7 +458,7 @@ fn Sha2_64(comptime params: Sha2Params64) type { var off: usize = 0; // Partial buffer exists from previous update. Copy into buffer then hash. - if (d.buf_len != 0 and d.buf_len + b.len > 128) { + if (d.buf_len != 0 and d.buf_len + b.len >= 128) { off += 128 - d.buf_len; mem.copy(u8, d.buf[d.buf_len..], b[0..off]); diff --git a/lib/std/cstr.zig b/lib/std/cstr.zig @@ -72,7 +72,7 @@ pub const NullTerminated2DArray = struct { errdefer allocator.free(buf); var write_index = index_size; - const index_buf = @bytesToSlice(?[*]u8, buf); + const index_buf = mem.bytesAsSlice(?[*]u8, buf); var i: usize = 0; for (slices) |slice| { diff --git a/lib/std/debug/leb128.zig b/lib/std/debug/leb128.zig @@ -2,7 +2,7 @@ const std = @import("std"); const testing = std.testing; pub fn readULEB128(comptime T: type, in_stream: var) !T { - const ShiftT = @IntType(false, std.math.log2(T.bit_count)); + const ShiftT = std.meta.IntType(false, std.math.log2(T.bit_count)); var result: T = 0; var shift: usize = 0; @@ -27,7 +27,7 @@ pub fn readULEB128(comptime T: type, in_stream: var) !T { } pub fn readULEB128Mem(comptime T: type, ptr: *[*]const u8) !T { - const ShiftT = @IntType(false, std.math.log2(T.bit_count)); + const ShiftT = std.meta.IntType(false, std.math.log2(T.bit_count)); var result: T = 0; var shift: usize = 0; @@ -55,8 +55,8 @@ pub fn readULEB128Mem(comptime T: type, ptr: *[*]const u8) !T { } pub fn readILEB128(comptime T: type, in_stream: var) !T { - const UT = @IntType(false, T.bit_count); - const ShiftT = @IntType(false, std.math.log2(T.bit_count)); + const UT = std.meta.IntType(false, T.bit_count); + const ShiftT = std.meta.IntType(false, std.math.log2(T.bit_count)); var result: UT = 0; var shift: usize = 0; @@ -87,8 +87,8 @@ pub fn readILEB128(comptime T: type, in_stream: var) !T { } pub fn readILEB128Mem(comptime T: type, ptr: *[*]const u8) !T { - const UT = @IntType(false, T.bit_count); - const ShiftT = @IntType(false, std.math.log2(T.bit_count)); + const UT = std.meta.IntType(false, T.bit_count); + const ShiftT = std.meta.IntType(false, std.math.log2(T.bit_count)); var result: UT = 0; var shift: usize = 0; diff --git a/lib/std/event.zig b/lib/std/event.zig @@ -1,6 +1,7 @@ pub const Channel = @import("event/channel.zig").Channel; pub const Future = @import("event/future.zig").Future; pub const Group = @import("event/group.zig").Group; +pub const Batch = @import("event/batch.zig").Batch; pub const Lock = @import("event/lock.zig").Lock; pub const Locked = @import("event/locked.zig").Locked; pub const RwLock = @import("event/rwlock.zig").RwLock; @@ -11,6 +12,7 @@ test "import event tests" { _ = @import("event/channel.zig"); _ = @import("event/future.zig"); _ = @import("event/group.zig"); + _ = @import("event/batch.zig"); _ = @import("event/lock.zig"); _ = @import("event/locked.zig"); _ = @import("event/rwlock.zig"); diff --git a/lib/std/event/batch.zig b/lib/std/event/batch.zig @@ -0,0 +1,139 @@ +const std = @import("../std.zig"); +const testing = std.testing; + +/// Performs multiple async functions in parallel, without heap allocation. +/// Async function frames are managed externally to this abstraction, and +/// passed in via the `add` function. Once all the jobs are added, call `wait`. +/// This API is *not* thread-safe. The object must be accessed from one thread at +/// a time, however, it need not be the same thread. +pub fn Batch( + /// The return value for each job. + /// If a job slot was re-used due to maxed out concurrency, then its result + /// value will be overwritten. The values can be accessed with the `results` field. + comptime Result: type, + /// How many jobs to run in parallel. + comptime max_jobs: comptime_int, + /// Controls whether the `add` and `wait` functions will be async functions. + comptime async_behavior: enum { + /// Observe the value of `std.io.is_async` to decide whether `add` + /// and `wait` will be async functions. Asserts that the jobs do not suspend when + /// `std.io.mode == .blocking`. This is a generally safe assumption, and the + /// usual recommended option for this parameter. + auto_async, + + /// Always uses the `noasync` keyword when using `await` on the jobs, + /// making `add` and `wait` non-async functions. Asserts that the jobs do not suspend. + never_async, + + /// `add` and `wait` use regular `await` keyword, making them async functions. + always_async, + }, +) type { + return struct { + jobs: [max_jobs]Job, + next_job_index: usize, + collected_result: CollectedResult, + + const Job = struct { + frame: ?anyframe->Result, + result: Result, + }; + + const Self = @This(); + + const CollectedResult = switch (@typeInfo(Result)) { + .ErrorUnion => Result, + else => void, + }; + + const async_ok = switch (async_behavior) { + .auto_async => std.io.is_async, + .never_async => false, + .always_async => true, + }; + + pub fn init() Self { + return Self{ + .jobs = [1]Job{ + .{ + .frame = null, + .result = undefined, + }, + } ** max_jobs, + .next_job_index = 0, + .collected_result = {}, + }; + } + + /// Add a frame to the Batch. If all jobs are in-flight, then this function + /// waits until one completes. + /// This function is *not* thread-safe. It must be called from one thread at + /// a time, however, it need not be the same thread. + /// TODO: "select" language feature to use the next available slot, rather than + /// awaiting the next index. + pub fn add(self: *Self, frame: anyframe->Result) void { + const job = &self.jobs[self.next_job_index]; + self.next_job_index = (self.next_job_index + 1) % max_jobs; + if (job.frame) |existing| { + job.result = if (async_ok) await existing else noasync await existing; + if (CollectedResult != void) { + job.result catch |err| { + self.collected_result = err; + }; + } + } + job.frame = frame; + } + + /// Wait for all the jobs to complete. + /// Safe to call any number of times. + /// If `Result` is an error union, this function returns the last error that occurred, if any. + /// Unlike the `results` field, the return value of `wait` will report any error that occurred; + /// hitting max parallelism will not compromise the result. + /// This function is *not* thread-safe. It must be called from one thread at + /// a time, however, it need not be the same thread. + pub fn wait(self: *Self) CollectedResult { + for (self.jobs) |*job| if (job.frame) |f| { + job.result = if (async_ok) await f else noasync await f; + if (CollectedResult != void) { + job.result catch |err| { + self.collected_result = err; + }; + } + job.frame = null; + }; + return self.collected_result; + } + }; +} + +test "std.event.Batch" { + var count: usize = 0; + var batch = Batch(void, 2, .auto_async).init(); + batch.add(&async sleepALittle(&count)); + batch.add(&async increaseByTen(&count)); + batch.wait(); + testing.expect(count == 11); + + var another = Batch(anyerror!void, 2, .auto_async).init(); + another.add(&async somethingElse()); + another.add(&async doSomethingThatFails()); + testing.expectError(error.ItBroke, another.wait()); +} + +fn sleepALittle(count: *usize) void { + std.time.sleep(1 * std.time.millisecond); + _ = @atomicRmw(usize, count, .Add, 1, .SeqCst); +} + +fn increaseByTen(count: *usize) void { + var i: usize = 0; + while (i < 10) : (i += 1) { + _ = @atomicRmw(usize, count, .Add, 1, .SeqCst); + } +} + +fn doSomethingThatFails() anyerror!void {} +fn somethingElse() anyerror!void { + return error.ItBroke; +} diff --git a/lib/std/event/group.zig b/lib/std/event/group.zig @@ -5,6 +5,11 @@ const testing = std.testing; const Allocator = std.mem.Allocator; /// ReturnType must be `void` or `E!void` +/// TODO This API was created back with the old design of async/await, when calling any +/// async function required an allocator. There is an ongoing experiment to transition +/// all uses of this API to the simpler and more resource-aware `std.event.Batch` API. +/// If the transition goes well, all usages of `Group` will be gone, and this API +/// will be deleted. pub fn Group(comptime ReturnType: type) type { return struct { frame_stack: Stack, diff --git a/lib/std/event/loop.zig b/lib/std/event/loop.zig @@ -12,15 +12,18 @@ const maxInt = std.math.maxInt; const Thread = std.Thread; pub const Loop = struct { - allocator: *mem.Allocator, next_tick_queue: std.atomic.Queue(anyframe), os_data: OsData, final_resume_node: ResumeNode, pending_event_count: usize, extra_threads: []*Thread, - // pre-allocated eventfds. all permanently active. - // this is how we send promises to be resumed on other threads. + /// For resources that have the same lifetime as the `Loop`. + /// This is only used by `Loop` for the thread pool and associated resources. + arena: std.heap.ArenaAllocator, + + /// Pre-allocated eventfds. All permanently active. + /// This is how `Loop` sends promises to be resumed on other threads. available_eventfd_resume_nodes: std.atomic.Stack(ResumeNode.EventFd), eventfd_resume_nodes: []std.atomic.Stack(ResumeNode.EventFd).Node, @@ -127,11 +130,9 @@ pub const Loop = struct { /// Thread count is the total thread count. The thread pool size will be /// max(thread_count - 1, 0) pub fn initThreadPool(self: *Loop, thread_count: usize) !void { - // TODO: https://github.com/ziglang/zig/issues/3539 - const allocator = std.heap.page_allocator; self.* = Loop{ + .arena = std.heap.ArenaAllocator.init(std.heap.page_allocator), .pending_event_count = 1, - .allocator = allocator, .os_data = undefined, .next_tick_queue = std.atomic.Queue(anyframe).init(), .extra_threads = undefined, @@ -143,17 +144,17 @@ pub const Loop = struct { .overlapped = ResumeNode.overlapped_init, }, }; + errdefer self.arena.deinit(); + // We need at least one of these in case the fs thread wants to use onNextTick const extra_thread_count = thread_count - 1; const resume_node_count = std.math.max(extra_thread_count, 1); - self.eventfd_resume_nodes = try self.allocator.alloc( + self.eventfd_resume_nodes = try self.arena.allocator.alloc( std.atomic.Stack(ResumeNode.EventFd).Node, resume_node_count, ); - errdefer self.allocator.free(self.eventfd_resume_nodes); - self.extra_threads = try self.allocator.alloc(*Thread, extra_thread_count); - errdefer self.allocator.free(self.extra_threads); + self.extra_threads = try self.arena.allocator.alloc(*Thread, extra_thread_count); try self.initOsData(extra_thread_count); errdefer self.deinitOsData(); @@ -161,7 +162,8 @@ pub const Loop = struct { pub fn deinit(self: *Loop) void { self.deinitOsData(); - self.allocator.free(self.extra_threads); + self.arena.deinit(); + self.* = undefined; } const InitOsDataError = os.EpollCreateError || mem.Allocator.Error || os.EventFdError || @@ -407,7 +409,6 @@ pub const Loop = struct { noasync os.close(self.os_data.final_eventfd); while (self.available_eventfd_resume_nodes.pop()) |node| noasync os.close(node.data.eventfd); noasync os.close(self.os_data.epollfd); - self.allocator.free(self.eventfd_resume_nodes); }, .macosx, .freebsd, .netbsd, .dragonfly => { noasync os.close(self.os_data.kqfd); diff --git a/lib/std/fifo.zig b/lib/std/fifo.zig @@ -101,7 +101,7 @@ pub fn LinearFifo( } } { // set unused area to undefined - const unused = @sliceToBytes(self.buf[self.count..]); + const unused = mem.sliceAsBytes(self.buf[self.count..]); @memset(unused.ptr, undefined, unused.len); } } @@ -166,12 +166,12 @@ pub fn LinearFifo( { // set old range to undefined. Note: may be wrapped around const slice = self.readableSliceMut(0); if (slice.len >= count) { - const unused = @sliceToBytes(slice[0..count]); + const unused = mem.sliceAsBytes(slice[0..count]); @memset(unused.ptr, undefined, unused.len); } else { - const unused = @sliceToBytes(slice[0..]); + const unused = mem.sliceAsBytes(slice[0..]); @memset(unused.ptr, undefined, unused.len); - const unused2 = @sliceToBytes(self.readableSliceMut(slice.len)[0 .. count - slice.len]); + const unused2 = mem.sliceAsBytes(self.readableSliceMut(slice.len)[0 .. count - slice.len]); @memset(unused2.ptr, undefined, unused2.len); } } diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig @@ -82,7 +82,7 @@ pub fn format( comptime fmt: []const u8, args: var, ) Errors!void { - const ArgSetType = @IntType(false, 32); + const ArgSetType = u32; if (@typeInfo(@TypeOf(args)) != .Struct) { @compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(args))); } @@ -405,7 +405,7 @@ pub fn formatType( try format(context, Errors, output, "@{x}", .{@ptrToInt(&value)}); } }, - .Struct => { + .Struct => |StructT| { if (comptime std.meta.trait.hasFn("format")(T)) { return value.format(fmt, options, context, Errors, output); } @@ -416,27 +416,28 @@ pub fn formatType( } comptime var field_i = 0; try output(context, "{"); - inline while (field_i < @memberCount(T)) : (field_i += 1) { + inline for (StructT.fields) |f| { if (field_i == 0) { try output(context, " ."); } else { try output(context, ", ."); } - try output(context, @memberName(T, field_i)); + try output(context, f.name); try output(context, " = "); - try formatType(@field(value, @memberName(T, field_i)), fmt, options, context, Errors, output, max_depth - 1); + try formatType(@field(value, f.name), fmt, options, context, Errors, output, max_depth - 1); + field_i += 1; } try output(context, " }"); }, .Pointer => |ptr_info| switch (ptr_info.size) { .One => switch (@typeInfo(ptr_info.child)) { - builtin.TypeId.Array => |info| { + .Array => |info| { if (info.child == u8) { return formatText(value, fmt, options, context, Errors, output); } return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }); }, - builtin.TypeId.Enum, builtin.TypeId.Union, builtin.TypeId.Struct => { + .Enum, .Union, .Struct => { return formatType(value.*, fmt, options, context, Errors, output, max_depth); }, else => return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }), @@ -509,7 +510,7 @@ fn formatValue( } const T = @TypeOf(value); - switch (@typeId(T)) { + switch (@typeInfo(T)) { .Float => return formatFloatValue(value, fmt, options, context, Errors, output), .Int, .ComptimeInt => return formatIntValue(value, fmt, options, context, Errors, output), .Bool => return output(context, if (value) "true" else "false"), @@ -757,8 +758,6 @@ pub fn formatFloatDecimal( } else { try output(context, ".0"); } - } else { - try output(context, "0"); } return; @@ -945,7 +944,7 @@ fn formatIntSigned( .fill = options.fill, }; - const uint = @IntType(false, @TypeOf(value).bit_count); + const uint = std.meta.IntType(false, @TypeOf(value).bit_count); if (value < 0) { const minus_sign: u8 = '-'; try output(context, @as(*const [1]u8, &minus_sign)[0..]); @@ -973,7 +972,7 @@ fn formatIntUnsigned( assert(base >= 2); var buf: [math.max(@TypeOf(value).bit_count, 1)]u8 = undefined; const min_int_bits = comptime math.max(@TypeOf(value).bit_count, @TypeOf(base).bit_count); - const MinInt = @IntType(@TypeOf(value).is_signed, min_int_bits); + const MinInt = std.meta.IntType(@TypeOf(value).is_signed, min_int_bits); var a: MinInt = value; var index: usize = buf.len; @@ -1399,6 +1398,7 @@ test "float.special" { test "float.decimal" { try testFmt("f64: 152314000000000000000000000000", "f64: {d}", .{@as(f64, 1.52314e+29)}); + try testFmt("f32: 0", "f32: {d}", .{@as(f32, 0.0)}); try testFmt("f32: 1.1", "f32: {d:.1}", .{@as(f32, 1.1234)}); try testFmt("f32: 1234.57", "f32: {d:.2}", .{@as(f32, 1234.567)}); // -11.1234 is converted to f64 -11.12339... internally (errol3() function takes f64). diff --git a/lib/std/fmt/parse_float.zig b/lib/std/fmt/parse_float.zig @@ -389,7 +389,7 @@ test "fmt.parseFloat" { const epsilon = 1e-7; inline for ([_]type{ f16, f32, f64, f128 }) |T| { - const Z = @IntType(false, T.bit_count); + const Z = std.meta.IntType(false, T.bit_count); testing.expectError(error.InvalidCharacter, parseFloat(T, "")); testing.expectError(error.InvalidCharacter, parseFloat(T, " 1")); diff --git a/lib/std/fs.zig b/lib/std/fs.zig @@ -96,7 +96,6 @@ pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus { /// atime, and mode of the source file so that the next call to `updateFile` will not need a copy. /// Returns the previous status of the file before updating. /// If any of the directories do not exist for dest_path, they are created. -/// TODO https://github.com/ziglang/zig/issues/2885 pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !PrevStatus { const my_cwd = cwd(); @@ -818,6 +817,13 @@ pub const Dir = struct { ) File.OpenError!File { const w = os.windows; + if (sub_path_w[0] == '.' and sub_path_w[1] == 0) { + return error.IsDir; + } + if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) { + return error.IsDir; + } + var result = File{ .handle = undefined, .io_mode = .blocking, @@ -839,12 +845,6 @@ pub const Dir = struct { .SecurityDescriptor = null, .SecurityQualityOfService = null, }; - if (sub_path_w[0] == '.' and sub_path_w[1] == 0) { - return error.IsDir; - } - if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) { - return error.IsDir; - } var io: w.IO_STATUS_BLOCK = undefined; const rc = w.ntdll.NtCreateFile( &result.handle, @@ -864,6 +864,7 @@ pub const Dir = struct { .OBJECT_NAME_INVALID => unreachable, .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, + .NO_MEDIA_IN_DEVICE => return error.NoDevice, .INVALID_PARAMETER => unreachable, .SHARING_VIOLATION => return error.SharingViolation, .ACCESS_DENIED => return error.AccessDenied, @@ -1323,6 +1324,50 @@ pub const Dir = struct { defer file.close(); try file.write(data); } + + pub const AccessError = os.AccessError; + + /// Test accessing `path`. + /// `path` is UTF8-encoded. + /// Be careful of Time-Of-Check-Time-Of-Use race conditions when using this function. + /// For example, instead of testing if a file exists and then opening it, just + /// open it and handle the error for file not found. + pub fn access(self: Dir, sub_path: []const u8, flags: File.OpenFlags) AccessError!void { + if (builtin.os == .windows) { + const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); + return self.accessW(&sub_path_w, flags); + } + const path_c = try os.toPosixPath(sub_path); + return self.accessZ(&path_c, flags); + } + + /// Same as `access` except the path parameter is null-terminated. + pub fn accessZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) AccessError!void { + if (builtin.os == .windows) { + const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path); + return self.accessW(&sub_path_w, flags); + } + const os_mode = if (flags.write and flags.read) + @as(u32, os.R_OK | os.W_OK) + else if (flags.write) + @as(u32, os.W_OK) + else + @as(u32, os.F_OK); + const result = if (need_async_thread) + std.event.Loop.instance.?.faccessatZ(self.fd, sub_path, os_mode) + else + os.faccessatZ(self.fd, sub_path, os_mode, 0); + return result; + } + + /// Same as `access` except asserts the target OS is Windows and the path parameter is + /// * WTF-16 encoded + /// * null-terminated + /// * NtDll prefixed + /// TODO currently this ignores `flags`. + pub fn accessW(self: Dir, sub_path_w: [*:0]const u16, flags: File.OpenFlags) AccessError!void { + return os.faccessatW(self.fd, sub_path_w, 0, 0); + } }; /// Returns an handle to the current working directory that is open for traversal. diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig @@ -60,31 +60,6 @@ pub const File = struct { mode: Mode = default_mode, }; - /// Test for the existence of `path`. - /// `path` is UTF8-encoded. - /// In general it is recommended to avoid this function. For example, - /// instead of testing if a file exists and then opening it, just - /// open it and handle the error for file not found. - /// TODO: deprecate this and move it to `std.fs.Dir`. - /// TODO: integrate with async I/O - pub fn access(path: []const u8) !void { - return os.access(path, os.F_OK); - } - - /// Same as `access` except the parameter is null-terminated. - /// TODO: deprecate this and move it to `std.fs.Dir`. - /// TODO: integrate with async I/O - pub fn accessC(path: [*:0]const u8) !void { - return os.accessC(path, os.F_OK); - } - - /// Same as `access` except the parameter is null-terminated UTF16LE-encoded. - /// TODO: deprecate this and move it to `std.fs.Dir`. - /// TODO: integrate with async I/O - pub fn accessW(path: [*:0]const u16) !void { - return os.accessW(path, os.F_OK); - } - /// Upon success, the stream is in an uninitialized state. To continue using it, /// you must use the open() function. pub fn close(self: File) void { diff --git a/lib/std/fs/watch.zig b/lib/std/fs/watch.zig @@ -26,7 +26,7 @@ fn eqlString(a: []const u16, b: []const u16) bool { } fn hashString(s: []const u16) u32 { - return @truncate(u32, std.hash.Wyhash.hash(0, @sliceToBytes(s))); + return @truncate(u32, std.hash.Wyhash.hash(0, mem.sliceAsBytes(s))); } const WatchEventError = error{ diff --git a/lib/std/hash/auto_hash.zig b/lib/std/hash/auto_hash.zig @@ -93,7 +93,7 @@ pub fn hash(hasher: var, key: var, comptime strat: HashStrategy) void { // TODO Check if the situation is better after #561 is resolved. .Int => @call(.{ .modifier = .always_inline }, hasher.update, .{std.mem.asBytes(&key)}), - .Float => |info| hash(hasher, @bitCast(@IntType(false, info.bits), key), strat), + .Float => |info| hash(hasher, @bitCast(std.meta.IntType(false, info.bits), key), strat), .Bool => hash(hasher, @boolToInt(key), strat), .Enum => hash(hasher, @enumToInt(key), strat), diff --git a/lib/std/hash/wyhash.zig b/lib/std/hash/wyhash.zig @@ -10,7 +10,7 @@ const primes = [_]u64{ }; fn read_bytes(comptime bytes: u8, data: []const u8) u64 { - const T = @IntType(false, 8 * bytes); + const T = std.meta.IntType(false, 8 * bytes); return mem.readIntSliceLittle(T, data[0..bytes]); } diff --git a/lib/std/heap.zig b/lib/std/heap.zig @@ -283,14 +283,14 @@ const WasmPageAllocator = struct { fn getBit(self: FreeBlock, idx: usize) PageStatus { const bit_offset = 0; - return @intToEnum(PageStatus, Io.get(@sliceToBytes(self.data), idx, bit_offset)); + return @intToEnum(PageStatus, Io.get(mem.sliceAsBytes(self.data), idx, bit_offset)); } fn setBits(self: FreeBlock, start_idx: usize, len: usize, val: PageStatus) void { const bit_offset = 0; var i: usize = 0; while (i < len) : (i += 1) { - Io.set(@sliceToBytes(self.data), start_idx + i, bit_offset, @enumToInt(val)); + Io.set(mem.sliceAsBytes(self.data), start_idx + i, bit_offset, @enumToInt(val)); } } @@ -552,7 +552,7 @@ pub const ArenaAllocator = struct { if (len >= actual_min_size) break; } const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len); - const buf_node_slice = @bytesToSlice(BufNode, buf[0..@sizeOf(BufNode)]); + const buf_node_slice = mem.bytesAsSlice(BufNode, buf[0..@sizeOf(BufNode)]); const buf_node = &buf_node_slice[0]; buf_node.* = BufNode{ .data = buf, @@ -1015,7 +1015,7 @@ fn testAllocatorLargeAlignment(allocator: *mem.Allocator) mem.Allocator.Error!vo // very near usize? if (mem.page_size << 2 > maxInt(usize)) return; - const USizeShift = @IntType(false, std.math.log2(usize.bit_count)); + const USizeShift = std.meta.IntType(false, std.math.log2(usize.bit_count)); const large_align = @as(u29, mem.page_size << 2); var align_mask: usize = undefined; diff --git a/lib/std/io.zig b/lib/std/io.zig @@ -121,76 +121,37 @@ pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) unbuffered_in_stream: *Stream, - buffer: [buffer_size]u8, - start_index: usize, - end_index: usize, + const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size }); + fifo: FifoType, pub fn init(unbuffered_in_stream: *Stream) Self { return Self{ .unbuffered_in_stream = unbuffered_in_stream, - .buffer = undefined, - - // Initialize these two fields to buffer_size so that - // in `readFn` we treat the state as being able to read - // more from the unbuffered stream. If we set them to 0 - // and 0, the code would think we already hit EOF. - .start_index = buffer_size, - .end_index = buffer_size, - + .fifo = FifoType.init(), .stream = Stream{ .readFn = readFn }, }; } fn readFn(in_stream: *Stream, dest: []u8) !usize { const self = @fieldParentPtr(Self, "stream", in_stream); - - // Hot path for one byte reads - if (dest.len == 1 and self.end_index > self.start_index) { - dest[0] = self.buffer[self.start_index]; - self.start_index += 1; - return 1; - } - var dest_index: usize = 0; - while (true) { - const dest_space = dest.len - dest_index; - if (dest_space == 0) { - return dest_index; - } - const amt_buffered = self.end_index - self.start_index; - if (amt_buffered == 0) { - assert(self.end_index <= buffer_size); - // Make sure the last read actually gave us some data - if (self.end_index == 0) { + while (dest_index < dest.len) { + const written = self.fifo.read(dest[dest_index..]); + if (written == 0) { + // fifo empty, fill it + const writable = self.fifo.writableSlice(0); + assert(writable.len > 0); + const n = try self.unbuffered_in_stream.read(writable); + if (n == 0) { // reading from the unbuffered stream returned nothing // so we have nothing left to read. return dest_index; } - // we can read more data from the unbuffered stream - if (dest_space < buffer_size) { - self.start_index = 0; - self.end_index = try self.unbuffered_in_stream.read(self.buffer[0..]); - - // Shortcut - if (self.end_index >= dest_space) { - mem.copy(u8, dest[dest_index..], self.buffer[0..dest_space]); - self.start_index = dest_space; - return dest.len; - } - } else { - // asking for so much data that buffering is actually less efficient. - // forward the request directly to the unbuffered stream - const amt_read = try self.unbuffered_in_stream.read(dest[dest_index..]); - return dest_index + amt_read; - } + self.fifo.update(n); } - - const copy_amount = math.min(dest_space, amt_buffered); - const copy_end_index = self.start_index + copy_amount; - mem.copy(u8, dest[dest_index..], self.buffer[self.start_index..copy_end_index]); - self.start_index = copy_end_index; - dest_index += copy_amount; + dest_index += written; } + return dest.len; } }; } @@ -235,7 +196,7 @@ test "io.BufferedInStream" { /// Creates a stream which supports 'un-reading' data, so that it can be read again. /// This makes look-ahead style parsing much easier. -pub fn PeekStream(comptime buffer_size: usize, comptime InStreamError: type) type { +pub fn PeekStream(comptime buffer_type: std.fifo.LinearFifoBufferType, comptime InStreamError: type) type { return struct { const Self = @This(); pub const Error = InStreamError; @@ -244,57 +205,57 @@ pub fn PeekStream(comptime buffer_size: usize, comptime InStreamError: type) typ stream: Stream, base: *Stream, - // Right now the look-ahead space is statically allocated, but a version with dynamic allocation - // is not too difficult to derive from this. - buffer: [buffer_size]u8, - index: usize, - at_end: bool, - - pub fn init(base: *Stream) Self { - return Self{ - .base = base, - .buffer = undefined, - .index = 0, - .at_end = false, - .stream = Stream{ .readFn = readFn }, - }; - } + const FifoType = std.fifo.LinearFifo(u8, buffer_type); + fifo: FifoType, + + pub usingnamespace switch (buffer_type) { + .Static => struct { + pub fn init(base: *Stream) Self { + return .{ + .base = base, + .fifo = FifoType.init(), + .stream = Stream{ .readFn = readFn }, + }; + } + }, + .Slice => struct { + pub fn init(base: *Stream, buf: []u8) Self { + return .{ + .base = base, + .fifo = FifoType.init(buf), + .stream = Stream{ .readFn = readFn }, + }; + } + }, + .Dynamic => struct { + pub fn init(base: *Stream, allocator: *mem.Allocator) Self { + return .{ + .base = base, + .fifo = FifoType.init(allocator), + .stream = Stream{ .readFn = readFn }, + }; + } + }, + }; - pub fn putBackByte(self: *Self, byte: u8) void { - self.buffer[self.index] = byte; - self.index += 1; + pub fn putBackByte(self: *Self, byte: u8) !void { + try self.putBack(&[_]u8{byte}); } - pub fn putBack(self: *Self, bytes: []const u8) void { - var pos = bytes.len; - while (pos != 0) { - pos -= 1; - self.putBackByte(bytes[pos]); - } + pub fn putBack(self: *Self, bytes: []const u8) !void { + try self.fifo.unget(bytes); } fn readFn(in_stream: *Stream, dest: []u8) Error!usize { const self = @fieldParentPtr(Self, "stream", in_stream); // copy over anything putBack()'d - var pos: usize = 0; - while (pos < dest.len and self.index != 0) { - dest[pos] = self.buffer[self.index - 1]; - self.index -= 1; - pos += 1; - } - - if (pos == dest.len or self.at_end) { - return pos; - } + var dest_index = self.fifo.read(dest); + if (dest_index == dest.len) return dest_index; // ask the backing stream for more - const left = dest.len - pos; - const read = try self.base.read(dest[pos..]); - assert(read <= left); - - self.at_end = (read < left); - return pos + read; + dest_index += try self.base.read(dest[dest_index..]); + return dest_index; } }; } @@ -376,7 +337,7 @@ pub fn BitInStream(endian: builtin.Endian, comptime Error: type) type { assert(u_bit_count >= bits); break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count; }; - const Buf = @IntType(false, buf_bit_count); + const Buf = std.meta.IntType(false, buf_bit_count); const BufShift = math.Log2Int(Buf); out_bits.* = @as(usize, 0); @@ -607,52 +568,33 @@ pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamEr unbuffered_out_stream: *Stream, - buffer: [buffer_size]u8, - index: usize, + const FifoType = std.fifo.LinearFifo(u8, std.fifo.LinearFifoBufferType{ .Static = buffer_size }); + fifo: FifoType, pub fn init(unbuffered_out_stream: *Stream) Self { return Self{ .unbuffered_out_stream = unbuffered_out_stream, - .buffer = undefined, - .index = 0, + .fifo = FifoType.init(), .stream = Stream{ .writeFn = writeFn }, }; } pub fn flush(self: *Self) !void { - try self.unbuffered_out_stream.write(self.buffer[0..self.index]); - self.index = 0; + while (true) { + const slice = self.fifo.readableSlice(0); + if (slice.len == 0) break; + try self.unbuffered_out_stream.write(slice); + self.fifo.discard(slice.len); + } } fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void { const self = @fieldParentPtr(Self, "stream", out_stream); - - if (bytes.len == 1) { - // This is not required logic but a shorter path - // for single byte writes - self.buffer[self.index] = bytes[0]; - self.index += 1; - if (self.index == buffer_size) { - try self.flush(); - } - return; - } else if (bytes.len >= self.buffer.len) { + if (bytes.len >= self.fifo.writableLength()) { try self.flush(); return self.unbuffered_out_stream.write(bytes); } - var src_index: usize = 0; - - while (src_index < bytes.len) { - const dest_space_left = self.buffer.len - self.index; - const copy_amt = math.min(dest_space_left, bytes.len - src_index); - mem.copy(u8, self.buffer[self.index..], bytes[src_index .. src_index + copy_amt]); - self.index += copy_amt; - assert(self.index <= self.buffer.len); - if (self.index == self.buffer.len) { - try self.flush(); - } - src_index += copy_amt; - } + self.fifo.writeAssumeCapacity(bytes); } }; } @@ -717,7 +659,7 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type { assert(u_bit_count >= bits); break :bc if (u_bit_count <= u8_bit_count) u8_bit_count else u_bit_count; }; - const Buf = @IntType(false, buf_bit_count); + const Buf = std.meta.IntType(false, buf_bit_count); const BufShift = math.Log2Int(Buf); const buf_value = @intCast(Buf, value); @@ -848,73 +790,6 @@ pub const BufferedAtomicFile = struct { } }; -pub fn readLine(buf: *std.Buffer) ![]u8 { - var stdin_stream = getStdIn().inStream(); - return readLineFrom(&stdin_stream.stream, buf); -} - -/// Reads all characters until the next newline into buf, and returns -/// a slice of the characters read (excluding the newline character(s)). -pub fn readLineFrom(stream: var, buf: *std.Buffer) ![]u8 { - const start = buf.len(); - while (true) { - const byte = try stream.readByte(); - switch (byte) { - '\r' => { - // trash the following \n - _ = try stream.readByte(); - return buf.toSlice()[start..]; - }, - '\n' => return buf.toSlice()[start..], - else => try buf.appendByte(byte), - } - } -} - -test "io.readLineFrom" { - var buf = try std.Buffer.initSize(testing.allocator, 0); - defer buf.deinit(); - var mem_stream = SliceInStream.init( - \\Line 1 - \\Line 22 - \\Line 333 - ); - const stream = &mem_stream.stream; - - testing.expectEqualSlices(u8, "Line 1", try readLineFrom(stream, &buf)); - testing.expectEqualSlices(u8, "Line 22", try readLineFrom(stream, &buf)); - testing.expectError(error.EndOfStream, readLineFrom(stream, &buf)); - testing.expectEqualSlices(u8, "Line 1Line 22Line 333", buf.toSlice()); -} - -pub fn readLineSlice(slice: []u8) ![]u8 { - var stdin_stream = getStdIn().inStream(); - return readLineSliceFrom(&stdin_stream.stream, slice); -} - -/// Reads all characters until the next newline into slice, and returns -/// a slice of the characters read (excluding the newline character(s)). -pub fn readLineSliceFrom(stream: var, slice: []u8) ![]u8 { - // We cannot use Buffer.fromOwnedSlice, as it wants to append a null byte - // after taking ownership, which would always require an allocation. - var buf = std.Buffer{ .list = std.ArrayList(u8).fromOwnedSlice(testing.failing_allocator, slice) }; - try buf.resize(0); - return try readLineFrom(stream, &buf); -} - -test "io.readLineSliceFrom" { - var buf: [7]u8 = undefined; - var mem_stream = SliceInStream.init( - \\Line 1 - \\Line 22 - \\Line 333 - ); - const stream = &mem_stream.stream; - - testing.expectEqualSlices(u8, "Line 1", try readLineSliceFrom(stream, buf[0..])); - testing.expectError(error.OutOfMemory, readLineSliceFrom(stream, buf[0..])); -} - pub const Packing = enum { /// Pack data to byte alignment Byte, @@ -956,12 +831,12 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, //@BUG: inferred error issue. See: #1386 fn deserializeInt(self: *Self, comptime T: type) (Error || error{EndOfStream})!T { - comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T)); + comptime assert(trait.is(.Int)(T) or trait.is(.Float)(T)); const u8_bit_count = 8; const t_bit_count = comptime meta.bitCount(T); - const U = @IntType(false, t_bit_count); + const U = std.meta.IntType(false, t_bit_count); const Log2U = math.Log2Int(U); const int_size = (U.bit_count + 7) / 8; @@ -976,7 +851,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, if (int_size == 1) { if (t_bit_count == 8) return @bitCast(T, buffer[0]); - const PossiblySignedByte = @IntType(T.is_signed, 8); + const PossiblySignedByte = std.meta.IntType(T.is_signed, 8); return @truncate(T, @bitCast(PossiblySignedByte, buffer[0])); } @@ -1005,9 +880,9 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, /// Deserializes data into the type pointed to by `ptr` pub fn deserializeInto(self: *Self, ptr: var) !void { const T = @TypeOf(ptr); - comptime assert(trait.is(builtin.TypeId.Pointer)(T)); + comptime assert(trait.is(.Pointer)(T)); - if (comptime trait.isSlice(T) or comptime trait.isPtrTo(builtin.TypeId.Array)(T)) { + if (comptime trait.isSlice(T) or comptime trait.isPtrTo(.Array)(T)) { for (ptr) |*v| try self.deserializeInto(v); return; @@ -1016,7 +891,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, comptime assert(trait.isSingleItemPtr(T)); const C = comptime meta.Child(T); - const child_type_id = @typeId(C); + const child_type_id = @typeInfo(C); //custom deserializer: fn(self: *Self, deserializer: var) !void if (comptime trait.hasFn("deserialize")(C)) return C.deserialize(ptr, self); @@ -1027,10 +902,10 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, } switch (child_type_id) { - builtin.TypeId.Void => return, - builtin.TypeId.Bool => ptr.* = (try self.deserializeInt(u1)) > 0, - builtin.TypeId.Float, builtin.TypeId.Int => ptr.* = try self.deserializeInt(C), - builtin.TypeId.Struct => { + .Void => return, + .Bool => ptr.* = (try self.deserializeInt(u1)) > 0, + .Float, .Int => ptr.* = try self.deserializeInt(C), + .Struct => { const info = @typeInfo(C).Struct; inline for (info.fields) |*field_info| { @@ -1040,7 +915,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, if (FieldType == void or FieldType == u0) continue; //it doesn't make any sense to read pointers - if (comptime trait.is(builtin.TypeId.Pointer)(FieldType)) { + if (comptime trait.is(.Pointer)(FieldType)) { @compileError("Will not " ++ "read field " ++ name ++ " of struct " ++ @typeName(C) ++ " because it " ++ "is of pointer-type " ++ @typeName(FieldType) ++ "."); @@ -1049,7 +924,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, try self.deserializeInto(&@field(ptr, name)); } }, - builtin.TypeId.Union => { + .Union => { const info = @typeInfo(C).Union; if (info.tag_type) |TagType| { //we avoid duplicate iteration over the enum tags @@ -1073,7 +948,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, @compileError("Cannot meaningfully deserialize " ++ @typeName(C) ++ " because it is an untagged union. Use a custom deserialize()."); }, - builtin.TypeId.Optional => { + .Optional => { const OC = comptime meta.Child(C); const exists = (try self.deserializeInt(u1)) > 0; if (!exists) { @@ -1085,7 +960,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, const val_ptr = &ptr.*.?; try self.deserializeInto(val_ptr); }, - builtin.TypeId.Enum => { + .Enum => { var value = try self.deserializeInt(@TagType(C)); ptr.* = try meta.intToEnum(C, value); }, @@ -1134,12 +1009,12 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co fn serializeInt(self: *Self, value: var) Error!void { const T = @TypeOf(value); - comptime assert(trait.is(builtin.TypeId.Int)(T) or trait.is(builtin.TypeId.Float)(T)); + comptime assert(trait.is(.Int)(T) or trait.is(.Float)(T)); const t_bit_count = comptime meta.bitCount(T); const u8_bit_count = comptime meta.bitCount(u8); - const U = @IntType(false, t_bit_count); + const U = std.meta.IntType(false, t_bit_count); const Log2U = math.Log2Int(U); const int_size = (U.bit_count + 7) / 8; @@ -1183,11 +1058,11 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co return; } - switch (@typeId(T)) { - builtin.TypeId.Void => return, - builtin.TypeId.Bool => try self.serializeInt(@as(u1, @boolToInt(value))), - builtin.TypeId.Float, builtin.TypeId.Int => try self.serializeInt(value), - builtin.TypeId.Struct => { + switch (@typeInfo(T)) { + .Void => return, + .Bool => try self.serializeInt(@as(u1, @boolToInt(value))), + .Float, .Int => try self.serializeInt(value), + .Struct => { const info = @typeInfo(T); inline for (info.Struct.fields) |*field_info| { @@ -1197,7 +1072,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co if (FieldType == void or FieldType == u0) continue; //It doesn't make sense to write pointers - if (comptime trait.is(builtin.TypeId.Pointer)(FieldType)) { + if (comptime trait.is(.Pointer)(FieldType)) { @compileError("Will not " ++ "serialize field " ++ name ++ " of struct " ++ @typeName(T) ++ " because it " ++ "is of pointer-type " ++ @typeName(FieldType) ++ "."); @@ -1205,7 +1080,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co try self.serialize(@field(value, name)); } }, - builtin.TypeId.Union => { + .Union => { const info = @typeInfo(T).Union; if (info.tag_type) |TagType| { const active_tag = meta.activeTag(value); @@ -1226,7 +1101,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co @compileError("Cannot meaningfully serialize " ++ @typeName(T) ++ " because it is an untagged union. Use a custom serialize()."); }, - builtin.TypeId.Optional => { + .Optional => { if (value == null) { try self.serializeInt(@as(u1, @boolToInt(false))); return; @@ -1237,10 +1112,10 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co const val_ptr = &value.?; try self.serialize(val_ptr.*); }, - builtin.TypeId.Enum => { + .Enum => { try self.serializeInt(@enumToInt(value)); }, - else => @compileError("Cannot serialize " ++ @tagName(@typeId(T)) ++ " types (unimplemented)."), + else => @compileError("Cannot serialize " ++ @tagName(@typeInfo(T)) ++ " types (unimplemented)."), } } }; diff --git a/lib/std/io/in_stream.zig b/lib/std/io/in_stream.zig @@ -235,7 +235,7 @@ pub fn InStream(comptime ReadError: type) type { // Only extern and packed structs have defined in-memory layout. comptime assert(@typeInfo(T).Struct.layout != builtin.TypeInfo.ContainerLayout.Auto); var res: [1]T = undefined; - try self.readNoEof(@sliceToBytes(res[0..])); + try self.readNoEof(mem.sliceAsBytes(res[0..])); return res[0]; } diff --git a/lib/std/io/test.zig b/lib/std/io/test.zig @@ -5,6 +5,7 @@ const meta = std.meta; const trait = std.trait; const DefaultPrng = std.rand.DefaultPrng; const expect = std.testing.expect; +const expectEqual = std.testing.expectEqual; const expectError = std.testing.expectError; const mem = std.mem; const fs = std.fs; @@ -44,8 +45,8 @@ test "write a file, read it, then delete it" { defer file.close(); const file_size = try file.getEndPos(); - const expected_file_size = "begin".len + data.len + "end".len; - expect(file_size == expected_file_size); + const expected_file_size: u64 = "begin".len + data.len + "end".len; + expectEqual(expected_file_size, file_size); var file_in_stream = file.inStream(); var buf_stream = io.BufferedInStream(File.ReadError).init(&file_in_stream.stream); @@ -93,12 +94,12 @@ test "SliceInStream" { test "PeekStream" { const bytes = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 }; var ss = io.SliceInStream.init(&bytes); - var ps = io.PeekStream(2, io.SliceInStream.Error).init(&ss.stream); + var ps = io.PeekStream(.{ .Static = 2 }, io.SliceInStream.Error).init(&ss.stream); var dest: [4]u8 = undefined; - ps.putBackByte(9); - ps.putBackByte(10); + try ps.putBackByte(9); + try ps.putBackByte(10); var read = try ps.stream.read(dest[0..4]); expect(read == 4); @@ -114,8 +115,8 @@ test "PeekStream" { expect(read == 2); expect(mem.eql(u8, dest[0..2], bytes[6..8])); - ps.putBackByte(11); - ps.putBackByte(12); + try ps.putBackByte(11); + try ps.putBackByte(12); read = try ps.stream.read(dest[0..4]); expect(read == 2); @@ -317,6 +318,7 @@ test "BitStreams with File Stream" { } fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void { + @setEvalBranchQuota(1500); //@NOTE: if this test is taking too long, reduce the maximum tested bitsize const max_test_bitsize = 128; @@ -340,8 +342,8 @@ fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packi comptime var i = 0; inline while (i <= max_test_bitsize) : (i += 1) { - const U = @IntType(false, i); - const S = @IntType(true, i); + const U = std.meta.IntType(false, i); + const S = std.meta.IntType(true, i); try serializer.serializeInt(@as(U, i)); if (i != 0) try serializer.serializeInt(@as(S, -1)) else try serializer.serialize(@as(S, 0)); } @@ -349,8 +351,8 @@ fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packi i = 0; inline while (i <= max_test_bitsize) : (i += 1) { - const U = @IntType(false, i); - const S = @IntType(true, i); + const U = std.meta.IntType(false, i); + const S = std.meta.IntType(true, i); const x = try deserializer.deserializeInt(U); const y = try deserializer.deserializeInt(S); expect(x == @as(U, i)); diff --git a/lib/std/json.zig b/lib/std/json.zig @@ -19,6 +19,74 @@ const StringEscapes = union(enum) { }, }; +/// Checks to see if a string matches what it would be as a json-encoded string +/// Assumes that `encoded` is a well-formed json string +fn encodesTo(decoded: []const u8, encoded: []const u8) bool { + var i: usize = 0; + var j: usize = 0; + while (i < decoded.len) { + if (j >= encoded.len) return false; + if (encoded[j] != '\\') { + if (decoded[i] != encoded[j]) return false; + j += 1; + i += 1; + } else { + const escape_type = encoded[j + 1]; + if (escape_type != 'u') { + const t: u8 = switch (escape_type) { + '\\' => '\\', + '/' => '/', + 'n' => '\n', + 'r' => '\r', + 't' => '\t', + 'f' => 12, + 'b' => 8, + '"' => '"', + else => unreachable, + }; + if (decoded[i] != t) return false; + j += 2; + i += 1; + } else { + var codepoint = std.fmt.parseInt(u21, encoded[j + 2 .. j + 6], 16) catch unreachable; + j += 6; + if (codepoint >= 0xD800 and codepoint < 0xDC00) { + // surrogate pair + assert(encoded[j] == '\\'); + assert(encoded[j + 1] == 'u'); + const low_surrogate = std.fmt.parseInt(u21, encoded[j + 2 .. j + 6], 16) catch unreachable; + codepoint = 0x10000 + (((codepoint & 0x03ff) << 10) | (low_surrogate & 0x03ff)); + j += 6; + } + var buf: [4]u8 = undefined; + const len = std.unicode.utf8Encode(codepoint, &buf) catch unreachable; + if (i + len > decoded.len) return false; + if (!mem.eql(u8, decoded[i .. i + len], buf[0..len])) return false; + i += len; + } + } + } + assert(i == decoded.len); + assert(j == encoded.len); + return true; +} + +test "encodesTo" { + // same + testing.expectEqual(true, encodesTo("false", "false")); + // totally different + testing.expectEqual(false, encodesTo("false", "true")); + // differnt lengths + testing.expectEqual(false, encodesTo("false", "other")); + // with escape + testing.expectEqual(true, encodesTo("\\", "\\\\")); + testing.expectEqual(true, encodesTo("with\nescape", "with\\nescape")); + // with unicode + testing.expectEqual(true, encodesTo("ą", "\\u0105")); + testing.expectEqual(true, encodesTo("😂", "\\ud83d\\ude02")); + testing.expectEqual(true, encodesTo("withąunicode😂", "with\\u0105unicode\\ud83d\\ude02")); +} + /// A single token slice into the parent string. /// /// Use `token.slice()` on the input at the current position to get the current slice. @@ -1026,10 +1094,8 @@ pub const TokenStream = struct { pub fn next(self: *TokenStream) Error!?Token { if (self.token) |token| { - // TODO: Audit this pattern once #2915 is closed - const copy = token; self.token = null; - return copy; + return token; } var t1: ?Token = undefined; @@ -1203,6 +1269,493 @@ pub const Value = union(enum) { } }; +pub const ParseOptions = struct { + allocator: ?*Allocator = null, + + /// Behaviour when a duplicate field is encountered. + duplicate_field_behavior: enum { + UseFirst, + Error, + UseLast, + } = .Error, +}; + +fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options: ParseOptions) !T { + switch (@typeInfo(T)) { + .Bool => { + return switch (token) { + .True => true, + .False => false, + else => error.UnexpectedToken, + }; + }, + .Float, .ComptimeFloat => { + const numberToken = switch (token) { + .Number => |n| n, + else => return error.UnexpectedToken, + }; + return try std.fmt.parseFloat(T, numberToken.slice(tokens.slice, tokens.i - 1)); + }, + .Int, .ComptimeInt => { + const numberToken = switch (token) { + .Number => |n| n, + else => return error.UnexpectedToken, + }; + if (!numberToken.is_integer) return error.UnexpectedToken; + return try std.fmt.parseInt(T, numberToken.slice(tokens.slice, tokens.i - 1), 10); + }, + .Optional => |optionalInfo| { + if (token == .Null) { + return null; + } else { + return try parseInternal(optionalInfo.child, token, tokens, options); + } + }, + .Enum => |enumInfo| { + switch (token) { + .Number => |numberToken| { + if (!numberToken.is_integer) return error.UnexpectedToken; + const n = try std.fmt.parseInt(enumInfo.tag_type, numberToken.slice(tokens.slice, tokens.i - 1), 10); + return try std.meta.intToEnum(T, n); + }, + .String => |stringToken| { + const source_slice = stringToken.slice(tokens.slice, tokens.i - 1); + switch (stringToken.escapes) { + .None => return std.meta.stringToEnum(T, source_slice) orelse return error.InvalidEnumTag, + .Some => { + inline for (enumInfo.fields) |field| { + if (field.name.len == stringToken.decodedLength() and encodesTo(field.name, source_slice)) { + return @field(T, field.name); + } + } + return error.InvalidEnumTag; + }, + } + }, + else => return error.UnexpectedToken, + } + }, + .Union => |unionInfo| { + if (unionInfo.tag_type) |_| { + // try each of the union fields until we find one that matches + inline for (unionInfo.fields) |u_field| { + if (parseInternal(u_field.field_type, token, tokens, options)) |value| { + return @unionInit(T, u_field.name, value); + } else |err| { + // Bubble up error.OutOfMemory + // Parsing some types won't have OutOfMemory in their + // error-sets, for the condition to be valid, merge it in. + if (@as(@TypeOf(err) || error{OutOfMemory}, err) == error.OutOfMemory) return err; + // otherwise continue through the `inline for` + } + } + return error.NoUnionMembersMatched; + } else { + @compileError("Unable to parse into untagged union '" ++ @typeName(T) ++ "'"); + } + }, + .Struct => |structInfo| { + switch (token) { + .ObjectBegin => {}, + else => return error.UnexpectedToken, + } + var r: T = undefined; + var fields_seen = [_]bool{false} ** structInfo.fields.len; + errdefer { + inline for (structInfo.fields) |field, i| { + if (fields_seen[i]) { + parseFree(field.field_type, @field(r, field.name), options); + } + } + } + + while (true) { + switch ((try tokens.next()) orelse return error.UnexpectedEndOfJson) { + .ObjectEnd => break, + .String => |stringToken| { + const key_source_slice = stringToken.slice(tokens.slice, tokens.i - 1); + var found = false; + inline for (structInfo.fields) |field, i| { + // TODO: using switches here segfault the compiler (#2727?) + if ((stringToken.escapes == .None and mem.eql(u8, field.name, key_source_slice)) or (stringToken.escapes == .Some and (field.name.len == stringToken.decodedLength() and encodesTo(field.name, key_source_slice)))) { + // if (switch (stringToken.escapes) { + // .None => mem.eql(u8, field.name, key_source_slice), + // .Some => (field.name.len == stringToken.decodedLength() and encodesTo(field.name, key_source_slice)), + // }) { + if (fields_seen[i]) { + // switch (options.duplicate_field_behavior) { + // .UseFirst => {}, + // .Error => {}, + // .UseLast => {}, + // } + if (options.duplicate_field_behavior == .UseFirst) { + break; + } else if (options.duplicate_field_behavior == .Error) { + return error.DuplicateJSONField; + } else if (options.duplicate_field_behavior == .UseLast) { + parseFree(field.field_type, @field(r, field.name), options); + } + } + @field(r, field.name) = try parse(field.field_type, tokens, options); + fields_seen[i] = true; + found = true; + break; + } + } + if (!found) return error.UnknownField; + }, + else => return error.UnexpectedToken, + } + } + inline for (structInfo.fields) |field, i| { + if (!fields_seen[i]) { + if (field.default_value) |default| { + @field(r, field.name) = default; + } else { + return error.MissingField; + } + } + } + return r; + }, + .Array => |arrayInfo| { + switch (token) { + .ArrayBegin => { + var r: T = undefined; + var i: usize = 0; + errdefer { + while (true) : (i -= 1) { + parseFree(arrayInfo.child, r[i], options); + if (i == 0) break; + } + } + while (i < r.len) : (i += 1) { + r[i] = try parse(arrayInfo.child, tokens, options); + } + const tok = (try tokens.next()) orelse return error.UnexpectedEndOfJson; + switch (tok) { + .ArrayEnd => {}, + else => return error.UnexpectedToken, + } + return r; + }, + .String => |stringToken| { + if (arrayInfo.child != u8) return error.UnexpectedToken; + var r: T = undefined; + const source_slice = stringToken.slice(tokens.slice, tokens.i - 1); + switch (stringToken.escapes) { + .None => mem.copy(u8, &r, source_slice), + .Some => try unescapeString(&r, source_slice), + } + return r; + }, + else => return error.UnexpectedToken, + } + }, + .Pointer => |ptrInfo| { + const allocator = options.allocator orelse return error.AllocatorRequired; + switch (ptrInfo.size) { + .One => { + const r: T = allocator.create(ptrInfo.child); + r.* = try parseInternal(ptrInfo.child, token, tokens, options); + return r; + }, + .Slice => { + switch (token) { + .ArrayBegin => { + var arraylist = std.ArrayList(ptrInfo.child).init(allocator); + errdefer { + while (arraylist.popOrNull()) |v| { + parseFree(ptrInfo.child, v, options); + } + arraylist.deinit(); + } + + while (true) { + const tok = (try tokens.next()) orelse return error.UnexpectedEndOfJson; + switch (tok) { + .ArrayEnd => break, + else => {}, + } + + try arraylist.ensureCapacity(arraylist.len + 1); + const v = try parseInternal(ptrInfo.child, tok, tokens, options); + arraylist.appendAssumeCapacity(v); + } + return arraylist.toOwnedSlice(); + }, + .String => |stringToken| { + if (ptrInfo.child != u8) return error.UnexpectedToken; + const source_slice = stringToken.slice(tokens.slice, tokens.i - 1); + switch (stringToken.escapes) { + .None => return mem.dupe(allocator, u8, source_slice), + .Some => |some_escapes| { + const output = try allocator.alloc(u8, stringToken.decodedLength()); + errdefer allocator.free(output); + try unescapeString(output, source_slice); + return output; + }, + } + }, + else => return error.UnexpectedToken, + } + }, + else => @compileError("Unable to parse into type '" ++ @typeName(T) ++ "'"), + } + }, + else => @compileError("Unable to parse into type '" ++ @typeName(T) ++ "'"), + } + unreachable; +} + +pub fn parse(comptime T: type, tokens: *TokenStream, options: ParseOptions) !T { + const token = (try tokens.next()) orelse return error.UnexpectedEndOfJson; + return parseInternal(T, token, tokens, options); +} + +/// Releases resources created by `parse`. +/// Should be called with the same type and `ParseOptions` that were passed to `parse` +pub fn parseFree(comptime T: type, value: T, options: ParseOptions) void { + switch (@typeInfo(T)) { + .Bool, .Float, .ComptimeFloat, .Int, .ComptimeInt, .Enum => {}, + .Optional => { + if (value) |v| { + return parseFree(@TypeOf(v), v, options); + } + }, + .Union => |unionInfo| { + if (unionInfo.tag_type) |UnionTagType| { + inline for (unionInfo.fields) |u_field| { + if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) { + parseFree(u_field.field_type, @field(value, u_field.name), options); + break; + } + } + } else { + unreachable; + } + }, + .Struct => |structInfo| { + inline for (structInfo.fields) |field| { + parseFree(field.field_type, @field(value, field.name), options); + } + }, + .Array => |arrayInfo| { + for (value) |v| { + parseFree(arrayInfo.child, v, options); + } + }, + .Pointer => |ptrInfo| { + const allocator = options.allocator orelse unreachable; + switch (ptrInfo.size) { + .One => { + parseFree(ptrInfo.child, value.*, options); + allocator.destroy(v); + }, + .Slice => { + for (value) |v| { + parseFree(ptrInfo.child, v, options); + } + allocator.free(value); + }, + else => unreachable, + } + }, + else => unreachable, + } +} + +test "parse" { + testing.expectEqual(false, try parse(bool, &TokenStream.init("false"), ParseOptions{})); + testing.expectEqual(true, try parse(bool, &TokenStream.init("true"), ParseOptions{})); + testing.expectEqual(@as(u1, 1), try parse(u1, &TokenStream.init("1"), ParseOptions{})); + testing.expectError(error.Overflow, parse(u1, &TokenStream.init("50"), ParseOptions{})); + testing.expectEqual(@as(u64, 42), try parse(u64, &TokenStream.init("42"), ParseOptions{})); + testing.expectEqual(@as(f64, 42), try parse(f64, &TokenStream.init("42.0"), ParseOptions{})); + testing.expectEqual(@as(?bool, null), try parse(?bool, &TokenStream.init("null"), ParseOptions{})); + testing.expectEqual(@as(?bool, true), try parse(?bool, &TokenStream.init("true"), ParseOptions{})); + + testing.expectEqual(@as([3]u8, "foo".*), try parse([3]u8, &TokenStream.init("\"foo\""), ParseOptions{})); + testing.expectEqual(@as([3]u8, "foo".*), try parse([3]u8, &TokenStream.init("[102, 111, 111]"), ParseOptions{})); +} + +test "parse into enum" { + const T = extern enum { + Foo = 42, + Bar, + @"with\\escape", + }; + testing.expectEqual(@as(T, .Foo), try parse(T, &TokenStream.init("\"Foo\""), ParseOptions{})); + testing.expectEqual(@as(T, .Foo), try parse(T, &TokenStream.init("42"), ParseOptions{})); + testing.expectEqual(@as(T, .@"with\\escape"), try parse(T, &TokenStream.init("\"with\\\\escape\""), ParseOptions{})); + testing.expectError(error.InvalidEnumTag, parse(T, &TokenStream.init("5"), ParseOptions{})); + testing.expectError(error.InvalidEnumTag, parse(T, &TokenStream.init("\"Qux\""), ParseOptions{})); +} + +test "parse into that allocates a slice" { + testing.expectError(error.AllocatorRequired, parse([]u8, &TokenStream.init("\"foo\""), ParseOptions{})); + + const options = ParseOptions{ .allocator = testing.allocator }; + { + const r = try parse([]u8, &TokenStream.init("\"foo\""), options); + defer parseFree([]u8, r, options); + testing.expectEqualSlices(u8, "foo", r); + } + { + const r = try parse([]u8, &TokenStream.init("[102, 111, 111]"), options); + defer parseFree([]u8, r, options); + testing.expectEqualSlices(u8, "foo", r); + } + { + const r = try parse([]u8, &TokenStream.init("\"with\\\\escape\""), options); + defer parseFree([]u8, r, options); + testing.expectEqualSlices(u8, "with\\escape", r); + } +} + +test "parse into tagged union" { + { + const T = union(enum) { + int: i32, + float: f64, + string: []const u8, + }; + testing.expectEqual(T{ .float = 1.5 }, try parse(T, &TokenStream.init("1.5"), ParseOptions{})); + } + + { // if union matches string member, fails with NoUnionMembersMatched rather than AllocatorRequired + // Note that this behaviour wasn't necessarily by design, but was + // what fell out of the implementation and may result in interesting + // API breakage if changed + const T = union(enum) { + int: i32, + float: f64, + string: []const u8, + }; + testing.expectError(error.NoUnionMembersMatched, parse(T, &TokenStream.init("\"foo\""), ParseOptions{})); + } + + { // failing allocations should be bubbled up instantly without trying next member + var fail_alloc = testing.FailingAllocator.init(testing.allocator, 0); + const options = ParseOptions{ .allocator = &fail_alloc.allocator }; + const T = union(enum) { + // both fields here match the input + string: []const u8, + array: [3]u8, + }; + testing.expectError(error.OutOfMemory, parse(T, &TokenStream.init("[1,2,3]"), options)); + } + + { + // if multiple matches possible, takes first option + const T = union(enum) { + x: u8, + y: u8, + }; + testing.expectEqual(T{ .x = 42 }, try parse(T, &TokenStream.init("42"), ParseOptions{})); + } +} + +test "parseFree descends into tagged union" { + // tagged unions are broken on arm64: https://github.com/ziglang/zig/issues/4492 + if (std.builtin.arch == .aarch64) return error.SkipZigTest; + + var fail_alloc = testing.FailingAllocator.init(testing.allocator, 1); + const options = ParseOptions{ .allocator = &fail_alloc.allocator }; + const T = union(enum) { + int: i32, + float: f64, + string: []const u8, + }; + // use a string with unicode escape so we know result can't be a reference to global constant + const r = try parse(T, &TokenStream.init("\"with\\u0105unicode\""), options); + testing.expectEqual(@TagType(T).string, @as(@TagType(T), r)); + testing.expectEqualSlices(u8, "withąunicode", r.string); + testing.expectEqual(@as(usize, 0), fail_alloc.deallocations); + parseFree(T, r, options); + testing.expectEqual(@as(usize, 1), fail_alloc.deallocations); +} + +test "parse into struct with no fields" { + const T = struct {}; + testing.expectEqual(T{}, try parse(T, &TokenStream.init("{}"), ParseOptions{})); +} + +test "parse into struct with misc fields" { + @setEvalBranchQuota(10000); + const options = ParseOptions{ .allocator = testing.allocator }; + const T = struct { + int: i64, + float: f64, + @"with\\escape": bool, + @"withąunicode😂": bool, + language: []const u8, + optional: ?bool, + default_field: i32 = 42, + static_array: [3]f64, + dynamic_array: []f64, + + const Bar = struct { + nested: []const u8, + }; + complex: Bar, + + const Baz = struct { + foo: []const u8, + }; + veryComplex: []Baz, + + const Union = union(enum) { + x: u8, + float: f64, + string: []const u8, + }; + a_union: Union, + }; + const r = try parse(T, &TokenStream.init( + \\{ + \\ "int": 420, + \\ "float": 3.14, + \\ "with\\escape": true, + \\ "with\u0105unicode\ud83d\ude02": false, + \\ "language": "zig", + \\ "optional": null, + \\ "static_array": [66.6, 420.420, 69.69], + \\ "dynamic_array": [66.6, 420.420, 69.69], + \\ "complex": { + \\ "nested": "zig" + \\ }, + \\ "veryComplex": [ + \\ { + \\ "foo": "zig" + \\ }, { + \\ "foo": "rocks" + \\ } + \\ ], + \\ "a_union": 100000 + \\} + ), options); + defer parseFree(T, r, options); + testing.expectEqual(@as(i64, 420), r.int); + testing.expectEqual(@as(f64, 3.14), r.float); + testing.expectEqual(true, r.@"with\\escape"); + testing.expectEqual(false, r.@"withąunicode😂"); + testing.expectEqualSlices(u8, "zig", r.language); + testing.expectEqual(@as(?bool, null), r.optional); + testing.expectEqual(@as(i32, 42), r.default_field); + testing.expectEqual(@as(f64, 66.6), r.static_array[0]); + testing.expectEqual(@as(f64, 420.420), r.static_array[1]); + testing.expectEqual(@as(f64, 69.69), r.static_array[2]); + testing.expectEqual(@as(usize, 3), r.dynamic_array.len); + testing.expectEqual(@as(f64, 66.6), r.dynamic_array[0]); + testing.expectEqual(@as(f64, 420.420), r.dynamic_array[1]); + testing.expectEqual(@as(f64, 69.69), r.dynamic_array[2]); + testing.expectEqualSlices(u8, r.complex.nested, "zig"); + testing.expectEqualSlices(u8, "zig", r.veryComplex[0].foo); + testing.expectEqualSlices(u8, "rocks", r.veryComplex[1].foo); + testing.expectEqual(T.Union{ .float = 100000 }, r.a_union); +} + /// A non-stream JSON parser which constructs a tree of Value's. pub const Parser = struct { allocator: *Allocator, @@ -1688,3 +2241,269 @@ test "string copy option" { } testing.expect(found_nocopy); } + +pub const StringifyOptions = struct { + // TODO: indentation options? + // TODO: make escaping '/' in strings optional? + // TODO: allow picking if []u8 is string or array? +}; + +pub fn stringify( + value: var, + options: StringifyOptions, + context: var, + comptime Errors: type, + comptime output: fn (@TypeOf(context), []const u8) Errors!void, +) Errors!void { + const T = @TypeOf(value); + switch (@typeInfo(T)) { + .Float, .ComptimeFloat => { + return std.fmt.formatFloatScientific(value, std.fmt.FormatOptions{}, context, Errors, output); + }, + .Int, .ComptimeInt => { + return std.fmt.formatIntValue(value, "", std.fmt.FormatOptions{}, context, Errors, output); + }, + .Bool => { + return output(context, if (value) "true" else "false"); + }, + .Optional => { + if (value) |payload| { + return try stringify(payload, options, context, Errors, output); + } else { + return output(context, "null"); + } + }, + .Enum => { + if (comptime std.meta.trait.hasFn("jsonStringify")(T)) { + return value.jsonStringify(options, context, Errors, output); + } + + @compileError("Unable to stringify enum '" ++ @typeName(T) ++ "'"); + }, + .Union => { + if (comptime std.meta.trait.hasFn("jsonStringify")(T)) { + return value.jsonStringify(options, context, Errors, output); + } + + const info = @typeInfo(T).Union; + if (info.tag_type) |UnionTagType| { + inline for (info.fields) |u_field| { + if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) { + return try stringify(@field(value, u_field.name), options, context, Errors, output); + } + } + } else { + @compileError("Unable to stringify untagged union '" ++ @typeName(T) ++ "'"); + } + }, + .Struct => |S| { + if (comptime std.meta.trait.hasFn("jsonStringify")(T)) { + return value.jsonStringify(options, context, Errors, output); + } + + try output(context, "{"); + comptime var field_output = false; + inline for (S.fields) |Field, field_i| { + // don't include void fields + if (Field.field_type == void) continue; + + if (!field_output) { + field_output = true; + } else { + try output(context, ","); + } + + try stringify(Field.name, options, context, Errors, output); + try output(context, ":"); + try stringify(@field(value, Field.name), options, context, Errors, output); + } + try output(context, "}"); + return; + }, + .Pointer => |ptr_info| switch (ptr_info.size) { + .One => { + // TODO: avoid loops? + return try stringify(value.*, options, context, Errors, output); + }, + // TODO: .Many when there is a sentinel (waiting for https://github.com/ziglang/zig/pull/3972) + .Slice => { + if (ptr_info.child == u8 and std.unicode.utf8ValidateSlice(value)) { + try output(context, "\""); + var i: usize = 0; + while (i < value.len) : (i += 1) { + switch (value[i]) { + // normal ascii characters + 0x20...0x21, 0x23...0x2E, 0x30...0x5B, 0x5D...0x7F => try output(context, value[i .. i + 1]), + // control characters with short escapes + '\\' => try output(context, "\\\\"), + '\"' => try output(context, "\\\""), + '/' => try output(context, "\\/"), + 0x8 => try output(context, "\\b"), + 0xC => try output(context, "\\f"), + '\n' => try output(context, "\\n"), + '\r' => try output(context, "\\r"), + '\t' => try output(context, "\\t"), + else => { + const ulen = std.unicode.utf8ByteSequenceLength(value[i]) catch unreachable; + const codepoint = std.unicode.utf8Decode(value[i .. i + ulen]) catch unreachable; + if (codepoint <= 0xFFFF) { + // If the character is in the Basic Multilingual Plane (U+0000 through U+FFFF), + // then it may be represented as a six-character sequence: a reverse solidus, followed + // by the lowercase letter u, followed by four hexadecimal digits that encode the character's code point. + try output(context, "\\u"); + try std.fmt.formatIntValue(codepoint, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, context, Errors, output); + } else { + // To escape an extended character that is not in the Basic Multilingual Plane, + // the character is represented as a 12-character sequence, encoding the UTF-16 surrogate pair. + const high = @intCast(u16, (codepoint - 0x10000) >> 10) + 0xD800; + const low = @intCast(u16, codepoint & 0x3FF) + 0xDC00; + try output(context, "\\u"); + try std.fmt.formatIntValue(high, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, context, Errors, output); + try output(context, "\\u"); + try std.fmt.formatIntValue(low, "x", std.fmt.FormatOptions{ .width = 4, .fill = '0' }, context, Errors, output); + } + i += ulen - 1; + }, + } + } + try output(context, "\""); + return; + } + + try output(context, "["); + for (value) |x, i| { + if (i != 0) { + try output(context, ","); + } + try stringify(x, options, context, Errors, output); + } + try output(context, "]"); + return; + }, + else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"), + }, + .Array => |info| { + return try stringify(value[0..], options, context, Errors, output); + }, + else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"), + } + unreachable; +} + +fn teststringify(expected: []const u8, value: var) !void { + const TestStringifyContext = struct { + expected_remaining: []const u8, + fn testStringifyWrite(context: *@This(), bytes: []const u8) !void { + if (context.expected_remaining.len < bytes.len) { + std.debug.warn( + \\====== expected this output: ========= + \\{} + \\======== instead found this: ========= + \\{} + \\====================================== + , .{ + context.expected_remaining, + bytes, + }); + return error.TooMuchData; + } + if (!mem.eql(u8, context.expected_remaining[0..bytes.len], bytes)) { + std.debug.warn( + \\====== expected this output: ========= + \\{} + \\======== instead found this: ========= + \\{} + \\====================================== + , .{ + context.expected_remaining[0..bytes.len], + bytes, + }); + return error.DifferentData; + } + context.expected_remaining = context.expected_remaining[bytes.len..]; + } + }; + var buf: [100]u8 = undefined; + var context = TestStringifyContext{ .expected_remaining = expected }; + try stringify(value, StringifyOptions{}, &context, error{ + TooMuchData, + DifferentData, + }, TestStringifyContext.testStringifyWrite); + if (context.expected_remaining.len > 0) return error.NotEnoughData; +} + +test "stringify basic types" { + try teststringify("false", false); + try teststringify("true", true); + try teststringify("null", @as(?u8, null)); + try teststringify("null", @as(?*u32, null)); + try teststringify("42", 42); + try teststringify("4.2e+01", 42.0); + try teststringify("42", @as(u8, 42)); + try teststringify("42", @as(u128, 42)); + try teststringify("4.2e+01", @as(f32, 42)); + try teststringify("4.2e+01", @as(f64, 42)); +} + +test "stringify string" { + try teststringify("\"hello\"", "hello"); + try teststringify("\"with\\nescapes\\r\"", "with\nescapes\r"); + try teststringify("\"with unicode\\u0001\"", "with unicode\u{1}"); + try teststringify("\"with unicode\\u0080\"", "with unicode\u{80}"); + try teststringify("\"with unicode\\u00ff\"", "with unicode\u{FF}"); + try teststringify("\"with unicode\\u0100\"", "with unicode\u{100}"); + try teststringify("\"with unicode\\u0800\"", "with unicode\u{800}"); + try teststringify("\"with unicode\\u8000\"", "with unicode\u{8000}"); + try teststringify("\"with unicode\\ud799\"", "with unicode\u{D799}"); + try teststringify("\"with unicode\\ud800\\udc00\"", "with unicode\u{10000}"); + try teststringify("\"with unicode\\udbff\\udfff\"", "with unicode\u{10FFFF}"); +} + +test "stringify tagged unions" { + try teststringify("42", union(enum) { + Foo: u32, + Bar: bool, + }{ .Foo = 42 }); +} + +test "stringify struct" { + try teststringify("{\"foo\":42}", struct { + foo: u32, + }{ .foo = 42 }); +} + +test "stringify struct with void field" { + try teststringify("{\"foo\":42}", struct { + foo: u32, + bar: void = {}, + }{ .foo = 42 }); +} + +test "stringify array of structs" { + const MyStruct = struct { + foo: u32, + }; + try teststringify("[{\"foo\":42},{\"foo\":100},{\"foo\":1000}]", [_]MyStruct{ + MyStruct{ .foo = 42 }, + MyStruct{ .foo = 100 }, + MyStruct{ .foo = 1000 }, + }); +} + +test "stringify struct with custom stringifier" { + try teststringify("[\"something special\",42]", struct { + foo: u32, + const Self = @This(); + pub fn jsonStringify( + value: Self, + options: StringifyOptions, + context: var, + comptime Errors: type, + comptime output: fn (@TypeOf(context), []const u8) Errors!void, + ) !void { + try output(context, "[\"something special\","); + try stringify(42, options, context, Errors, output); + try output(context, "]"); + } + }{ .foo = 42 }); +} diff --git a/lib/std/math.zig b/lib/std/math.zig @@ -1,6 +1,4 @@ -const builtin = @import("builtin"); const std = @import("std.zig"); -const TypeId = builtin.TypeId; const assert = std.debug.assert; const testing = std.testing; @@ -89,7 +87,7 @@ pub const snan = @import("math/nan.zig").snan; pub const inf = @import("math/inf.zig").inf; pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) bool { - assert(@typeId(T) == TypeId.Float); + assert(@typeInfo(T) == .Float); return fabs(x - y) < epsilon; } @@ -198,7 +196,7 @@ test "" { } pub fn floatMantissaBits(comptime T: type) comptime_int { - assert(@typeId(T) == builtin.TypeId.Float); + assert(@typeInfo(T) == .Float); return switch (T.bit_count) { 16 => 10, @@ -211,7 +209,7 @@ pub fn floatMantissaBits(comptime T: type) comptime_int { } pub fn floatExponentBits(comptime T: type) comptime_int { - assert(@typeId(T) == builtin.TypeId.Float); + assert(@typeInfo(T) == .Float); return switch (T.bit_count) { 16 => 5, @@ -446,7 +444,7 @@ pub fn Log2Int(comptime T: type) type { count += 1; } - return @IntType(false, count); + return std.meta.IntType(false, count); } pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) type { @@ -462,7 +460,7 @@ pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) t if (is_signed) { magnitude_bits += 1; } - return @IntType(is_signed, magnitude_bits); + return std.meta.IntType(is_signed, magnitude_bits); } test "math.IntFittingRange" { @@ -526,7 +524,7 @@ fn testOverflow() void { pub fn absInt(x: var) !@TypeOf(x) { const T = @TypeOf(x); - comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt + comptime assert(@typeInfo(T) == .Int); // must pass an integer to absInt comptime assert(T.is_signed); // must pass a signed integer to absInt if (x == minInt(@TypeOf(x))) { @@ -560,7 +558,7 @@ fn testAbsFloat() void { pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T { @setRuntimeSafety(false); if (denominator == 0) return error.DivisionByZero; - if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow; + if (@typeInfo(T) == .Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow; return @divTrunc(numerator, denominator); } @@ -581,7 +579,7 @@ fn testDivTrunc() void { pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T { @setRuntimeSafety(false); if (denominator == 0) return error.DivisionByZero; - if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow; + if (@typeInfo(T) == .Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow; return @divFloor(numerator, denominator); } @@ -602,7 +600,7 @@ fn testDivFloor() void { pub fn divExact(comptime T: type, numerator: T, denominator: T) !T { @setRuntimeSafety(false); if (denominator == 0) return error.DivisionByZero; - if (@typeId(T) == builtin.TypeId.Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow; + if (@typeInfo(T) == .Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow; const result = @divTrunc(numerator, denominator); if (result * denominator != numerator) return error.UnexpectedRemainder; return result; @@ -676,13 +674,13 @@ pub fn absCast(x: var) t: { if (@TypeOf(x) == comptime_int) { break :t comptime_int; } else { - break :t @IntType(false, @TypeOf(x).bit_count); + break :t std.meta.IntType(false, @TypeOf(x).bit_count); } } { if (@TypeOf(x) == comptime_int) { return if (x < 0) -x else x; } - const uint = @IntType(false, @TypeOf(x).bit_count); + const uint = std.meta.IntType(false, @TypeOf(x).bit_count); if (x >= 0) return @intCast(uint, x); return @intCast(uint, -(x + 1)) + 1; @@ -703,10 +701,10 @@ test "math.absCast" { /// Returns the negation of the integer parameter. /// Result is a signed integer. -pub fn negateCast(x: var) !@IntType(true, @TypeOf(x).bit_count) { +pub fn negateCast(x: var) !std.meta.IntType(true, @TypeOf(x).bit_count) { if (@TypeOf(x).is_signed) return negate(x); - const int = @IntType(true, @TypeOf(x).bit_count); + const int = std.meta.IntType(true, @TypeOf(x).bit_count); if (x > -minInt(int)) return error.Overflow; if (x == -minInt(int)) return minInt(int); @@ -727,8 +725,8 @@ test "math.negateCast" { /// Cast an integer to a different integer type. If the value doesn't fit, /// return an error. pub fn cast(comptime T: type, x: var) (error{Overflow}!T) { - comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer - comptime assert(@typeId(@TypeOf(x)) == builtin.TypeId.Int); // must pass an integer + comptime assert(@typeInfo(T) == .Int); // must pass an integer + comptime assert(@typeInfo(@TypeOf(x)) == .Int); // must pass an integer if (maxInt(@TypeOf(x)) > maxInt(T) and x > maxInt(T)) { return error.Overflow; } else if (minInt(@TypeOf(x)) < minInt(T) and x < minInt(T)) { @@ -792,11 +790,11 @@ fn testFloorPowerOfTwo() void { /// Returns the next power of two (if the value is not already a power of two). /// Only unsigned integers can be used. Zero is not an allowed input. /// Result is a type with 1 more bit than the input type. -pub fn ceilPowerOfTwoPromote(comptime T: type, value: T) @IntType(T.is_signed, T.bit_count + 1) { - comptime assert(@typeId(T) == builtin.TypeId.Int); +pub fn ceilPowerOfTwoPromote(comptime T: type, value: T) std.meta.IntType(T.is_signed, T.bit_count + 1) { + comptime assert(@typeInfo(T) == .Int); comptime assert(!T.is_signed); assert(value != 0); - comptime const PromotedType = @IntType(T.is_signed, T.bit_count + 1); + comptime const PromotedType = std.meta.IntType(T.is_signed, T.bit_count + 1); comptime const shiftType = std.math.Log2Int(PromotedType); return @as(PromotedType, 1) << @intCast(shiftType, T.bit_count - @clz(T, value - 1)); } @@ -805,9 +803,9 @@ pub fn ceilPowerOfTwoPromote(comptime T: type, value: T) @IntType(T.is_signed, T /// Only unsigned integers can be used. Zero is not an allowed input. /// If the value doesn't fit, returns an error. pub fn ceilPowerOfTwo(comptime T: type, value: T) (error{Overflow}!T) { - comptime assert(@typeId(T) == builtin.TypeId.Int); + comptime assert(@typeInfo(T) == .Int); comptime assert(!T.is_signed); - comptime const PromotedType = @IntType(T.is_signed, T.bit_count + 1); + comptime const PromotedType = std.meta.IntType(T.is_signed, T.bit_count + 1); comptime const overflowBit = @as(PromotedType, 1) << T.bit_count; var x = ceilPowerOfTwoPromote(T, value); if (overflowBit & x != 0) { @@ -878,10 +876,10 @@ test "std.math.log2_int_ceil" { pub fn lossyCast(comptime T: type, value: var) T { switch (@typeInfo(@TypeOf(value))) { - builtin.TypeId.Int => return @intToFloat(T, value), - builtin.TypeId.Float => return @floatCast(T, value), - builtin.TypeId.ComptimeInt => return @as(T, value), - builtin.TypeId.ComptimeFloat => return @as(T, value), + .Int => return @intToFloat(T, value), + .Float => return @floatCast(T, value), + .ComptimeInt => return @as(T, value), + .ComptimeFloat => return @as(T, value), else => @compileError("bad type"), } } @@ -949,8 +947,8 @@ test "max value type" { testing.expect(x == 2147483647); } -pub fn mulWide(comptime T: type, a: T, b: T) @IntType(T.is_signed, T.bit_count * 2) { - const ResultInt = @IntType(T.is_signed, T.bit_count * 2); +pub fn mulWide(comptime T: type, a: T, b: T) std.meta.IntType(T.is_signed, T.bit_count * 2) { + const ResultInt = std.meta.IntType(T.is_signed, T.bit_count * 2); return @as(ResultInt, a) * @as(ResultInt, b); } diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig @@ -1,5 +1,4 @@ const std = @import("../../std.zig"); -const builtin = @import("builtin"); const debug = std.debug; const testing = std.testing; const math = std.math; @@ -9,10 +8,8 @@ const ArrayList = std.ArrayList; const maxInt = std.math.maxInt; const minInt = std.math.minInt; -const TypeId = builtin.TypeId; - pub const Limb = usize; -pub const DoubleLimb = @IntType(false, 2 * Limb.bit_count); +pub const DoubleLimb = std.meta.IntType(false, 2 * Limb.bit_count); pub const Log2Limb = math.Log2Int(Limb); comptime { @@ -270,8 +267,8 @@ pub const Int = struct { const T = @TypeOf(value); switch (@typeInfo(T)) { - TypeId.Int => |info| { - const UT = if (T.is_signed) @IntType(false, T.bit_count - 1) else T; + .Int => |info| { + const UT = if (T.is_signed) std.meta.IntType(false, T.bit_count - 1) else T; try self.ensureCapacity(@sizeOf(UT) / @sizeOf(Limb)); self.metadata = 0; @@ -294,7 +291,7 @@ pub const Int = struct { } } }, - TypeId.ComptimeInt => { + .ComptimeInt => { comptime var w_value = if (value < 0) -value else value; const req_limbs = @divFloor(math.log2(w_value), Limb.bit_count) + 1; @@ -332,9 +329,9 @@ pub const Int = struct { /// /// Returns an error if self cannot be narrowed into the requested type without truncation. pub fn to(self: Int, comptime T: type) ConvertError!T { - switch (@typeId(T)) { - TypeId.Int => { - const UT = @IntType(false, T.bit_count); + switch (@typeInfo(T)) { + .Int => { + const UT = std.meta.IntType(false, T.bit_count); if (self.bitCountTwosComp() > T.bit_count) { return error.TargetTooSmall; diff --git a/lib/std/math/big/rational.zig b/lib/std/math/big/rational.zig @@ -1,5 +1,4 @@ const std = @import("../../std.zig"); -const builtin = @import("builtin"); const debug = std.debug; const math = std.math; const mem = std.mem; @@ -7,8 +6,6 @@ const testing = std.testing; const Allocator = mem.Allocator; const ArrayList = std.ArrayList; -const TypeId = builtin.TypeId; - const bn = @import("int.zig"); const Limb = bn.Limb; const DoubleLimb = bn.DoubleLimb; @@ -129,9 +126,9 @@ pub const Rational = struct { /// completely represent the provided float. pub fn setFloat(self: *Rational, comptime T: type, f: T) !void { // Translated from golang.go/src/math/big/rat.go. - debug.assert(@typeId(T) == builtin.TypeId.Float); + debug.assert(@typeInfo(T) == .Float); - const UnsignedIntType = @IntType(false, T.bit_count); + const UnsignedIntType = std.meta.IntType(false, T.bit_count); const f_bits = @bitCast(UnsignedIntType, f); const exponent_bits = math.floatExponentBits(T); @@ -187,10 +184,10 @@ pub const Rational = struct { pub fn toFloat(self: Rational, comptime T: type) !T { // Translated from golang.go/src/math/big/rat.go. // TODO: Indicate whether the result is not exact. - debug.assert(@typeId(T) == builtin.TypeId.Float); + debug.assert(@typeInfo(T) == .Float); const fsize = T.bit_count; - const BitReprType = @IntType(false, T.bit_count); + const BitReprType = std.meta.IntType(false, T.bit_count); const msize = math.floatMantissaBits(T); const msize1 = msize + 1; @@ -465,7 +462,7 @@ pub const Rational = struct { } }; -const SignedDoubleLimb = @IntType(true, DoubleLimb.bit_count); +const SignedDoubleLimb = std.meta.IntType(true, DoubleLimb.bit_count); fn gcd(rma: *Int, x: Int, y: Int) !void { rma.assertWritable(); @@ -653,7 +650,7 @@ test "big.rational gcd one large" { } fn extractLowBits(a: Int, comptime T: type) T { - testing.expect(@typeId(T) == builtin.TypeId.Int); + testing.expect(@typeInfo(T) == .Int); if (T.bit_count <= Limb.bit_count) { return @truncate(T, a.limbs[0]); diff --git a/lib/std/math/cos.zig b/lib/std/math/cos.zig @@ -44,7 +44,7 @@ const pi4c = 2.69515142907905952645E-15; const m4pi = 1.273239544735162542821171882678754627704620361328125; fn cos_(comptime T: type, x_: T) T { - const I = @IntType(true, T.bit_count); + const I = std.meta.IntType(true, T.bit_count); var x = x_; if (math.isNan(x) or math.isInf(x)) { diff --git a/lib/std/math/ln.zig b/lib/std/math/ln.zig @@ -7,8 +7,6 @@ const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; -const builtin = @import("builtin"); -const TypeId = builtin.TypeId; /// Returns the natural logarithm of x. /// @@ -19,21 +17,21 @@ const TypeId = builtin.TypeId; /// - ln(nan) = nan pub fn ln(x: var) @TypeOf(x) { const T = @TypeOf(x); - switch (@typeId(T)) { - TypeId.ComptimeFloat => { + switch (@typeInfo(T)) { + .ComptimeFloat => { return @as(comptime_float, ln_64(x)); }, - TypeId.Float => { + .Float => { return switch (T) { f32 => ln_32(x), f64 => ln_64(x), else => @compileError("ln not implemented for " ++ @typeName(T)), }; }, - TypeId.ComptimeInt => { + .ComptimeInt => { return @as(comptime_int, math.floor(ln_64(@as(f64, x)))); }, - TypeId.Int => { + .Int => { return @as(T, math.floor(ln_64(@as(f64, x)))); }, else => @compileError("ln not implemented for " ++ @typeName(T)), diff --git a/lib/std/math/log.zig b/lib/std/math/log.zig @@ -6,8 +6,6 @@ const std = @import("../std.zig"); const math = std.math; -const builtin = @import("builtin"); -const TypeId = builtin.TypeId; const expect = std.testing.expect; /// Returns the logarithm of x for the provided base. @@ -16,24 +14,24 @@ pub fn log(comptime T: type, base: T, x: T) T { return math.log2(x); } else if (base == 10) { return math.log10(x); - } else if ((@typeId(T) == TypeId.Float or @typeId(T) == TypeId.ComptimeFloat) and base == math.e) { + } else if ((@typeInfo(T) == .Float or @typeInfo(T) == .ComptimeFloat) and base == math.e) { return math.ln(x); } const float_base = math.lossyCast(f64, base); - switch (@typeId(T)) { - TypeId.ComptimeFloat => { + switch (@typeInfo(T)) { + .ComptimeFloat => { return @as(comptime_float, math.ln(@as(f64, x)) / math.ln(float_base)); }, - TypeId.ComptimeInt => { + .ComptimeInt => { return @as(comptime_int, math.floor(math.ln(@as(f64, x)) / math.ln(float_base))); }, - builtin.TypeId.Int => { + .Int => { // TODO implement integer log without using float math return @floatToInt(T, math.floor(math.ln(@intToFloat(f64, x)) / math.ln(float_base))); }, - builtin.TypeId.Float => { + .Float => { switch (T) { f32 => return @floatCast(f32, math.ln(@as(f64, x)) / math.ln(float_base)), f64 => return math.ln(x) / math.ln(float_base), diff --git a/lib/std/math/log10.zig b/lib/std/math/log10.zig @@ -7,8 +7,6 @@ const std = @import("../std.zig"); const math = std.math; const testing = std.testing; -const builtin = @import("builtin"); -const TypeId = builtin.TypeId; const maxInt = std.math.maxInt; /// Returns the base-10 logarithm of x. @@ -20,21 +18,21 @@ const maxInt = std.math.maxInt; /// - log10(nan) = nan pub fn log10(x: var) @TypeOf(x) { const T = @TypeOf(x); - switch (@typeId(T)) { - TypeId.ComptimeFloat => { + switch (@typeInfo(T)) { + .ComptimeFloat => { return @as(comptime_float, log10_64(x)); }, - TypeId.Float => { + .Float => { return switch (T) { f32 => log10_32(x), f64 => log10_64(x), else => @compileError("log10 not implemented for " ++ @typeName(T)), }; }, - TypeId.ComptimeInt => { + .ComptimeInt => { return @as(comptime_int, math.floor(log10_64(@as(f64, x)))); }, - TypeId.Int => { + .Int => { return @floatToInt(T, math.floor(log10_64(@intToFloat(f64, x)))); }, else => @compileError("log10 not implemented for " ++ @typeName(T)), diff --git a/lib/std/math/log2.zig b/lib/std/math/log2.zig @@ -7,8 +7,6 @@ const std = @import("../std.zig"); const math = std.math; const expect = std.testing.expect; -const builtin = @import("builtin"); -const TypeId = builtin.TypeId; const maxInt = std.math.maxInt; /// Returns the base-2 logarithm of x. @@ -20,18 +18,18 @@ const maxInt = std.math.maxInt; /// - log2(nan) = nan pub fn log2(x: var) @TypeOf(x) { const T = @TypeOf(x); - switch (@typeId(T)) { - TypeId.ComptimeFloat => { + switch (@typeInfo(T)) { + .ComptimeFloat => { return @as(comptime_float, log2_64(x)); }, - TypeId.Float => { + .Float => { return switch (T) { f32 => log2_32(x), f64 => log2_64(x), else => @compileError("log2 not implemented for " ++ @typeName(T)), }; }, - TypeId.ComptimeInt => comptime { + .ComptimeInt => comptime { var result = 0; var x_shifted = x; while (b: { @@ -40,7 +38,7 @@ pub fn log2(x: var) @TypeOf(x) { }) : (result += 1) {} return result; }, - TypeId.Int => { + .Int => { return math.log2_int(T, x); }, else => @compileError("log2 not implemented for " ++ @typeName(T)), diff --git a/lib/std/math/pow.zig b/lib/std/math/pow.zig @@ -145,7 +145,7 @@ pub fn pow(comptime T: type, x: T, y: T) T { var xe = r2.exponent; var x1 = r2.significand; - var i = @floatToInt(@IntType(true, T.bit_count), yi); + var i = @floatToInt(std.meta.IntType(true, T.bit_count), yi); while (i != 0) : (i >>= 1) { const overflow_shift = math.floatExponentBits(T) + 1; if (xe < -(1 << overflow_shift) or (1 << overflow_shift) < xe) { diff --git a/lib/std/math/sin.zig b/lib/std/math/sin.zig @@ -45,7 +45,7 @@ const pi4c = 2.69515142907905952645E-15; const m4pi = 1.273239544735162542821171882678754627704620361328125; fn sin_(comptime T: type, x_: T) T { - const I = @IntType(true, T.bit_count); + const I = std.meta.IntType(true, T.bit_count); var x = x_; if (x == 0 or math.isNan(x)) { diff --git a/lib/std/math/sqrt.zig b/lib/std/math/sqrt.zig @@ -31,7 +31,7 @@ pub fn sqrt(x: var) Sqrt(@TypeOf(x)) { } } -fn sqrt_int(comptime T: type, value: T) @IntType(false, T.bit_count / 2) { +fn sqrt_int(comptime T: type, value: T) std.meta.IntType(false, T.bit_count / 2) { var op = value; var res: T = 0; var one: T = 1 << (T.bit_count - 2); @@ -50,7 +50,7 @@ fn sqrt_int(comptime T: type, value: T) @IntType(false, T.bit_count / 2) { one >>= 2; } - const ResultType = @IntType(false, T.bit_count / 2); + const ResultType = std.meta.IntType(false, T.bit_count / 2); return @intCast(ResultType, res); } @@ -66,7 +66,7 @@ test "math.sqrt_int" { /// Returns the return type `sqrt` will return given an operand of type `T`. pub fn Sqrt(comptime T: type) type { return switch (@typeInfo(T)) { - .Int => |int| @IntType(false, int.bits / 2), + .Int => |int| std.meta.IntType(false, int.bits / 2), else => T, }; } diff --git a/lib/std/math/tan.zig b/lib/std/math/tan.zig @@ -38,7 +38,7 @@ const pi4c = 2.69515142907905952645E-15; const m4pi = 1.273239544735162542821171882678754627704620361328125; fn tan_(comptime T: type, x_: T) T { - const I = @IntType(true, T.bit_count); + const I = std.meta.IntType(true, T.bit_count); var x = x_; if (x == 0 or math.isNan(x)) { diff --git a/lib/std/mem.zig b/lib/std/mem.zig @@ -132,7 +132,7 @@ pub const Allocator = struct { // their own frame with @Frame(func). return @intToPtr([*]T, @ptrToInt(byte_slice.ptr))[0..n]; } else { - return @bytesToSlice(T, @alignCast(a, byte_slice)); + return mem.bytesAsSlice(T, @alignCast(a, byte_slice)); } } @@ -173,7 +173,7 @@ pub const Allocator = struct { return @as([*]align(new_alignment) T, undefined)[0..0]; } - const old_byte_slice = @sliceToBytes(old_mem); + const old_byte_slice = mem.sliceAsBytes(old_mem); const byte_count = math.mul(usize, @sizeOf(T), new_n) catch return Error.OutOfMemory; // Note: can't set shrunk memory to undefined as memory shouldn't be modified on realloc failure const byte_slice = try self.reallocFn(self, old_byte_slice, Slice.alignment, byte_count, new_alignment); @@ -181,7 +181,7 @@ pub const Allocator = struct { if (new_n > old_mem.len) { @memset(byte_slice.ptr + old_byte_slice.len, undefined, byte_slice.len - old_byte_slice.len); } - return @bytesToSlice(T, @alignCast(new_alignment, byte_slice)); + return mem.bytesAsSlice(T, @alignCast(new_alignment, byte_slice)); } /// Prefer calling realloc to shrink if you can tolerate failure, such as @@ -221,18 +221,18 @@ pub const Allocator = struct { // new_n <= old_mem.len and the multiplication didn't overflow for that operation. const byte_count = @sizeOf(T) * new_n; - const old_byte_slice = @sliceToBytes(old_mem); + const old_byte_slice = mem.sliceAsBytes(old_mem); @memset(old_byte_slice.ptr + byte_count, undefined, old_byte_slice.len - byte_count); const byte_slice = self.shrinkFn(self, old_byte_slice, Slice.alignment, byte_count, new_alignment); assert(byte_slice.len == byte_count); - return @bytesToSlice(T, @alignCast(new_alignment, byte_slice)); + return mem.bytesAsSlice(T, @alignCast(new_alignment, byte_slice)); } /// Free an array allocated with `alloc`. To free a single item, /// see `destroy`. pub fn free(self: *Allocator, memory: var) void { const Slice = @typeInfo(@TypeOf(memory)).Pointer; - const bytes = @sliceToBytes(memory); + const bytes = mem.sliceAsBytes(memory); const bytes_len = bytes.len + if (Slice.sentinel != null) @sizeOf(Slice.child) else 0; if (bytes_len == 0) return; const non_const_ptr = @intToPtr([*]u8, @ptrToInt(bytes.ptr)); @@ -276,18 +276,67 @@ pub fn set(comptime T: type, dest: []T, value: T) void { d.* = value; } +/// Generally, Zig users are encouraged to explicitly initialize all fields of a struct explicitly rather than using this function. +/// However, it is recognized that there are sometimes use cases for initializing all fields to a "zero" value. For example, when +/// interfacing with a C API where this practice is more common and relied upon. If you are performing code review and see this +/// function used, examine closely - it may be a code smell. /// Zero initializes the type. -/// This can be used to zero initialize a C-struct. +/// This can be used to zero initialize a any type for which it makes sense. Structs will be initialized recursively. pub fn zeroes(comptime T: type) T { - if (@sizeOf(T) == 0) return T{}; - - if (comptime meta.containerLayout(T) != .Extern) { - @compileError("TODO: Currently this only works for extern types"); + switch (@typeInfo(T)) { + .ComptimeInt, .Int, .ComptimeFloat, .Float => { + return @as(T, 0); + }, + .Enum, .EnumLiteral => { + return @intToEnum(T, 0); + }, + .Void => { + return {}; + }, + .Bool => { + return false; + }, + .Optional, .Null => { + return null; + }, + .Struct => |struct_info| { + if (@sizeOf(T) == 0) return T{}; + if (comptime meta.containerLayout(T) == .Extern) { + var item: T = undefined; + @memset(@ptrCast([*]u8, &item), 0, @sizeOf(T)); + return item; + } else { + var structure: T = undefined; + inline for (struct_info.fields) |field| { + @field(structure, field.name) = zeroes(@TypeOf(@field(structure, field.name))); + } + return structure; + } + }, + .Pointer => |ptr_info| { + switch (ptr_info.size) { + .Slice => { + return &[_]ptr_info.child{}; + }, + .C => { + return null; + }, + .One, .Many => { + @compileError("Can't set a non nullable pointer to zero."); + }, + } + }, + .Array => |info| { + var array: T = undefined; + for (array) |*element| { + element.* = zeroes(info.child); + } + return array; + }, + .Vector, .ErrorUnion, .ErrorSet, .Union, .Fn, .BoundFn, .Type, .NoReturn, .Undefined, .Opaque, .Frame, .AnyFrame, => { + @compileError("Can't set a "++ @typeName(T) ++" to zero."); + }, } - - var item: T = undefined; - @memset(@ptrCast([*]u8, &item), 0, @sizeOf(T)); - return item; } test "mem.zeroes" { @@ -301,6 +350,62 @@ test "mem.zeroes" { testing.expect(a.x == 0); testing.expect(a.y == 10); + + const ZigStruct = struct { + const IntegralTypes = struct { + integer_0: i0, + integer_8: i8, + integer_16: i16, + integer_32: i32, + integer_64: i64, + integer_128: i128, + unsigned_0: u0, + unsigned_8: u8, + unsigned_16: u16, + unsigned_32: u32, + unsigned_64: u64, + unsigned_128: u128, + + float_32: f32, + float_64: f64, + }; + + integral_types: IntegralTypes, + + const Pointers = struct { + optional: ?*u8, + c_pointer: [*c]u8, + slice: []u8, + }; + pointers: Pointers, + + array: [2]u32, + optional_int: ?u8, + empty: void, + }; + + const b = zeroes(ZigStruct); + testing.expectEqual(@as(i8, 0), b.integral_types.integer_0); + testing.expectEqual(@as(i8, 0), b.integral_types.integer_8); + testing.expectEqual(@as(i16, 0), b.integral_types.integer_16); + testing.expectEqual(@as(i32, 0), b.integral_types.integer_32); + testing.expectEqual(@as(i64, 0), b.integral_types.integer_64); + testing.expectEqual(@as(i128, 0), b.integral_types.integer_128); + testing.expectEqual(@as(u8, 0), b.integral_types.unsigned_0); + testing.expectEqual(@as(u8, 0), b.integral_types.unsigned_8); + testing.expectEqual(@as(u16, 0), b.integral_types.unsigned_16); + testing.expectEqual(@as(u32, 0), b.integral_types.unsigned_32); + testing.expectEqual(@as(u64, 0), b.integral_types.unsigned_64); + testing.expectEqual(@as(u128, 0), b.integral_types.unsigned_128); + testing.expectEqual(@as(f32, 0), b.integral_types.float_32); + testing.expectEqual(@as(f64, 0), b.integral_types.float_64); + testing.expectEqual(@as(?*u8, null), b.pointers.optional); + testing.expectEqual(@as([*c]u8, null), b.pointers.c_pointer); + testing.expectEqual(@as([]u8, &[_]u8{}), b.pointers.slice); + for (b.array) |e| { + testing.expectEqual(@as(u32, 0), e); + } + testing.expectEqual(@as(?u8, null), b.optional_int); } pub fn secureZero(comptime T: type, s: []T) void { @@ -387,13 +492,21 @@ pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool { return true; } -/// Copies ::m to newly allocated memory. Caller is responsible to free it. +/// Copies `m` to newly allocated memory. Caller owns the memory. pub fn dupe(allocator: *Allocator, comptime T: type, m: []const T) ![]T { const new_buf = try allocator.alloc(T, m.len); copy(T, new_buf, m); return new_buf; } +/// Copies `m` to newly allocated memory, with a null-terminated element. Caller owns the memory. +pub fn dupeZ(allocator: *Allocator, comptime T: type, m: []const T) ![:0]T { + const new_buf = try allocator.alloc(T, m.len + 1); + copy(T, new_buf, m); + new_buf[m.len] = 0; + return new_buf[0..m.len :0]; +} + /// Remove values from the beginning of a slice. pub fn trimLeft(comptime T: type, slice: []const T, values_to_strip: []const T) []const T { var begin: usize = 0; @@ -700,7 +813,7 @@ pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void { assert(buffer.len >= @divExact(T.bit_count, 8)); // TODO I want to call writeIntLittle here but comptime eval facilities aren't good enough - const uint = @IntType(false, T.bit_count); + const uint = std.meta.IntType(false, T.bit_count); var bits = @truncate(uint, value); for (buffer) |*b| { b.* = @truncate(u8, bits); @@ -717,7 +830,7 @@ pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void { assert(buffer.len >= @divExact(T.bit_count, 8)); // TODO I want to call writeIntBig here but comptime eval facilities aren't good enough - const uint = @IntType(false, T.bit_count); + const uint = std.meta.IntType(false, T.bit_count); var bits = @truncate(uint, value); var index: usize = buffer.len; while (index != 0) { @@ -1478,6 +1591,162 @@ test "bytesToValue" { testing.expect(deadbeef == @as(u32, 0xDEADBEEF)); } +//TODO copy also is_volatile, etc. I tried to use @typeInfo, modify child type, use @Type, but ran into issues. +fn BytesAsSliceReturnType(comptime T: type, comptime bytesType: type) type { + if (!(trait.isSlice(bytesType) and meta.Child(bytesType) == u8) and !(trait.isPtrTo(.Array)(bytesType) and meta.Child(meta.Child(bytesType)) == u8)) { + @compileError("expected []u8 or *[_]u8, passed " ++ @typeName(bytesType)); + } + + if (trait.isPtrTo(.Array)(bytesType) and @typeInfo(meta.Child(bytesType)).Array.len % @sizeOf(T) != 0) { + @compileError("number of bytes in " ++ @typeName(bytesType) ++ " is not divisible by size of " ++ @typeName(T)); + } + + const alignment = meta.alignment(bytesType); + + return if (trait.isConstPtr(bytesType)) []align(alignment) const T else []align(alignment) T; +} + +pub fn bytesAsSlice(comptime T: type, bytes: var) BytesAsSliceReturnType(T, @TypeOf(bytes)) { + const bytesSlice = if (comptime trait.isPtrTo(.Array)(@TypeOf(bytes))) bytes[0..] else bytes; + + // let's not give an undefined pointer to @ptrCast + // it may be equal to zero and fail a null check + if (bytesSlice.len == 0) { + return &[0]T{}; + } + + const bytesType = @TypeOf(bytesSlice); + const alignment = comptime meta.alignment(bytesType); + + const castTarget = if (comptime trait.isConstPtr(bytesType)) [*]align(alignment) const T else [*]align(alignment) T; + + return @ptrCast(castTarget, bytesSlice.ptr)[0..@divExact(bytes.len, @sizeOf(T))]; +} + +test "bytesAsSlice" { + const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF }; + const slice = bytesAsSlice(u16, bytes[0..]); + testing.expect(slice.len == 2); + testing.expect(bigToNative(u16, slice[0]) == 0xDEAD); + testing.expect(bigToNative(u16, slice[1]) == 0xBEEF); +} + +test "bytesAsSlice keeps pointer alignment" { + var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 }; + const numbers = bytesAsSlice(u32, bytes[0..]); + comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32); +} + +test "bytesAsSlice on a packed struct" { + const F = packed struct { + a: u8, + }; + + var b = [1]u8{9}; + var f = bytesAsSlice(F, &b); + testing.expect(f[0].a == 9); +} + +test "bytesAsSlice with specified alignment" { + var bytes align(4) = [_]u8{ + 0x33, + 0x33, + 0x33, + 0x33, + }; + const slice: []u32 = std.mem.bytesAsSlice(u32, bytes[0..]); + testing.expect(slice[0] == 0x33333333); +} + +//TODO copy also is_volatile, etc. I tried to use @typeInfo, modify child type, use @Type, but ran into issues. +fn SliceAsBytesReturnType(comptime sliceType: type) type { + if (!trait.isSlice(sliceType) and !trait.isPtrTo(.Array)(sliceType)) { + @compileError("expected []T or *[_]T, passed " ++ @typeName(sliceType)); + } + + const alignment = meta.alignment(sliceType); + + return if (trait.isConstPtr(sliceType)) []align(alignment) const u8 else []align(alignment) u8; +} + +pub fn sliceAsBytes(slice: var) SliceAsBytesReturnType(@TypeOf(slice)) { + const actualSlice = if (comptime trait.isPtrTo(.Array)(@TypeOf(slice))) slice[0..] else slice; + + // let's not give an undefined pointer to @ptrCast + // it may be equal to zero and fail a null check + if (actualSlice.len == 0) { + return &[0]u8{}; + } + + const sliceType = @TypeOf(actualSlice); + const alignment = comptime meta.alignment(sliceType); + + const castTarget = if (comptime trait.isConstPtr(sliceType)) [*]align(alignment) const u8 else [*]align(alignment) u8; + + return @ptrCast(castTarget, actualSlice.ptr)[0 .. actualSlice.len * @sizeOf(comptime meta.Child(sliceType))]; +} + +test "sliceAsBytes" { + const bytes = [_]u16{ 0xDEAD, 0xBEEF }; + const slice = sliceAsBytes(bytes[0..]); + testing.expect(slice.len == 4); + testing.expect(eql(u8, slice, switch (builtin.endian) { + .Big => "\xDE\xAD\xBE\xEF", + .Little => "\xAD\xDE\xEF\xBE", + })); +} + +test "sliceAsBytes packed struct at runtime and comptime" { + const Foo = packed struct { + a: u4, + b: u4, + }; + const S = struct { + fn doTheTest() void { + var foo: Foo = undefined; + var slice = sliceAsBytes(@as(*[1]Foo, &foo)[0..1]); + slice[0] = 0x13; + switch (builtin.endian) { + .Big => { + testing.expect(foo.a == 0x1); + testing.expect(foo.b == 0x3); + }, + .Little => { + testing.expect(foo.a == 0x3); + testing.expect(foo.b == 0x1); + }, + } + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} + +test "sliceAsBytes and bytesAsSlice back" { + testing.expect(@sizeOf(i32) == 4); + + var big_thing_array = [_]i32{ 1, 2, 3, 4 }; + const big_thing_slice: []i32 = big_thing_array[0..]; + + const bytes = sliceAsBytes(big_thing_slice); + testing.expect(bytes.len == 4 * 4); + + bytes[4] = 0; + bytes[5] = 0; + bytes[6] = 0; + bytes[7] = 0; + testing.expect(big_thing_slice[1] == 0); + + const big_thing_again = bytesAsSlice(i32, bytes); + testing.expect(big_thing_again[2] == 3); + + big_thing_again[2] = -1; + testing.expect(bytes[8] == math.maxInt(u8)); + testing.expect(bytes[9] == math.maxInt(u8)); + testing.expect(bytes[10] == math.maxInt(u8)); + testing.expect(bytes[11] == math.maxInt(u8)); +} + fn SubArrayPtrReturnType(comptime T: type, comptime length: usize) type { if (trait.isConstPtr(T)) return *const [length]meta.Child(meta.Child(T)); diff --git a/lib/std/meta.zig b/lib/std/meta.zig @@ -437,7 +437,7 @@ pub fn eql(a: var, b: @TypeOf(a)) bool { }, .Pointer => |info| { return switch (info.size) { - .One, .Many, .C, => a == b, + .One, .Many, .C => a == b, .Slice => a.ptr == b.ptr and a.len == b.len, }; }, @@ -536,9 +536,8 @@ test "intToEnum with error return" { pub const IntToEnumError = error{InvalidEnumTag}; pub fn intToEnum(comptime Tag: type, tag_int: var) IntToEnumError!Tag { - comptime var i = 0; - inline while (i != @memberCount(Tag)) : (i += 1) { - const this_tag_value = @field(Tag, @memberName(Tag, i)); + inline for (@typeInfo(Tag).Enum.fields) |f| { + const this_tag_value = @field(Tag, f.name); if (tag_int == @enumToInt(this_tag_value)) { return this_tag_value; } @@ -559,7 +558,9 @@ pub fn fieldIndex(comptime T: type, comptime name: []const u8) ?comptime_int { /// Given a type, reference all the declarations inside, so that the semantic analyzer sees them. pub fn refAllDecls(comptime T: type) void { if (!builtin.is_test) return; - _ = declarations(T); + inline for (declarations(T)) |decl| { + _ = decl; + } } /// Returns a slice of pointers to public declarations of a namespace. @@ -579,3 +580,12 @@ pub fn declList(comptime Namespace: type, comptime Decl: type) []const *const De return &array; } } + +pub fn IntType(comptime is_signed: bool, comptime bit_count: u16) type { + return @Type(TypeInfo{ + .Int = .{ + .is_signed = is_signed, + .bits = bit_count, + }, + }); +} diff --git a/lib/std/meta/trait.zig b/lib/std/meta/trait.zig @@ -1,5 +1,5 @@ const std = @import("../std.zig"); -const builtin = @import("builtin"); +const builtin = std.builtin; const mem = std.mem; const debug = std.debug; const testing = std.testing; @@ -54,7 +54,7 @@ pub fn hasFn(comptime name: []const u8) TraitFn { if (!comptime isContainer(T)) return false; if (!comptime @hasDecl(T, name)) return false; const DeclType = @TypeOf(@field(T, name)); - return @typeId(DeclType) == .Fn; + return @typeInfo(DeclType) == .Fn; } }; return Closure.trait; @@ -105,7 +105,7 @@ test "std.meta.trait.hasField" { pub fn is(comptime id: builtin.TypeId) TraitFn { const Closure = struct { pub fn trait(comptime T: type) bool { - return id == @typeId(T); + return id == @typeInfo(T); } }; return Closure.trait; @@ -123,7 +123,7 @@ pub fn isPtrTo(comptime id: builtin.TypeId) TraitFn { const Closure = struct { pub fn trait(comptime T: type) bool { if (!comptime isSingleItemPtr(T)) return false; - return id == @typeId(meta.Child(T)); + return id == @typeInfo(meta.Child(T)); } }; return Closure.trait; @@ -135,6 +135,22 @@ test "std.meta.trait.isPtrTo" { testing.expect(!isPtrTo(.Struct)(**struct {})); } +pub fn isSliceOf(comptime id: builtin.TypeId) TraitFn { + const Closure = struct { + pub fn trait(comptime T: type) bool { + if (!comptime isSlice(T)) return false; + return id == @typeInfo(meta.Child(T)); + } + }; + return Closure.trait; +} + +test "std.meta.trait.isSliceOf" { + testing.expect(!isSliceOf(.Struct)(struct {})); + testing.expect(isSliceOf(.Struct)([]struct {})); + testing.expect(!isSliceOf(.Struct)([][]struct {})); +} + ///////////Strait trait Fns //@TODO: @@ -269,7 +285,7 @@ test "std.meta.trait.isIndexable" { } pub fn isNumber(comptime T: type) bool { - return switch (@typeId(T)) { + return switch (@typeInfo(T)) { .Int, .Float, .ComptimeInt, .ComptimeFloat => true, else => false, }; @@ -304,7 +320,7 @@ test "std.meta.trait.isConstPtr" { } pub fn isContainer(comptime T: type) bool { - return switch (@typeId(T)) { + return switch (@typeInfo(T)) { .Struct, .Union, .Enum => true, else => false, }; diff --git a/lib/std/net.zig b/lib/std/net.zig @@ -18,7 +18,7 @@ pub const Address = extern union { in6: os.sockaddr_in6, un: if (has_unix_sockets) os.sockaddr_un else void, - // TODO this crashed the compiler + // TODO this crashed the compiler. https://github.com/ziglang/zig/issues/3512 //pub const localhost = initIp4(parseIp4("127.0.0.1") catch unreachable, 0); pub fn parseIp(name: []const u8, port: u16) !Address { @@ -120,7 +120,7 @@ pub const Address = extern union { ip_slice[10] = 0xff; ip_slice[11] = 0xff; - const ptr = @sliceToBytes(@as(*const [1]u32, &addr)[0..]); + const ptr = mem.sliceAsBytes(@as(*const [1]u32, &addr)[0..]); ip_slice[12] = ptr[0]; ip_slice[13] = ptr[1]; @@ -164,7 +164,7 @@ pub const Address = extern union { .addr = undefined, }, }; - const out_ptr = @sliceToBytes(@as(*[1]u32, &result.in.addr)[0..]); + const out_ptr = mem.sliceAsBytes(@as(*[1]u32, &result.in.addr)[0..]); var x: u8 = 0; var index: u8 = 0; diff --git a/lib/std/os.zig b/lib/std/os.zig @@ -70,6 +70,8 @@ else switch (builtin.os) { pub usingnamespace @import("os/bits.zig"); /// See also `getenv`. Populated by startup code before main(). +/// TODO this is a footgun because the value will be undefined when using `zig build-lib`. +/// https://github.com/ziglang/zig/issues/4524 pub var environ: [][*:0]u8 = undefined; /// Populated by startup code before main(). @@ -916,10 +918,17 @@ pub const ExecveError = error{ NameTooLong, } || UnexpectedError; +/// Deprecated in favor of `execveZ`. +pub const execveC = execveZ; + /// Like `execve` except the parameters are null-terminated, /// matching the syscall API on all targets. This removes the need for an allocator. -/// This function ignores PATH environment variable. See `execvpeC` for that. -pub fn execveC(path: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) ExecveError { +/// This function ignores PATH environment variable. See `execvpeZ` for that. +pub fn execveZ( + path: [*:0]const u8, + child_argv: [*:null]const ?[*:0]const u8, + envp: [*:null]const ?[*:0]const u8, +) ExecveError { switch (errno(system.execve(path, child_argv, envp))) { 0 => unreachable, EFAULT => unreachable, @@ -942,19 +951,42 @@ pub fn execveC(path: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, en } } -/// Like `execvpe` except the parameters are null-terminated, -/// matching the syscall API on all targets. This removes the need for an allocator. -/// This function also uses the PATH environment variable to get the full path to the executable. -/// If `file` is an absolute path, this is the same as `execveC`. -pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) ExecveError { +/// Deprecated in favor of `execvpeZ`. +pub const execvpeC = execvpeZ; + +pub const Arg0Expand = enum { + expand, + no_expand, +}; + +/// Like `execvpeZ` except if `arg0_expand` is `.expand`, then `argv` is mutable, +/// and `argv[0]` is expanded to be the same absolute path that is passed to the execve syscall. +/// If this function returns with an error, `argv[0]` will be restored to the value it was when it was passed in. +pub fn execvpeZ_expandArg0( + comptime arg0_expand: Arg0Expand, + file: [*:0]const u8, + child_argv: switch (arg0_expand) { + .expand => [*:null]?[*:0]const u8, + .no_expand => [*:null]const ?[*:0]const u8, + }, + envp: [*:null]const ?[*:0]const u8, +) ExecveError { const file_slice = mem.toSliceConst(u8, file); - if (mem.indexOfScalar(u8, file_slice, '/') != null) return execveC(file, child_argv, envp); + if (mem.indexOfScalar(u8, file_slice, '/') != null) return execveZ(file, child_argv, envp); - const PATH = getenv("PATH") orelse "/usr/local/bin:/bin/:/usr/bin"; + const PATH = getenvZ("PATH") orelse "/usr/local/bin:/bin/:/usr/bin"; var path_buf: [MAX_PATH_BYTES]u8 = undefined; var it = mem.tokenize(PATH, ":"); var seen_eacces = false; var err: ExecveError = undefined; + + // In case of expanding arg0 we must put it back if we return with an error. + const prev_arg0 = child_argv[0]; + defer switch (arg0_expand) { + .expand => child_argv[0] = prev_arg0, + .no_expand => {}, + }; + while (it.next()) |search_path| { if (path_buf.len < search_path.len + file_slice.len + 1) return error.NameTooLong; mem.copy(u8, &path_buf, search_path); @@ -962,7 +994,12 @@ pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, e mem.copy(u8, path_buf[search_path.len + 1 ..], file_slice); const path_len = search_path.len + file_slice.len + 1; path_buf[path_len] = 0; - err = execveC(path_buf[0..path_len :0].ptr, child_argv, envp); + const full_path = path_buf[0..path_len :0].ptr; + switch (arg0_expand) { + .expand => child_argv[0] = full_path, + .no_expand => {}, + } + err = execveZ(full_path, child_argv, envp); switch (err) { error.AccessDenied => seen_eacces = true, error.FileNotFound, error.NotDir => {}, @@ -973,13 +1010,24 @@ pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, e return err; } -/// This function must allocate memory to add a null terminating bytes on path and each arg. -/// It must also convert to KEY=VALUE\0 format for environment variables, and include null -/// pointers after the args and after the environment variables. -/// `argv_slice[0]` is the executable path. +/// Like `execvpe` except the parameters are null-terminated, +/// matching the syscall API on all targets. This removes the need for an allocator. /// This function also uses the PATH environment variable to get the full path to the executable. -pub fn execvpe( +/// If `file` is an absolute path, this is the same as `execveZ`. +pub fn execvpeZ( + file: [*:0]const u8, + argv: [*:null]const ?[*:0]const u8, + envp: [*:null]const ?[*:0]const u8, +) ExecveError { + return execvpeZ_expandArg0(.no_expand, file, argv, envp); +} + +/// This is the same as `execvpe` except if the `arg0_expand` parameter is set to `.expand`, +/// then argv[0] will be replaced with the expanded version of it, after resolving in accordance +/// with the PATH environment variable. +pub fn execvpe_expandArg0( allocator: *mem.Allocator, + arg0_expand: Arg0Expand, argv_slice: []const []const u8, env_map: *const std.BufMap, ) (ExecveError || error{OutOfMemory}) { @@ -1004,7 +1052,23 @@ pub fn execvpe( const envp_buf = try createNullDelimitedEnvMap(allocator, env_map); defer freeNullDelimitedEnvMap(allocator, envp_buf); - return execvpeC(argv_buf.ptr[0].?, argv_ptr, envp_buf.ptr); + switch (arg0_expand) { + .expand => return execvpeZ_expandArg0(.expand, argv_buf.ptr[0].?, argv_ptr, envp_buf.ptr), + .no_expand => return execvpeZ_expandArg0(.no_expand, argv_buf.ptr[0].?, argv_ptr, envp_buf.ptr), + } +} + +/// This function must allocate memory to add a null terminating bytes on path and each arg. +/// It must also convert to KEY=VALUE\0 format for environment variables, and include null +/// pointers after the args and after the environment variables. +/// `argv_slice[0]` is the executable path. +/// This function also uses the PATH environment variable to get the full path to the executable. +pub fn execvpe( + allocator: *mem.Allocator, + argv_slice: []const []const u8, + env_map: *const std.BufMap, +) (ExecveError || error{OutOfMemory}) { + return execvpe_expandArg0(allocator, .no_expand, argv_slice, env_map); } pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.BufMap) ![:null]?[*:0]u8 { @@ -1038,9 +1102,37 @@ pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) } /// Get an environment variable. -/// See also `getenvC`. -/// TODO make this go through libc when we have it +/// See also `getenvZ`. pub fn getenv(key: []const u8) ?[]const u8 { + if (builtin.link_libc) { + var small_key_buf: [64]u8 = undefined; + if (key.len < small_key_buf.len) { + mem.copy(u8, &small_key_buf, key); + small_key_buf[key.len] = 0; + const key0 = small_key_buf[0..key.len :0]; + return getenvZ(key0); + } + // Search the entire `environ` because we don't have a null terminated pointer. + var ptr = std.c.environ; + while (ptr.*) |line| : (ptr += 1) { + var line_i: usize = 0; + while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {} + const this_key = line[0..line_i]; + + if (!mem.eql(u8, this_key, key)) continue; + + var end_i: usize = line_i; + while (line[end_i] != 0) : (end_i += 1) {} + const value = line[line_i + 1 .. end_i]; + + return value; + } + return null; + } + if (builtin.os == .windows) { + @compileError("std.os.getenv is unavailable for Windows because environment string is in WTF-16 format. See std.process.getEnvVarOwned for cross-platform API or std.os.getenvW for Windows-specific API."); + } + // TODO see https://github.com/ziglang/zig/issues/4524 for (environ) |ptr| { var line_i: usize = 0; while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {} @@ -1056,16 +1148,50 @@ pub fn getenv(key: []const u8) ?[]const u8 { return null; } +/// Deprecated in favor of `getenvZ`. +pub const getenvC = getenvZ; + /// Get an environment variable with a null-terminated name. /// See also `getenv`. -pub fn getenvC(key: [*:0]const u8) ?[]const u8 { +pub fn getenvZ(key: [*:0]const u8) ?[]const u8 { if (builtin.link_libc) { const value = system.getenv(key) orelse return null; return mem.toSliceConst(u8, value); } + if (builtin.os == .windows) { + @compileError("std.os.getenvZ is unavailable for Windows because environment string is in WTF-16 format. See std.process.getEnvVarOwned for cross-platform API or std.os.getenvW for Windows-specific API."); + } return getenv(mem.toSliceConst(u8, key)); } +/// Windows-only. Get an environment variable with a null-terminated, WTF-16 encoded name. +/// See also `getenv`. +pub fn getenvW(key: [*:0]const u16) ?[:0]const u16 { + if (builtin.os != .windows) { + @compileError("std.os.getenvW is a Windows-only API"); + } + const key_slice = mem.toSliceConst(u16, key); + const ptr = windows.peb().ProcessParameters.Environment; + var i: usize = 0; + while (ptr[i] != 0) { + const key_start = i; + + while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {} + const this_key = ptr[key_start..i]; + + if (ptr[i] == '=') i += 1; + + const value_start = i; + while (ptr[i] != 0) : (i += 1) {} + const this_value = ptr[value_start..i :0]; + + if (mem.eql(u16, key_slice, this_key)) return this_value; + + i += 1; // skip over null byte + } + return null; +} + pub const GetCwdError = error{ NameTooLong, CurrentWorkingDirectoryUnlinked, @@ -1726,7 +1852,7 @@ pub fn isCygwinPty(handle: fd_t) bool { const name_info = @ptrCast(*const windows.FILE_NAME_INFO, &name_info_bytes[0]); const name_bytes = name_info_bytes[size .. size + @as(usize, name_info.FileNameLength)]; - const name_wide = @bytesToSlice(u16, name_bytes); + const name_wide = mem.bytesAsSlice(u16, name_bytes); return mem.indexOf(u16, name_wide, &[_]u16{ 'm', 's', 'y', 's', '-' }) != null or mem.indexOf(u16, name_wide, &[_]u16{ '-', 'p', 't', 'y' }) != null; } @@ -2452,6 +2578,9 @@ pub const AccessError = error{ InputOutput, SystemResources, BadPathName, + FileBusy, + SymLinkLoop, + ReadOnlyFileSystem, /// On Windows, file paths must be valid Unicode. InvalidUtf8, @@ -2469,8 +2598,11 @@ pub fn access(path: []const u8, mode: u32) AccessError!void { return accessC(&path_c, mode); } +/// Deprecated in favor of `accessZ`. +pub const accessC = accessZ; + /// Same as `access` except `path` is null-terminated. -pub fn accessC(path: [*:0]const u8, mode: u32) AccessError!void { +pub fn accessZ(path: [*:0]const u8, mode: u32) AccessError!void { if (builtin.os == .windows) { const path_w = try windows.cStrToPrefixedFileW(path); _ = try windows.GetFileAttributesW(&path_w); @@ -2479,12 +2611,11 @@ pub fn accessC(path: [*:0]const u8, mode: u32) AccessError!void { switch (errno(system.access(path, mode))) { 0 => return, EACCES => return error.PermissionDenied, - EROFS => return error.PermissionDenied, - ELOOP => return error.PermissionDenied, - ETXTBSY => return error.PermissionDenied, + EROFS => return error.ReadOnlyFileSystem, + ELOOP => return error.SymLinkLoop, + ETXTBSY => return error.FileBusy, ENOTDIR => return error.FileNotFound, ENOENT => return error.FileNotFound, - ENAMETOOLONG => return error.NameTooLong, EINVAL => unreachable, EFAULT => unreachable, @@ -2510,6 +2641,79 @@ pub fn accessW(path: [*:0]const u16, mode: u32) windows.GetFileAttributesError!v } } +/// Check user's permissions for a file, based on an open directory handle. +/// TODO currently this ignores `mode` and `flags` on Windows. +pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessError!void { + if (builtin.os == .windows) { + const path_w = try windows.sliceToPrefixedFileW(path); + return faccessatW(dirfd, &path_w, mode, flags); + } + const path_c = try toPosixPath(path); + return faccessatZ(dirfd, &path_c, mode, flags); +} + +/// Same as `faccessat` except the path parameter is null-terminated. +pub fn faccessatZ(dirfd: fd_t, path: [*:0]const u8, mode: u32, flags: u32) AccessError!void { + if (builtin.os == .windows) { + const path_w = try windows.cStrToPrefixedFileW(path); + return faccessatW(dirfd, &path_w, mode, flags); + } + switch (errno(system.faccessat(dirfd, path, mode, flags))) { + 0 => return, + EACCES => return error.PermissionDenied, + EROFS => return error.ReadOnlyFileSystem, + ELOOP => return error.SymLinkLoop, + ETXTBSY => return error.FileBusy, + ENOTDIR => return error.FileNotFound, + ENOENT => return error.FileNotFound, + ENAMETOOLONG => return error.NameTooLong, + EINVAL => unreachable, + EFAULT => unreachable, + EIO => return error.InputOutput, + ENOMEM => return error.SystemResources, + else => |err| return unexpectedErrno(err), + } +} + +/// Same as `faccessat` except asserts the target is Windows and the path parameter +/// is NtDll-prefixed, null-terminated, WTF-16 encoded. +/// TODO currently this ignores `mode` and `flags` +pub fn faccessatW(dirfd: fd_t, sub_path_w: [*:0]const u16, mode: u32, flags: u32) AccessError!void { + if (sub_path_w[0] == '.' and sub_path_w[1] == 0) { + return; + } + if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) { + return; + } + + const path_len_bytes = math.cast(u16, mem.toSliceConst(u16, sub_path_w).len * 2) catch |err| switch (err) { + error.Overflow => return error.NameTooLong, + }; + var nt_name = windows.UNICODE_STRING{ + .Length = path_len_bytes, + .MaximumLength = path_len_bytes, + .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)), + }; + var attr = windows.OBJECT_ATTRIBUTES{ + .Length = @sizeOf(windows.OBJECT_ATTRIBUTES), + .RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sub_path_w)) null else dirfd, + .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here. + .ObjectName = &nt_name, + .SecurityDescriptor = null, + .SecurityQualityOfService = null, + }; + var basic_info: windows.FILE_BASIC_INFORMATION = undefined; + switch (windows.ntdll.NtQueryAttributesFile(&attr, &basic_info)) { + .SUCCESS => return, + .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, + .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, + .INVALID_PARAMETER => unreachable, + .ACCESS_DENIED => return error.PermissionDenied, + .OBJECT_PATH_SYNTAX_BAD => unreachable, + else => |rc| return windows.unexpectedStatus(rc), + } +} + pub const PipeError = error{ SystemFdQuotaExceeded, ProcessFdQuotaExceeded, @@ -2844,18 +3048,26 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void { } pub fn dl_iterate_phdr( - comptime T: type, - callback: extern fn (info: *dl_phdr_info, size: usize, data: ?*T) i32, - data: ?*T, -) isize { + context: var, + comptime Error: type, + comptime callback: fn (info: *dl_phdr_info, size: usize, context: @TypeOf(context)) Error!void, +) Error!void { + const Context = @TypeOf(context); + if (builtin.object_format != .elf) @compileError("dl_iterate_phdr is not available for this target"); if (builtin.link_libc) { - return system.dl_iterate_phdr( - @ptrCast(std.c.dl_iterate_phdr_callback, callback), - @ptrCast(?*c_void, data), - ); + switch (system.dl_iterate_phdr(struct { + fn callbackC(info: *dl_phdr_info, size: usize, data: ?*c_void) callconv(.C) c_int { + const context_ptr = @ptrCast(*const Context, @alignCast(@alignOf(*const Context), data)); + callback(info, size, context_ptr.*) catch |err| return @errorToInt(err); + return 0; + } + }.callbackC, @intToPtr(?*c_void, @ptrToInt(&context)))) { + 0 => return, + else => |err| return @errSetCast(Error, @intToError(@intCast(u16, err))), // TODO don't hardcode u16 + } } const elf_base = std.process.getBaseAddress(); @@ -2877,11 +3089,10 @@ pub fn dl_iterate_phdr( .dlpi_phnum = ehdr.e_phnum, }; - return callback(&info, @sizeOf(dl_phdr_info), data); + return callback(&info, @sizeOf(dl_phdr_info), context); } // Last return value from the callback function - var last_r: isize = 0; while (it.next()) |entry| { var dlpi_phdr: [*]elf.Phdr = undefined; var dlpi_phnum: u16 = undefined; @@ -2903,11 +3114,8 @@ pub fn dl_iterate_phdr( .dlpi_phnum = dlpi_phnum, }; - last_r = callback(&info, @sizeOf(dl_phdr_info), data); - if (last_r != 0) break; + try callback(&info, @sizeOf(dl_phdr_info), context); } - - return last_r; } pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError; @@ -3141,7 +3349,7 @@ pub fn res_mkquery( // Make a reasonably unpredictable id var ts: timespec = undefined; clock_gettime(CLOCK_REALTIME, &ts) catch {}; - const UInt = @IntType(false, @TypeOf(ts.tv_nsec).bit_count); + const UInt = std.meta.IntType(false, @TypeOf(ts.tv_nsec).bit_count); const unsec = @bitCast(UInt, ts.tv_nsec); const id = @truncate(u32, unsec + unsec / 65536); q[0] = @truncate(u8, id / 256); diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig @@ -1004,7 +1004,7 @@ pub const dl_phdr_info = extern struct { pub const CPU_SETSIZE = 128; pub const cpu_set_t = [CPU_SETSIZE / @sizeOf(usize)]usize; -pub const cpu_count_t = @IntType(false, std.math.log2(CPU_SETSIZE * 8)); +pub const cpu_count_t = std.meta.IntType(false, std.math.log2(CPU_SETSIZE * 8)); pub fn CPU_COUNT(set: cpu_set_t) cpu_count_t { var sum: cpu_count_t = 0; diff --git a/lib/std/os/linux/tls.zig b/lib/std/os/linux/tls.zig @@ -152,7 +152,7 @@ pub fn setThreadPointer(addr: usize) void { : [addr] "r" (addr) ); }, - .arm => |arm| { + .arm => { const rc = std.os.linux.syscall1(std.os.linux.SYS_set_tls, addr); assert(rc == 0); }, diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig @@ -29,7 +29,7 @@ test "makePath, put some files in it, deleteTree" { test "access file" { try fs.makePath(a, "os_test_tmp"); - if (File.access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt")) |ok| { + if (fs.cwd().access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", .{})) |ok| { @panic("expected error"); } else |err| { expect(err == error.FileNotFound); @@ -165,16 +165,19 @@ test "sigaltstack" { // analyzed const dl_phdr_info = if (@hasDecl(os, "dl_phdr_info")) os.dl_phdr_info else c_void; -fn iter_fn(info: *dl_phdr_info, size: usize, data: ?*usize) callconv(.C) i32 { - if (builtin.os == .windows or builtin.os == .wasi or builtin.os == .macosx) - return 0; +const IterFnError = error{ + MissingPtLoadSegment, + MissingLoad, + BadElfMagic, + FailedConsistencyCheck, +}; - var counter = data.?; +fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void { // Count how many libraries are loaded counter.* += @as(usize, 1); // The image should contain at least a PT_LOAD segment - if (info.dlpi_phnum < 1) return -1; + if (info.dlpi_phnum < 1) return error.MissingPtLoadSegment; // Quick & dirty validation of the phdr pointers, make sure we're not // pointing to some random gibberish @@ -189,17 +192,15 @@ fn iter_fn(info: *dl_phdr_info, size: usize, data: ?*usize) callconv(.C) i32 { // Find the ELF header const elf_header = @intToPtr(*elf.Ehdr, reloc_addr - phdr.p_offset); // Validate the magic - if (!mem.eql(u8, elf_header.e_ident[0..4], "\x7fELF")) return -1; + if (!mem.eql(u8, elf_header.e_ident[0..4], "\x7fELF")) return error.BadElfMagic; // Consistency check - if (elf_header.e_phnum != info.dlpi_phnum) return -1; + if (elf_header.e_phnum != info.dlpi_phnum) return error.FailedConsistencyCheck; found_load = true; break; } - if (!found_load) return -1; - - return 42; + if (!found_load) return error.MissingLoad; } test "dl_iterate_phdr" { @@ -207,7 +208,7 @@ test "dl_iterate_phdr" { return error.SkipZigTest; var counter: usize = 0; - expect(os.dl_iterate_phdr(usize, iter_fn, &counter) != 0); + try os.dl_iterate_phdr(&counter, IterFnError, iter_fn); expect(counter != 0); } @@ -350,3 +351,11 @@ test "mmap" { try fs.cwd().deleteFile(test_out_file); } + +test "getenv" { + if (builtin.os == .windows) { + expect(os.getenvW(&[_:0]u16{ 'B', 'O', 'G', 'U', 'S', 0x11, 0x22, 0x33, 0x44, 0x55 }) == null); + } else { + expect(os.getenvZ("BOGUSDOESNOTEXISTENVVAR") == null); + } +} diff --git a/lib/std/os/windows/bits.zig b/lib/std/os/windows/bits.zig @@ -1187,7 +1187,7 @@ pub const RTL_USER_PROCESS_PARAMETERS = extern struct { DllPath: UNICODE_STRING, ImagePathName: UNICODE_STRING, CommandLine: UNICODE_STRING, - Environment: [*]WCHAR, + Environment: [*:0]WCHAR, dwX: ULONG, dwY: ULONG, dwXSize: ULONG, diff --git a/lib/std/os/windows/ntdll.zig b/lib/std/os/windows/ntdll.zig @@ -8,6 +8,12 @@ pub extern "NtDll" fn NtQueryInformationFile( Length: ULONG, FileInformationClass: FILE_INFORMATION_CLASS, ) callconv(.Stdcall) NTSTATUS; + +pub extern "NtDll" fn NtQueryAttributesFile( + ObjectAttributes: *OBJECT_ATTRIBUTES, + FileAttributes: *FILE_BASIC_INFORMATION, +) callconv(.Stdcall) NTSTATUS; + pub extern "NtDll" fn NtCreateFile( FileHandle: *HANDLE, DesiredAccess: ACCESS_MASK, diff --git a/lib/std/packed_int_array.zig b/lib/std/packed_int_array.zig @@ -34,13 +34,13 @@ pub fn PackedIntIo(comptime Int: type, comptime endian: builtin.Endian) type { //we bitcast the desired Int type to an unsigned version of itself // to avoid issues with shifting signed ints. - const UnInt = @IntType(false, int_bits); + const UnInt = std.meta.IntType(false, int_bits); //The maximum container int type - const MinIo = @IntType(false, min_io_bits); + const MinIo = std.meta.IntType(false, min_io_bits); //The minimum container int type - const MaxIo = @IntType(false, max_io_bits); + const MaxIo = std.meta.IntType(false, max_io_bits); return struct { pub fn get(bytes: []const u8, index: usize, bit_offset: u7) Int { @@ -322,7 +322,7 @@ test "PackedIntArray" { inline while (bits <= 256) : (bits += 1) { //alternate unsigned and signed const even = bits % 2 == 0; - const I = @IntType(even, bits); + const I = std.meta.IntType(even, bits); const PackedArray = PackedIntArray(I, int_count); const expected_bytes = ((bits * int_count) + 7) / 8; @@ -369,7 +369,7 @@ test "PackedIntSlice" { inline while (bits <= 256) : (bits += 1) { //alternate unsigned and signed const even = bits % 2 == 0; - const I = @IntType(even, bits); + const I = std.meta.IntType(even, bits); const P = PackedIntSlice(I); var data = P.init(&buffer, int_count); @@ -399,7 +399,7 @@ test "PackedIntSlice of PackedInt(Array/Slice)" { comptime var bits = 0; inline while (bits <= max_bits) : (bits += 1) { - const Int = @IntType(false, bits); + const Int = std.meta.IntType(false, bits); const PackedArray = PackedIntArray(Int, int_count); var packed_array = @as(PackedArray, undefined); diff --git a/lib/std/process.zig b/lib/std/process.zig @@ -1,5 +1,5 @@ -const builtin = @import("builtin"); const std = @import("std.zig"); +const builtin = std.builtin; const os = std.os; const fs = std.fs; const BufMap = std.BufMap; @@ -31,20 +31,16 @@ test "getCwdAlloc" { testing.allocator.free(cwd); } -/// Caller must free result when done. -/// TODO make this go through libc when we have it +/// Caller owns resulting `BufMap`. pub fn getEnvMap(allocator: *Allocator) !BufMap { var result = BufMap.init(allocator); errdefer result.deinit(); if (builtin.os == .windows) { - const ptr = try os.windows.GetEnvironmentStringsW(); - defer os.windows.FreeEnvironmentStringsW(ptr); + const ptr = os.windows.peb().ProcessParameters.Environment; var i: usize = 0; - while (true) { - if (ptr[i] == 0) return result; - + while (ptr[i] != 0) { const key_start = i; while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {} @@ -64,6 +60,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { try result.setMove(key, value); } + return result; } else if (builtin.os == .wasi) { var environ_count: usize = undefined; var environ_buf_size: usize = undefined; @@ -95,15 +92,29 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { } } return result; + } else if (builtin.link_libc) { + var ptr = std.c.environ; + while (ptr.*) |line| : (ptr += 1) { + var line_i: usize = 0; + while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {} + const key = line[0..line_i]; + + var end_i: usize = line_i; + while (line[end_i] != 0) : (end_i += 1) {} + const value = line[line_i + 1 .. end_i]; + + try result.set(key, value); + } + return result; } else { - for (os.environ) |ptr| { + for (os.environ) |line| { var line_i: usize = 0; - while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {} - const key = ptr[0..line_i]; + while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {} + const key = line[0..line_i]; var end_i: usize = line_i; - while (ptr[end_i] != 0) : (end_i += 1) {} - const value = ptr[line_i + 1 .. end_i]; + while (line[end_i] != 0) : (end_i += 1) {} + const value = line[line_i + 1 .. end_i]; try result.set(key, value); } @@ -125,37 +136,20 @@ pub const GetEnvVarOwnedError = error{ }; /// Caller must free returned memory. -/// TODO make this go through libc when we have it pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 { if (builtin.os == .windows) { - const key_with_null = try std.unicode.utf8ToUtf16LeWithNull(allocator, key); - defer allocator.free(key_with_null); - - var buf = try allocator.alloc(u16, 256); - defer allocator.free(buf); - - while (true) { - const windows_buf_len = math.cast(os.windows.DWORD, buf.len) catch return error.OutOfMemory; - const result = os.windows.GetEnvironmentVariableW( - key_with_null.ptr, - buf.ptr, - windows_buf_len, - ) catch |err| switch (err) { - error.Unexpected => return error.EnvironmentVariableNotFound, - else => |e| return e, - }; - if (result > buf.len) { - buf = try allocator.realloc(buf, result); - continue; - } + const result_w = blk: { + const key_w = try std.unicode.utf8ToUtf16LeWithNull(allocator, key); + defer allocator.free(key_w); - return std.unicode.utf16leToUtf8Alloc(allocator, buf[0..result]) catch |err| switch (err) { - error.DanglingSurrogateHalf => return error.InvalidUtf8, - error.ExpectedSecondSurrogateHalf => return error.InvalidUtf8, - error.UnexpectedSecondSurrogateHalf => return error.InvalidUtf8, - else => |e| return e, - }; - } + break :blk std.os.getenvW(key_w) orelse return error.EnvironmentVariableNotFound; + }; + return std.unicode.utf16leToUtf8Alloc(allocator, result_w) catch |err| switch (err) { + error.DanglingSurrogateHalf => return error.InvalidUtf8, + error.ExpectedSecondSurrogateHalf => return error.InvalidUtf8, + error.UnexpectedSecondSurrogateHalf => return error.InvalidUtf8, + else => |e| return e, + }; } else { const result = os.getenv(key) orelse return error.EnvironmentVariableNotFound; return mem.dupe(allocator, u8, result); @@ -436,7 +430,7 @@ pub fn argsAlloc(allocator: *mem.Allocator) ![][]u8 { const buf = try allocator.alignedAlloc(u8, @alignOf([]u8), total_bytes); errdefer allocator.free(buf); - const result_slice_list = @bytesToSlice([]u8, buf[0..slice_list_bytes]); + const result_slice_list = mem.bytesAsSlice([]u8, buf[0..slice_list_bytes]); const result_contents = buf[slice_list_bytes..]; mem.copy(u8, result_contents, contents_slice); @@ -613,3 +607,59 @@ pub fn getBaseAddress() usize { else => @compileError("Unsupported OS"), } } + +/// Caller owns the result value and each inner slice. +pub fn getSelfExeSharedLibPaths(allocator: *Allocator) error{OutOfMemory}![][:0]u8 { + switch (builtin.link_mode) { + .Static => return &[_][:0]u8{}, + .Dynamic => {}, + } + const List = std.ArrayList([:0]u8); + switch (builtin.os) { + .linux, + .freebsd, + .netbsd, + .dragonfly, + => { + var paths = List.init(allocator); + errdefer { + const slice = paths.toOwnedSlice(); + for (slice) |item| { + allocator.free(item); + } + allocator.free(slice); + } + try os.dl_iterate_phdr(&paths, error{OutOfMemory}, struct { + fn callback(info: *os.dl_phdr_info, size: usize, list: *List) !void { + const name = info.dlpi_name orelse return; + if (name[0] == '/') { + const item = try mem.dupeZ(list.allocator, u8, mem.toSliceConst(u8, name)); + errdefer list.allocator.free(item); + try list.append(item); + } + } + }.callback); + return paths.toOwnedSlice(); + }, + .macosx, .ios, .watchos, .tvos => { + var paths = List.init(allocator); + errdefer { + const slice = paths.toOwnedSlice(); + for (slice) |item| { + allocator.free(item); + } + allocator.free(slice); + } + const img_count = std.c._dyld_image_count(); + var i: u32 = 0; + while (i < img_count) : (i += 1) { + const name = std.c._dyld_get_image_name(i); + const item = try mem.dupeZ(allocator, u8, mem.toSliceConst(u8, name)); + errdefer allocator.free(item); + try paths.append(item); + } + return paths.toOwnedSlice(); + }, + else => @compileError("getSelfExeSharedLibPaths unimplemented for this target"), + } +} diff --git a/lib/std/rand.zig b/lib/std/rand.zig @@ -45,8 +45,8 @@ pub const Random = struct { /// Returns a random int `i` such that `0 <= i <= maxInt(T)`. /// `i` is evenly distributed. pub fn int(r: *Random, comptime T: type) T { - const UnsignedT = @IntType(false, T.bit_count); - const ByteAlignedT = @IntType(false, @divTrunc(T.bit_count + 7, 8) * 8); + const UnsignedT = std.meta.IntType(false, T.bit_count); + const ByteAlignedT = std.meta.IntType(false, @divTrunc(T.bit_count + 7, 8) * 8); var rand_bytes: [@sizeOf(ByteAlignedT)]u8 = undefined; r.bytes(rand_bytes[0..]); @@ -85,9 +85,9 @@ pub const Random = struct { comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation! assert(0 < less_than); // Small is typically u32 - const Small = @IntType(false, @divTrunc(T.bit_count + 31, 32) * 32); + const Small = std.meta.IntType(false, @divTrunc(T.bit_count + 31, 32) * 32); // Large is typically u64 - const Large = @IntType(false, Small.bit_count * 2); + const Large = std.meta.IntType(false, Small.bit_count * 2); // adapted from: // http://www.pcg-random.org/posts/bounded-rands.html @@ -99,7 +99,7 @@ pub const Random = struct { // TODO: workaround for https://github.com/ziglang/zig/issues/1770 // should be: // var t: Small = -%less_than; - var t: Small = @bitCast(Small, -%@bitCast(@IntType(true, Small.bit_count), @as(Small, less_than))); + var t: Small = @bitCast(Small, -%@bitCast(std.meta.IntType(true, Small.bit_count), @as(Small, less_than))); if (t >= less_than) { t -= less_than; @@ -145,7 +145,7 @@ pub const Random = struct { assert(at_least < less_than); if (T.is_signed) { // Two's complement makes this math pretty easy. - const UnsignedT = @IntType(false, T.bit_count); + const UnsignedT = std.meta.IntType(false, T.bit_count); const lo = @bitCast(UnsignedT, at_least); const hi = @bitCast(UnsignedT, less_than); const result = lo +% r.uintLessThanBiased(UnsignedT, hi -% lo); @@ -163,7 +163,7 @@ pub const Random = struct { assert(at_least < less_than); if (T.is_signed) { // Two's complement makes this math pretty easy. - const UnsignedT = @IntType(false, T.bit_count); + const UnsignedT = std.meta.IntType(false, T.bit_count); const lo = @bitCast(UnsignedT, at_least); const hi = @bitCast(UnsignedT, less_than); const result = lo +% r.uintLessThan(UnsignedT, hi -% lo); @@ -180,7 +180,7 @@ pub const Random = struct { assert(at_least <= at_most); if (T.is_signed) { // Two's complement makes this math pretty easy. - const UnsignedT = @IntType(false, T.bit_count); + const UnsignedT = std.meta.IntType(false, T.bit_count); const lo = @bitCast(UnsignedT, at_least); const hi = @bitCast(UnsignedT, at_most); const result = lo +% r.uintAtMostBiased(UnsignedT, hi -% lo); @@ -198,7 +198,7 @@ pub const Random = struct { assert(at_least <= at_most); if (T.is_signed) { // Two's complement makes this math pretty easy. - const UnsignedT = @IntType(false, T.bit_count); + const UnsignedT = std.meta.IntType(false, T.bit_count); const lo = @bitCast(UnsignedT, at_least); const hi = @bitCast(UnsignedT, at_most); const result = lo +% r.uintAtMost(UnsignedT, hi -% lo); @@ -281,7 +281,7 @@ pub const Random = struct { /// This function introduces a minor bias. pub fn limitRangeBiased(comptime T: type, random_int: T, less_than: T) T { comptime assert(T.is_signed == false); - const T2 = @IntType(false, T.bit_count * 2); + const T2 = std.meta.IntType(false, T.bit_count * 2); // adapted from: // http://www.pcg-random.org/posts/bounded-rands.html diff --git a/lib/std/special/build_runner.zig b/lib/std/special/build_runner.zig @@ -96,6 +96,8 @@ pub fn main() !void { builder.verbose_cimport = true; } else if (mem.eql(u8, arg, "--verbose-cc")) { builder.verbose_cc = true; + } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) { + builder.verbose_llvm_cpu_features = true; } else if (mem.eql(u8, arg, "--")) { builder.args = argsRest(args, arg_idx); break; @@ -126,7 +128,7 @@ pub fn main() !void { } fn runBuild(builder: *Builder) anyerror!void { - switch (@typeId(@TypeOf(root.build).ReturnType)) { + switch (@typeInfo(@TypeOf(root.build).ReturnType)) { .Void => root.build(builder), .ErrorUnion => try root.build(builder), else => @compileError("expected return type of build to be 'void' or '!void'"), @@ -185,16 +187,17 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void { try out_stream.write( \\ \\Advanced Options: - \\ --build-file [file] Override path to build.zig - \\ --cache-dir [path] Override path to zig cache directory - \\ --override-lib-dir [arg] Override path to Zig lib directory - \\ --verbose-tokenize Enable compiler debug output for tokenization - \\ --verbose-ast Enable compiler debug output for parsing into an AST - \\ --verbose-link Enable compiler debug output for linking - \\ --verbose-ir Enable compiler debug output for Zig IR - \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR - \\ --verbose-cimport Enable compiler debug output for C imports - \\ --verbose-cc Enable compiler debug output for C compilation + \\ --build-file [file] Override path to build.zig + \\ --cache-dir [path] Override path to zig cache directory + \\ --override-lib-dir [arg] Override path to Zig lib directory + \\ --verbose-tokenize Enable compiler debug output for tokenization + \\ --verbose-ast Enable compiler debug output for parsing into an AST + \\ --verbose-link Enable compiler debug output for linking + \\ --verbose-ir Enable compiler debug output for Zig IR + \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR + \\ --verbose-cimport Enable compiler debug output for C imports + \\ --verbose-cc Enable compiler debug output for C compilation + \\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features \\ ); } diff --git a/lib/std/special/c.zig b/lib/std/special/c.zig @@ -511,7 +511,7 @@ export fn roundf(a: f32) f32 { fn generic_fmod(comptime T: type, x: T, y: T) T { @setRuntimeSafety(false); - const uint = @IntType(false, T.bit_count); + const uint = std.meta.IntType(false, T.bit_count); const log2uint = math.Log2Int(uint); const digits = if (T == f32) 23 else 52; const exp_bits = if (T == f32) 9 else 12; diff --git a/lib/std/special/compiler_rt/addXf3.zig b/lib/std/special/compiler_rt/addXf3.zig @@ -54,21 +54,21 @@ pub fn __aeabi_dsub(a: f64, b: f64) callconv(.AAPCS) f64 { } // TODO: restore inline keyword, see: https://github.com/ziglang/zig/issues/2154 -fn normalize(comptime T: type, significand: *@IntType(false, T.bit_count)) i32 { - const Z = @IntType(false, T.bit_count); - const S = @IntType(false, T.bit_count - @clz(Z, @as(Z, T.bit_count) - 1)); +fn normalize(comptime T: type, significand: *std.meta.IntType(false, T.bit_count)) i32 { + const Z = std.meta.IntType(false, T.bit_count); + const S = std.meta.IntType(false, T.bit_count - @clz(Z, @as(Z, T.bit_count) - 1)); const significandBits = std.math.floatMantissaBits(T); const implicitBit = @as(Z, 1) << significandBits; - const shift = @clz(@IntType(false, T.bit_count), significand.*) - @clz(Z, implicitBit); + const shift = @clz(std.meta.IntType(false, T.bit_count), significand.*) - @clz(Z, implicitBit); significand.* <<= @intCast(S, shift); return 1 - shift; } // TODO: restore inline keyword, see: https://github.com/ziglang/zig/issues/2154 fn addXf3(comptime T: type, a: T, b: T) T { - const Z = @IntType(false, T.bit_count); - const S = @IntType(false, T.bit_count - @clz(Z, @as(Z, T.bit_count) - 1)); + const Z = std.meta.IntType(false, T.bit_count); + const S = std.meta.IntType(false, T.bit_count - @clz(Z, @as(Z, T.bit_count) - 1)); const typeWidth = T.bit_count; const significandBits = std.math.floatMantissaBits(T); @@ -182,7 +182,7 @@ fn addXf3(comptime T: type, a: T, b: T) T { // If partial cancellation occured, we need to left-shift the result // and adjust the exponent: if (aSignificand < implicitBit << 3) { - const shift = @intCast(i32, @clz(Z, aSignificand)) - @intCast(i32, @clz(@IntType(false, T.bit_count), implicitBit << 3)); + const shift = @intCast(i32, @clz(Z, aSignificand)) - @intCast(i32, @clz(std.meta.IntType(false, T.bit_count), implicitBit << 3)); aSignificand <<= @intCast(S, shift); aExponent -= shift; } diff --git a/lib/std/special/compiler_rt/compareXf2.zig b/lib/std/special/compiler_rt/compareXf2.zig @@ -22,8 +22,8 @@ const GE = extern enum(i32) { pub fn cmp(comptime T: type, comptime RT: type, a: T, b: T) RT { @setRuntimeSafety(builtin.is_test); - const srep_t = @IntType(true, T.bit_count); - const rep_t = @IntType(false, T.bit_count); + const srep_t = std.meta.IntType(true, T.bit_count); + const rep_t = std.meta.IntType(false, T.bit_count); const significandBits = std.math.floatMantissaBits(T); const exponentBits = std.math.floatExponentBits(T); @@ -68,7 +68,7 @@ pub fn cmp(comptime T: type, comptime RT: type, a: T, b: T) RT { pub fn unordcmp(comptime T: type, a: T, b: T) i32 { @setRuntimeSafety(builtin.is_test); - const rep_t = @IntType(false, T.bit_count); + const rep_t = std.meta.IntType(false, T.bit_count); const significandBits = std.math.floatMantissaBits(T); const exponentBits = std.math.floatExponentBits(T); diff --git a/lib/std/special/compiler_rt/divdf3.zig b/lib/std/special/compiler_rt/divdf3.zig @@ -7,8 +7,8 @@ const builtin = @import("builtin"); pub fn __divdf3(a: f64, b: f64) callconv(.C) f64 { @setRuntimeSafety(builtin.is_test); - const Z = @IntType(false, f64.bit_count); - const SignedZ = @IntType(true, f64.bit_count); + const Z = std.meta.IntType(false, f64.bit_count); + const SignedZ = std.meta.IntType(true, f64.bit_count); const typeWidth = f64.bit_count; const significandBits = std.math.floatMantissaBits(f64); @@ -312,9 +312,9 @@ fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { } } -fn normalize(comptime T: type, significand: *@IntType(false, T.bit_count)) i32 { +fn normalize(comptime T: type, significand: *std.meta.IntType(false, T.bit_count)) i32 { @setRuntimeSafety(builtin.is_test); - const Z = @IntType(false, T.bit_count); + const Z = std.meta.IntType(false, T.bit_count); const significandBits = std.math.floatMantissaBits(T); const implicitBit = @as(Z, 1) << significandBits; diff --git a/lib/std/special/compiler_rt/divsf3.zig b/lib/std/special/compiler_rt/divsf3.zig @@ -7,7 +7,7 @@ const builtin = @import("builtin"); pub fn __divsf3(a: f32, b: f32) callconv(.C) f32 { @setRuntimeSafety(builtin.is_test); - const Z = @IntType(false, f32.bit_count); + const Z = std.meta.IntType(false, f32.bit_count); const typeWidth = f32.bit_count; const significandBits = std.math.floatMantissaBits(f32); @@ -185,9 +185,9 @@ pub fn __divsf3(a: f32, b: f32) callconv(.C) f32 { } } -fn normalize(comptime T: type, significand: *@IntType(false, T.bit_count)) i32 { +fn normalize(comptime T: type, significand: *std.meta.IntType(false, T.bit_count)) i32 { @setRuntimeSafety(builtin.is_test); - const Z = @IntType(false, T.bit_count); + const Z = std.meta.IntType(false, T.bit_count); const significandBits = std.math.floatMantissaBits(T); const implicitBit = @as(Z, 1) << significandBits; diff --git a/lib/std/special/compiler_rt/extendXfYf2.zig b/lib/std/special/compiler_rt/extendXfYf2.zig @@ -30,11 +30,11 @@ pub fn __aeabi_f2d(arg: f32) callconv(.AAPCS) f64 { const CHAR_BIT = 8; -fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: @IntType(false, @typeInfo(src_t).Float.bits)) dst_t { +fn extendXfYf2(comptime dst_t: type, comptime src_t: type, a: std.meta.IntType(false, @typeInfo(src_t).Float.bits)) dst_t { @setRuntimeSafety(builtin.is_test); - const src_rep_t = @IntType(false, @typeInfo(src_t).Float.bits); - const dst_rep_t = @IntType(false, @typeInfo(dst_t).Float.bits); + const src_rep_t = std.meta.IntType(false, @typeInfo(src_t).Float.bits); + const dst_rep_t = std.meta.IntType(false, @typeInfo(dst_t).Float.bits); const srcSigBits = std.math.floatMantissaBits(src_t); const dstSigBits = std.math.floatMantissaBits(dst_t); const SrcShift = std.math.Log2Int(src_rep_t); diff --git a/lib/std/special/compiler_rt/fixint.zig b/lib/std/special/compiler_rt/fixint.zig @@ -45,7 +45,7 @@ pub fn fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t) fixint_t { if (exponent < 0) return 0; // The unsigned result needs to be large enough to handle an fixint_t or rep_t - const fixuint_t = @IntType(false, fixint_t.bit_count); + const fixuint_t = std.meta.IntType(false, fixint_t.bit_count); const UintResultType = if (fixint_t.bit_count > rep_t.bit_count) fixuint_t else rep_t; var uint_result: UintResultType = undefined; diff --git a/lib/std/special/compiler_rt/fixuint.zig b/lib/std/special/compiler_rt/fixuint.zig @@ -10,7 +10,7 @@ pub fn fixuint(comptime fp_t: type, comptime fixuint_t: type, a: fp_t) fixuint_t f128 => u128, else => unreachable, }; - const srep_t = @IntType(true, rep_t.bit_count); + const srep_t = @import("std").meta.IntType(true, rep_t.bit_count); const significandBits = switch (fp_t) { f32 => 23, f64 => 52, diff --git a/lib/std/special/compiler_rt/floatsiXf.zig b/lib/std/special/compiler_rt/floatsiXf.zig @@ -5,8 +5,8 @@ const maxInt = std.math.maxInt; fn floatsiXf(comptime T: type, a: i32) T { @setRuntimeSafety(builtin.is_test); - const Z = @IntType(false, T.bit_count); - const S = @IntType(false, T.bit_count - @clz(Z, @as(Z, T.bit_count) - 1)); + const Z = std.meta.IntType(false, T.bit_count); + const S = std.meta.IntType(false, T.bit_count - @clz(Z, @as(Z, T.bit_count) - 1)); if (a == 0) { return @as(T, 0.0); diff --git a/lib/std/special/compiler_rt/mulXf3.zig b/lib/std/special/compiler_rt/mulXf3.zig @@ -28,7 +28,7 @@ pub fn __aeabi_dmul(a: f64, b: f64) callconv(.C) f64 { fn mulXf3(comptime T: type, a: T, b: T) T { @setRuntimeSafety(builtin.is_test); - const Z = @IntType(false, T.bit_count); + const Z = std.meta.IntType(false, T.bit_count); const typeWidth = T.bit_count; const significandBits = std.math.floatMantissaBits(T); @@ -264,9 +264,9 @@ fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { } } -fn normalize(comptime T: type, significand: *@IntType(false, T.bit_count)) i32 { +fn normalize(comptime T: type, significand: *std.meta.IntType(false, T.bit_count)) i32 { @setRuntimeSafety(builtin.is_test); - const Z = @IntType(false, T.bit_count); + const Z = std.meta.IntType(false, T.bit_count); const significandBits = std.math.floatMantissaBits(T); const implicitBit = @as(Z, 1) << significandBits; diff --git a/lib/std/special/compiler_rt/negXf2.zig b/lib/std/special/compiler_rt/negXf2.zig @@ -19,7 +19,7 @@ pub fn __aeabi_dneg(arg: f64) callconv(.AAPCS) f64 { } fn negXf2(comptime T: type, a: T) T { - const Z = @IntType(false, T.bit_count); + const Z = std.meta.IntType(false, T.bit_count); const typeWidth = T.bit_count; const significandBits = std.math.floatMantissaBits(T); diff --git a/lib/std/special/compiler_rt/truncXfYf2.zig b/lib/std/special/compiler_rt/truncXfYf2.zig @@ -36,8 +36,8 @@ pub fn __aeabi_f2h(a: f32) callconv(.AAPCS) u16 { } inline fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t { - const src_rep_t = @IntType(false, @typeInfo(src_t).Float.bits); - const dst_rep_t = @IntType(false, @typeInfo(dst_t).Float.bits); + const src_rep_t = std.meta.IntType(false, @typeInfo(src_t).Float.bits); + const dst_rep_t = std.meta.IntType(false, @typeInfo(dst_t).Float.bits); const srcSigBits = std.math.floatMantissaBits(src_t); const dstSigBits = std.math.floatMantissaBits(dst_t); const SrcShift = std.math.Log2Int(src_rep_t); diff --git a/lib/std/special/compiler_rt/udivmod.zig b/lib/std/special/compiler_rt/udivmod.zig @@ -10,8 +10,8 @@ const high = 1 - low; pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: ?*DoubleInt) DoubleInt { @setRuntimeSafety(is_test); - const SingleInt = @IntType(false, @divExact(DoubleInt.bit_count, 2)); - const SignedDoubleInt = @IntType(true, DoubleInt.bit_count); + const SingleInt = @import("std").meta.IntType(false, @divExact(DoubleInt.bit_count, 2)); + const SignedDoubleInt = @import("std").meta.IntType(true, DoubleInt.bit_count); const Log2SingleInt = @import("std").math.Log2Int(SingleInt); const n = @ptrCast(*const [2]SingleInt, &a).*; // TODO issue #421 diff --git a/lib/std/start.zig b/lib/std/start.zig @@ -21,7 +21,9 @@ comptime { @export(main, .{ .name = "main", .linkage = .Weak }); } } else if (builtin.os == .windows) { - if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup")) { + if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and + !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup")) + { @export(WinMainCRTStartup, .{ .name = "WinMainCRTStartup" }); } } else if (builtin.os == .uefi) { @@ -34,7 +36,11 @@ comptime { } } -fn _DllMainCRTStartup(hinstDLL: std.os.windows.HINSTANCE, fdwReason: std.os.windows.DWORD, lpReserved: std.os.windows.LPVOID) callconv(.Stdcall) std.os.windows.BOOL { +fn _DllMainCRTStartup( + hinstDLL: std.os.windows.HINSTANCE, + fdwReason: std.os.windows.DWORD, + lpReserved: std.os.windows.LPVOID, +) callconv(.Stdcall) std.os.windows.BOOL { if (@hasDecl(root, "DllMain")) { return root.DllMain(hinstDLL, fdwReason, lpReserved); } diff --git a/lib/std/target.zig b/lib/std/target.zig @@ -47,6 +47,16 @@ pub const Target = union(enum) { emscripten, uefi, other, + + pub fn parse(text: []const u8) !Os { + const info = @typeInfo(Os); + inline for (info.Enum.fields) |field| { + if (mem.eql(u8, text, field.name)) { + return @field(Os, field.name); + } + } + return error.UnknownOperatingSystem; + } }; pub const aarch64 = @import("target/aarch64.zig"); @@ -65,463 +75,6 @@ pub const Target = union(enum) { pub const wasm = @import("target/wasm.zig"); pub const x86 = @import("target/x86.zig"); - pub const Arch = union(enum) { - arm: Arm32, - armeb: Arm32, - aarch64: Arm64, - aarch64_be: Arm64, - aarch64_32: Arm64, - arc, - avr, - bpfel, - bpfeb, - hexagon, - mips, - mipsel, - mips64, - mips64el, - msp430, - powerpc, - powerpc64, - powerpc64le, - r600, - amdgcn, - riscv32, - riscv64, - sparc, - sparcv9, - sparcel, - s390x, - tce, - tcele, - thumb: Arm32, - thumbeb: Arm32, - i386, - x86_64, - xcore, - nvptx, - nvptx64, - le32, - le64, - amdil, - amdil64, - hsail, - hsail64, - spir, - spir64, - kalimba: Kalimba, - shave, - lanai, - wasm32, - wasm64, - renderscript32, - renderscript64, - ve, - - pub const Arm32 = enum { - v8_5a, - v8_4a, - v8_3a, - v8_2a, - v8_1a, - v8a, - v8r, - v8m_baseline, - v8m_mainline, - v8_1m_mainline, - v7a, - v7em, - v7m, - v7s, - v7k, - v7ve, - v6, - v6m, - v6k, - v6t2, - v5, - v5te, - v4t, - - pub fn version(version: Arm32) comptime_int { - return switch (version) { - .v8_5a, .v8_4a, .v8_3a, .v8_2a, .v8_1a, .v8a, .v8r, .v8m_baseline, .v8m_mainline, .v8_1m_mainline => 8, - .v7a, .v7em, .v7m, .v7s, .v7k, .v7ve => 7, - .v6, .v6m, .v6k, .v6t2 => 6, - .v5, .v5te => 5, - .v4t => 4, - }; - } - }; - pub const Arm64 = enum { - v8_5a, - v8_4a, - v8_3a, - v8_2a, - v8_1a, - v8a, - }; - pub const Kalimba = enum { - v5, - v4, - v3, - }; - pub const Mips = enum { - r6, - }; - pub const PPC = enum { - spe, - }; - - pub fn subArchName(arch: Arch) ?[]const u8 { - return switch (arch) { - .arm, .armeb, .thumb, .thumbeb => |arm32| @tagName(arm32), - .aarch64, .aarch64_be, .aarch64_32 => |arm64| @tagName(arm64), - .kalimba => |kalimba| @tagName(kalimba), - else => return null, - }; - } - - pub fn subArchFeature(arch: Arch) ?Cpu.Feature.Set.Index { - return switch (arch) { - .arm, .armeb, .thumb, .thumbeb => |arm32| switch (arm32) { - .v8_5a => @enumToInt(arm.Feature.armv8_5_a), - .v8_4a => @enumToInt(arm.Feature.armv8_4_a), - .v8_3a => @enumToInt(arm.Feature.armv8_3_a), - .v8_2a => @enumToInt(arm.Feature.armv8_2_a), - .v8_1a => @enumToInt(arm.Feature.armv8_1_a), - .v8a => @enumToInt(arm.Feature.armv8_a), - .v8r => @enumToInt(arm.Feature.armv8_r), - .v8m_baseline => @enumToInt(arm.Feature.armv8_m_base), - .v8m_mainline => @enumToInt(arm.Feature.armv8_m_main), - .v8_1m_mainline => @enumToInt(arm.Feature.armv8_1_m_main), - .v7a => @enumToInt(arm.Feature.armv7_a), - .v7em => @enumToInt(arm.Feature.armv7e_m), - .v7m => @enumToInt(arm.Feature.armv7_m), - .v7s => @enumToInt(arm.Feature.armv7s), - .v7k => @enumToInt(arm.Feature.armv7k), - .v7ve => @enumToInt(arm.Feature.armv7ve), - .v6 => @enumToInt(arm.Feature.armv6), - .v6m => @enumToInt(arm.Feature.armv6_m), - .v6k => @enumToInt(arm.Feature.armv6k), - .v6t2 => @enumToInt(arm.Feature.armv6t2), - .v5 => @enumToInt(arm.Feature.armv5t), - .v5te => @enumToInt(arm.Feature.armv5te), - .v4t => @enumToInt(arm.Feature.armv4t), - }, - .aarch64, .aarch64_be, .aarch64_32 => |arm64| switch (arm64) { - .v8_5a => @enumToInt(aarch64.Feature.v8_5a), - .v8_4a => @enumToInt(aarch64.Feature.v8_4a), - .v8_3a => @enumToInt(aarch64.Feature.v8_3a), - .v8_2a => @enumToInt(aarch64.Feature.v8_2a), - .v8_1a => @enumToInt(aarch64.Feature.v8_1a), - .v8a => @enumToInt(aarch64.Feature.v8a), - }, - else => return null, - }; - } - - pub fn isARM(arch: Arch) bool { - return switch (arch) { - .arm, .armeb => true, - else => false, - }; - } - - pub fn isThumb(arch: Arch) bool { - return switch (arch) { - .thumb, .thumbeb => true, - else => false, - }; - } - - pub fn isWasm(arch: Arch) bool { - return switch (arch) { - .wasm32, .wasm64 => true, - else => false, - }; - } - - pub fn isRISCV(arch: Arch) bool { - return switch (arch) { - .riscv32, .riscv64 => true, - else => false, - }; - } - - pub fn isMIPS(arch: Arch) bool { - return switch (arch) { - .mips, .mipsel, .mips64, .mips64el => true, - else => false, - }; - } - - pub fn parseCpu(arch: Arch, cpu_name: []const u8) !*const Cpu { - for (arch.allCpus()) |cpu| { - if (mem.eql(u8, cpu_name, cpu.name)) { - return cpu; - } - } - return error.UnknownCpu; - } - - /// Comma-separated list of features, with + or - in front of each feature. This - /// form represents a deviation from baseline CPU, which is provided as a parameter. - /// Extra commas are ignored. - pub fn parseCpuFeatureSet(arch: Arch, cpu: *const Cpu, features_text: []const u8) !Cpu.Feature.Set { - const all_features = arch.allFeaturesList(); - var set = cpu.features; - var it = mem.tokenize(features_text, ","); - while (it.next()) |item_text| { - var feature_name: []const u8 = undefined; - var op: enum { - add, - sub, - } = undefined; - if (mem.startsWith(u8, item_text, "+")) { - op = .add; - feature_name = item_text[1..]; - } else if (mem.startsWith(u8, item_text, "-")) { - op = .sub; - feature_name = item_text[1..]; - } else { - return error.InvalidCpuFeatures; - } - for (all_features) |feature, index_usize| { - const index = @intCast(Cpu.Feature.Set.Index, index_usize); - if (mem.eql(u8, feature_name, feature.name)) { - switch (op) { - .add => set.addFeature(index), - .sub => set.removeFeature(index), - } - break; - } - } else { - return error.UnknownCpuFeature; - } - } - return set; - } - - pub fn toElfMachine(arch: Arch) std.elf.EM { - return switch (arch) { - .avr => ._AVR, - .msp430 => ._MSP430, - .arc => ._ARC, - .arm => ._ARM, - .armeb => ._ARM, - .hexagon => ._HEXAGON, - .le32 => ._NONE, - .mips => ._MIPS, - .mipsel => ._MIPS_RS3_LE, - .powerpc => ._PPC, - .r600 => ._NONE, - .riscv32 => ._RISCV, - .sparc => ._SPARC, - .sparcel => ._SPARC, - .tce => ._NONE, - .tcele => ._NONE, - .thumb => ._ARM, - .thumbeb => ._ARM, - .i386 => ._386, - .xcore => ._XCORE, - .nvptx => ._NONE, - .amdil => ._NONE, - .hsail => ._NONE, - .spir => ._NONE, - .kalimba => ._CSR_KALIMBA, - .shave => ._NONE, - .lanai => ._LANAI, - .wasm32 => ._NONE, - .renderscript32 => ._NONE, - .aarch64_32 => ._AARCH64, - .aarch64 => ._AARCH64, - .aarch64_be => ._AARCH64, - .mips64 => ._MIPS, - .mips64el => ._MIPS_RS3_LE, - .powerpc64 => ._PPC64, - .powerpc64le => ._PPC64, - .riscv64 => ._RISCV, - .x86_64 => ._X86_64, - .nvptx64 => ._NONE, - .le64 => ._NONE, - .amdil64 => ._NONE, - .hsail64 => ._NONE, - .spir64 => ._NONE, - .wasm64 => ._NONE, - .renderscript64 => ._NONE, - .amdgcn => ._NONE, - .bpfel => ._BPF, - .bpfeb => ._BPF, - .sparcv9 => ._SPARCV9, - .s390x => ._S390, - .ve => ._NONE, - }; - } - - pub fn endian(arch: Arch) builtin.Endian { - return switch (arch) { - .avr, - .arm, - .aarch64_32, - .aarch64, - .amdgcn, - .amdil, - .amdil64, - .bpfel, - .hexagon, - .hsail, - .hsail64, - .kalimba, - .le32, - .le64, - .mipsel, - .mips64el, - .msp430, - .nvptx, - .nvptx64, - .sparcel, - .tcele, - .powerpc64le, - .r600, - .riscv32, - .riscv64, - .i386, - .x86_64, - .wasm32, - .wasm64, - .xcore, - .thumb, - .spir, - .spir64, - .renderscript32, - .renderscript64, - .shave, - .ve, - => .Little, - - .arc, - .armeb, - .aarch64_be, - .bpfeb, - .mips, - .mips64, - .powerpc, - .powerpc64, - .thumbeb, - .sparc, - .sparcv9, - .tce, - .lanai, - .s390x, - => .Big, - }; - } - - /// Returns a name that matches the lib/std/target/* directory name. - pub fn genericName(arch: Arch) []const u8 { - return switch (arch) { - .arm, .armeb, .thumb, .thumbeb => "arm", - .aarch64, .aarch64_be, .aarch64_32 => "aarch64", - .avr => "avr", - .bpfel, .bpfeb => "bpf", - .hexagon => "hexagon", - .mips, .mipsel, .mips64, .mips64el => "mips", - .msp430 => "msp430", - .powerpc, .powerpc64, .powerpc64le => "powerpc", - .amdgcn => "amdgpu", - .riscv32, .riscv64 => "riscv", - .sparc, .sparcv9, .sparcel => "sparc", - .s390x => "systemz", - .i386, .x86_64 => "x86", - .nvptx, .nvptx64 => "nvptx", - .wasm32, .wasm64 => "wasm", - else => @tagName(arch), - }; - } - - /// All CPU features Zig is aware of, sorted lexicographically by name. - pub fn allFeaturesList(arch: Arch) []const Cpu.Feature { - return switch (arch) { - .arm, .armeb, .thumb, .thumbeb => &arm.all_features, - .aarch64, .aarch64_be, .aarch64_32 => &aarch64.all_features, - .avr => &avr.all_features, - .bpfel, .bpfeb => &bpf.all_features, - .hexagon => &hexagon.all_features, - .mips, .mipsel, .mips64, .mips64el => &mips.all_features, - .msp430 => &msp430.all_features, - .powerpc, .powerpc64, .powerpc64le => &powerpc.all_features, - .amdgcn => &amdgpu.all_features, - .riscv32, .riscv64 => &riscv.all_features, - .sparc, .sparcv9, .sparcel => &sparc.all_features, - .s390x => &systemz.all_features, - .i386, .x86_64 => &x86.all_features, - .nvptx, .nvptx64 => &nvptx.all_features, - .wasm32, .wasm64 => &wasm.all_features, - - else => &[0]Cpu.Feature{}, - }; - } - - /// The "default" set of CPU features for cross-compiling. A conservative set - /// of features that is expected to be supported on most available hardware. - pub fn getBaselineCpuFeatures(arch: Arch) CpuFeatures { - const S = struct { - const generic_cpu = Cpu{ - .name = "generic", - .llvm_name = null, - .features = Cpu.Feature.Set.empty, - }; - }; - const cpu = switch (arch) { - .arm, .armeb, .thumb, .thumbeb => &arm.cpu.generic, - .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic, - .avr => &avr.cpu.avr1, - .bpfel, .bpfeb => &bpf.cpu.generic, - .hexagon => &hexagon.cpu.generic, - .mips, .mipsel => &mips.cpu.mips32, - .mips64, .mips64el => &mips.cpu.mips64, - .msp430 => &msp430.cpu.generic, - .powerpc, .powerpc64, .powerpc64le => &powerpc.cpu.generic, - .amdgcn => &amdgpu.cpu.generic, - .riscv32 => &riscv.cpu.baseline_rv32, - .riscv64 => &riscv.cpu.baseline_rv64, - .sparc, .sparcv9, .sparcel => &sparc.cpu.generic, - .s390x => &systemz.cpu.generic, - .i386 => &x86.cpu.pentium4, - .x86_64 => &x86.cpu.x86_64, - .nvptx, .nvptx64 => &nvptx.cpu.sm_20, - .wasm32, .wasm64 => &wasm.cpu.generic, - - else => &S.generic_cpu, - }; - return CpuFeatures.initFromCpu(arch, cpu); - } - - /// All CPUs Zig is aware of, sorted lexicographically by name. - pub fn allCpus(arch: Arch) []const *const Cpu { - return switch (arch) { - .arm, .armeb, .thumb, .thumbeb => arm.all_cpus, - .aarch64, .aarch64_be, .aarch64_32 => aarch64.all_cpus, - .avr => avr.all_cpus, - .bpfel, .bpfeb => bpf.all_cpus, - .hexagon => hexagon.all_cpus, - .mips, .mipsel, .mips64, .mips64el => mips.all_cpus, - .msp430 => msp430.all_cpus, - .powerpc, .powerpc64, .powerpc64le => powerpc.all_cpus, - .amdgcn => amdgpu.all_cpus, - .riscv32, .riscv64 => riscv.all_cpus, - .sparc, .sparcv9, .sparcel => sparc.all_cpus, - .s390x => systemz.all_cpus, - .i386, .x86_64 => x86.all_cpus, - .nvptx, .nvptx64 => nvptx.all_cpus, - .wasm32, .wasm64 => wasm.all_cpus, - - else => &[0]*const Cpu{}, - }; - } - }; - pub const Abi = enum { none, gnu, @@ -543,11 +96,102 @@ pub const Target = union(enum) { coreclr, simulator, macabi, + + pub fn default(arch: Cpu.Arch, target_os: Os) Abi { + switch (arch) { + .wasm32, .wasm64 => return .musl, + else => {}, + } + switch (target_os) { + .freestanding, + .ananas, + .cloudabi, + .dragonfly, + .lv2, + .solaris, + .haiku, + .minix, + .rtems, + .nacl, + .cnk, + .aix, + .cuda, + .nvcl, + .amdhsa, + .ps4, + .elfiamcu, + .mesa3d, + .contiki, + .amdpal, + .hermit, + .other, + => return .eabi, + .openbsd, + .macosx, + .freebsd, + .ios, + .tvos, + .watchos, + .fuchsia, + .kfreebsd, + .netbsd, + .hurd, + => return .gnu, + .windows, + .uefi, + => return .msvc, + .linux, + .wasi, + .emscripten, + => return .musl, + } + } + + pub fn parse(text: []const u8) !Abi { + const info = @typeInfo(Abi); + inline for (info.Enum.fields) |field| { + if (mem.eql(u8, text, field.name)) { + return @field(Abi, field.name); + } + } + return error.UnknownApplicationBinaryInterface; + } + }; + + pub const ObjectFormat = enum { + unknown, + coff, + elf, + macho, + wasm, + }; + + pub const SubSystem = enum { + Console, + Windows, + Posix, + Native, + EfiApplication, + EfiBootServiceDriver, + EfiRom, + EfiRuntimeDriver, + }; + + pub const Cross = struct { + cpu: Cpu, + os: Os, + abi: Abi, }; pub const Cpu = struct { - name: []const u8, - llvm_name: ?[:0]const u8, + /// Architecture + arch: Arch, + + /// The CPU model to target. It has a set of features + /// which are overridden with the `features` field. + model: *const Model, + + /// An explicit list of the entire CPU feature set. It may differ from the specific CPU model's features. features: Feature.Set, pub const Feature = struct { @@ -573,10 +217,10 @@ pub const Target = union(enum) { pub const Set = struct { ints: [usize_count]usize, - pub const needed_bit_count = 175; + pub const needed_bit_count = 155; pub const byte_count = (needed_bit_count + 7) / 8; pub const usize_count = (byte_count + (@sizeOf(usize) - 1)) / @sizeOf(usize); - pub const Index = std.math.Log2Int(@IntType(false, usize_count * @bitSizeOf(usize))); + pub const Index = std.math.Log2Int(std.meta.IntType(false, usize_count * @bitSizeOf(usize))); pub const ShiftInt = std.math.Log2Int(usize); pub const empty = Set{ .ints = [1]usize{0} ** usize_count }; @@ -597,6 +241,12 @@ pub const Target = union(enum) { set.ints[usize_index] |= @as(usize, 1) << bit_index; } + /// Adds the specified feature set but not its dependencies. + pub fn addFeatureSet(set: *Set, other_set: Set) void { + set.ints = @as(@Vector(usize_count, usize), set.ints) | + @as(@Vector(usize_count, usize), other_set.ints); + } + /// Removes the specified feature but not its dependents. pub fn removeFeature(set: *Set, arch_feature_index: Index) void { const usize_index = arch_feature_index / @bitSizeOf(usize); @@ -612,8 +262,7 @@ pub const Target = union(enum) { for (all_features_list) |feature, index_usize| { const index = @intCast(Index, index_usize); if (set.isEnabled(index)) { - set.ints = @as(@Vector(usize_count, usize), set.ints) | - @as(@Vector(usize_count, usize), feature.dependencies.ints); + set.addFeatureSet(feature.dependencies); } } const nothing_changed = mem.eql(usize, &old, &set.ints); @@ -648,77 +297,361 @@ pub const Target = union(enum) { }; } }; - }; - pub const ObjectFormat = enum { - unknown, - coff, - elf, - macho, - wasm, - }; + pub const Arch = enum { + arm, + armeb, + aarch64, + aarch64_be, + aarch64_32, + arc, + avr, + bpfel, + bpfeb, + hexagon, + mips, + mipsel, + mips64, + mips64el, + msp430, + powerpc, + powerpc64, + powerpc64le, + r600, + amdgcn, + riscv32, + riscv64, + sparc, + sparcv9, + sparcel, + s390x, + tce, + tcele, + thumb, + thumbeb, + i386, + x86_64, + xcore, + nvptx, + nvptx64, + le32, + le64, + amdil, + amdil64, + hsail, + hsail64, + spir, + spir64, + kalimba, + shave, + lanai, + wasm32, + wasm64, + renderscript32, + renderscript64, + ve, + + pub fn isARM(arch: Arch) bool { + return switch (arch) { + .arm, .armeb => true, + else => false, + }; + } - pub const SubSystem = enum { - Console, - Windows, - Posix, - Native, - EfiApplication, - EfiBootServiceDriver, - EfiRom, - EfiRuntimeDriver, - }; + pub fn isThumb(arch: Arch) bool { + return switch (arch) { + .thumb, .thumbeb => true, + else => false, + }; + } - pub const Cross = struct { - arch: Arch, - os: Os, - abi: Abi, - cpu_features: CpuFeatures, - }; + pub fn isWasm(arch: Arch) bool { + return switch (arch) { + .wasm32, .wasm64 => true, + else => false, + }; + } - pub const CpuFeatures = struct { - /// The CPU to target. It has a set of features - /// which are overridden with the `features` field. - cpu: *const Cpu, + pub fn isRISCV(arch: Arch) bool { + return switch (arch) { + .riscv32, .riscv64 => true, + else => false, + }; + } - /// Explicitly provide the entire CPU feature set. - features: Cpu.Feature.Set, + pub fn isMIPS(arch: Arch) bool { + return switch (arch) { + .mips, .mipsel, .mips64, .mips64el => true, + else => false, + }; + } - pub fn initFromCpu(arch: Arch, cpu: *const Cpu) CpuFeatures { - var features = cpu.features; - if (arch.subArchFeature()) |sub_arch_index| { - features.addFeature(sub_arch_index); + pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) !*const Cpu.Model { + for (arch.allCpuModels()) |cpu| { + if (mem.eql(u8, cpu_name, cpu.name)) { + return cpu; + } + } + return error.UnknownCpu; + } + + pub fn toElfMachine(arch: Arch) std.elf.EM { + return switch (arch) { + .avr => ._AVR, + .msp430 => ._MSP430, + .arc => ._ARC, + .arm => ._ARM, + .armeb => ._ARM, + .hexagon => ._HEXAGON, + .le32 => ._NONE, + .mips => ._MIPS, + .mipsel => ._MIPS_RS3_LE, + .powerpc => ._PPC, + .r600 => ._NONE, + .riscv32 => ._RISCV, + .sparc => ._SPARC, + .sparcel => ._SPARC, + .tce => ._NONE, + .tcele => ._NONE, + .thumb => ._ARM, + .thumbeb => ._ARM, + .i386 => ._386, + .xcore => ._XCORE, + .nvptx => ._NONE, + .amdil => ._NONE, + .hsail => ._NONE, + .spir => ._NONE, + .kalimba => ._CSR_KALIMBA, + .shave => ._NONE, + .lanai => ._LANAI, + .wasm32 => ._NONE, + .renderscript32 => ._NONE, + .aarch64_32 => ._AARCH64, + .aarch64 => ._AARCH64, + .aarch64_be => ._AARCH64, + .mips64 => ._MIPS, + .mips64el => ._MIPS_RS3_LE, + .powerpc64 => ._PPC64, + .powerpc64le => ._PPC64, + .riscv64 => ._RISCV, + .x86_64 => ._X86_64, + .nvptx64 => ._NONE, + .le64 => ._NONE, + .amdil64 => ._NONE, + .hsail64 => ._NONE, + .spir64 => ._NONE, + .wasm64 => ._NONE, + .renderscript64 => ._NONE, + .amdgcn => ._NONE, + .bpfel => ._BPF, + .bpfeb => ._BPF, + .sparcv9 => ._SPARCV9, + .s390x => ._S390, + }; + } + + pub fn endian(arch: Arch) builtin.Endian { + return switch (arch) { + .avr, + .arm, + .aarch64_32, + .aarch64, + .amdgcn, + .amdil, + .amdil64, + .bpfel, + .hexagon, + .hsail, + .hsail64, + .kalimba, + .le32, + .le64, + .mipsel, + .mips64el, + .msp430, + .nvptx, + .nvptx64, + .sparcel, + .tcele, + .powerpc64le, + .r600, + .riscv32, + .riscv64, + .i386, + .x86_64, + .wasm32, + .wasm64, + .xcore, + .thumb, + .spir, + .spir64, + .renderscript32, + .renderscript64, + .shave, + => .Little, + + .arc, + .armeb, + .aarch64_be, + .bpfeb, + .mips, + .mips64, + .powerpc, + .powerpc64, + .thumbeb, + .sparc, + .sparcv9, + .tce, + .lanai, + .s390x, + => .Big, + }; + } + + /// Returns a name that matches the lib/std/target/* directory name. + pub fn genericName(arch: Arch) []const u8 { + return switch (arch) { + .arm, .armeb, .thumb, .thumbeb => "arm", + .aarch64, .aarch64_be, .aarch64_32 => "aarch64", + .avr => "avr", + .bpfel, .bpfeb => "bpf", + .hexagon => "hexagon", + .mips, .mipsel, .mips64, .mips64el => "mips", + .msp430 => "msp430", + .powerpc, .powerpc64, .powerpc64le => "powerpc", + .amdgcn => "amdgpu", + .riscv32, .riscv64 => "riscv", + .sparc, .sparcv9, .sparcel => "sparc", + .s390x => "systemz", + .i386, .x86_64 => "x86", + .nvptx, .nvptx64 => "nvptx", + .wasm32, .wasm64 => "wasm", + else => @tagName(arch), + }; } - features.populateDependencies(arch.allFeaturesList()); - return CpuFeatures{ - .cpu = cpu, - .features = features, + + /// All CPU features Zig is aware of, sorted lexicographically by name. + pub fn allFeaturesList(arch: Arch) []const Cpu.Feature { + return switch (arch) { + .arm, .armeb, .thumb, .thumbeb => &arm.all_features, + .aarch64, .aarch64_be, .aarch64_32 => &aarch64.all_features, + .avr => &avr.all_features, + .bpfel, .bpfeb => &bpf.all_features, + .hexagon => &hexagon.all_features, + .mips, .mipsel, .mips64, .mips64el => &mips.all_features, + .msp430 => &msp430.all_features, + .powerpc, .powerpc64, .powerpc64le => &powerpc.all_features, + .amdgcn => &amdgpu.all_features, + .riscv32, .riscv64 => &riscv.all_features, + .sparc, .sparcv9, .sparcel => &sparc.all_features, + .s390x => &systemz.all_features, + .i386, .x86_64 => &x86.all_features, + .nvptx, .nvptx64 => &nvptx.all_features, + .wasm32, .wasm64 => &wasm.all_features, + + else => &[0]Cpu.Feature{}, + }; + } + + /// All processors Zig is aware of, sorted lexicographically by name. + pub fn allCpuModels(arch: Arch) []const *const Cpu.Model { + return switch (arch) { + .arm, .armeb, .thumb, .thumbeb => arm.all_cpus, + .aarch64, .aarch64_be, .aarch64_32 => aarch64.all_cpus, + .avr => avr.all_cpus, + .bpfel, .bpfeb => bpf.all_cpus, + .hexagon => hexagon.all_cpus, + .mips, .mipsel, .mips64, .mips64el => mips.all_cpus, + .msp430 => msp430.all_cpus, + .powerpc, .powerpc64, .powerpc64le => powerpc.all_cpus, + .amdgcn => amdgpu.all_cpus, + .riscv32, .riscv64 => riscv.all_cpus, + .sparc, .sparcv9, .sparcel => sparc.all_cpus, + .s390x => systemz.all_cpus, + .i386, .x86_64 => x86.all_cpus, + .nvptx, .nvptx64 => nvptx.all_cpus, + .wasm32, .wasm64 => wasm.all_cpus, + + else => &[0]*const Model{}, + }; + } + + pub fn parse(text: []const u8) !Arch { + const info = @typeInfo(Arch); + inline for (info.Enum.fields) |field| { + if (mem.eql(u8, text, field.name)) { + return @as(Arch, @field(Arch, field.name)); + } + } + return error.UnknownArchitecture; + } + }; + + pub const Model = struct { + name: []const u8, + llvm_name: ?[:0]const u8, + features: Feature.Set, + + pub fn toCpu(model: *const Model, arch: Arch) Cpu { + var features = model.features; + features.populateDependencies(arch.allFeaturesList()); + return .{ + .arch = arch, + .model = model, + .features = features, + }; + } + }; + + /// The "default" set of CPU features for cross-compiling. A conservative set + /// of features that is expected to be supported on most available hardware. + pub fn baseline(arch: Arch) Cpu { + const S = struct { + const generic_model = Model{ + .name = "generic", + .llvm_name = null, + .features = Cpu.Feature.Set.empty, + }; }; + const model = switch (arch) { + .arm, .armeb, .thumb, .thumbeb => &arm.cpu.baseline, + .aarch64, .aarch64_be, .aarch64_32 => &aarch64.cpu.generic, + .avr => &avr.cpu.avr1, + .bpfel, .bpfeb => &bpf.cpu.generic, + .hexagon => &hexagon.cpu.generic, + .mips, .mipsel => &mips.cpu.mips32, + .mips64, .mips64el => &mips.cpu.mips64, + .msp430 => &msp430.cpu.generic, + .powerpc, .powerpc64, .powerpc64le => &powerpc.cpu.generic, + .amdgcn => &amdgpu.cpu.generic, + .riscv32 => &riscv.cpu.baseline_rv32, + .riscv64 => &riscv.cpu.baseline_rv64, + .sparc, .sparcv9, .sparcel => &sparc.cpu.generic, + .s390x => &systemz.cpu.generic, + .i386 => &x86.cpu.pentium4, + .x86_64 => &x86.cpu.x86_64, + .nvptx, .nvptx64 => &nvptx.cpu.sm_20, + .wasm32, .wasm64 => &wasm.cpu.generic, + + else => &S.generic_model, + }; + return model.toCpu(arch); } }; pub const current = Target{ .Cross = Cross{ - .arch = builtin.arch, + .cpu = builtin.cpu, .os = builtin.os, .abi = builtin.abi, - .cpu_features = builtin.cpu_features, }, }; pub const stack_align = 16; - pub fn getCpuFeatures(self: Target) CpuFeatures { - return switch (self) { - .Native => builtin.cpu_features, - .Cross => |cross| cross.cpu_features, - }; - } - pub fn zigTriple(self: Target, allocator: *mem.Allocator) ![]u8 { - return std.fmt.allocPrint(allocator, "{}{}-{}-{}", .{ + return std.fmt.allocPrint(allocator, "{}-{}-{}", .{ @tagName(self.getArch()), - Target.archSubArchName(self.getArch()), @tagName(self.getOs()), @tagName(self.getAbi()), }); @@ -780,139 +713,115 @@ pub const Target = union(enum) { }); } - /// TODO: Support CPU features here? - /// https://github.com/ziglang/zig/issues/4261 - pub fn parse(text: []const u8) !Target { - var it = mem.separate(text, "-"); - const arch_name = it.next() orelse return error.MissingArchitecture; - const os_name = it.next() orelse return error.MissingOperatingSystem; - const abi_name = it.next(); - const arch = try parseArchSub(arch_name); + pub const ParseOptions = struct { + /// This is sometimes called a "triple". It looks roughly like this: + /// riscv64-linux-gnu + /// The fields are, respectively: + /// * CPU Architecture + /// * Operating System + /// * C ABI (optional) + arch_os_abi: []const u8, - var cross = Cross{ - .arch = arch, - .cpu_features = arch.getBaselineCpuFeatures(), - .os = try parseOs(os_name), - .abi = undefined, - }; - cross.abi = if (abi_name) |n| try parseAbi(n) else defaultAbi(cross.arch, cross.os); - return Target{ .Cross = cross }; - } + /// Looks like "name+a+b-c-d+e", where "name" is a CPU Model name, "a", "b", and "e" + /// are examples of CPU features to add to the set, and "c" and "d" are examples of CPU features + /// to remove from the set. + cpu_features: []const u8 = "baseline", - pub fn defaultAbi(arch: Arch, target_os: Os) Abi { - switch (arch) { - .wasm32, .wasm64 => return .musl, - else => {}, - } - switch (target_os) { - .freestanding, - .ananas, - .cloudabi, - .dragonfly, - .lv2, - .solaris, - .haiku, - .minix, - .rtems, - .nacl, - .cnk, - .aix, - .cuda, - .nvcl, - .amdhsa, - .ps4, - .elfiamcu, - .mesa3d, - .contiki, - .amdpal, - .hermit, - .other, - => return .eabi, - .openbsd, - .macosx, - .freebsd, - .ios, - .tvos, - .watchos, - .fuchsia, - .kfreebsd, - .netbsd, - .hurd, - => return .gnu, - .windows, - .uefi, - => return .msvc, - .linux, - .wasi, - .emscripten, - => return .musl, - } - } + /// If this is provided, the function will populate some information about parsing failures, + /// so that user-friendly error messages can be delivered. + diagnostics: ?*Diagnostics = null, - pub const ParseArchSubError = error{ - UnknownArchitecture, - UnknownSubArchitecture, - }; + pub const Diagnostics = struct { + /// If the architecture was determined, this will be populated. + arch: ?Cpu.Arch = null, - pub fn parseArchSub(text: []const u8) ParseArchSubError!Arch { - const info = @typeInfo(Arch); - inline for (info.Union.fields) |field| { - if (mem.startsWith(u8, text, field.name)) { - if (field.field_type == void) { - return @as(Arch, @field(Arch, field.name)); - } else { - const sub_info = @typeInfo(field.field_type); - inline for (sub_info.Enum.fields) |sub_field| { - const combined = field.name ++ sub_field.name; - if (mem.eql(u8, text, combined)) { - return @unionInit(Arch, field.name, @field(field.field_type, sub_field.name)); - } - } - return error.UnknownSubArchitecture; - } - } - } - return error.UnknownArchitecture; - } + /// If the OS was determined, this will be populated. + os: ?Os = null, - pub fn parseOs(text: []const u8) !Os { - const info = @typeInfo(Os); - inline for (info.Enum.fields) |field| { - if (mem.eql(u8, text, field.name)) { - return @field(Os, field.name); - } - } - return error.UnknownOperatingSystem; - } + /// If the ABI was determined, this will be populated. + abi: ?Abi = null, - pub fn parseAbi(text: []const u8) !Abi { - const info = @typeInfo(Abi); - inline for (info.Enum.fields) |field| { - if (mem.eql(u8, text, field.name)) { - return @field(Abi, field.name); - } - } - return error.UnknownApplicationBinaryInterface; - } + /// If the CPU name was determined, this will be populated. + cpu_name: ?[]const u8 = null, - fn archSubArchName(arch: Arch) []const u8 { - return switch (arch) { - .arm => |sub| @tagName(sub), - .armeb => |sub| @tagName(sub), - .thumb => |sub| @tagName(sub), - .thumbeb => |sub| @tagName(sub), - .aarch64 => |sub| @tagName(sub), - .aarch64_be => |sub| @tagName(sub), - .kalimba => |sub| @tagName(sub), - else => "", + /// If error.UnknownCpuFeature is returned, this will be populated. + unknown_feature_name: ?[]const u8 = null, }; - } + }; - pub fn subArchName(self: Target) []const u8 { - switch (self) { - .Native => return archSubArchName(builtin.arch), - .Cross => |cross| return archSubArchName(cross.arch), + pub fn parse(args: ParseOptions) !Target { + var dummy_diags: ParseOptions.Diagnostics = undefined; + var diags = args.diagnostics orelse &dummy_diags; + + var it = mem.separate(args.arch_os_abi, "-"); + const arch_name = it.next() orelse return error.MissingArchitecture; + const arch = try Cpu.Arch.parse(arch_name); + diags.arch = arch; + + const os_name = it.next() orelse return error.MissingOperatingSystem; + const os = try Os.parse(os_name); + diags.os = os; + + const abi_name = it.next(); + const abi = if (abi_name) |n| try Abi.parse(n) else Abi.default(arch, os); + diags.abi = abi; + + if (it.next() != null) return error.UnexpectedExtraField; + + const all_features = arch.allFeaturesList(); + var index: usize = 0; + while (index < args.cpu_features.len and + args.cpu_features[index] != '+' and + args.cpu_features[index] != '-') + { + index += 1; } + const cpu_name = args.cpu_features[0..index]; + diags.cpu_name = cpu_name; + + const cpu: Cpu = if (mem.eql(u8, cpu_name, "baseline")) Cpu.baseline(arch) else blk: { + const cpu_model = try arch.parseCpuModel(cpu_name); + + var set = cpu_model.features; + while (index < args.cpu_features.len) { + const op = args.cpu_features[index]; + index += 1; + const start = index; + while (index < args.cpu_features.len and + args.cpu_features[index] != '+' and + args.cpu_features[index] != '-') + { + index += 1; + } + const feature_name = args.cpu_features[start..index]; + for (all_features) |feature, feat_index_usize| { + const feat_index = @intCast(Cpu.Feature.Set.Index, feat_index_usize); + if (mem.eql(u8, feature_name, feature.name)) { + switch (op) { + '+' => set.addFeature(feat_index), + '-' => set.removeFeature(feat_index), + else => unreachable, + } + break; + } + } else { + diags.unknown_feature_name = feature_name; + return error.UnknownCpuFeature; + } + } + set.populateDependencies(all_features); + break :blk .{ + .arch = arch, + .model = cpu_model, + .features = set, + }; + }; + var cross = Cross{ + .cpu = cpu, + .os = os, + .abi = abi, + }; + return Target{ .Cross = cross }; } pub fn oFileExt(self: Target) []const u8 { @@ -971,11 +880,15 @@ pub const Target = union(enum) { }; } - pub fn getArch(self: Target) Arch { - switch (self) { - .Native => return builtin.arch, - .Cross => |t| return t.arch, - } + pub fn getCpu(self: Target) Cpu { + return switch (self) { + .Native => builtin.cpu, + .Cross => |cross| cross.cpu, + }; + } + + pub fn getArch(self: Target) Cpu.Arch { + return self.getCpu().arch; } pub fn getAbi(self: Target) Abi { @@ -1041,6 +954,20 @@ pub const Target = union(enum) { }; } + pub fn isAndroid(self: Target) bool { + return switch (self.getAbi()) { + .android => true, + else => false, + }; + } + + pub fn isDragonFlyBSD(self: Target) bool { + return switch (self.getOs()) { + .dragonfly => true, + else => false, + }; + } + pub fn isUefi(self: Target) bool { return switch (self.getOs()) { .uefi => true, @@ -1194,16 +1121,202 @@ pub const Target = union(enum) { return .unavailable; } + + pub const FloatAbi = enum { + hard, + soft, + soft_fp, + }; + + pub fn getFloatAbi(self: Target) FloatAbi { + return switch (self.getAbi()) { + .gnueabihf, + .eabihf, + .musleabihf, + => .hard, + else => .soft, + }; + } + + pub fn hasDynamicLinker(self: Target) bool { + switch (self.getArch()) { + .wasm32, + .wasm64, + => return false, + else => {}, + } + switch (self.getOs()) { + .freestanding, + .ios, + .tvos, + .watchos, + .macosx, + .uefi, + .windows, + .emscripten, + .other, + => return false, + else => return true, + } + } + + /// Caller owns returned memory. + pub fn getStandardDynamicLinkerPath( + self: Target, + allocator: *mem.Allocator, + ) error{ + OutOfMemory, + UnknownDynamicLinkerPath, + TargetHasNoDynamicLinker, + }![:0]u8 { + const a = allocator; + if (self.isAndroid()) { + return mem.dupeZ(a, u8, if (self.getArchPtrBitWidth() == 64) + "/system/bin/linker64" + else + "/system/bin/linker"); + } + + if (self.isMusl()) { + var result = try std.Buffer.init(allocator, "/lib/ld-musl-"); + defer result.deinit(); + + var is_arm = false; + switch (self.getArch()) { + .arm, .thumb => { + try result.append("arm"); + is_arm = true; + }, + .armeb, .thumbeb => { + try result.append("armeb"); + is_arm = true; + }, + else => |arch| try result.append(@tagName(arch)), + } + if (is_arm and self.getFloatAbi() == .hard) { + try result.append("hf"); + } + try result.append(".so.1"); + return result.toOwnedSlice(); + } + + switch (self.getOs()) { + .freebsd => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.1"), + .netbsd => return mem.dupeZ(a, u8, "/libexec/ld.elf_so"), + .dragonfly => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.2"), + .linux => switch (self.getArch()) { + .i386, + .sparc, + .sparcel, + => return mem.dupeZ(a, u8, "/lib/ld-linux.so.2"), + + .aarch64 => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64.so.1"), + .aarch64_be => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64_be.so.1"), + .aarch64_32 => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64_32.so.1"), + + .arm, + .armeb, + .thumb, + .thumbeb, + => return mem.dupeZ(a, u8, switch (self.getFloatAbi()) { + .hard => "/lib/ld-linux-armhf.so.3", + else => "/lib/ld-linux.so.3", + }), + + .mips, + .mipsel, + .mips64, + .mips64el, + => return error.UnknownDynamicLinkerPath, + + .powerpc => return mem.dupeZ(a, u8, "/lib/ld.so.1"), + .powerpc64, .powerpc64le => return mem.dupeZ(a, u8, "/lib64/ld64.so.2"), + .s390x => return mem.dupeZ(a, u8, "/lib64/ld64.so.1"), + .sparcv9 => return mem.dupeZ(a, u8, "/lib64/ld-linux.so.2"), + .x86_64 => return mem.dupeZ(a, u8, switch (self.getAbi()) { + .gnux32 => "/libx32/ld-linux-x32.so.2", + else => "/lib64/ld-linux-x86-64.so.2", + }), + + .riscv32 => return mem.dupeZ(a, u8, "/lib/ld-linux-riscv32-ilp32.so.1"), + .riscv64 => return mem.dupeZ(a, u8, "/lib/ld-linux-riscv64-lp64.so.1"), + + .wasm32, + .wasm64, + => return error.TargetHasNoDynamicLinker, + + .arc, + .avr, + .bpfel, + .bpfeb, + .hexagon, + .msp430, + .r600, + .amdgcn, + .tce, + .tcele, + .xcore, + .nvptx, + .nvptx64, + .le32, + .le64, + .amdil, + .amdil64, + .hsail, + .hsail64, + .spir, + .spir64, + .kalimba, + .shave, + .lanai, + .renderscript32, + .renderscript64, + .ve, + => return error.UnknownDynamicLinkerPath, + }, + + .freestanding, + .ios, + .tvos, + .watchos, + .macosx, + .uefi, + .windows, + .emscripten, + .other, + => return error.TargetHasNoDynamicLinker, + + else => return error.UnknownDynamicLinkerPath, + } + } }; -test "parseCpuFeatureSet" { - const arch: Target.Arch = .x86_64; - const baseline = arch.getBaselineCpuFeatures(); - const set = try arch.parseCpuFeatureSet(baseline.cpu, "-sse,-avx,-cx8"); - std.testing.expect(!Target.x86.featureSetHas(set, .sse)); - std.testing.expect(!Target.x86.featureSetHas(set, .avx)); - std.testing.expect(!Target.x86.featureSetHas(set, .cx8)); - // These are expected because they are part of the baseline - std.testing.expect(Target.x86.featureSetHas(set, .cmov)); - std.testing.expect(Target.x86.featureSetHas(set, .fxsr)); +test "Target.parse" { + { + const target = (try Target.parse(.{ + .arch_os_abi = "x86_64-linux-gnu", + .cpu_features = "x86_64-sse-sse2-avx-cx8", + })).Cross; + + std.testing.expect(target.os == .linux); + std.testing.expect(target.abi == .gnu); + std.testing.expect(target.cpu.arch == .x86_64); + std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .sse)); + std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .avx)); + std.testing.expect(!Target.x86.featureSetHas(target.cpu.features, .cx8)); + std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .cmov)); + std.testing.expect(Target.x86.featureSetHas(target.cpu.features, .fxsr)); + } + { + const target = (try Target.parse(.{ + .arch_os_abi = "arm-linux-musleabihf", + .cpu_features = "generic+v8a", + })).Cross; + + std.testing.expect(target.os == .linux); + std.testing.expect(target.abi == .musleabihf); + std.testing.expect(target.cpu.arch == .arm); + std.testing.expect(target.cpu.model == &Target.arm.cpu.generic); + std.testing.expect(Target.arm.featureSetHas(target.cpu.features, .v8a)); + } } diff --git a/lib/std/target/aarch64.zig b/lib/std/target/aarch64.zig @@ -1,15 +1,9 @@ const std = @import("../std.zig"); -const Cpu = std.Target.Cpu; +const CpuFeature = std.Target.Cpu.Feature; +const CpuModel = std.Target.Cpu.Model; pub const Feature = enum { - a35, - a53, - a55, - a57, a65, - a72, - a73, - a75, a76, aes, aggressive_fma, @@ -46,11 +40,7 @@ pub const Feature = enum { dotprod, ete, exynos_cheap_as_move, - exynosm1, - exynosm2, - exynosm3, exynosm4, - falkor, fmi, force_32bit_jump_tables, fp_armv8, @@ -64,7 +54,6 @@ pub const Feature = enum { fuse_csel, fuse_literals, jsconv, - kryo, lor, lse, lsl_fast, @@ -112,7 +101,6 @@ pub const Feature = enum { reserve_x6, reserve_x7, reserve_x9, - saphira, sb, sel2, sha2, @@ -132,11 +120,6 @@ pub const Feature = enum { sve2_sha3, sve2_sm4, tagged_globals, - thunderx, - thunderx2t99, - thunderxt81, - thunderxt83, - thunderxt88, tlb_rmi, tme, tpidr_el1, @@ -144,7 +127,6 @@ pub const Feature = enum { tpidr_el3, tracev8_4, trbe, - tsv110, uaops, use_aa, use_postra_scheduler, @@ -163,72 +145,13 @@ pub const Feature = enum { zcz_gp, }; -pub usingnamespace Cpu.Feature.feature_set_fns(Feature); +pub usingnamespace CpuFeature.feature_set_fns(Feature); pub const all_features = blk: { @setEvalBranchQuota(2000); const len = @typeInfo(Feature).Enum.fields.len; - std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); - var result: [len]Cpu.Feature = undefined; - result[@enumToInt(Feature.a35)] = .{ - .llvm_name = "a35", - .description = "Cortex-A35 ARM processors", - .dependencies = featureSet(&[_]Feature{ - .crc, - .crypto, - .fp_armv8, - .neon, - .perfmon, - }), - }; - result[@enumToInt(Feature.a53)] = .{ - .llvm_name = "a53", - .description = "Cortex-A53 ARM processors", - .dependencies = featureSet(&[_]Feature{ - .balance_fp_ops, - .crc, - .crypto, - .custom_cheap_as_move, - .fp_armv8, - .fuse_aes, - .neon, - .perfmon, - .use_aa, - .use_postra_scheduler, - }), - }; - result[@enumToInt(Feature.a55)] = .{ - .llvm_name = "a55", - .description = "Cortex-A55 ARM processors", - .dependencies = featureSet(&[_]Feature{ - .crypto, - .dotprod, - .fp_armv8, - .fullfp16, - .fuse_aes, - .neon, - .perfmon, - .rcpc, - .v8_2a, - }), - }; - result[@enumToInt(Feature.a57)] = .{ - .llvm_name = "a57", - .description = "Cortex-A57 ARM processors", - .dependencies = featureSet(&[_]Feature{ - .balance_fp_ops, - .crc, - .crypto, - .custom_cheap_as_move, - .fp_armv8, - .fuse_aes, - .fuse_literals, - .neon, - .perfmon, - .predictable_select_expensive, - .use_postra_scheduler, - }), - }; + std.debug.assert(len <= CpuFeature.Set.needed_bit_count); + var result: [len]CpuFeature = undefined; result[@enumToInt(Feature.a65)] = .{ .llvm_name = "a65", .description = "Cortex-A65 ARM processors", @@ -244,54 +167,13 @@ pub const all_features = blk: { .v8_2a, }), }; - result[@enumToInt(Feature.a72)] = .{ - .llvm_name = "a72", - .description = "Cortex-A72 ARM processors", - .dependencies = featureSet(&[_]Feature{ - .crc, - .crypto, - .fp_armv8, - .fuse_aes, - .neon, - .perfmon, - }), - }; - result[@enumToInt(Feature.a73)] = .{ - .llvm_name = "a73", - .description = "Cortex-A73 ARM processors", - .dependencies = featureSet(&[_]Feature{ - .crc, - .crypto, - .fp_armv8, - .fuse_aes, - .neon, - .perfmon, - }), - }; - result[@enumToInt(Feature.a75)] = .{ - .llvm_name = "a75", - .description = "Cortex-A75 ARM processors", - .dependencies = featureSet(&[_]Feature{ - .crypto, - .dotprod, - .fp_armv8, - .fullfp16, - .fuse_aes, - .neon, - .perfmon, - .rcpc, - .v8_2a, - }), - }; result[@enumToInt(Feature.a76)] = .{ .llvm_name = "a76", .description = "Cortex-A76 ARM processors", .dependencies = featureSet(&[_]Feature{ .crypto, .dotprod, - .fp_armv8, .fullfp16, - .neon, .rcpc, .ssbs, .v8_2a, @@ -563,58 +445,6 @@ pub const all_features = blk: { .custom_cheap_as_move, }), }; - result[@enumToInt(Feature.exynosm1)] = .{ - .llvm_name = null, - .description = "Samsung Exynos-M1 processors", - .dependencies = featureSet(&[_]Feature{ - .crc, - .crypto, - .exynos_cheap_as_move, - .force_32bit_jump_tables, - .fuse_aes, - .perfmon, - .slow_misaligned_128store, - .slow_paired_128, - .use_postra_scheduler, - .use_reciprocal_square_root, - .zcz_fp, - }), - }; - result[@enumToInt(Feature.exynosm2)] = .{ - .llvm_name = null, - .description = "Samsung Exynos-M2 processors", - .dependencies = featureSet(&[_]Feature{ - .crc, - .crypto, - .exynos_cheap_as_move, - .force_32bit_jump_tables, - .fuse_aes, - .perfmon, - .slow_misaligned_128store, - .slow_paired_128, - .use_postra_scheduler, - .zcz_fp, - }), - }; - result[@enumToInt(Feature.exynosm3)] = .{ - .llvm_name = "exynosm3", - .description = "Samsung Exynos-M3 processors", - .dependencies = featureSet(&[_]Feature{ - .crc, - .crypto, - .exynos_cheap_as_move, - .force_32bit_jump_tables, - .fuse_address, - .fuse_aes, - .fuse_csel, - .fuse_literals, - .lsl_fast, - .perfmon, - .predictable_select_expensive, - .use_postra_scheduler, - .zcz_fp, - }), - }; result[@enumToInt(Feature.exynosm4)] = .{ .llvm_name = "exynosm4", .description = "Samsung Exynos-M4 processors", @@ -638,24 +468,6 @@ pub const all_features = blk: { .zcz, }), }; - result[@enumToInt(Feature.falkor)] = .{ - .llvm_name = "falkor", - .description = "Qualcomm Falkor processors", - .dependencies = featureSet(&[_]Feature{ - .crc, - .crypto, - .custom_cheap_as_move, - .fp_armv8, - .lsl_fast, - .neon, - .perfmon, - .predictable_select_expensive, - .rdm, - .slow_strqro_store, - .use_postra_scheduler, - .zcz, - }), - }; result[@enumToInt(Feature.fmi)] = .{ .llvm_name = "fmi", .description = "Enable v8.4-A Flag Manipulation Instructions", @@ -727,22 +539,6 @@ pub const all_features = blk: { .fp_armv8, }), }; - result[@enumToInt(Feature.kryo)] = .{ - .llvm_name = "kryo", - .description = "Qualcomm Kryo processors", - .dependencies = featureSet(&[_]Feature{ - .crc, - .crypto, - .custom_cheap_as_move, - .fp_armv8, - .lsl_fast, - .neon, - .perfmon, - .predictable_select_expensive, - .use_postra_scheduler, - .zcz, - }), - }; result[@enumToInt(Feature.lor)] = .{ .llvm_name = "lor", .description = "Enables ARM v8.1 Limited Ordering Regions extension", @@ -1005,23 +801,6 @@ pub const all_features = blk: { .description = "Reserve X9, making it unavailable as a GPR", .dependencies = featureSet(&[_]Feature{}), }; - result[@enumToInt(Feature.saphira)] = .{ - .llvm_name = "saphira", - .description = "Qualcomm Saphira processors", - .dependencies = featureSet(&[_]Feature{ - .crypto, - .custom_cheap_as_move, - .fp_armv8, - .lsl_fast, - .neon, - .perfmon, - .predictable_select_expensive, - .spe, - .use_postra_scheduler, - .v8_4a, - .zcz, - }), - }; result[@enumToInt(Feature.sb)] = .{ .llvm_name = "sb", .description = "Enable v8.5 Speculation Barrier", @@ -1137,74 +916,6 @@ pub const all_features = blk: { .description = "Use an instruction sequence for taking the address of a global that allows a memory tag in the upper address bits", .dependencies = featureSet(&[_]Feature{}), }; - result[@enumToInt(Feature.thunderx)] = .{ - .llvm_name = "thunderx", - .description = "Cavium ThunderX processors", - .dependencies = featureSet(&[_]Feature{ - .crc, - .crypto, - .fp_armv8, - .neon, - .perfmon, - .predictable_select_expensive, - .use_postra_scheduler, - }), - }; - result[@enumToInt(Feature.thunderx2t99)] = .{ - .llvm_name = "thunderx2t99", - .description = "Cavium ThunderX2 processors", - .dependencies = featureSet(&[_]Feature{ - .aggressive_fma, - .arith_bcc_fusion, - .crc, - .crypto, - .fp_armv8, - .lse, - .neon, - .predictable_select_expensive, - .use_postra_scheduler, - .v8_1a, - }), - }; - result[@enumToInt(Feature.thunderxt81)] = .{ - .llvm_name = "thunderxt81", - .description = "Cavium ThunderX processors", - .dependencies = featureSet(&[_]Feature{ - .crc, - .crypto, - .fp_armv8, - .neon, - .perfmon, - .predictable_select_expensive, - .use_postra_scheduler, - }), - }; - result[@enumToInt(Feature.thunderxt83)] = .{ - .llvm_name = "thunderxt83", - .description = "Cavium ThunderX processors", - .dependencies = featureSet(&[_]Feature{ - .crc, - .crypto, - .fp_armv8, - .neon, - .perfmon, - .predictable_select_expensive, - .use_postra_scheduler, - }), - }; - result[@enumToInt(Feature.thunderxt88)] = .{ - .llvm_name = "thunderxt88", - .description = "Cavium ThunderX processors", - .dependencies = featureSet(&[_]Feature{ - .crc, - .crypto, - .fp_armv8, - .neon, - .perfmon, - .predictable_select_expensive, - .use_postra_scheduler, - }), - }; result[@enumToInt(Feature.tlb_rmi)] = .{ .llvm_name = "tlb-rmi", .description = "Enable v8.4-A TLB Range and Maintenance Instructions", @@ -1240,24 +951,6 @@ pub const all_features = blk: { .description = "Enable Trace Buffer Extension", .dependencies = featureSet(&[_]Feature{}), }; - result[@enumToInt(Feature.tsv110)] = .{ - .llvm_name = "tsv110", - .description = "HiSilicon TS-V110 processors", - .dependencies = featureSet(&[_]Feature{ - .crypto, - .custom_cheap_as_move, - .dotprod, - .fp_armv8, - .fp16fml, - .fullfp16, - .fuse_aes, - .neon, - .perfmon, - .spe, - .use_postra_scheduler, - .v8_2a, - }), - }; result[@enumToInt(Feature.uaops)] = .{ .llvm_name = "uaops", .description = "Enable v8.2 UAO PState", @@ -1398,282 +1091,417 @@ pub const all_features = blk: { }; pub const cpu = struct { - pub const apple_a10 = Cpu{ + pub const apple_a10 = CpuModel{ .name = "apple_a10", .llvm_name = "apple-a10", .features = featureSet(&[_]Feature{ .apple_a10, }), }; - pub const apple_a11 = Cpu{ + pub const apple_a11 = CpuModel{ .name = "apple_a11", .llvm_name = "apple-a11", .features = featureSet(&[_]Feature{ .apple_a11, }), }; - pub const apple_a12 = Cpu{ + pub const apple_a12 = CpuModel{ .name = "apple_a12", .llvm_name = "apple-a12", .features = featureSet(&[_]Feature{ .apple_a12, }), }; - pub const apple_a13 = Cpu{ + pub const apple_a13 = CpuModel{ .name = "apple_a13", .llvm_name = "apple-a13", .features = featureSet(&[_]Feature{ .apple_a13, }), }; - pub const apple_a7 = Cpu{ + pub const apple_a7 = CpuModel{ .name = "apple_a7", .llvm_name = "apple-a7", .features = featureSet(&[_]Feature{ .apple_a7, }), }; - pub const apple_a8 = Cpu{ + pub const apple_a8 = CpuModel{ .name = "apple_a8", .llvm_name = "apple-a8", .features = featureSet(&[_]Feature{ .apple_a7, }), }; - pub const apple_a9 = Cpu{ + pub const apple_a9 = CpuModel{ .name = "apple_a9", .llvm_name = "apple-a9", .features = featureSet(&[_]Feature{ .apple_a7, }), }; - pub const apple_latest = Cpu{ + pub const apple_latest = CpuModel{ .name = "apple_latest", .llvm_name = "apple-latest", .features = featureSet(&[_]Feature{ .apple_a13, }), }; - pub const apple_s4 = Cpu{ + pub const apple_s4 = CpuModel{ .name = "apple_s4", .llvm_name = "apple-s4", .features = featureSet(&[_]Feature{ .apple_a12, }), }; - pub const apple_s5 = Cpu{ + pub const apple_s5 = CpuModel{ .name = "apple_s5", .llvm_name = "apple-s5", .features = featureSet(&[_]Feature{ .apple_a12, }), }; - pub const cortex_a35 = Cpu{ + pub const cortex_a35 = CpuModel{ .name = "cortex_a35", .llvm_name = "cortex-a35", .features = featureSet(&[_]Feature{ - .a35, + .crc, + .crypto, + .perfmon, + .v8a, }), }; - pub const cortex_a53 = Cpu{ + pub const cortex_a53 = CpuModel{ .name = "cortex_a53", .llvm_name = "cortex-a53", .features = featureSet(&[_]Feature{ - .a53, + .balance_fp_ops, + .crc, + .crypto, + .custom_cheap_as_move, + .fuse_aes, + .perfmon, + .use_aa, + .use_postra_scheduler, + .v8a, }), }; - pub const cortex_a55 = Cpu{ + pub const cortex_a55 = CpuModel{ .name = "cortex_a55", .llvm_name = "cortex-a55", .features = featureSet(&[_]Feature{ - .a55, + .crypto, + .dotprod, + .fullfp16, + .fuse_aes, + .perfmon, + .rcpc, + .v8_2a, }), }; - pub const cortex_a57 = Cpu{ + pub const cortex_a57 = CpuModel{ .name = "cortex_a57", .llvm_name = "cortex-a57", .features = featureSet(&[_]Feature{ - .a57, + .balance_fp_ops, + .crc, + .crypto, + .custom_cheap_as_move, + .fuse_aes, + .fuse_literals, + .perfmon, + .predictable_select_expensive, + .use_postra_scheduler, + .v8a, }), }; - pub const cortex_a65 = Cpu{ + pub const cortex_a65 = CpuModel{ .name = "cortex_a65", .llvm_name = "cortex-a65", .features = featureSet(&[_]Feature{ .a65, }), }; - pub const cortex_a65ae = Cpu{ + pub const cortex_a65ae = CpuModel{ .name = "cortex_a65ae", .llvm_name = "cortex-a65ae", .features = featureSet(&[_]Feature{ .a65, }), }; - pub const cortex_a72 = Cpu{ + pub const cortex_a72 = CpuModel{ .name = "cortex_a72", .llvm_name = "cortex-a72", .features = featureSet(&[_]Feature{ - .a72, + .crc, + .crypto, + .fuse_aes, + .perfmon, + .v8a, }), }; - pub const cortex_a73 = Cpu{ + pub const cortex_a73 = CpuModel{ .name = "cortex_a73", .llvm_name = "cortex-a73", .features = featureSet(&[_]Feature{ - .a73, + .crc, + .crypto, + .fuse_aes, + .perfmon, + .v8a, }), }; - pub const cortex_a75 = Cpu{ + pub const cortex_a75 = CpuModel{ .name = "cortex_a75", .llvm_name = "cortex-a75", .features = featureSet(&[_]Feature{ - .a75, + .crypto, + .dotprod, + .fullfp16, + .fuse_aes, + .perfmon, + .rcpc, + .v8_2a, }), }; - pub const cortex_a76 = Cpu{ + pub const cortex_a76 = CpuModel{ .name = "cortex_a76", .llvm_name = "cortex-a76", .features = featureSet(&[_]Feature{ .a76, }), }; - pub const cortex_a76ae = Cpu{ + pub const cortex_a76ae = CpuModel{ .name = "cortex_a76ae", .llvm_name = "cortex-a76ae", .features = featureSet(&[_]Feature{ .a76, }), }; - pub const cyclone = Cpu{ + pub const cyclone = CpuModel{ .name = "cyclone", .llvm_name = "cyclone", .features = featureSet(&[_]Feature{ .apple_a7, }), }; - pub const exynos_m1 = Cpu{ + pub const exynos_m1 = CpuModel{ .name = "exynos_m1", .llvm_name = null, .features = featureSet(&[_]Feature{ - .exynosm1, + .crc, + .crypto, + .exynos_cheap_as_move, + .force_32bit_jump_tables, + .fuse_aes, + .perfmon, + .slow_misaligned_128store, + .slow_paired_128, + .use_postra_scheduler, + .use_reciprocal_square_root, + .v8a, + .zcz_fp, }), }; - pub const exynos_m2 = Cpu{ + pub const exynos_m2 = CpuModel{ .name = "exynos_m2", .llvm_name = null, .features = featureSet(&[_]Feature{ - .exynosm2, + .crc, + .crypto, + .exynos_cheap_as_move, + .force_32bit_jump_tables, + .fuse_aes, + .perfmon, + .slow_misaligned_128store, + .slow_paired_128, + .use_postra_scheduler, + .v8a, + .zcz_fp, }), }; - pub const exynos_m3 = Cpu{ + pub const exynos_m3 = CpuModel{ .name = "exynos_m3", .llvm_name = "exynos-m3", .features = featureSet(&[_]Feature{ - .exynosm3, + .crc, + .crypto, + .exynos_cheap_as_move, + .force_32bit_jump_tables, + .fuse_address, + .fuse_aes, + .fuse_csel, + .fuse_literals, + .lsl_fast, + .perfmon, + .predictable_select_expensive, + .use_postra_scheduler, + .v8a, + .zcz_fp, }), }; - pub const exynos_m4 = Cpu{ + pub const exynos_m4 = CpuModel{ .name = "exynos_m4", .llvm_name = "exynos-m4", .features = featureSet(&[_]Feature{ .exynosm4, }), }; - pub const exynos_m5 = Cpu{ + pub const exynos_m5 = CpuModel{ .name = "exynos_m5", .llvm_name = "exynos-m5", .features = featureSet(&[_]Feature{ .exynosm4, }), }; - pub const falkor = Cpu{ + pub const falkor = CpuModel{ .name = "falkor", .llvm_name = "falkor", .features = featureSet(&[_]Feature{ - .falkor, + .crc, + .crypto, + .custom_cheap_as_move, + .lsl_fast, + .perfmon, + .predictable_select_expensive, + .rdm, + .slow_strqro_store, + .use_postra_scheduler, + .v8a, + .zcz, }), }; - pub const generic = Cpu{ + pub const generic = CpuModel{ .name = "generic", .llvm_name = "generic", .features = featureSet(&[_]Feature{ .ete, - .fp_armv8, .fuse_aes, - .neon, .perfmon, .use_postra_scheduler, + .v8a, }), }; - pub const kryo = Cpu{ + pub const kryo = CpuModel{ .name = "kryo", .llvm_name = "kryo", .features = featureSet(&[_]Feature{ - .kryo, + .crc, + .crypto, + .custom_cheap_as_move, + .lsl_fast, + .perfmon, + .predictable_select_expensive, + .use_postra_scheduler, + .zcz, + .v8a, }), }; - pub const neoverse_e1 = Cpu{ + pub const neoverse_e1 = CpuModel{ .name = "neoverse_e1", .llvm_name = "neoverse-e1", .features = featureSet(&[_]Feature{ .neoversee1, }), }; - pub const neoverse_n1 = Cpu{ + pub const neoverse_n1 = CpuModel{ .name = "neoverse_n1", .llvm_name = "neoverse-n1", .features = featureSet(&[_]Feature{ .neoversen1, }), }; - pub const saphira = Cpu{ + pub const saphira = CpuModel{ .name = "saphira", .llvm_name = "saphira", .features = featureSet(&[_]Feature{ - .saphira, + .crypto, + .custom_cheap_as_move, + .lsl_fast, + .perfmon, + .predictable_select_expensive, + .spe, + .use_postra_scheduler, + .v8_4a, + .zcz, }), }; - pub const thunderx = Cpu{ + pub const thunderx = CpuModel{ .name = "thunderx", .llvm_name = "thunderx", .features = featureSet(&[_]Feature{ - .thunderx, + .crc, + .crypto, + .perfmon, + .predictable_select_expensive, + .use_postra_scheduler, + .v8a, }), }; - pub const thunderx2t99 = Cpu{ + pub const thunderx2t99 = CpuModel{ .name = "thunderx2t99", .llvm_name = "thunderx2t99", .features = featureSet(&[_]Feature{ - .thunderx2t99, + .aggressive_fma, + .arith_bcc_fusion, + .crc, + .crypto, + .lse, + .predictable_select_expensive, + .use_postra_scheduler, + .v8_1a, }), }; - pub const thunderxt81 = Cpu{ + pub const thunderxt81 = CpuModel{ .name = "thunderxt81", .llvm_name = "thunderxt81", .features = featureSet(&[_]Feature{ - .thunderxt81, + .crc, + .crypto, + .perfmon, + .predictable_select_expensive, + .use_postra_scheduler, + .v8a, }), }; - pub const thunderxt83 = Cpu{ + pub const thunderxt83 = CpuModel{ .name = "thunderxt83", .llvm_name = "thunderxt83", .features = featureSet(&[_]Feature{ - .thunderxt83, + .crc, + .crypto, + .perfmon, + .predictable_select_expensive, + .use_postra_scheduler, + .v8a, }), }; - pub const thunderxt88 = Cpu{ + pub const thunderxt88 = CpuModel{ .name = "thunderxt88", .llvm_name = "thunderxt88", .features = featureSet(&[_]Feature{ - .thunderxt88, + .crc, + .crypto, + .perfmon, + .predictable_select_expensive, + .use_postra_scheduler, + .v8a, }), }; - pub const tsv110 = Cpu{ + pub const tsv110 = CpuModel{ .name = "tsv110", .llvm_name = "tsv110", .features = featureSet(&[_]Feature{ - .tsv110, + .crypto, + .custom_cheap_as_move, + .dotprod, + .fp16fml, + .fullfp16, + .fuse_aes, + .perfmon, + .spe, + .use_postra_scheduler, + .v8_2a, }), }; }; @@ -1681,7 +1509,7 @@ pub const cpu = struct { /// All aarch64 CPUs, sorted alphabetically by name. /// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 /// compiler has inefficient memory and CPU usage, affecting build times. -pub const all_cpus = &[_]*const Cpu{ +pub const all_cpus = &[_]*const CpuModel{ &cpu.apple_a10, &cpu.apple_a11, &cpu.apple_a12, diff --git a/lib/std/target/amdgpu.zig b/lib/std/target/amdgpu.zig @@ -1,5 +1,6 @@ const std = @import("../std.zig"); -const Cpu = std.Target.Cpu; +const CpuFeature = std.Target.Cpu.Feature; +const CpuModel = std.Target.Cpu.Model; pub const Feature = enum { @"16_bit_insts", @@ -112,12 +113,12 @@ pub const Feature = enum { xnack, }; -pub usingnamespace Cpu.Feature.feature_set_fns(Feature); +pub usingnamespace CpuFeature.feature_set_fns(Feature); pub const all_features = blk: { const len = @typeInfo(Feature).Enum.fields.len; - std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); - var result: [len]Cpu.Feature = undefined; + std.debug.assert(len <= CpuFeature.Set.needed_bit_count); + var result: [len]CpuFeature = undefined; result[@enumToInt(Feature.@"16_bit_insts")] = .{ .llvm_name = "16-bit-insts", .description = "Has i16/f16 instructions", @@ -784,7 +785,7 @@ pub const all_features = blk: { }; pub const cpu = struct { - pub const bonaire = Cpu{ + pub const bonaire = CpuModel{ .name = "bonaire", .llvm_name = "bonaire", .features = featureSet(&[_]Feature{ @@ -794,7 +795,7 @@ pub const cpu = struct { .sea_islands, }), }; - pub const carrizo = Cpu{ + pub const carrizo = CpuModel{ .name = "carrizo", .llvm_name = "carrizo", .features = featureSet(&[_]Feature{ @@ -807,7 +808,7 @@ pub const cpu = struct { .xnack, }), }; - pub const fiji = Cpu{ + pub const fiji = CpuModel{ .name = "fiji", .llvm_name = "fiji", .features = featureSet(&[_]Feature{ @@ -818,14 +819,14 @@ pub const cpu = struct { .volcanic_islands, }), }; - pub const generic = Cpu{ + pub const generic = CpuModel{ .name = "generic", .llvm_name = "generic", .features = featureSet(&[_]Feature{ .wavefrontsize64, }), }; - pub const generic_hsa = Cpu{ + pub const generic_hsa = CpuModel{ .name = "generic_hsa", .llvm_name = "generic-hsa", .features = featureSet(&[_]Feature{ @@ -833,7 +834,7 @@ pub const cpu = struct { .wavefrontsize64, }), }; - pub const gfx1010 = Cpu{ + pub const gfx1010 = CpuModel{ .name = "gfx1010", .llvm_name = "gfx1010", .features = featureSet(&[_]Feature{ @@ -859,7 +860,7 @@ pub const cpu = struct { .wavefrontsize32, }), }; - pub const gfx1011 = Cpu{ + pub const gfx1011 = CpuModel{ .name = "gfx1011", .llvm_name = "gfx1011", .features = featureSet(&[_]Feature{ @@ -888,7 +889,7 @@ pub const cpu = struct { .wavefrontsize32, }), }; - pub const gfx1012 = Cpu{ + pub const gfx1012 = CpuModel{ .name = "gfx1012", .llvm_name = "gfx1012", .features = featureSet(&[_]Feature{ @@ -918,7 +919,7 @@ pub const cpu = struct { .wavefrontsize32, }), }; - pub const gfx600 = Cpu{ + pub const gfx600 = CpuModel{ .name = "gfx600", .llvm_name = "gfx600", .features = featureSet(&[_]Feature{ @@ -930,7 +931,7 @@ pub const cpu = struct { .southern_islands, }), }; - pub const gfx601 = Cpu{ + pub const gfx601 = CpuModel{ .name = "gfx601", .llvm_name = "gfx601", .features = featureSet(&[_]Feature{ @@ -940,7 +941,7 @@ pub const cpu = struct { .southern_islands, }), }; - pub const gfx700 = Cpu{ + pub const gfx700 = CpuModel{ .name = "gfx700", .llvm_name = "gfx700", .features = featureSet(&[_]Feature{ @@ -950,7 +951,7 @@ pub const cpu = struct { .sea_islands, }), }; - pub const gfx701 = Cpu{ + pub const gfx701 = CpuModel{ .name = "gfx701", .llvm_name = "gfx701", .features = featureSet(&[_]Feature{ @@ -962,7 +963,7 @@ pub const cpu = struct { .sea_islands, }), }; - pub const gfx702 = Cpu{ + pub const gfx702 = CpuModel{ .name = "gfx702", .llvm_name = "gfx702", .features = featureSet(&[_]Feature{ @@ -973,7 +974,7 @@ pub const cpu = struct { .sea_islands, }), }; - pub const gfx703 = Cpu{ + pub const gfx703 = CpuModel{ .name = "gfx703", .llvm_name = "gfx703", .features = featureSet(&[_]Feature{ @@ -983,7 +984,7 @@ pub const cpu = struct { .sea_islands, }), }; - pub const gfx704 = Cpu{ + pub const gfx704 = CpuModel{ .name = "gfx704", .llvm_name = "gfx704", .features = featureSet(&[_]Feature{ @@ -993,7 +994,7 @@ pub const cpu = struct { .sea_islands, }), }; - pub const gfx801 = Cpu{ + pub const gfx801 = CpuModel{ .name = "gfx801", .llvm_name = "gfx801", .features = featureSet(&[_]Feature{ @@ -1006,7 +1007,7 @@ pub const cpu = struct { .xnack, }), }; - pub const gfx802 = Cpu{ + pub const gfx802 = CpuModel{ .name = "gfx802", .llvm_name = "gfx802", .features = featureSet(&[_]Feature{ @@ -1018,7 +1019,7 @@ pub const cpu = struct { .volcanic_islands, }), }; - pub const gfx803 = Cpu{ + pub const gfx803 = CpuModel{ .name = "gfx803", .llvm_name = "gfx803", .features = featureSet(&[_]Feature{ @@ -1029,7 +1030,7 @@ pub const cpu = struct { .volcanic_islands, }), }; - pub const gfx810 = Cpu{ + pub const gfx810 = CpuModel{ .name = "gfx810", .llvm_name = "gfx810", .features = featureSet(&[_]Feature{ @@ -1039,7 +1040,7 @@ pub const cpu = struct { .xnack, }), }; - pub const gfx900 = Cpu{ + pub const gfx900 = CpuModel{ .name = "gfx900", .llvm_name = "gfx900", .features = featureSet(&[_]Feature{ @@ -1051,7 +1052,7 @@ pub const cpu = struct { .no_xnack_support, }), }; - pub const gfx902 = Cpu{ + pub const gfx902 = CpuModel{ .name = "gfx902", .llvm_name = "gfx902", .features = featureSet(&[_]Feature{ @@ -1063,7 +1064,7 @@ pub const cpu = struct { .xnack, }), }; - pub const gfx904 = Cpu{ + pub const gfx904 = CpuModel{ .name = "gfx904", .llvm_name = "gfx904", .features = featureSet(&[_]Feature{ @@ -1075,7 +1076,7 @@ pub const cpu = struct { .no_xnack_support, }), }; - pub const gfx906 = Cpu{ + pub const gfx906 = CpuModel{ .name = "gfx906", .llvm_name = "gfx906", .features = featureSet(&[_]Feature{ @@ -1090,7 +1091,7 @@ pub const cpu = struct { .no_xnack_support, }), }; - pub const gfx908 = Cpu{ + pub const gfx908 = CpuModel{ .name = "gfx908", .llvm_name = "gfx908", .features = featureSet(&[_]Feature{ @@ -1113,7 +1114,7 @@ pub const cpu = struct { .sram_ecc, }), }; - pub const gfx909 = Cpu{ + pub const gfx909 = CpuModel{ .name = "gfx909", .llvm_name = "gfx909", .features = featureSet(&[_]Feature{ @@ -1124,7 +1125,7 @@ pub const cpu = struct { .xnack, }), }; - pub const hainan = Cpu{ + pub const hainan = CpuModel{ .name = "hainan", .llvm_name = "hainan", .features = featureSet(&[_]Feature{ @@ -1134,7 +1135,7 @@ pub const cpu = struct { .southern_islands, }), }; - pub const hawaii = Cpu{ + pub const hawaii = CpuModel{ .name = "hawaii", .llvm_name = "hawaii", .features = featureSet(&[_]Feature{ @@ -1146,7 +1147,7 @@ pub const cpu = struct { .sea_islands, }), }; - pub const iceland = Cpu{ + pub const iceland = CpuModel{ .name = "iceland", .llvm_name = "iceland", .features = featureSet(&[_]Feature{ @@ -1158,7 +1159,7 @@ pub const cpu = struct { .volcanic_islands, }), }; - pub const kabini = Cpu{ + pub const kabini = CpuModel{ .name = "kabini", .llvm_name = "kabini", .features = featureSet(&[_]Feature{ @@ -1168,7 +1169,7 @@ pub const cpu = struct { .sea_islands, }), }; - pub const kaveri = Cpu{ + pub const kaveri = CpuModel{ .name = "kaveri", .llvm_name = "kaveri", .features = featureSet(&[_]Feature{ @@ -1178,7 +1179,7 @@ pub const cpu = struct { .sea_islands, }), }; - pub const mullins = Cpu{ + pub const mullins = CpuModel{ .name = "mullins", .llvm_name = "mullins", .features = featureSet(&[_]Feature{ @@ -1188,7 +1189,7 @@ pub const cpu = struct { .sea_islands, }), }; - pub const oland = Cpu{ + pub const oland = CpuModel{ .name = "oland", .llvm_name = "oland", .features = featureSet(&[_]Feature{ @@ -1198,7 +1199,7 @@ pub const cpu = struct { .southern_islands, }), }; - pub const pitcairn = Cpu{ + pub const pitcairn = CpuModel{ .name = "pitcairn", .llvm_name = "pitcairn", .features = featureSet(&[_]Feature{ @@ -1208,7 +1209,7 @@ pub const cpu = struct { .southern_islands, }), }; - pub const polaris10 = Cpu{ + pub const polaris10 = CpuModel{ .name = "polaris10", .llvm_name = "polaris10", .features = featureSet(&[_]Feature{ @@ -1219,7 +1220,7 @@ pub const cpu = struct { .volcanic_islands, }), }; - pub const polaris11 = Cpu{ + pub const polaris11 = CpuModel{ .name = "polaris11", .llvm_name = "polaris11", .features = featureSet(&[_]Feature{ @@ -1230,7 +1231,7 @@ pub const cpu = struct { .volcanic_islands, }), }; - pub const stoney = Cpu{ + pub const stoney = CpuModel{ .name = "stoney", .llvm_name = "stoney", .features = featureSet(&[_]Feature{ @@ -1240,7 +1241,7 @@ pub const cpu = struct { .xnack, }), }; - pub const tahiti = Cpu{ + pub const tahiti = CpuModel{ .name = "tahiti", .llvm_name = "tahiti", .features = featureSet(&[_]Feature{ @@ -1252,7 +1253,7 @@ pub const cpu = struct { .southern_islands, }), }; - pub const tonga = Cpu{ + pub const tonga = CpuModel{ .name = "tonga", .llvm_name = "tonga", .features = featureSet(&[_]Feature{ @@ -1264,7 +1265,7 @@ pub const cpu = struct { .volcanic_islands, }), }; - pub const verde = Cpu{ + pub const verde = CpuModel{ .name = "verde", .llvm_name = "verde", .features = featureSet(&[_]Feature{ @@ -1279,7 +1280,7 @@ pub const cpu = struct { /// All amdgpu CPUs, sorted alphabetically by name. /// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 /// compiler has inefficient memory and CPU usage, affecting build times. -pub const all_cpus = &[_]*const Cpu{ +pub const all_cpus = &[_]*const CpuModel{ &cpu.bonaire, &cpu.carrizo, &cpu.fiji, diff --git a/lib/std/target/arm.zig b/lib/std/target/arm.zig @@ -1,61 +1,14 @@ const std = @import("../std.zig"); -const Cpu = std.Target.Cpu; +const CpuFeature = std.Target.Cpu.Feature; +const CpuModel = std.Target.Cpu.Model; pub const Feature = enum { @"32bit", @"8msecext", - a12, - a15, - a17, - a32, - a35, - a5, - a53, - a55, - a57, - a7, - a72, - a73, - a75, a76, - a8, - a9, aclass, acquire_release, aes, - armv2, - armv2a, - armv3, - armv3m, - armv4, - armv4t, - armv5t, - armv5te, - armv5tej, - armv6, - armv6_m, - armv6j, - armv6k, - armv6kz, - armv6s_m, - armv6t2, - armv7_a, - armv7_m, - armv7_r, - armv7e_m, - armv7k, - armv7s, - armv7ve, - armv8_a, - armv8_m_base, - armv8_m_main, - armv8_r, - armv8_1_a, - armv8_1_m_main, - armv8_2_a, - armv8_3_a, - armv8_4_a, - armv8_5_a, avoid_movs_shop, avoid_partial_cpsr, cheap_predicable_cpsr, @@ -71,13 +24,13 @@ pub const Feature = enum { execute_only, expand_fp_mlx, exynos, + fp16, + fp16fml, + fp64, fp_armv8, fp_armv8d16, fp_armv8d16sp, fp_armv8sp, - fp16, - fp16fml, - fp64, fpao, fpregs, fpregs16, @@ -85,12 +38,28 @@ pub const Feature = enum { fullfp16, fuse_aes, fuse_literals, + has_v4t, + has_v5t, + has_v5te, + has_v6, + has_v6k, + has_v6m, + has_v6t2, + has_v7, + has_v7clrex, + has_v8_1a, + has_v8_1m_main, + has_v8_2a, + has_v8_3a, + has_v8_4a, + has_v8_5a, + has_v8, + has_v8m, + has_v8m_main, hwdiv, hwdiv_arm, iwmmxt, iwmmxt2, - krait, - kryo, lob, long_calls, loop_align, @@ -117,9 +86,6 @@ pub const Feature = enum { prefer_vmovsr, prof_unpr, r4, - r5, - r52, - r7, ras, rclass, read_tp_hard, @@ -138,28 +104,43 @@ pub const Feature = enum { splat_vfp_neon, strict_align, swift, - thumb_mode, thumb2, + thumb_mode, trustzone, use_misched, + v2, + v2a, + v3, + v3m, + v4, v4t, v5t, v5te, + v5tej, v6, + v6j, v6k, + v6kz, v6m, + v6sm, v6t2, - v7, - v7clrex, - v8, + v7a, + v7em, + v7k, + v7m, + v7r, + v7s, + v7ve, + v8a, + v8m, + v8m_main, + v8r, v8_1a, v8_1m_main, v8_2a, v8_3a, v8_4a, v8_5a, - v8m, - v8m_main, vfp2, vfp2sp, vfp3, @@ -179,13 +160,13 @@ pub const Feature = enum { zcz, }; -pub usingnamespace Cpu.Feature.feature_set_fns(Feature); +pub usingnamespace CpuFeature.feature_set_fns(Feature); pub const all_features = blk: { @setEvalBranchQuota(10000); const len = @typeInfo(Feature).Enum.fields.len; - std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); - var result: [len]Cpu.Feature = undefined; + std.debug.assert(len <= CpuFeature.Set.needed_bit_count); + var result: [len]CpuFeature = undefined; result[@enumToInt(Feature.@"32bit")] = .{ .llvm_name = "32bit", .description = "Prefer 32-bit Thumb instrs", @@ -196,86 +177,11 @@ pub const all_features = blk: { .description = "Enable support for ARMv8-M Security Extensions", .dependencies = featureSet(&[_]Feature{}), }; - result[@enumToInt(Feature.a12)] = .{ - .llvm_name = "a12", - .description = "Cortex-A12 ARM processors", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.a15)] = .{ - .llvm_name = "a15", - .description = "Cortex-A15 ARM processors", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.a17)] = .{ - .llvm_name = "a17", - .description = "Cortex-A17 ARM processors", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.a32)] = .{ - .llvm_name = "a32", - .description = "Cortex-A32 ARM processors", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.a35)] = .{ - .llvm_name = "a35", - .description = "Cortex-A35 ARM processors", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.a5)] = .{ - .llvm_name = "a5", - .description = "Cortex-A5 ARM processors", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.a53)] = .{ - .llvm_name = "a53", - .description = "Cortex-A53 ARM processors", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.a55)] = .{ - .llvm_name = "a55", - .description = "Cortex-A55 ARM processors", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.a57)] = .{ - .llvm_name = "a57", - .description = "Cortex-A57 ARM processors", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.a7)] = .{ - .llvm_name = "a7", - .description = "Cortex-A7 ARM processors", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.a72)] = .{ - .llvm_name = "a72", - .description = "Cortex-A72 ARM processors", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.a73)] = .{ - .llvm_name = "a73", - .description = "Cortex-A73 ARM processors", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.a75)] = .{ - .llvm_name = "a75", - .description = "Cortex-A75 ARM processors", - .dependencies = featureSet(&[_]Feature{}), - }; result[@enumToInt(Feature.a76)] = .{ .llvm_name = "a76", .description = "Cortex-A76 ARM processors", .dependencies = featureSet(&[_]Feature{}), }; - result[@enumToInt(Feature.a8)] = .{ - .llvm_name = "a8", - .description = "Cortex-A8 ARM processors", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.a9)] = .{ - .llvm_name = "a9", - .description = "Cortex-A9 ARM processors", - .dependencies = featureSet(&[_]Feature{}), - }; result[@enumToInt(Feature.aclass)] = .{ .llvm_name = "aclass", .description = "Is application profile ('A' series)", @@ -293,368 +199,6 @@ pub const all_features = blk: { .neon, }), }; - result[@enumToInt(Feature.armv2)] = .{ - .llvm_name = "armv2", - .description = "ARMv2 architecture", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.armv2a)] = .{ - .llvm_name = "armv2a", - .description = "ARMv2a architecture", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.armv3)] = .{ - .llvm_name = "armv3", - .description = "ARMv3 architecture", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.armv3m)] = .{ - .llvm_name = "armv3m", - .description = "ARMv3m architecture", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.armv4)] = .{ - .llvm_name = "armv4", - .description = "ARMv4 architecture", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.armv4t)] = .{ - .llvm_name = "armv4t", - .description = "ARMv4t architecture", - .dependencies = featureSet(&[_]Feature{ - .v4t, - }), - }; - result[@enumToInt(Feature.armv5t)] = .{ - .llvm_name = "armv5t", - .description = "ARMv5t architecture", - .dependencies = featureSet(&[_]Feature{ - .v5t, - }), - }; - result[@enumToInt(Feature.armv5te)] = .{ - .llvm_name = "armv5te", - .description = "ARMv5te architecture", - .dependencies = featureSet(&[_]Feature{ - .v5te, - }), - }; - result[@enumToInt(Feature.armv5tej)] = .{ - .llvm_name = "armv5tej", - .description = "ARMv5tej architecture", - .dependencies = featureSet(&[_]Feature{ - .v5te, - }), - }; - result[@enumToInt(Feature.armv6)] = .{ - .llvm_name = "armv6", - .description = "ARMv6 architecture", - .dependencies = featureSet(&[_]Feature{ - .dsp, - .v6, - }), - }; - result[@enumToInt(Feature.armv6_m)] = .{ - .llvm_name = "armv6-m", - .description = "ARMv6m architecture", - .dependencies = featureSet(&[_]Feature{ - .db, - .mclass, - .noarm, - .strict_align, - .thumb_mode, - .v6m, - }), - }; - result[@enumToInt(Feature.armv6j)] = .{ - .llvm_name = "armv6j", - .description = "ARMv7a architecture", - .dependencies = featureSet(&[_]Feature{ - .armv6, - }), - }; - result[@enumToInt(Feature.armv6k)] = .{ - .llvm_name = "armv6k", - .description = "ARMv6k architecture", - .dependencies = featureSet(&[_]Feature{ - .v6k, - }), - }; - result[@enumToInt(Feature.armv6kz)] = .{ - .llvm_name = "armv6kz", - .description = "ARMv6kz architecture", - .dependencies = featureSet(&[_]Feature{ - .trustzone, - .v6k, - }), - }; - result[@enumToInt(Feature.armv6s_m)] = .{ - .llvm_name = "armv6s-m", - .description = "ARMv6sm architecture", - .dependencies = featureSet(&[_]Feature{ - .db, - .mclass, - .noarm, - .strict_align, - .thumb_mode, - .v6m, - }), - }; - result[@enumToInt(Feature.armv6t2)] = .{ - .llvm_name = "armv6t2", - .description = "ARMv6t2 architecture", - .dependencies = featureSet(&[_]Feature{ - .dsp, - .v6t2, - }), - }; - result[@enumToInt(Feature.armv7_a)] = .{ - .llvm_name = "armv7-a", - .description = "ARMv7a architecture", - .dependencies = featureSet(&[_]Feature{ - .aclass, - .db, - .dsp, - .neon, - .v7, - }), - }; - result[@enumToInt(Feature.armv7_m)] = .{ - .llvm_name = "armv7-m", - .description = "ARMv7m architecture", - .dependencies = featureSet(&[_]Feature{ - .db, - .hwdiv, - .mclass, - .noarm, - .thumb_mode, - .thumb2, - .v7, - }), - }; - result[@enumToInt(Feature.armv7_r)] = .{ - .llvm_name = "armv7-r", - .description = "ARMv7r architecture", - .dependencies = featureSet(&[_]Feature{ - .db, - .dsp, - .hwdiv, - .rclass, - .v7, - }), - }; - result[@enumToInt(Feature.armv7e_m)] = .{ - .llvm_name = "armv7e-m", - .description = "ARMv7em architecture", - .dependencies = featureSet(&[_]Feature{ - .db, - .dsp, - .hwdiv, - .mclass, - .noarm, - .thumb_mode, - .thumb2, - .v7, - }), - }; - result[@enumToInt(Feature.armv7k)] = .{ - .llvm_name = "armv7k", - .description = "ARMv7a architecture", - .dependencies = featureSet(&[_]Feature{ - .armv7_a, - }), - }; - result[@enumToInt(Feature.armv7s)] = .{ - .llvm_name = "armv7s", - .description = "ARMv7a architecture", - .dependencies = featureSet(&[_]Feature{ - .armv7_a, - }), - }; - result[@enumToInt(Feature.armv7ve)] = .{ - .llvm_name = "armv7ve", - .description = "ARMv7ve architecture", - .dependencies = featureSet(&[_]Feature{ - .aclass, - .db, - .dsp, - .mp, - .neon, - .trustzone, - .v7, - .virtualization, - }), - }; - result[@enumToInt(Feature.armv8_a)] = .{ - .llvm_name = "armv8-a", - .description = "ARMv8a architecture", - .dependencies = featureSet(&[_]Feature{ - .aclass, - .crc, - .crypto, - .db, - .dsp, - .fp_armv8, - .mp, - .neon, - .trustzone, - .v8, - .virtualization, - }), - }; - result[@enumToInt(Feature.armv8_m_base)] = .{ - .llvm_name = "armv8-m.base", - .description = "ARMv8mBaseline architecture", - .dependencies = featureSet(&[_]Feature{ - .@"8msecext", - .acquire_release, - .db, - .hwdiv, - .mclass, - .noarm, - .strict_align, - .thumb_mode, - .v7clrex, - .v8m, - }), - }; - result[@enumToInt(Feature.armv8_m_main)] = .{ - .llvm_name = "armv8-m.main", - .description = "ARMv8mMainline architecture", - .dependencies = featureSet(&[_]Feature{ - .@"8msecext", - .acquire_release, - .db, - .hwdiv, - .mclass, - .noarm, - .thumb_mode, - .v8m_main, - }), - }; - result[@enumToInt(Feature.armv8_r)] = .{ - .llvm_name = "armv8-r", - .description = "ARMv8r architecture", - .dependencies = featureSet(&[_]Feature{ - .crc, - .db, - .dfb, - .dsp, - .fp_armv8, - .mp, - .neon, - .rclass, - .v8, - .virtualization, - }), - }; - result[@enumToInt(Feature.armv8_1_a)] = .{ - .llvm_name = "armv8.1-a", - .description = "ARMv81a architecture", - .dependencies = featureSet(&[_]Feature{ - .aclass, - .crc, - .crypto, - .db, - .dsp, - .fp_armv8, - .mp, - .neon, - .trustzone, - .v8_1a, - .virtualization, - }), - }; - result[@enumToInt(Feature.armv8_1_m_main)] = .{ - .llvm_name = "armv8.1-m.main", - .description = "ARMv81mMainline architecture", - .dependencies = featureSet(&[_]Feature{ - .@"8msecext", - .acquire_release, - .db, - .hwdiv, - .lob, - .mclass, - .noarm, - .ras, - .thumb_mode, - .v8_1m_main, - }), - }; - result[@enumToInt(Feature.armv8_2_a)] = .{ - .llvm_name = "armv8.2-a", - .description = "ARMv82a architecture", - .dependencies = featureSet(&[_]Feature{ - .aclass, - .crc, - .crypto, - .db, - .dsp, - .fp_armv8, - .mp, - .neon, - .ras, - .trustzone, - .v8_2a, - .virtualization, - }), - }; - result[@enumToInt(Feature.armv8_3_a)] = .{ - .llvm_name = "armv8.3-a", - .description = "ARMv83a architecture", - .dependencies = featureSet(&[_]Feature{ - .aclass, - .crc, - .crypto, - .db, - .dsp, - .fp_armv8, - .mp, - .neon, - .ras, - .trustzone, - .v8_3a, - .virtualization, - }), - }; - result[@enumToInt(Feature.armv8_4_a)] = .{ - .llvm_name = "armv8.4-a", - .description = "ARMv84a architecture", - .dependencies = featureSet(&[_]Feature{ - .aclass, - .crc, - .crypto, - .db, - .dotprod, - .dsp, - .fp_armv8, - .mp, - .neon, - .ras, - .trustzone, - .v8_4a, - .virtualization, - }), - }; - result[@enumToInt(Feature.armv8_5_a)] = .{ - .llvm_name = "armv8.5-a", - .description = "ARMv85a architecture", - .dependencies = featureSet(&[_]Feature{ - .aclass, - .crc, - .crypto, - .db, - .dotprod, - .dsp, - .fp_armv8, - .mp, - .neon, - .ras, - .trustzone, - .v8_5a, - .virtualization, - }), - }; result[@enumToInt(Feature.avoid_movs_shop)] = .{ .llvm_name = "avoid-movs-shop", .description = "Avoid movs instructions with shifter operand", @@ -754,6 +298,25 @@ pub const all_features = blk: { .zcz, }), }; + result[@enumToInt(Feature.fp16)] = .{ + .llvm_name = "fp16", + .description = "Enable half-precision floating point", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.fp16fml)] = .{ + .llvm_name = "fp16fml", + .description = "Enable full half-precision floating point fml instructions", + .dependencies = featureSet(&[_]Feature{ + .fullfp16, + }), + }; + result[@enumToInt(Feature.fp64)] = .{ + .llvm_name = "fp64", + .description = "Floating point unit supports double precision", + .dependencies = featureSet(&[_]Feature{ + .fpregs64, + }), + }; result[@enumToInt(Feature.fp_armv8)] = .{ .llvm_name = "fp-armv8", .description = "Enable ARMv8 FP", @@ -772,39 +335,20 @@ pub const all_features = blk: { .vfp4d16, }), }; - result[@enumToInt(Feature.fp_armv8d16sp)] = .{ - .llvm_name = "fp-armv8d16sp", - .description = "Enable ARMv8 FP with only 16 d-registers and no double precision", - .dependencies = featureSet(&[_]Feature{ - .vfp4d16sp, - }), - }; - result[@enumToInt(Feature.fp_armv8sp)] = .{ - .llvm_name = "fp-armv8sp", - .description = "Enable ARMv8 FP with no double precision", - .dependencies = featureSet(&[_]Feature{ - .d32, - .fp_armv8d16sp, - .vfp4sp, - }), - }; - result[@enumToInt(Feature.fp16)] = .{ - .llvm_name = "fp16", - .description = "Enable half-precision floating point", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.fp16fml)] = .{ - .llvm_name = "fp16fml", - .description = "Enable full half-precision floating point fml instructions", + result[@enumToInt(Feature.fp_armv8d16sp)] = .{ + .llvm_name = "fp-armv8d16sp", + .description = "Enable ARMv8 FP with only 16 d-registers and no double precision", .dependencies = featureSet(&[_]Feature{ - .fullfp16, + .vfp4d16sp, }), }; - result[@enumToInt(Feature.fp64)] = .{ - .llvm_name = "fp64", - .description = "Floating point unit supports double precision", + result[@enumToInt(Feature.fp_armv8sp)] = .{ + .llvm_name = "fp-armv8sp", + .description = "Enable ARMv8 FP with no double precision", .dependencies = featureSet(&[_]Feature{ - .fpregs64, + .d32, + .fp_armv8d16sp, + .vfp4sp, }), }; result[@enumToInt(Feature.fpao)] = .{ @@ -849,6 +393,135 @@ pub const all_features = blk: { .description = "CPU fuses literal generation operations", .dependencies = featureSet(&[_]Feature{}), }; + result[@enumToInt(Feature.has_v4t)] = .{ + .llvm_name = "v4t", + .description = "Support ARM v4T instructions", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.has_v5t)] = .{ + .llvm_name = "v5t", + .description = "Support ARM v5T instructions", + .dependencies = featureSet(&[_]Feature{ + .has_v4t, + }), + }; + result[@enumToInt(Feature.has_v5te)] = .{ + .llvm_name = "v5te", + .description = "Support ARM v5TE, v5TEj, and v5TExp instructions", + .dependencies = featureSet(&[_]Feature{ + .has_v5t, + }), + }; + result[@enumToInt(Feature.has_v6)] = .{ + .llvm_name = "v6", + .description = "Support ARM v6 instructions", + .dependencies = featureSet(&[_]Feature{ + .has_v5te, + }), + }; + result[@enumToInt(Feature.has_v6k)] = .{ + .llvm_name = "v6k", + .description = "Support ARM v6k instructions", + .dependencies = featureSet(&[_]Feature{ + .has_v6, + }), + }; + result[@enumToInt(Feature.has_v6m)] = .{ + .llvm_name = "v6m", + .description = "Support ARM v6M instructions", + .dependencies = featureSet(&[_]Feature{ + .has_v6, + }), + }; + result[@enumToInt(Feature.has_v6t2)] = .{ + .llvm_name = "v6t2", + .description = "Support ARM v6t2 instructions", + .dependencies = featureSet(&[_]Feature{ + .thumb2, + .has_v6k, + .has_v8m, + }), + }; + result[@enumToInt(Feature.has_v7)] = .{ + .llvm_name = "v7", + .description = "Support ARM v7 instructions", + .dependencies = featureSet(&[_]Feature{ + .perfmon, + .has_v6t2, + .has_v7clrex, + }), + }; + result[@enumToInt(Feature.has_v7clrex)] = .{ + .llvm_name = "v7clrex", + .description = "Has v7 clrex instruction", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.has_v8)] = .{ + .llvm_name = "v8", + .description = "Support ARM v8 instructions", + .dependencies = featureSet(&[_]Feature{ + .acquire_release, + .has_v7, + }), + }; + result[@enumToInt(Feature.has_v8_1a)] = .{ + .llvm_name = "v8.1a", + .description = "Support ARM v8.1a instructions", + .dependencies = featureSet(&[_]Feature{ + .has_v8, + }), + }; + result[@enumToInt(Feature.has_v8_1m_main)] = .{ + .llvm_name = "v8.1m.main", + .description = "Support ARM v8-1M Mainline instructions", + .dependencies = featureSet(&[_]Feature{ + .has_v8m_main, + }), + }; + result[@enumToInt(Feature.has_v8_2a)] = .{ + .llvm_name = "v8.2a", + .description = "Support ARM v8.2a instructions", + .dependencies = featureSet(&[_]Feature{ + .has_v8_1a, + }), + }; + result[@enumToInt(Feature.has_v8_3a)] = .{ + .llvm_name = "v8.3a", + .description = "Support ARM v8.3a instructions", + .dependencies = featureSet(&[_]Feature{ + .has_v8_2a, + }), + }; + result[@enumToInt(Feature.has_v8_4a)] = .{ + .llvm_name = "v8.4a", + .description = "Support ARM v8.4a instructions", + .dependencies = featureSet(&[_]Feature{ + .dotprod, + .has_v8_3a, + }), + }; + result[@enumToInt(Feature.has_v8_5a)] = .{ + .llvm_name = "v8.5a", + .description = "Support ARM v8.5a instructions", + .dependencies = featureSet(&[_]Feature{ + .sb, + .has_v8_4a, + }), + }; + result[@enumToInt(Feature.has_v8m)] = .{ + .llvm_name = "v8m", + .description = "Support ARM v8M Baseline instructions", + .dependencies = featureSet(&[_]Feature{ + .has_v6m, + }), + }; + result[@enumToInt(Feature.has_v8m_main)] = .{ + .llvm_name = "v8m.main", + .description = "Support ARM v8M Mainline instructions", + .dependencies = featureSet(&[_]Feature{ + .has_v7, + }), + }; result[@enumToInt(Feature.hwdiv)] = .{ .llvm_name = "hwdiv", .description = "Enable divide instructions in Thumb", @@ -863,26 +536,16 @@ pub const all_features = blk: { .llvm_name = "iwmmxt", .description = "ARMv5te architecture", .dependencies = featureSet(&[_]Feature{ - .armv5te, + .has_v5te, }), }; result[@enumToInt(Feature.iwmmxt2)] = .{ .llvm_name = "iwmmxt2", .description = "ARMv5te architecture", .dependencies = featureSet(&[_]Feature{ - .armv5te, + .has_v5te, }), }; - result[@enumToInt(Feature.krait)] = .{ - .llvm_name = "krait", - .description = "Qualcomm Krait processors", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.kryo)] = .{ - .llvm_name = "kryo", - .description = "Qualcomm Kryo processors", - .dependencies = featureSet(&[_]Feature{}), - }; result[@enumToInt(Feature.lob)] = .{ .llvm_name = "lob", .description = "Enable Low Overhead Branch extensions", @@ -925,7 +588,7 @@ pub const all_features = blk: { .dsp, .fpregs16, .fpregs64, - .v8_1m_main, + .has_v8_1m_main, }), }; result[@enumToInt(Feature.mve_fp)] = .{ @@ -1024,21 +687,6 @@ pub const all_features = blk: { .description = "Cortex-R4 ARM processors", .dependencies = featureSet(&[_]Feature{}), }; - result[@enumToInt(Feature.r5)] = .{ - .llvm_name = "r5", - .description = "Cortex-R5 ARM processors", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.r52)] = .{ - .llvm_name = "r52", - .description = "Cortex-R52 ARM processors", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.r7)] = .{ - .llvm_name = "r7", - .description = "Cortex-R7 ARM processors", - .dependencies = featureSet(&[_]Feature{}), - }; result[@enumToInt(Feature.ras)] = .{ .llvm_name = "ras", .description = "Enable Reliability, Availability and Serviceability extensions", @@ -1133,16 +781,16 @@ pub const all_features = blk: { .description = "Swift ARM processors", .dependencies = featureSet(&[_]Feature{}), }; - result[@enumToInt(Feature.thumb_mode)] = .{ - .llvm_name = "thumb-mode", - .description = "Thumb mode", - .dependencies = featureSet(&[_]Feature{}), - }; result[@enumToInt(Feature.thumb2)] = .{ .llvm_name = "thumb2", .description = "Enable Thumb2 instructions", .dependencies = featureSet(&[_]Feature{}), }; + result[@enumToInt(Feature.thumb_mode)] = .{ + .llvm_name = "thumb-mode", + .description = "Thumb mode", + .dependencies = featureSet(&[_]Feature{}), + }; result[@enumToInt(Feature.trustzone)] = .{ .llvm_name = "trustzone", .description = "Enable support for TrustZone security extensions", @@ -1153,133 +801,366 @@ pub const all_features = blk: { .description = "Use the MachineScheduler", .dependencies = featureSet(&[_]Feature{}), }; - result[@enumToInt(Feature.v4t)] = .{ - .llvm_name = "v4t", - .description = "Support ARM v4T instructions", + result[@enumToInt(Feature.v2)] = .{ + .llvm_name = "armv2", + .description = "ARMv2 architecture", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.v2a)] = .{ + .llvm_name = "armv2a", + .description = "ARMv2a architecture", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.v3)] = .{ + .llvm_name = "armv3", + .description = "ARMv3 architecture", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.v3m)] = .{ + .llvm_name = "armv3m", + .description = "ARMv3m architecture", + .dependencies = featureSet(&[_]Feature{}), + }; + result[@enumToInt(Feature.v4)] = .{ + .llvm_name = "armv4", + .description = "ARMv4 architecture", .dependencies = featureSet(&[_]Feature{}), }; - result[@enumToInt(Feature.v5t)] = .{ - .llvm_name = "v5t", - .description = "Support ARM v5T instructions", + result[@enumToInt(Feature.v4t)] = .{ + .llvm_name = "armv4t", + .description = "ARMv4t architecture", + .dependencies = featureSet(&[_]Feature{ + .has_v4t, + }), + }; + result[@enumToInt(Feature.v5t)] = .{ + .llvm_name = "armv5t", + .description = "ARMv5t architecture", + .dependencies = featureSet(&[_]Feature{ + .has_v5t, + }), + }; + result[@enumToInt(Feature.v5te)] = .{ + .llvm_name = "armv5te", + .description = "ARMv5te architecture", + .dependencies = featureSet(&[_]Feature{ + .has_v5te, + }), + }; + result[@enumToInt(Feature.v5tej)] = .{ + .llvm_name = "armv5tej", + .description = "ARMv5tej architecture", + .dependencies = featureSet(&[_]Feature{ + .has_v5te, + }), + }; + result[@enumToInt(Feature.v6)] = .{ + .llvm_name = "armv6", + .description = "ARMv6 architecture", + .dependencies = featureSet(&[_]Feature{ + .dsp, + .has_v6, + }), + }; + result[@enumToInt(Feature.v6m)] = .{ + .llvm_name = "armv6-m", + .description = "ARMv6m architecture", + .dependencies = featureSet(&[_]Feature{ + .db, + .mclass, + .noarm, + .strict_align, + .thumb_mode, + .has_v6m, + }), + }; + result[@enumToInt(Feature.v6j)] = .{ + .llvm_name = "armv6j", + .description = "ARMv7a architecture", + .dependencies = featureSet(&[_]Feature{ + .v6, + }), + }; + result[@enumToInt(Feature.v6k)] = .{ + .llvm_name = "armv6k", + .description = "ARMv6k architecture", + .dependencies = featureSet(&[_]Feature{ + .has_v6k, + }), + }; + result[@enumToInt(Feature.v6kz)] = .{ + .llvm_name = "armv6kz", + .description = "ARMv6kz architecture", + .dependencies = featureSet(&[_]Feature{ + .trustzone, + .has_v6k, + }), + }; + result[@enumToInt(Feature.v6sm)] = .{ + .llvm_name = "armv6s-m", + .description = "ARMv6sm architecture", + .dependencies = featureSet(&[_]Feature{ + .db, + .mclass, + .noarm, + .strict_align, + .thumb_mode, + .has_v6m, + }), + }; + result[@enumToInt(Feature.v6t2)] = .{ + .llvm_name = "armv6t2", + .description = "ARMv6t2 architecture", + .dependencies = featureSet(&[_]Feature{ + .dsp, + .has_v6t2, + }), + }; + result[@enumToInt(Feature.v7a)] = .{ + .llvm_name = "armv7-a", + .description = "ARMv7a architecture", + .dependencies = featureSet(&[_]Feature{ + .aclass, + .db, + .dsp, + .neon, + .has_v7, + }), + }; + result[@enumToInt(Feature.v7m)] = .{ + .llvm_name = "armv7-m", + .description = "ARMv7m architecture", + .dependencies = featureSet(&[_]Feature{ + .db, + .hwdiv, + .mclass, + .noarm, + .thumb_mode, + .thumb2, + .has_v7, + }), + }; + result[@enumToInt(Feature.v7r)] = .{ + .llvm_name = "armv7-r", + .description = "ARMv7r architecture", + .dependencies = featureSet(&[_]Feature{ + .db, + .dsp, + .hwdiv, + .rclass, + .has_v7, + }), + }; + result[@enumToInt(Feature.v7em)] = .{ + .llvm_name = "armv7e-m", + .description = "ARMv7em architecture", .dependencies = featureSet(&[_]Feature{ - .v4t, + .db, + .dsp, + .hwdiv, + .mclass, + .noarm, + .thumb_mode, + .thumb2, + .has_v7, }), }; - result[@enumToInt(Feature.v5te)] = .{ - .llvm_name = "v5te", - .description = "Support ARM v5TE, v5TEj, and v5TExp instructions", + result[@enumToInt(Feature.v7k)] = .{ + .llvm_name = "armv7k", + .description = "ARMv7a architecture", .dependencies = featureSet(&[_]Feature{ - .v5t, + .v7a, }), }; - result[@enumToInt(Feature.v6)] = .{ - .llvm_name = "v6", - .description = "Support ARM v6 instructions", + result[@enumToInt(Feature.v7s)] = .{ + .llvm_name = "armv7s", + .description = "ARMv7a architecture", .dependencies = featureSet(&[_]Feature{ - .v5te, + .v7a, }), }; - result[@enumToInt(Feature.v6k)] = .{ - .llvm_name = "v6k", - .description = "Support ARM v6k instructions", + result[@enumToInt(Feature.v7ve)] = .{ + .llvm_name = "armv7ve", + .description = "ARMv7ve architecture", .dependencies = featureSet(&[_]Feature{ - .v6, + .aclass, + .db, + .dsp, + .mp, + .neon, + .trustzone, + .has_v7, + .virtualization, }), }; - result[@enumToInt(Feature.v6m)] = .{ - .llvm_name = "v6m", - .description = "Support ARM v6M instructions", + result[@enumToInt(Feature.v8a)] = .{ + .llvm_name = "armv8-a", + .description = "ARMv8a architecture", .dependencies = featureSet(&[_]Feature{ - .v6, + .aclass, + .crc, + .crypto, + .db, + .dsp, + .fp_armv8, + .mp, + .neon, + .trustzone, + .has_v8, + .virtualization, }), }; - result[@enumToInt(Feature.v6t2)] = .{ - .llvm_name = "v6t2", - .description = "Support ARM v6t2 instructions", + result[@enumToInt(Feature.v8m)] = .{ + .llvm_name = "armv8-m.base", + .description = "ARMv8mBaseline architecture", .dependencies = featureSet(&[_]Feature{ - .thumb2, - .v6k, - .v8m, + .@"8msecext", + .acquire_release, + .db, + .hwdiv, + .mclass, + .noarm, + .strict_align, + .thumb_mode, + .has_v7clrex, + .has_v8m, }), }; - result[@enumToInt(Feature.v7)] = .{ - .llvm_name = "v7", - .description = "Support ARM v7 instructions", + result[@enumToInt(Feature.v8m_main)] = .{ + .llvm_name = "armv8-m.main", + .description = "ARMv8mMainline architecture", .dependencies = featureSet(&[_]Feature{ - .perfmon, - .v6t2, - .v7clrex, + .@"8msecext", + .acquire_release, + .db, + .hwdiv, + .mclass, + .noarm, + .thumb_mode, + .has_v8m_main, }), }; - result[@enumToInt(Feature.v7clrex)] = .{ - .llvm_name = "v7clrex", - .description = "Has v7 clrex instruction", - .dependencies = featureSet(&[_]Feature{}), - }; - result[@enumToInt(Feature.v8)] = .{ - .llvm_name = "v8", - .description = "Support ARM v8 instructions", + result[@enumToInt(Feature.v8r)] = .{ + .llvm_name = "armv8-r", + .description = "ARMv8r architecture", .dependencies = featureSet(&[_]Feature{ - .acquire_release, - .v7, + .crc, + .db, + .dfb, + .dsp, + .fp_armv8, + .mp, + .neon, + .rclass, + .has_v8, + .virtualization, }), }; result[@enumToInt(Feature.v8_1a)] = .{ - .llvm_name = "v8.1a", - .description = "Support ARM v8.1a instructions", + .llvm_name = "armv8.1-a", + .description = "ARMv81a architecture", .dependencies = featureSet(&[_]Feature{ - .v8, + .aclass, + .crc, + .crypto, + .db, + .dsp, + .fp_armv8, + .mp, + .neon, + .trustzone, + .has_v8_1a, + .virtualization, }), }; result[@enumToInt(Feature.v8_1m_main)] = .{ - .llvm_name = "v8.1m.main", - .description = "Support ARM v8-1M Mainline instructions", + .llvm_name = "armv8.1-m.main", + .description = "ARMv81mMainline architecture", .dependencies = featureSet(&[_]Feature{ - .v8m_main, + .@"8msecext", + .acquire_release, + .db, + .hwdiv, + .lob, + .mclass, + .noarm, + .ras, + .thumb_mode, + .has_v8_1m_main, }), }; result[@enumToInt(Feature.v8_2a)] = .{ - .llvm_name = "v8.2a", - .description = "Support ARM v8.2a instructions", + .llvm_name = "armv8.2-a", + .description = "ARMv82a architecture", .dependencies = featureSet(&[_]Feature{ - .v8_1a, + .aclass, + .crc, + .crypto, + .db, + .dsp, + .fp_armv8, + .mp, + .neon, + .ras, + .trustzone, + .has_v8_2a, + .virtualization, }), }; result[@enumToInt(Feature.v8_3a)] = .{ - .llvm_name = "v8.3a", - .description = "Support ARM v8.3a instructions", + .llvm_name = "armv8.3-a", + .description = "ARMv83a architecture", .dependencies = featureSet(&[_]Feature{ - .v8_2a, + .aclass, + .crc, + .crypto, + .db, + .dsp, + .fp_armv8, + .mp, + .neon, + .ras, + .trustzone, + .has_v8_3a, + .virtualization, }), }; result[@enumToInt(Feature.v8_4a)] = .{ - .llvm_name = "v8.4a", - .description = "Support ARM v8.4a instructions", + .llvm_name = "armv8.4-a", + .description = "ARMv84a architecture", .dependencies = featureSet(&[_]Feature{ + .aclass, + .crc, + .crypto, + .db, .dotprod, - .v8_3a, + .dsp, + .fp_armv8, + .mp, + .neon, + .ras, + .trustzone, + .has_v8_4a, + .virtualization, }), }; result[@enumToInt(Feature.v8_5a)] = .{ - .llvm_name = "v8.5a", - .description = "Support ARM v8.5a instructions", - .dependencies = featureSet(&[_]Feature{ - .sb, - .v8_4a, - }), - }; - result[@enumToInt(Feature.v8m)] = .{ - .llvm_name = "v8m", - .description = "Support ARM v8M Baseline instructions", - .dependencies = featureSet(&[_]Feature{ - .v6m, - }), - }; - result[@enumToInt(Feature.v8m_main)] = .{ - .llvm_name = "v8m.main", - .description = "Support ARM v8M Mainline instructions", + .llvm_name = "armv8.5-a", + .description = "ARMv85a architecture", .dependencies = featureSet(&[_]Feature{ - .v7, + .aclass, + .crc, + .crypto, + .db, + .dotprod, + .dsp, + .fp_armv8, + .mp, + .neon, + .ras, + .trustzone, + .has_v8_5a, + .virtualization, }), }; result[@enumToInt(Feature.vfp2)] = .{ @@ -1399,7 +1280,7 @@ pub const all_features = blk: { .llvm_name = "xscale", .description = "ARMv5te architecture", .dependencies = featureSet(&[_]Feature{ - .armv5te, + .has_v5te, }), }; result[@enumToInt(Feature.zcz)] = .{ @@ -1416,221 +1297,227 @@ pub const all_features = blk: { }; pub const cpu = struct { - pub const arm1020e = Cpu{ + pub const arm1020e = CpuModel{ .name = "arm1020e", .llvm_name = "arm1020e", .features = featureSet(&[_]Feature{ - .armv5te, + .v5te, }), }; - pub const arm1020t = Cpu{ + pub const arm1020t = CpuModel{ .name = "arm1020t", .llvm_name = "arm1020t", .features = featureSet(&[_]Feature{ - .armv5t, + .v5t, }), }; - pub const arm1022e = Cpu{ + pub const arm1022e = CpuModel{ .name = "arm1022e", .llvm_name = "arm1022e", .features = featureSet(&[_]Feature{ - .armv5te, + .v5te, }), }; - pub const arm10e = Cpu{ + pub const arm10e = CpuModel{ .name = "arm10e", .llvm_name = "arm10e", .features = featureSet(&[_]Feature{ - .armv5te, + .v5te, }), }; - pub const arm10tdmi = Cpu{ + pub const arm10tdmi = CpuModel{ .name = "arm10tdmi", .llvm_name = "arm10tdmi", .features = featureSet(&[_]Feature{ - .armv5t, + .v5t, }), }; - pub const arm1136j_s = Cpu{ + pub const arm1136j_s = CpuModel{ .name = "arm1136j_s", .llvm_name = "arm1136j-s", .features = featureSet(&[_]Feature{ - .armv6, + .v6, }), }; - pub const arm1136jf_s = Cpu{ + pub const arm1136jf_s = CpuModel{ .name = "arm1136jf_s", .llvm_name = "arm1136jf-s", .features = featureSet(&[_]Feature{ - .armv6, + .v6, .slowfpvmlx, .vfp2, }), }; - pub const arm1156t2_s = Cpu{ + pub const arm1156t2_s = CpuModel{ .name = "arm1156t2_s", .llvm_name = "arm1156t2-s", .features = featureSet(&[_]Feature{ - .armv6t2, + .v6t2, }), }; - pub const arm1156t2f_s = Cpu{ + pub const arm1156t2f_s = CpuModel{ .name = "arm1156t2f_s", .llvm_name = "arm1156t2f-s", .features = featureSet(&[_]Feature{ - .armv6t2, + .v6t2, .slowfpvmlx, .vfp2, }), }; - pub const arm1176j_s = Cpu{ + pub const arm1176j_s = CpuModel{ .name = "arm1176j_s", .llvm_name = "arm1176j-s", .features = featureSet(&[_]Feature{ - .armv6kz, + .v6kz, }), }; - pub const arm1176jz_s = Cpu{ + pub const arm1176jz_s = CpuModel{ .name = "arm1176jz_s", .llvm_name = "arm1176jz-s", .features = featureSet(&[_]Feature{ - .armv6kz, + .v6kz, }), }; - pub const arm1176jzf_s = Cpu{ + pub const arm1176jzf_s = CpuModel{ .name = "arm1176jzf_s", .llvm_name = "arm1176jzf-s", .features = featureSet(&[_]Feature{ - .armv6kz, + .v6kz, .slowfpvmlx, .vfp2, }), }; - pub const arm710t = Cpu{ + pub const arm710t = CpuModel{ .name = "arm710t", .llvm_name = "arm710t", .features = featureSet(&[_]Feature{ - .armv4t, + .v4t, }), }; - pub const arm720t = Cpu{ + pub const arm720t = CpuModel{ .name = "arm720t", .llvm_name = "arm720t", .features = featureSet(&[_]Feature{ - .armv4t, + .v4t, }), }; - pub const arm7tdmi = Cpu{ + pub const arm7tdmi = CpuModel{ .name = "arm7tdmi", .llvm_name = "arm7tdmi", .features = featureSet(&[_]Feature{ - .armv4t, + .v4t, }), }; - pub const arm7tdmi_s = Cpu{ + pub const arm7tdmi_s = CpuModel{ .name = "arm7tdmi_s", .llvm_name = "arm7tdmi-s", .features = featureSet(&[_]Feature{ - .armv4t, + .v4t, }), }; - pub const arm8 = Cpu{ + pub const arm8 = CpuModel{ .name = "arm8", .llvm_name = "arm8", .features = featureSet(&[_]Feature{ - .armv4, + .v4, }), }; - pub const arm810 = Cpu{ + pub const arm810 = CpuModel{ .name = "arm810", .llvm_name = "arm810", .features = featureSet(&[_]Feature{ - .armv4, + .v4, }), }; - pub const arm9 = Cpu{ + pub const arm9 = CpuModel{ .name = "arm9", .llvm_name = "arm9", .features = featureSet(&[_]Feature{ - .armv4t, + .v4t, }), }; - pub const arm920 = Cpu{ + pub const arm920 = CpuModel{ .name = "arm920", .llvm_name = "arm920", .features = featureSet(&[_]Feature{ - .armv4t, + .v4t, }), }; - pub const arm920t = Cpu{ + pub const arm920t = CpuModel{ .name = "arm920t", .llvm_name = "arm920t", .features = featureSet(&[_]Feature{ - .armv4t, + .v4t, }), }; - pub const arm922t = Cpu{ + pub const arm922t = CpuModel{ .name = "arm922t", .llvm_name = "arm922t", .features = featureSet(&[_]Feature{ - .armv4t, + .v4t, }), }; - pub const arm926ej_s = Cpu{ + pub const arm926ej_s = CpuModel{ .name = "arm926ej_s", .llvm_name = "arm926ej-s", .features = featureSet(&[_]Feature{ - .armv5te, + .v5te, }), }; - pub const arm940t = Cpu{ + pub const arm940t = CpuModel{ .name = "arm940t", .llvm_name = "arm940t", .features = featureSet(&[_]Feature{ - .armv4t, + .v4t, }), }; - pub const arm946e_s = Cpu{ + pub const arm946e_s = CpuModel{ .name = "arm946e_s", .llvm_name = "arm946e-s", .features = featureSet(&[_]Feature{ - .armv5te, + .v5te, }), }; - pub const arm966e_s = Cpu{ + pub const arm966e_s = CpuModel{ .name = "arm966e_s", .llvm_name = "arm966e-s", .features = featureSet(&[_]Feature{ - .armv5te, + .v5te, }), }; - pub const arm968e_s = Cpu{ + pub const arm968e_s = CpuModel{ .name = "arm968e_s", .llvm_name = "arm968e-s", .features = featureSet(&[_]Feature{ - .armv5te, + .v5te, }), }; - pub const arm9e = Cpu{ + pub const arm9e = CpuModel{ .name = "arm9e", .llvm_name = "arm9e", .features = featureSet(&[_]Feature{ - .armv5te, + .v5te, }), }; - pub const arm9tdmi = Cpu{ + pub const arm9tdmi = CpuModel{ .name = "arm9tdmi", .llvm_name = "arm9tdmi", .features = featureSet(&[_]Feature{ - .armv4t, + .v4t, + }), + }; + pub const baseline = CpuModel{ + .name = "baseline", + .llvm_name = "generic", + .features = featureSet(&[_]Feature{ + .v6m, }), }; - pub const cortex_a12 = Cpu{ + pub const cortex_a12 = CpuModel{ .name = "cortex_a12", .llvm_name = "cortex-a12", .features = featureSet(&[_]Feature{ - .a12, - .armv7_a, + .v7a, .avoid_partial_cpsr, .mp, .ret_addr_stack, @@ -1640,12 +1527,11 @@ pub const cpu = struct { .vmlx_forwarding, }), }; - pub const cortex_a15 = Cpu{ + pub const cortex_a15 = CpuModel{ .name = "cortex_a15", .llvm_name = "cortex-a15", .features = featureSet(&[_]Feature{ - .a15, - .armv7_a, + .v7a, .avoid_partial_cpsr, .dont_widen_vmovs, .mp, @@ -1658,12 +1544,11 @@ pub const cpu = struct { .vldn_align, }), }; - pub const cortex_a17 = Cpu{ + pub const cortex_a17 = CpuModel{ .name = "cortex_a17", .llvm_name = "cortex-a17", .features = featureSet(&[_]Feature{ - .a17, - .armv7_a, + .v7a, .avoid_partial_cpsr, .mp, .ret_addr_stack, @@ -1673,35 +1558,33 @@ pub const cpu = struct { .vmlx_forwarding, }), }; - pub const cortex_a32 = Cpu{ + pub const cortex_a32 = CpuModel{ .name = "cortex_a32", .llvm_name = "cortex-a32", .features = featureSet(&[_]Feature{ - .armv8_a, .crc, .crypto, .hwdiv, .hwdiv_arm, + .v8a, }), }; - pub const cortex_a35 = Cpu{ + pub const cortex_a35 = CpuModel{ .name = "cortex_a35", .llvm_name = "cortex-a35", .features = featureSet(&[_]Feature{ - .a35, - .armv8_a, .crc, .crypto, .hwdiv, .hwdiv_arm, + .v8a, }), }; - pub const cortex_a5 = Cpu{ + pub const cortex_a5 = CpuModel{ .name = "cortex_a5", .llvm_name = "cortex-a5", .features = featureSet(&[_]Feature{ - .a5, - .armv7_a, + .v7a, .mp, .ret_addr_stack, .slow_fp_brcc, @@ -1712,12 +1595,11 @@ pub const cpu = struct { .vmlx_forwarding, }), }; - pub const cortex_a53 = Cpu{ + pub const cortex_a53 = CpuModel{ .name = "cortex_a53", .llvm_name = "cortex-a53", .features = featureSet(&[_]Feature{ - .a53, - .armv8_a, + .v8a, .crc, .crypto, .fpao, @@ -1725,23 +1607,21 @@ pub const cpu = struct { .hwdiv_arm, }), }; - pub const cortex_a55 = Cpu{ + pub const cortex_a55 = CpuModel{ .name = "cortex_a55", .llvm_name = "cortex-a55", .features = featureSet(&[_]Feature{ - .a55, - .armv8_2_a, + .v8_2a, .dotprod, .hwdiv, .hwdiv_arm, }), }; - pub const cortex_a57 = Cpu{ + pub const cortex_a57 = CpuModel{ .name = "cortex_a57", .llvm_name = "cortex-a57", .features = featureSet(&[_]Feature{ - .a57, - .armv8_a, + .v8a, .avoid_partial_cpsr, .cheap_predicable_cpsr, .crc, @@ -1751,12 +1631,11 @@ pub const cpu = struct { .hwdiv_arm, }), }; - pub const cortex_a7 = Cpu{ + pub const cortex_a7 = CpuModel{ .name = "cortex_a7", .llvm_name = "cortex-a7", .features = featureSet(&[_]Feature{ - .a7, - .armv7_a, + .v7a, .mp, .ret_addr_stack, .slow_fp_brcc, @@ -1769,47 +1648,44 @@ pub const cpu = struct { .vmlx_hazards, }), }; - pub const cortex_a72 = Cpu{ + pub const cortex_a72 = CpuModel{ .name = "cortex_a72", .llvm_name = "cortex-a72", .features = featureSet(&[_]Feature{ - .a72, - .armv8_a, + .v8a, .crc, .crypto, .hwdiv, .hwdiv_arm, }), }; - pub const cortex_a73 = Cpu{ + pub const cortex_a73 = CpuModel{ .name = "cortex_a73", .llvm_name = "cortex-a73", .features = featureSet(&[_]Feature{ - .a73, - .armv8_a, + .v8a, .crc, .crypto, .hwdiv, .hwdiv_arm, }), }; - pub const cortex_a75 = Cpu{ + pub const cortex_a75 = CpuModel{ .name = "cortex_a75", .llvm_name = "cortex-a75", .features = featureSet(&[_]Feature{ - .a75, - .armv8_2_a, + .v8_2a, .dotprod, .hwdiv, .hwdiv_arm, }), }; - pub const cortex_a76 = Cpu{ + pub const cortex_a76 = CpuModel{ .name = "cortex_a76", .llvm_name = "cortex-a76", .features = featureSet(&[_]Feature{ .a76, - .armv8_2_a, + .v8_2a, .crc, .crypto, .dotprod, @@ -1818,12 +1694,12 @@ pub const cpu = struct { .hwdiv_arm, }), }; - pub const cortex_a76ae = Cpu{ + pub const cortex_a76ae = CpuModel{ .name = "cortex_a76ae", .llvm_name = "cortex-a76ae", .features = featureSet(&[_]Feature{ .a76, - .armv8_2_a, + .v8_2a, .crc, .crypto, .dotprod, @@ -1832,12 +1708,11 @@ pub const cpu = struct { .hwdiv_arm, }), }; - pub const cortex_a8 = Cpu{ + pub const cortex_a8 = CpuModel{ .name = "cortex_a8", .llvm_name = "cortex-a8", .features = featureSet(&[_]Feature{ - .a8, - .armv7_a, + .v7a, .nonpipelined_vfp, .ret_addr_stack, .slow_fp_brcc, @@ -1848,12 +1723,11 @@ pub const cpu = struct { .vmlx_hazards, }), }; - pub const cortex_a9 = Cpu{ + pub const cortex_a9 = CpuModel{ .name = "cortex_a9", .llvm_name = "cortex-a9", .features = featureSet(&[_]Feature{ - .a9, - .armv7_a, + .v7a, .avoid_partial_cpsr, .expand_fp_mlx, .fp16, @@ -1868,51 +1742,51 @@ pub const cpu = struct { .vmlx_hazards, }), }; - pub const cortex_m0 = Cpu{ + pub const cortex_m0 = CpuModel{ .name = "cortex_m0", .llvm_name = "cortex-m0", .features = featureSet(&[_]Feature{ - .armv6_m, + .v6m, }), }; - pub const cortex_m0plus = Cpu{ + pub const cortex_m0plus = CpuModel{ .name = "cortex_m0plus", .llvm_name = "cortex-m0plus", .features = featureSet(&[_]Feature{ - .armv6_m, + .v6m, }), }; - pub const cortex_m1 = Cpu{ + pub const cortex_m1 = CpuModel{ .name = "cortex_m1", .llvm_name = "cortex-m1", .features = featureSet(&[_]Feature{ - .armv6_m, + .v6m, }), }; - pub const cortex_m23 = Cpu{ + pub const cortex_m23 = CpuModel{ .name = "cortex_m23", .llvm_name = "cortex-m23", .features = featureSet(&[_]Feature{ - .armv8_m_base, + .v8m, .no_movt, }), }; - pub const cortex_m3 = Cpu{ + pub const cortex_m3 = CpuModel{ .name = "cortex_m3", .llvm_name = "cortex-m3", .features = featureSet(&[_]Feature{ - .armv7_m, + .v7m, .loop_align, .m3, .no_branch_predictor, .use_misched, }), }; - pub const cortex_m33 = Cpu{ + pub const cortex_m33 = CpuModel{ .name = "cortex_m33", .llvm_name = "cortex-m33", .features = featureSet(&[_]Feature{ - .armv8_m_main, + .v8m_main, .dsp, .fp_armv8d16sp, .loop_align, @@ -1922,11 +1796,11 @@ pub const cpu = struct { .use_misched, }), }; - pub const cortex_m35p = Cpu{ + pub const cortex_m35p = CpuModel{ .name = "cortex_m35p", .llvm_name = "cortex-m35p", .features = featureSet(&[_]Feature{ - .armv8_m_main, + .v8m_main, .dsp, .fp_armv8d16sp, .loop_align, @@ -1936,11 +1810,11 @@ pub const cpu = struct { .use_misched, }), }; - pub const cortex_m4 = Cpu{ + pub const cortex_m4 = CpuModel{ .name = "cortex_m4", .llvm_name = "cortex-m4", .features = featureSet(&[_]Feature{ - .armv7e_m, + .v7em, .loop_align, .no_branch_predictor, .slowfpvfmx, @@ -1949,29 +1823,29 @@ pub const cpu = struct { .vfp4d16sp, }), }; - pub const cortex_m7 = Cpu{ + pub const cortex_m7 = CpuModel{ .name = "cortex_m7", .llvm_name = "cortex-m7", .features = featureSet(&[_]Feature{ - .armv7e_m, + .v7em, .fp_armv8d16, }), }; - pub const cortex_r4 = Cpu{ + pub const cortex_r4 = CpuModel{ .name = "cortex_r4", .llvm_name = "cortex-r4", .features = featureSet(&[_]Feature{ - .armv7_r, + .v7r, .avoid_partial_cpsr, .r4, .ret_addr_stack, }), }; - pub const cortex_r4f = Cpu{ + pub const cortex_r4f = CpuModel{ .name = "cortex_r4f", .llvm_name = "cortex-r4f", .features = featureSet(&[_]Feature{ - .armv7_r, + .v7r, .avoid_partial_cpsr, .r4, .ret_addr_stack, @@ -1981,14 +1855,13 @@ pub const cpu = struct { .vfp3d16, }), }; - pub const cortex_r5 = Cpu{ + pub const cortex_r5 = CpuModel{ .name = "cortex_r5", .llvm_name = "cortex-r5", .features = featureSet(&[_]Feature{ - .armv7_r, + .v7r, .avoid_partial_cpsr, .hwdiv_arm, - .r5, .ret_addr_stack, .slow_fp_brcc, .slowfpvfmx, @@ -1996,26 +1869,24 @@ pub const cpu = struct { .vfp3d16, }), }; - pub const cortex_r52 = Cpu{ + pub const cortex_r52 = CpuModel{ .name = "cortex_r52", .llvm_name = "cortex-r52", .features = featureSet(&[_]Feature{ - .armv8_r, + .v8r, .fpao, - .r52, .use_misched, }), }; - pub const cortex_r7 = Cpu{ + pub const cortex_r7 = CpuModel{ .name = "cortex_r7", .llvm_name = "cortex-r7", .features = featureSet(&[_]Feature{ - .armv7_r, + .v7r, .avoid_partial_cpsr, .fp16, .hwdiv_arm, .mp, - .r7, .ret_addr_stack, .slow_fp_brcc, .slowfpvfmx, @@ -2023,11 +1894,11 @@ pub const cpu = struct { .vfp3d16, }), }; - pub const cortex_r8 = Cpu{ + pub const cortex_r8 = CpuModel{ .name = "cortex_r8", .llvm_name = "cortex-r8", .features = featureSet(&[_]Feature{ - .armv7_r, + .v7r, .avoid_partial_cpsr, .fp16, .hwdiv_arm, @@ -2039,11 +1910,11 @@ pub const cpu = struct { .vfp3d16, }), }; - pub const cyclone = Cpu{ + pub const cyclone = CpuModel{ .name = "cyclone", .llvm_name = "cyclone", .features = featureSet(&[_]Feature{ - .armv8_a, + .v8a, .avoid_movs_shop, .avoid_partial_cpsr, .crypto, @@ -2061,119 +1932,117 @@ pub const cpu = struct { .zcz, }), }; - pub const ep9312 = Cpu{ + pub const ep9312 = CpuModel{ .name = "ep9312", .llvm_name = "ep9312", .features = featureSet(&[_]Feature{ - .armv4t, + .v4t, }), }; - pub const exynos_m1 = Cpu{ + pub const exynos_m1 = CpuModel{ .name = "exynos_m1", .llvm_name = null, .features = featureSet(&[_]Feature{ - .armv8_a, + .v8a, .exynos, }), }; - pub const exynos_m2 = Cpu{ + pub const exynos_m2 = CpuModel{ .name = "exynos_m2", .llvm_name = null, .features = featureSet(&[_]Feature{ - .armv8_a, + .v8a, .exynos, }), }; - pub const exynos_m3 = Cpu{ + pub const exynos_m3 = CpuModel{ .name = "exynos_m3", .llvm_name = "exynos-m3", .features = featureSet(&[_]Feature{ - .armv8_a, + .v8_2a, .exynos, }), }; - pub const exynos_m4 = Cpu{ + pub const exynos_m4 = CpuModel{ .name = "exynos_m4", .llvm_name = "exynos-m4", .features = featureSet(&[_]Feature{ - .armv8_2_a, + .v8_2a, .dotprod, .exynos, .fullfp16, }), }; - pub const exynos_m5 = Cpu{ + pub const exynos_m5 = CpuModel{ .name = "exynos_m5", .llvm_name = "exynos-m5", .features = featureSet(&[_]Feature{ - .armv8_2_a, .dotprod, .exynos, .fullfp16, + .v8_2a, }), }; - pub const generic = Cpu{ + pub const generic = CpuModel{ .name = "generic", .llvm_name = "generic", .features = featureSet(&[_]Feature{}), }; - pub const iwmmxt = Cpu{ + pub const iwmmxt = CpuModel{ .name = "iwmmxt", .llvm_name = "iwmmxt", .features = featureSet(&[_]Feature{ - .armv5te, + .v5te, }), }; - pub const krait = Cpu{ + pub const krait = CpuModel{ .name = "krait", .llvm_name = "krait", .features = featureSet(&[_]Feature{ - .armv7_a, .avoid_partial_cpsr, .fp16, .hwdiv, .hwdiv_arm, - .krait, .muxed_units, .ret_addr_stack, + .v7a, .vfp4, .vldn_align, .vmlx_forwarding, }), }; - pub const kryo = Cpu{ + pub const kryo = CpuModel{ .name = "kryo", .llvm_name = "kryo", .features = featureSet(&[_]Feature{ - .armv8_a, .crc, .crypto, .hwdiv, .hwdiv_arm, - .kryo, + .v8a, }), }; - pub const mpcore = Cpu{ + pub const mpcore = CpuModel{ .name = "mpcore", .llvm_name = "mpcore", .features = featureSet(&[_]Feature{ - .armv6k, + .v6k, .slowfpvmlx, .vfp2, }), }; - pub const mpcorenovfp = Cpu{ + pub const mpcorenovfp = CpuModel{ .name = "mpcorenovfp", .llvm_name = "mpcorenovfp", .features = featureSet(&[_]Feature{ - .armv6k, + .v6k, }), }; - pub const neoverse_n1 = Cpu{ + pub const neoverse_n1 = CpuModel{ .name = "neoverse_n1", .llvm_name = "neoverse-n1", .features = featureSet(&[_]Feature{ - .armv8_2_a, + .v8_2a, .crc, .crypto, .dotprod, @@ -2181,56 +2050,56 @@ pub const cpu = struct { .hwdiv_arm, }), }; - pub const sc000 = Cpu{ + pub const sc000 = CpuModel{ .name = "sc000", .llvm_name = "sc000", .features = featureSet(&[_]Feature{ - .armv6_m, + .v6m, }), }; - pub const sc300 = Cpu{ + pub const sc300 = CpuModel{ .name = "sc300", .llvm_name = "sc300", .features = featureSet(&[_]Feature{ - .armv7_m, + .v7m, .m3, .no_branch_predictor, .use_misched, }), }; - pub const strongarm = Cpu{ + pub const strongarm = CpuModel{ .name = "strongarm", .llvm_name = "strongarm", .features = featureSet(&[_]Feature{ - .armv4, + .v4, }), }; - pub const strongarm110 = Cpu{ + pub const strongarm110 = CpuModel{ .name = "strongarm110", .llvm_name = "strongarm110", .features = featureSet(&[_]Feature{ - .armv4, + .v4, }), }; - pub const strongarm1100 = Cpu{ + pub const strongarm1100 = CpuModel{ .name = "strongarm1100", .llvm_name = "strongarm1100", .features = featureSet(&[_]Feature{ - .armv4, + .v4, }), }; - pub const strongarm1110 = Cpu{ + pub const strongarm1110 = CpuModel{ .name = "strongarm1110", .llvm_name = "strongarm1110", .features = featureSet(&[_]Feature{ - .armv4, + .v4, }), }; - pub const swift = Cpu{ + pub const swift = CpuModel{ .name = "swift", .llvm_name = "swift", .features = featureSet(&[_]Feature{ - .armv7_a, + .v7a, .avoid_movs_shop, .avoid_partial_cpsr, .disable_postra_scheduler, @@ -2254,11 +2123,11 @@ pub const cpu = struct { .wide_stride_vfp, }), }; - pub const xscale = Cpu{ + pub const xscale = CpuModel{ .name = "xscale", .llvm_name = "xscale", .features = featureSet(&[_]Feature{ - .armv5te, + .v5te, }), }; }; @@ -2266,7 +2135,7 @@ pub const cpu = struct { /// All arm CPUs, sorted alphabetically by name. /// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 /// compiler has inefficient memory and CPU usage, affecting build times. -pub const all_cpus = &[_]*const Cpu{ +pub const all_cpus = &[_]*const CpuModel{ &cpu.arm1020e, &cpu.arm1020t, &cpu.arm1022e, diff --git a/lib/std/target/avr.zig b/lib/std/target/avr.zig @@ -1,5 +1,6 @@ const std = @import("../std.zig"); -const Cpu = std.Target.Cpu; +const CpuFeature = std.Target.Cpu.Feature; +const CpuModel = std.Target.Cpu.Model; pub const Feature = enum { addsubiw, @@ -37,12 +38,12 @@ pub const Feature = enum { xmegau, }; -pub usingnamespace Cpu.Feature.feature_set_fns(Feature); +pub usingnamespace CpuFeature.feature_set_fns(Feature); pub const all_features = blk: { const len = @typeInfo(Feature).Enum.fields.len; - std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); - var result: [len]Cpu.Feature = undefined; + std.debug.assert(len <= CpuFeature.Set.needed_bit_count); + var result: [len]CpuFeature = undefined; result[@enumToInt(Feature.addsubiw)] = .{ .llvm_name = "addsubiw", .description = "Enable 16-bit register-immediate addition and subtraction instructions", @@ -293,28 +294,28 @@ pub const all_features = blk: { }; pub const cpu = struct { - pub const at43usb320 = Cpu{ + pub const at43usb320 = CpuModel{ .name = "at43usb320", .llvm_name = "at43usb320", .features = featureSet(&[_]Feature{ .avr31, }), }; - pub const at43usb355 = Cpu{ + pub const at43usb355 = CpuModel{ .name = "at43usb355", .llvm_name = "at43usb355", .features = featureSet(&[_]Feature{ .avr3, }), }; - pub const at76c711 = Cpu{ + pub const at76c711 = CpuModel{ .name = "at76c711", .llvm_name = "at76c711", .features = featureSet(&[_]Feature{ .avr3, }), }; - pub const at86rf401 = Cpu{ + pub const at86rf401 = CpuModel{ .name = "at86rf401", .llvm_name = "at86rf401", .features = featureSet(&[_]Feature{ @@ -323,217 +324,217 @@ pub const cpu = struct { .movw, }), }; - pub const at90c8534 = Cpu{ + pub const at90c8534 = CpuModel{ .name = "at90c8534", .llvm_name = "at90c8534", .features = featureSet(&[_]Feature{ .avr2, }), }; - pub const at90can128 = Cpu{ + pub const at90can128 = CpuModel{ .name = "at90can128", .llvm_name = "at90can128", .features = featureSet(&[_]Feature{ .avr51, }), }; - pub const at90can32 = Cpu{ + pub const at90can32 = CpuModel{ .name = "at90can32", .llvm_name = "at90can32", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const at90can64 = Cpu{ + pub const at90can64 = CpuModel{ .name = "at90can64", .llvm_name = "at90can64", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const at90pwm1 = Cpu{ + pub const at90pwm1 = CpuModel{ .name = "at90pwm1", .llvm_name = "at90pwm1", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const at90pwm161 = Cpu{ + pub const at90pwm161 = CpuModel{ .name = "at90pwm161", .llvm_name = "at90pwm161", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const at90pwm2 = Cpu{ + pub const at90pwm2 = CpuModel{ .name = "at90pwm2", .llvm_name = "at90pwm2", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const at90pwm216 = Cpu{ + pub const at90pwm216 = CpuModel{ .name = "at90pwm216", .llvm_name = "at90pwm216", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const at90pwm2b = Cpu{ + pub const at90pwm2b = CpuModel{ .name = "at90pwm2b", .llvm_name = "at90pwm2b", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const at90pwm3 = Cpu{ + pub const at90pwm3 = CpuModel{ .name = "at90pwm3", .llvm_name = "at90pwm3", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const at90pwm316 = Cpu{ + pub const at90pwm316 = CpuModel{ .name = "at90pwm316", .llvm_name = "at90pwm316", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const at90pwm3b = Cpu{ + pub const at90pwm3b = CpuModel{ .name = "at90pwm3b", .llvm_name = "at90pwm3b", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const at90pwm81 = Cpu{ + pub const at90pwm81 = CpuModel{ .name = "at90pwm81", .llvm_name = "at90pwm81", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const at90s1200 = Cpu{ + pub const at90s1200 = CpuModel{ .name = "at90s1200", .llvm_name = "at90s1200", .features = featureSet(&[_]Feature{ .avr0, }), }; - pub const at90s2313 = Cpu{ + pub const at90s2313 = CpuModel{ .name = "at90s2313", .llvm_name = "at90s2313", .features = featureSet(&[_]Feature{ .avr2, }), }; - pub const at90s2323 = Cpu{ + pub const at90s2323 = CpuModel{ .name = "at90s2323", .llvm_name = "at90s2323", .features = featureSet(&[_]Feature{ .avr2, }), }; - pub const at90s2333 = Cpu{ + pub const at90s2333 = CpuModel{ .name = "at90s2333", .llvm_name = "at90s2333", .features = featureSet(&[_]Feature{ .avr2, }), }; - pub const at90s2343 = Cpu{ + pub const at90s2343 = CpuModel{ .name = "at90s2343", .llvm_name = "at90s2343", .features = featureSet(&[_]Feature{ .avr2, }), }; - pub const at90s4414 = Cpu{ + pub const at90s4414 = CpuModel{ .name = "at90s4414", .llvm_name = "at90s4414", .features = featureSet(&[_]Feature{ .avr2, }), }; - pub const at90s4433 = Cpu{ + pub const at90s4433 = CpuModel{ .name = "at90s4433", .llvm_name = "at90s4433", .features = featureSet(&[_]Feature{ .avr2, }), }; - pub const at90s4434 = Cpu{ + pub const at90s4434 = CpuModel{ .name = "at90s4434", .llvm_name = "at90s4434", .features = featureSet(&[_]Feature{ .avr2, }), }; - pub const at90s8515 = Cpu{ + pub const at90s8515 = CpuModel{ .name = "at90s8515", .llvm_name = "at90s8515", .features = featureSet(&[_]Feature{ .avr2, }), }; - pub const at90s8535 = Cpu{ + pub const at90s8535 = CpuModel{ .name = "at90s8535", .llvm_name = "at90s8535", .features = featureSet(&[_]Feature{ .avr2, }), }; - pub const at90scr100 = Cpu{ + pub const at90scr100 = CpuModel{ .name = "at90scr100", .llvm_name = "at90scr100", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const at90usb1286 = Cpu{ + pub const at90usb1286 = CpuModel{ .name = "at90usb1286", .llvm_name = "at90usb1286", .features = featureSet(&[_]Feature{ .avr51, }), }; - pub const at90usb1287 = Cpu{ + pub const at90usb1287 = CpuModel{ .name = "at90usb1287", .llvm_name = "at90usb1287", .features = featureSet(&[_]Feature{ .avr51, }), }; - pub const at90usb162 = Cpu{ + pub const at90usb162 = CpuModel{ .name = "at90usb162", .llvm_name = "at90usb162", .features = featureSet(&[_]Feature{ .avr35, }), }; - pub const at90usb646 = Cpu{ + pub const at90usb646 = CpuModel{ .name = "at90usb646", .llvm_name = "at90usb646", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const at90usb647 = Cpu{ + pub const at90usb647 = CpuModel{ .name = "at90usb647", .llvm_name = "at90usb647", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const at90usb82 = Cpu{ + pub const at90usb82 = CpuModel{ .name = "at90usb82", .llvm_name = "at90usb82", .features = featureSet(&[_]Feature{ .avr35, }), }; - pub const at94k = Cpu{ + pub const at94k = CpuModel{ .name = "at94k", .llvm_name = "at94k", .features = featureSet(&[_]Feature{ @@ -543,133 +544,133 @@ pub const cpu = struct { .mul, }), }; - pub const ata5272 = Cpu{ + pub const ata5272 = CpuModel{ .name = "ata5272", .llvm_name = "ata5272", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const ata5505 = Cpu{ + pub const ata5505 = CpuModel{ .name = "ata5505", .llvm_name = "ata5505", .features = featureSet(&[_]Feature{ .avr35, }), }; - pub const ata5790 = Cpu{ + pub const ata5790 = CpuModel{ .name = "ata5790", .llvm_name = "ata5790", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const ata5795 = Cpu{ + pub const ata5795 = CpuModel{ .name = "ata5795", .llvm_name = "ata5795", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const ata6285 = Cpu{ + pub const ata6285 = CpuModel{ .name = "ata6285", .llvm_name = "ata6285", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const ata6286 = Cpu{ + pub const ata6286 = CpuModel{ .name = "ata6286", .llvm_name = "ata6286", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const ata6289 = Cpu{ + pub const ata6289 = CpuModel{ .name = "ata6289", .llvm_name = "ata6289", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const atmega103 = Cpu{ + pub const atmega103 = CpuModel{ .name = "atmega103", .llvm_name = "atmega103", .features = featureSet(&[_]Feature{ .avr31, }), }; - pub const atmega128 = Cpu{ + pub const atmega128 = CpuModel{ .name = "atmega128", .llvm_name = "atmega128", .features = featureSet(&[_]Feature{ .avr51, }), }; - pub const atmega1280 = Cpu{ + pub const atmega1280 = CpuModel{ .name = "atmega1280", .llvm_name = "atmega1280", .features = featureSet(&[_]Feature{ .avr51, }), }; - pub const atmega1281 = Cpu{ + pub const atmega1281 = CpuModel{ .name = "atmega1281", .llvm_name = "atmega1281", .features = featureSet(&[_]Feature{ .avr51, }), }; - pub const atmega1284 = Cpu{ + pub const atmega1284 = CpuModel{ .name = "atmega1284", .llvm_name = "atmega1284", .features = featureSet(&[_]Feature{ .avr51, }), }; - pub const atmega1284p = Cpu{ + pub const atmega1284p = CpuModel{ .name = "atmega1284p", .llvm_name = "atmega1284p", .features = featureSet(&[_]Feature{ .avr51, }), }; - pub const atmega1284rfr2 = Cpu{ + pub const atmega1284rfr2 = CpuModel{ .name = "atmega1284rfr2", .llvm_name = "atmega1284rfr2", .features = featureSet(&[_]Feature{ .avr51, }), }; - pub const atmega128a = Cpu{ + pub const atmega128a = CpuModel{ .name = "atmega128a", .llvm_name = "atmega128a", .features = featureSet(&[_]Feature{ .avr51, }), }; - pub const atmega128rfa1 = Cpu{ + pub const atmega128rfa1 = CpuModel{ .name = "atmega128rfa1", .llvm_name = "atmega128rfa1", .features = featureSet(&[_]Feature{ .avr51, }), }; - pub const atmega128rfr2 = Cpu{ + pub const atmega128rfr2 = CpuModel{ .name = "atmega128rfr2", .llvm_name = "atmega128rfr2", .features = featureSet(&[_]Feature{ .avr51, }), }; - pub const atmega16 = Cpu{ + pub const atmega16 = CpuModel{ .name = "atmega16", .llvm_name = "atmega16", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega161 = Cpu{ + pub const atmega161 = CpuModel{ .name = "atmega161", .llvm_name = "atmega161", .features = featureSet(&[_]Feature{ @@ -680,14 +681,14 @@ pub const cpu = struct { .spm, }), }; - pub const atmega162 = Cpu{ + pub const atmega162 = CpuModel{ .name = "atmega162", .llvm_name = "atmega162", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega163 = Cpu{ + pub const atmega163 = CpuModel{ .name = "atmega163", .llvm_name = "atmega163", .features = featureSet(&[_]Feature{ @@ -698,623 +699,623 @@ pub const cpu = struct { .spm, }), }; - pub const atmega164a = Cpu{ + pub const atmega164a = CpuModel{ .name = "atmega164a", .llvm_name = "atmega164a", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega164p = Cpu{ + pub const atmega164p = CpuModel{ .name = "atmega164p", .llvm_name = "atmega164p", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega164pa = Cpu{ + pub const atmega164pa = CpuModel{ .name = "atmega164pa", .llvm_name = "atmega164pa", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega165 = Cpu{ + pub const atmega165 = CpuModel{ .name = "atmega165", .llvm_name = "atmega165", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega165a = Cpu{ + pub const atmega165a = CpuModel{ .name = "atmega165a", .llvm_name = "atmega165a", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega165p = Cpu{ + pub const atmega165p = CpuModel{ .name = "atmega165p", .llvm_name = "atmega165p", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega165pa = Cpu{ + pub const atmega165pa = CpuModel{ .name = "atmega165pa", .llvm_name = "atmega165pa", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega168 = Cpu{ + pub const atmega168 = CpuModel{ .name = "atmega168", .llvm_name = "atmega168", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega168a = Cpu{ + pub const atmega168a = CpuModel{ .name = "atmega168a", .llvm_name = "atmega168a", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega168p = Cpu{ + pub const atmega168p = CpuModel{ .name = "atmega168p", .llvm_name = "atmega168p", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega168pa = Cpu{ + pub const atmega168pa = CpuModel{ .name = "atmega168pa", .llvm_name = "atmega168pa", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega169 = Cpu{ + pub const atmega169 = CpuModel{ .name = "atmega169", .llvm_name = "atmega169", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega169a = Cpu{ + pub const atmega169a = CpuModel{ .name = "atmega169a", .llvm_name = "atmega169a", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega169p = Cpu{ + pub const atmega169p = CpuModel{ .name = "atmega169p", .llvm_name = "atmega169p", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega169pa = Cpu{ + pub const atmega169pa = CpuModel{ .name = "atmega169pa", .llvm_name = "atmega169pa", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega16a = Cpu{ + pub const atmega16a = CpuModel{ .name = "atmega16a", .llvm_name = "atmega16a", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega16hva = Cpu{ + pub const atmega16hva = CpuModel{ .name = "atmega16hva", .llvm_name = "atmega16hva", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega16hva2 = Cpu{ + pub const atmega16hva2 = CpuModel{ .name = "atmega16hva2", .llvm_name = "atmega16hva2", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega16hvb = Cpu{ + pub const atmega16hvb = CpuModel{ .name = "atmega16hvb", .llvm_name = "atmega16hvb", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega16hvbrevb = Cpu{ + pub const atmega16hvbrevb = CpuModel{ .name = "atmega16hvbrevb", .llvm_name = "atmega16hvbrevb", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega16m1 = Cpu{ + pub const atmega16m1 = CpuModel{ .name = "atmega16m1", .llvm_name = "atmega16m1", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega16u2 = Cpu{ + pub const atmega16u2 = CpuModel{ .name = "atmega16u2", .llvm_name = "atmega16u2", .features = featureSet(&[_]Feature{ .avr35, }), }; - pub const atmega16u4 = Cpu{ + pub const atmega16u4 = CpuModel{ .name = "atmega16u4", .llvm_name = "atmega16u4", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega2560 = Cpu{ + pub const atmega2560 = CpuModel{ .name = "atmega2560", .llvm_name = "atmega2560", .features = featureSet(&[_]Feature{ .avr6, }), }; - pub const atmega2561 = Cpu{ + pub const atmega2561 = CpuModel{ .name = "atmega2561", .llvm_name = "atmega2561", .features = featureSet(&[_]Feature{ .avr6, }), }; - pub const atmega2564rfr2 = Cpu{ + pub const atmega2564rfr2 = CpuModel{ .name = "atmega2564rfr2", .llvm_name = "atmega2564rfr2", .features = featureSet(&[_]Feature{ .avr6, }), }; - pub const atmega256rfr2 = Cpu{ + pub const atmega256rfr2 = CpuModel{ .name = "atmega256rfr2", .llvm_name = "atmega256rfr2", .features = featureSet(&[_]Feature{ .avr6, }), }; - pub const atmega32 = Cpu{ + pub const atmega32 = CpuModel{ .name = "atmega32", .llvm_name = "atmega32", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega323 = Cpu{ + pub const atmega323 = CpuModel{ .name = "atmega323", .llvm_name = "atmega323", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega324a = Cpu{ + pub const atmega324a = CpuModel{ .name = "atmega324a", .llvm_name = "atmega324a", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega324p = Cpu{ + pub const atmega324p = CpuModel{ .name = "atmega324p", .llvm_name = "atmega324p", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega324pa = Cpu{ + pub const atmega324pa = CpuModel{ .name = "atmega324pa", .llvm_name = "atmega324pa", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega325 = Cpu{ + pub const atmega325 = CpuModel{ .name = "atmega325", .llvm_name = "atmega325", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega3250 = Cpu{ + pub const atmega3250 = CpuModel{ .name = "atmega3250", .llvm_name = "atmega3250", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega3250a = Cpu{ + pub const atmega3250a = CpuModel{ .name = "atmega3250a", .llvm_name = "atmega3250a", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega3250p = Cpu{ + pub const atmega3250p = CpuModel{ .name = "atmega3250p", .llvm_name = "atmega3250p", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega3250pa = Cpu{ + pub const atmega3250pa = CpuModel{ .name = "atmega3250pa", .llvm_name = "atmega3250pa", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega325a = Cpu{ + pub const atmega325a = CpuModel{ .name = "atmega325a", .llvm_name = "atmega325a", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega325p = Cpu{ + pub const atmega325p = CpuModel{ .name = "atmega325p", .llvm_name = "atmega325p", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega325pa = Cpu{ + pub const atmega325pa = CpuModel{ .name = "atmega325pa", .llvm_name = "atmega325pa", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega328 = Cpu{ + pub const atmega328 = CpuModel{ .name = "atmega328", .llvm_name = "atmega328", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega328p = Cpu{ + pub const atmega328p = CpuModel{ .name = "atmega328p", .llvm_name = "atmega328p", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega329 = Cpu{ + pub const atmega329 = CpuModel{ .name = "atmega329", .llvm_name = "atmega329", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega3290 = Cpu{ + pub const atmega3290 = CpuModel{ .name = "atmega3290", .llvm_name = "atmega3290", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega3290a = Cpu{ + pub const atmega3290a = CpuModel{ .name = "atmega3290a", .llvm_name = "atmega3290a", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega3290p = Cpu{ + pub const atmega3290p = CpuModel{ .name = "atmega3290p", .llvm_name = "atmega3290p", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega3290pa = Cpu{ + pub const atmega3290pa = CpuModel{ .name = "atmega3290pa", .llvm_name = "atmega3290pa", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega329a = Cpu{ + pub const atmega329a = CpuModel{ .name = "atmega329a", .llvm_name = "atmega329a", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega329p = Cpu{ + pub const atmega329p = CpuModel{ .name = "atmega329p", .llvm_name = "atmega329p", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega329pa = Cpu{ + pub const atmega329pa = CpuModel{ .name = "atmega329pa", .llvm_name = "atmega329pa", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega32a = Cpu{ + pub const atmega32a = CpuModel{ .name = "atmega32a", .llvm_name = "atmega32a", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega32c1 = Cpu{ + pub const atmega32c1 = CpuModel{ .name = "atmega32c1", .llvm_name = "atmega32c1", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega32hvb = Cpu{ + pub const atmega32hvb = CpuModel{ .name = "atmega32hvb", .llvm_name = "atmega32hvb", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega32hvbrevb = Cpu{ + pub const atmega32hvbrevb = CpuModel{ .name = "atmega32hvbrevb", .llvm_name = "atmega32hvbrevb", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega32m1 = Cpu{ + pub const atmega32m1 = CpuModel{ .name = "atmega32m1", .llvm_name = "atmega32m1", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega32u2 = Cpu{ + pub const atmega32u2 = CpuModel{ .name = "atmega32u2", .llvm_name = "atmega32u2", .features = featureSet(&[_]Feature{ .avr35, }), }; - pub const atmega32u4 = Cpu{ + pub const atmega32u4 = CpuModel{ .name = "atmega32u4", .llvm_name = "atmega32u4", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega32u6 = Cpu{ + pub const atmega32u6 = CpuModel{ .name = "atmega32u6", .llvm_name = "atmega32u6", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega406 = Cpu{ + pub const atmega406 = CpuModel{ .name = "atmega406", .llvm_name = "atmega406", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega48 = Cpu{ + pub const atmega48 = CpuModel{ .name = "atmega48", .llvm_name = "atmega48", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const atmega48a = Cpu{ + pub const atmega48a = CpuModel{ .name = "atmega48a", .llvm_name = "atmega48a", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const atmega48p = Cpu{ + pub const atmega48p = CpuModel{ .name = "atmega48p", .llvm_name = "atmega48p", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const atmega48pa = Cpu{ + pub const atmega48pa = CpuModel{ .name = "atmega48pa", .llvm_name = "atmega48pa", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const atmega64 = Cpu{ + pub const atmega64 = CpuModel{ .name = "atmega64", .llvm_name = "atmega64", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega640 = Cpu{ + pub const atmega640 = CpuModel{ .name = "atmega640", .llvm_name = "atmega640", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega644 = Cpu{ + pub const atmega644 = CpuModel{ .name = "atmega644", .llvm_name = "atmega644", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega644a = Cpu{ + pub const atmega644a = CpuModel{ .name = "atmega644a", .llvm_name = "atmega644a", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega644p = Cpu{ + pub const atmega644p = CpuModel{ .name = "atmega644p", .llvm_name = "atmega644p", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega644pa = Cpu{ + pub const atmega644pa = CpuModel{ .name = "atmega644pa", .llvm_name = "atmega644pa", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega644rfr2 = Cpu{ + pub const atmega644rfr2 = CpuModel{ .name = "atmega644rfr2", .llvm_name = "atmega644rfr2", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega645 = Cpu{ + pub const atmega645 = CpuModel{ .name = "atmega645", .llvm_name = "atmega645", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega6450 = Cpu{ + pub const atmega6450 = CpuModel{ .name = "atmega6450", .llvm_name = "atmega6450", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega6450a = Cpu{ + pub const atmega6450a = CpuModel{ .name = "atmega6450a", .llvm_name = "atmega6450a", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega6450p = Cpu{ + pub const atmega6450p = CpuModel{ .name = "atmega6450p", .llvm_name = "atmega6450p", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega645a = Cpu{ + pub const atmega645a = CpuModel{ .name = "atmega645a", .llvm_name = "atmega645a", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega645p = Cpu{ + pub const atmega645p = CpuModel{ .name = "atmega645p", .llvm_name = "atmega645p", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega649 = Cpu{ + pub const atmega649 = CpuModel{ .name = "atmega649", .llvm_name = "atmega649", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega6490 = Cpu{ + pub const atmega6490 = CpuModel{ .name = "atmega6490", .llvm_name = "atmega6490", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega6490a = Cpu{ + pub const atmega6490a = CpuModel{ .name = "atmega6490a", .llvm_name = "atmega6490a", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega6490p = Cpu{ + pub const atmega6490p = CpuModel{ .name = "atmega6490p", .llvm_name = "atmega6490p", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega649a = Cpu{ + pub const atmega649a = CpuModel{ .name = "atmega649a", .llvm_name = "atmega649a", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega649p = Cpu{ + pub const atmega649p = CpuModel{ .name = "atmega649p", .llvm_name = "atmega649p", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega64a = Cpu{ + pub const atmega64a = CpuModel{ .name = "atmega64a", .llvm_name = "atmega64a", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega64c1 = Cpu{ + pub const atmega64c1 = CpuModel{ .name = "atmega64c1", .llvm_name = "atmega64c1", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega64hve = Cpu{ + pub const atmega64hve = CpuModel{ .name = "atmega64hve", .llvm_name = "atmega64hve", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega64m1 = Cpu{ + pub const atmega64m1 = CpuModel{ .name = "atmega64m1", .llvm_name = "atmega64m1", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega64rfr2 = Cpu{ + pub const atmega64rfr2 = CpuModel{ .name = "atmega64rfr2", .llvm_name = "atmega64rfr2", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const atmega8 = Cpu{ + pub const atmega8 = CpuModel{ .name = "atmega8", .llvm_name = "atmega8", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const atmega8515 = Cpu{ + pub const atmega8515 = CpuModel{ .name = "atmega8515", .llvm_name = "atmega8515", .features = featureSet(&[_]Feature{ @@ -1325,7 +1326,7 @@ pub const cpu = struct { .spm, }), }; - pub const atmega8535 = Cpu{ + pub const atmega8535 = CpuModel{ .name = "atmega8535", .llvm_name = "atmega8535", .features = featureSet(&[_]Feature{ @@ -1336,175 +1337,175 @@ pub const cpu = struct { .spm, }), }; - pub const atmega88 = Cpu{ + pub const atmega88 = CpuModel{ .name = "atmega88", .llvm_name = "atmega88", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const atmega88a = Cpu{ + pub const atmega88a = CpuModel{ .name = "atmega88a", .llvm_name = "atmega88a", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const atmega88p = Cpu{ + pub const atmega88p = CpuModel{ .name = "atmega88p", .llvm_name = "atmega88p", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const atmega88pa = Cpu{ + pub const atmega88pa = CpuModel{ .name = "atmega88pa", .llvm_name = "atmega88pa", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const atmega8a = Cpu{ + pub const atmega8a = CpuModel{ .name = "atmega8a", .llvm_name = "atmega8a", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const atmega8hva = Cpu{ + pub const atmega8hva = CpuModel{ .name = "atmega8hva", .llvm_name = "atmega8hva", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const atmega8u2 = Cpu{ + pub const atmega8u2 = CpuModel{ .name = "atmega8u2", .llvm_name = "atmega8u2", .features = featureSet(&[_]Feature{ .avr35, }), }; - pub const attiny10 = Cpu{ + pub const attiny10 = CpuModel{ .name = "attiny10", .llvm_name = "attiny10", .features = featureSet(&[_]Feature{ .avrtiny, }), }; - pub const attiny102 = Cpu{ + pub const attiny102 = CpuModel{ .name = "attiny102", .llvm_name = "attiny102", .features = featureSet(&[_]Feature{ .avrtiny, }), }; - pub const attiny104 = Cpu{ + pub const attiny104 = CpuModel{ .name = "attiny104", .llvm_name = "attiny104", .features = featureSet(&[_]Feature{ .avrtiny, }), }; - pub const attiny11 = Cpu{ + pub const attiny11 = CpuModel{ .name = "attiny11", .llvm_name = "attiny11", .features = featureSet(&[_]Feature{ .avr1, }), }; - pub const attiny12 = Cpu{ + pub const attiny12 = CpuModel{ .name = "attiny12", .llvm_name = "attiny12", .features = featureSet(&[_]Feature{ .avr1, }), }; - pub const attiny13 = Cpu{ + pub const attiny13 = CpuModel{ .name = "attiny13", .llvm_name = "attiny13", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny13a = Cpu{ + pub const attiny13a = CpuModel{ .name = "attiny13a", .llvm_name = "attiny13a", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny15 = Cpu{ + pub const attiny15 = CpuModel{ .name = "attiny15", .llvm_name = "attiny15", .features = featureSet(&[_]Feature{ .avr1, }), }; - pub const attiny1634 = Cpu{ + pub const attiny1634 = CpuModel{ .name = "attiny1634", .llvm_name = "attiny1634", .features = featureSet(&[_]Feature{ .avr35, }), }; - pub const attiny167 = Cpu{ + pub const attiny167 = CpuModel{ .name = "attiny167", .llvm_name = "attiny167", .features = featureSet(&[_]Feature{ .avr35, }), }; - pub const attiny20 = Cpu{ + pub const attiny20 = CpuModel{ .name = "attiny20", .llvm_name = "attiny20", .features = featureSet(&[_]Feature{ .avrtiny, }), }; - pub const attiny22 = Cpu{ + pub const attiny22 = CpuModel{ .name = "attiny22", .llvm_name = "attiny22", .features = featureSet(&[_]Feature{ .avr2, }), }; - pub const attiny2313 = Cpu{ + pub const attiny2313 = CpuModel{ .name = "attiny2313", .llvm_name = "attiny2313", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny2313a = Cpu{ + pub const attiny2313a = CpuModel{ .name = "attiny2313a", .llvm_name = "attiny2313a", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny24 = Cpu{ + pub const attiny24 = CpuModel{ .name = "attiny24", .llvm_name = "attiny24", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny24a = Cpu{ + pub const attiny24a = CpuModel{ .name = "attiny24a", .llvm_name = "attiny24a", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny25 = Cpu{ + pub const attiny25 = CpuModel{ .name = "attiny25", .llvm_name = "attiny25", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny26 = Cpu{ + pub const attiny26 = CpuModel{ .name = "attiny26", .llvm_name = "attiny26", .features = featureSet(&[_]Feature{ @@ -1512,602 +1513,602 @@ pub const cpu = struct { .lpmx, }), }; - pub const attiny261 = Cpu{ + pub const attiny261 = CpuModel{ .name = "attiny261", .llvm_name = "attiny261", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny261a = Cpu{ + pub const attiny261a = CpuModel{ .name = "attiny261a", .llvm_name = "attiny261a", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny28 = Cpu{ + pub const attiny28 = CpuModel{ .name = "attiny28", .llvm_name = "attiny28", .features = featureSet(&[_]Feature{ .avr1, }), }; - pub const attiny4 = Cpu{ + pub const attiny4 = CpuModel{ .name = "attiny4", .llvm_name = "attiny4", .features = featureSet(&[_]Feature{ .avrtiny, }), }; - pub const attiny40 = Cpu{ + pub const attiny40 = CpuModel{ .name = "attiny40", .llvm_name = "attiny40", .features = featureSet(&[_]Feature{ .avrtiny, }), }; - pub const attiny4313 = Cpu{ + pub const attiny4313 = CpuModel{ .name = "attiny4313", .llvm_name = "attiny4313", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny43u = Cpu{ + pub const attiny43u = CpuModel{ .name = "attiny43u", .llvm_name = "attiny43u", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny44 = Cpu{ + pub const attiny44 = CpuModel{ .name = "attiny44", .llvm_name = "attiny44", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny44a = Cpu{ + pub const attiny44a = CpuModel{ .name = "attiny44a", .llvm_name = "attiny44a", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny45 = Cpu{ + pub const attiny45 = CpuModel{ .name = "attiny45", .llvm_name = "attiny45", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny461 = Cpu{ + pub const attiny461 = CpuModel{ .name = "attiny461", .llvm_name = "attiny461", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny461a = Cpu{ + pub const attiny461a = CpuModel{ .name = "attiny461a", .llvm_name = "attiny461a", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny48 = Cpu{ + pub const attiny48 = CpuModel{ .name = "attiny48", .llvm_name = "attiny48", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny5 = Cpu{ + pub const attiny5 = CpuModel{ .name = "attiny5", .llvm_name = "attiny5", .features = featureSet(&[_]Feature{ .avrtiny, }), }; - pub const attiny828 = Cpu{ + pub const attiny828 = CpuModel{ .name = "attiny828", .llvm_name = "attiny828", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny84 = Cpu{ + pub const attiny84 = CpuModel{ .name = "attiny84", .llvm_name = "attiny84", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny84a = Cpu{ + pub const attiny84a = CpuModel{ .name = "attiny84a", .llvm_name = "attiny84a", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny85 = Cpu{ + pub const attiny85 = CpuModel{ .name = "attiny85", .llvm_name = "attiny85", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny861 = Cpu{ + pub const attiny861 = CpuModel{ .name = "attiny861", .llvm_name = "attiny861", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny861a = Cpu{ + pub const attiny861a = CpuModel{ .name = "attiny861a", .llvm_name = "attiny861a", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny87 = Cpu{ + pub const attiny87 = CpuModel{ .name = "attiny87", .llvm_name = "attiny87", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny88 = Cpu{ + pub const attiny88 = CpuModel{ .name = "attiny88", .llvm_name = "attiny88", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const attiny9 = Cpu{ + pub const attiny9 = CpuModel{ .name = "attiny9", .llvm_name = "attiny9", .features = featureSet(&[_]Feature{ .avrtiny, }), }; - pub const atxmega128a1 = Cpu{ + pub const atxmega128a1 = CpuModel{ .name = "atxmega128a1", .llvm_name = "atxmega128a1", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega128a1u = Cpu{ + pub const atxmega128a1u = CpuModel{ .name = "atxmega128a1u", .llvm_name = "atxmega128a1u", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega128a3 = Cpu{ + pub const atxmega128a3 = CpuModel{ .name = "atxmega128a3", .llvm_name = "atxmega128a3", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega128a3u = Cpu{ + pub const atxmega128a3u = CpuModel{ .name = "atxmega128a3u", .llvm_name = "atxmega128a3u", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega128a4u = Cpu{ + pub const atxmega128a4u = CpuModel{ .name = "atxmega128a4u", .llvm_name = "atxmega128a4u", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega128b1 = Cpu{ + pub const atxmega128b1 = CpuModel{ .name = "atxmega128b1", .llvm_name = "atxmega128b1", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega128b3 = Cpu{ + pub const atxmega128b3 = CpuModel{ .name = "atxmega128b3", .llvm_name = "atxmega128b3", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega128c3 = Cpu{ + pub const atxmega128c3 = CpuModel{ .name = "atxmega128c3", .llvm_name = "atxmega128c3", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega128d3 = Cpu{ + pub const atxmega128d3 = CpuModel{ .name = "atxmega128d3", .llvm_name = "atxmega128d3", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega128d4 = Cpu{ + pub const atxmega128d4 = CpuModel{ .name = "atxmega128d4", .llvm_name = "atxmega128d4", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega16a4 = Cpu{ + pub const atxmega16a4 = CpuModel{ .name = "atxmega16a4", .llvm_name = "atxmega16a4", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega16a4u = Cpu{ + pub const atxmega16a4u = CpuModel{ .name = "atxmega16a4u", .llvm_name = "atxmega16a4u", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega16c4 = Cpu{ + pub const atxmega16c4 = CpuModel{ .name = "atxmega16c4", .llvm_name = "atxmega16c4", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega16d4 = Cpu{ + pub const atxmega16d4 = CpuModel{ .name = "atxmega16d4", .llvm_name = "atxmega16d4", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega16e5 = Cpu{ + pub const atxmega16e5 = CpuModel{ .name = "atxmega16e5", .llvm_name = "atxmega16e5", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega192a3 = Cpu{ + pub const atxmega192a3 = CpuModel{ .name = "atxmega192a3", .llvm_name = "atxmega192a3", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega192a3u = Cpu{ + pub const atxmega192a3u = CpuModel{ .name = "atxmega192a3u", .llvm_name = "atxmega192a3u", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega192c3 = Cpu{ + pub const atxmega192c3 = CpuModel{ .name = "atxmega192c3", .llvm_name = "atxmega192c3", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega192d3 = Cpu{ + pub const atxmega192d3 = CpuModel{ .name = "atxmega192d3", .llvm_name = "atxmega192d3", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega256a3 = Cpu{ + pub const atxmega256a3 = CpuModel{ .name = "atxmega256a3", .llvm_name = "atxmega256a3", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega256a3b = Cpu{ + pub const atxmega256a3b = CpuModel{ .name = "atxmega256a3b", .llvm_name = "atxmega256a3b", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega256a3bu = Cpu{ + pub const atxmega256a3bu = CpuModel{ .name = "atxmega256a3bu", .llvm_name = "atxmega256a3bu", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega256a3u = Cpu{ + pub const atxmega256a3u = CpuModel{ .name = "atxmega256a3u", .llvm_name = "atxmega256a3u", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega256c3 = Cpu{ + pub const atxmega256c3 = CpuModel{ .name = "atxmega256c3", .llvm_name = "atxmega256c3", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega256d3 = Cpu{ + pub const atxmega256d3 = CpuModel{ .name = "atxmega256d3", .llvm_name = "atxmega256d3", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega32a4 = Cpu{ + pub const atxmega32a4 = CpuModel{ .name = "atxmega32a4", .llvm_name = "atxmega32a4", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega32a4u = Cpu{ + pub const atxmega32a4u = CpuModel{ .name = "atxmega32a4u", .llvm_name = "atxmega32a4u", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega32c4 = Cpu{ + pub const atxmega32c4 = CpuModel{ .name = "atxmega32c4", .llvm_name = "atxmega32c4", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega32d4 = Cpu{ + pub const atxmega32d4 = CpuModel{ .name = "atxmega32d4", .llvm_name = "atxmega32d4", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega32e5 = Cpu{ + pub const atxmega32e5 = CpuModel{ .name = "atxmega32e5", .llvm_name = "atxmega32e5", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega32x1 = Cpu{ + pub const atxmega32x1 = CpuModel{ .name = "atxmega32x1", .llvm_name = "atxmega32x1", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega384c3 = Cpu{ + pub const atxmega384c3 = CpuModel{ .name = "atxmega384c3", .llvm_name = "atxmega384c3", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega384d3 = Cpu{ + pub const atxmega384d3 = CpuModel{ .name = "atxmega384d3", .llvm_name = "atxmega384d3", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega64a1 = Cpu{ + pub const atxmega64a1 = CpuModel{ .name = "atxmega64a1", .llvm_name = "atxmega64a1", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega64a1u = Cpu{ + pub const atxmega64a1u = CpuModel{ .name = "atxmega64a1u", .llvm_name = "atxmega64a1u", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega64a3 = Cpu{ + pub const atxmega64a3 = CpuModel{ .name = "atxmega64a3", .llvm_name = "atxmega64a3", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega64a3u = Cpu{ + pub const atxmega64a3u = CpuModel{ .name = "atxmega64a3u", .llvm_name = "atxmega64a3u", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega64a4u = Cpu{ + pub const atxmega64a4u = CpuModel{ .name = "atxmega64a4u", .llvm_name = "atxmega64a4u", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega64b1 = Cpu{ + pub const atxmega64b1 = CpuModel{ .name = "atxmega64b1", .llvm_name = "atxmega64b1", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega64b3 = Cpu{ + pub const atxmega64b3 = CpuModel{ .name = "atxmega64b3", .llvm_name = "atxmega64b3", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega64c3 = Cpu{ + pub const atxmega64c3 = CpuModel{ .name = "atxmega64c3", .llvm_name = "atxmega64c3", .features = featureSet(&[_]Feature{ .xmegau, }), }; - pub const atxmega64d3 = Cpu{ + pub const atxmega64d3 = CpuModel{ .name = "atxmega64d3", .llvm_name = "atxmega64d3", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega64d4 = Cpu{ + pub const atxmega64d4 = CpuModel{ .name = "atxmega64d4", .llvm_name = "atxmega64d4", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const atxmega8e5 = Cpu{ + pub const atxmega8e5 = CpuModel{ .name = "atxmega8e5", .llvm_name = "atxmega8e5", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const avr1 = Cpu{ + pub const avr1 = CpuModel{ .name = "avr1", .llvm_name = "avr1", .features = featureSet(&[_]Feature{ .avr1, }), }; - pub const avr2 = Cpu{ + pub const avr2 = CpuModel{ .name = "avr2", .llvm_name = "avr2", .features = featureSet(&[_]Feature{ .avr2, }), }; - pub const avr25 = Cpu{ + pub const avr25 = CpuModel{ .name = "avr25", .llvm_name = "avr25", .features = featureSet(&[_]Feature{ .avr25, }), }; - pub const avr3 = Cpu{ + pub const avr3 = CpuModel{ .name = "avr3", .llvm_name = "avr3", .features = featureSet(&[_]Feature{ .avr3, }), }; - pub const avr31 = Cpu{ + pub const avr31 = CpuModel{ .name = "avr31", .llvm_name = "avr31", .features = featureSet(&[_]Feature{ .avr31, }), }; - pub const avr35 = Cpu{ + pub const avr35 = CpuModel{ .name = "avr35", .llvm_name = "avr35", .features = featureSet(&[_]Feature{ .avr35, }), }; - pub const avr4 = Cpu{ + pub const avr4 = CpuModel{ .name = "avr4", .llvm_name = "avr4", .features = featureSet(&[_]Feature{ .avr4, }), }; - pub const avr5 = Cpu{ + pub const avr5 = CpuModel{ .name = "avr5", .llvm_name = "avr5", .features = featureSet(&[_]Feature{ .avr5, }), }; - pub const avr51 = Cpu{ + pub const avr51 = CpuModel{ .name = "avr51", .llvm_name = "avr51", .features = featureSet(&[_]Feature{ .avr51, }), }; - pub const avr6 = Cpu{ + pub const avr6 = CpuModel{ .name = "avr6", .llvm_name = "avr6", .features = featureSet(&[_]Feature{ .avr6, }), }; - pub const avrtiny = Cpu{ + pub const avrtiny = CpuModel{ .name = "avrtiny", .llvm_name = "avrtiny", .features = featureSet(&[_]Feature{ .avrtiny, }), }; - pub const avrxmega1 = Cpu{ + pub const avrxmega1 = CpuModel{ .name = "avrxmega1", .llvm_name = "avrxmega1", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const avrxmega2 = Cpu{ + pub const avrxmega2 = CpuModel{ .name = "avrxmega2", .llvm_name = "avrxmega2", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const avrxmega3 = Cpu{ + pub const avrxmega3 = CpuModel{ .name = "avrxmega3", .llvm_name = "avrxmega3", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const avrxmega4 = Cpu{ + pub const avrxmega4 = CpuModel{ .name = "avrxmega4", .llvm_name = "avrxmega4", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const avrxmega5 = Cpu{ + pub const avrxmega5 = CpuModel{ .name = "avrxmega5", .llvm_name = "avrxmega5", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const avrxmega6 = Cpu{ + pub const avrxmega6 = CpuModel{ .name = "avrxmega6", .llvm_name = "avrxmega6", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const avrxmega7 = Cpu{ + pub const avrxmega7 = CpuModel{ .name = "avrxmega7", .llvm_name = "avrxmega7", .features = featureSet(&[_]Feature{ .xmega, }), }; - pub const m3000 = Cpu{ + pub const m3000 = CpuModel{ .name = "m3000", .llvm_name = "m3000", .features = featureSet(&[_]Feature{ @@ -2119,7 +2120,7 @@ pub const cpu = struct { /// All avr CPUs, sorted alphabetically by name. /// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 /// compiler has inefficient memory and CPU usage, affecting build times. -pub const all_cpus = &[_]*const Cpu{ +pub const all_cpus = &[_]*const CpuModel{ &cpu.at43usb320, &cpu.at43usb355, &cpu.at76c711, diff --git a/lib/std/target/bpf.zig b/lib/std/target/bpf.zig @@ -1,5 +1,6 @@ const std = @import("../std.zig"); -const Cpu = std.Target.Cpu; +const CpuFeature = std.Target.Cpu.Feature; +const CpuModel = std.Target.Cpu.Model; pub const Feature = enum { alu32, @@ -7,12 +8,12 @@ pub const Feature = enum { dwarfris, }; -pub usingnamespace Cpu.Feature.feature_set_fns(Feature); +pub usingnamespace CpuFeature.feature_set_fns(Feature); pub const all_features = blk: { const len = @typeInfo(Feature).Enum.fields.len; - std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); - var result: [len]Cpu.Feature = undefined; + std.debug.assert(len <= CpuFeature.Set.needed_bit_count); + var result: [len]CpuFeature = undefined; result[@enumToInt(Feature.alu32)] = .{ .llvm_name = "alu32", .description = "Enable ALU32 instructions", @@ -37,27 +38,27 @@ pub const all_features = blk: { }; pub const cpu = struct { - pub const generic = Cpu{ + pub const generic = CpuModel{ .name = "generic", .llvm_name = "generic", .features = featureSet(&[_]Feature{}), }; - pub const probe = Cpu{ + pub const probe = CpuModel{ .name = "probe", .llvm_name = "probe", .features = featureSet(&[_]Feature{}), }; - pub const v1 = Cpu{ + pub const v1 = CpuModel{ .name = "v1", .llvm_name = "v1", .features = featureSet(&[_]Feature{}), }; - pub const v2 = Cpu{ + pub const v2 = CpuModel{ .name = "v2", .llvm_name = "v2", .features = featureSet(&[_]Feature{}), }; - pub const v3 = Cpu{ + pub const v3 = CpuModel{ .name = "v3", .llvm_name = "v3", .features = featureSet(&[_]Feature{}), @@ -67,7 +68,7 @@ pub const cpu = struct { /// All bpf CPUs, sorted alphabetically by name. /// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 /// compiler has inefficient memory and CPU usage, affecting build times. -pub const all_cpus = &[_]*const Cpu{ +pub const all_cpus = &[_]*const CpuModel{ &cpu.generic, &cpu.probe, &cpu.v1, diff --git a/lib/std/target/hexagon.zig b/lib/std/target/hexagon.zig @@ -1,5 +1,6 @@ const std = @import("../std.zig"); -const Cpu = std.Target.Cpu; +const CpuFeature = std.Target.Cpu.Feature; +const CpuModel = std.Target.Cpu.Model; pub const Feature = enum { duplex, @@ -28,12 +29,12 @@ pub const Feature = enum { zreg, }; -pub usingnamespace Cpu.Feature.feature_set_fns(Feature); +pub usingnamespace CpuFeature.feature_set_fns(Feature); pub const all_features = blk: { const len = @typeInfo(Feature).Enum.fields.len; - std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); - var result: [len]Cpu.Feature = undefined; + std.debug.assert(len <= CpuFeature.Set.needed_bit_count); + var result: [len]CpuFeature = undefined; result[@enumToInt(Feature.duplex)] = .{ .llvm_name = "duplex", .description = "Enable generation of duplex instruction", @@ -186,7 +187,7 @@ pub const all_features = blk: { }; pub const cpu = struct { - pub const generic = Cpu{ + pub const generic = CpuModel{ .name = "generic", .llvm_name = "generic", .features = featureSet(&[_]Feature{ @@ -201,7 +202,7 @@ pub const cpu = struct { .v60, }), }; - pub const hexagonv5 = Cpu{ + pub const hexagonv5 = CpuModel{ .name = "hexagonv5", .llvm_name = "hexagonv5", .features = featureSet(&[_]Feature{ @@ -214,7 +215,7 @@ pub const cpu = struct { .v5, }), }; - pub const hexagonv55 = Cpu{ + pub const hexagonv55 = CpuModel{ .name = "hexagonv55", .llvm_name = "hexagonv55", .features = featureSet(&[_]Feature{ @@ -228,7 +229,7 @@ pub const cpu = struct { .v55, }), }; - pub const hexagonv60 = Cpu{ + pub const hexagonv60 = CpuModel{ .name = "hexagonv60", .llvm_name = "hexagonv60", .features = featureSet(&[_]Feature{ @@ -243,7 +244,7 @@ pub const cpu = struct { .v60, }), }; - pub const hexagonv62 = Cpu{ + pub const hexagonv62 = CpuModel{ .name = "hexagonv62", .llvm_name = "hexagonv62", .features = featureSet(&[_]Feature{ @@ -259,7 +260,7 @@ pub const cpu = struct { .v62, }), }; - pub const hexagonv65 = Cpu{ + pub const hexagonv65 = CpuModel{ .name = "hexagonv65", .llvm_name = "hexagonv65", .features = featureSet(&[_]Feature{ @@ -277,7 +278,7 @@ pub const cpu = struct { .v65, }), }; - pub const hexagonv66 = Cpu{ + pub const hexagonv66 = CpuModel{ .name = "hexagonv66", .llvm_name = "hexagonv66", .features = featureSet(&[_]Feature{ @@ -301,7 +302,7 @@ pub const cpu = struct { /// All hexagon CPUs, sorted alphabetically by name. /// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 /// compiler has inefficient memory and CPU usage, affecting build times. -pub const all_cpus = &[_]*const Cpu{ +pub const all_cpus = &[_]*const CpuModel{ &cpu.generic, &cpu.hexagonv5, &cpu.hexagonv55, diff --git a/lib/std/target/mips.zig b/lib/std/target/mips.zig @@ -1,5 +1,6 @@ const std = @import("../std.zig"); -const Cpu = std.Target.Cpu; +const CpuFeature = std.Target.Cpu.Feature; +const CpuModel = std.Target.Cpu.Model; pub const Feature = enum { abs2008, @@ -55,12 +56,12 @@ pub const Feature = enum { xgot, }; -pub usingnamespace Cpu.Feature.feature_set_fns(Feature); +pub usingnamespace CpuFeature.feature_set_fns(Feature); pub const all_features = blk: { const len = @typeInfo(Feature).Enum.fields.len; - std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); - var result: [len]Cpu.Feature = undefined; + std.debug.assert(len <= CpuFeature.Set.needed_bit_count); + var result: [len]CpuFeature = undefined; result[@enumToInt(Feature.abs2008)] = .{ .llvm_name = "abs2008", .description = "Disable IEEE 754-2008 abs.fmt mode", @@ -386,119 +387,119 @@ pub const all_features = blk: { }; pub const cpu = struct { - pub const generic = Cpu{ + pub const generic = CpuModel{ .name = "generic", .llvm_name = "generic", .features = featureSet(&[_]Feature{ .mips32, }), }; - pub const mips1 = Cpu{ + pub const mips1 = CpuModel{ .name = "mips1", .llvm_name = "mips1", .features = featureSet(&[_]Feature{ .mips1, }), }; - pub const mips2 = Cpu{ + pub const mips2 = CpuModel{ .name = "mips2", .llvm_name = "mips2", .features = featureSet(&[_]Feature{ .mips2, }), }; - pub const mips3 = Cpu{ + pub const mips3 = CpuModel{ .name = "mips3", .llvm_name = "mips3", .features = featureSet(&[_]Feature{ .mips3, }), }; - pub const mips32 = Cpu{ + pub const mips32 = CpuModel{ .name = "mips32", .llvm_name = "mips32", .features = featureSet(&[_]Feature{ .mips32, }), }; - pub const mips32r2 = Cpu{ + pub const mips32r2 = CpuModel{ .name = "mips32r2", .llvm_name = "mips32r2", .features = featureSet(&[_]Feature{ .mips32r2, }), }; - pub const mips32r3 = Cpu{ + pub const mips32r3 = CpuModel{ .name = "mips32r3", .llvm_name = "mips32r3", .features = featureSet(&[_]Feature{ .mips32r3, }), }; - pub const mips32r5 = Cpu{ + pub const mips32r5 = CpuModel{ .name = "mips32r5", .llvm_name = "mips32r5", .features = featureSet(&[_]Feature{ .mips32r5, }), }; - pub const mips32r6 = Cpu{ + pub const mips32r6 = CpuModel{ .name = "mips32r6", .llvm_name = "mips32r6", .features = featureSet(&[_]Feature{ .mips32r6, }), }; - pub const mips4 = Cpu{ + pub const mips4 = CpuModel{ .name = "mips4", .llvm_name = "mips4", .features = featureSet(&[_]Feature{ .mips4, }), }; - pub const mips5 = Cpu{ + pub const mips5 = CpuModel{ .name = "mips5", .llvm_name = "mips5", .features = featureSet(&[_]Feature{ .mips5, }), }; - pub const mips64 = Cpu{ + pub const mips64 = CpuModel{ .name = "mips64", .llvm_name = "mips64", .features = featureSet(&[_]Feature{ .mips64, }), }; - pub const mips64r2 = Cpu{ + pub const mips64r2 = CpuModel{ .name = "mips64r2", .llvm_name = "mips64r2", .features = featureSet(&[_]Feature{ .mips64r2, }), }; - pub const mips64r3 = Cpu{ + pub const mips64r3 = CpuModel{ .name = "mips64r3", .llvm_name = "mips64r3", .features = featureSet(&[_]Feature{ .mips64r3, }), }; - pub const mips64r5 = Cpu{ + pub const mips64r5 = CpuModel{ .name = "mips64r5", .llvm_name = "mips64r5", .features = featureSet(&[_]Feature{ .mips64r5, }), }; - pub const mips64r6 = Cpu{ + pub const mips64r6 = CpuModel{ .name = "mips64r6", .llvm_name = "mips64r6", .features = featureSet(&[_]Feature{ .mips64r6, }), }; - pub const octeon = Cpu{ + pub const octeon = CpuModel{ .name = "octeon", .llvm_name = "octeon", .features = featureSet(&[_]Feature{ @@ -506,7 +507,7 @@ pub const cpu = struct { .mips64r2, }), }; - pub const @"octeon+" = Cpu{ + pub const @"octeon+" = CpuModel{ .name = "octeon+", .llvm_name = "octeon+", .features = featureSet(&[_]Feature{ @@ -515,7 +516,7 @@ pub const cpu = struct { .mips64r2, }), }; - pub const p5600 = Cpu{ + pub const p5600 = CpuModel{ .name = "p5600", .llvm_name = "p5600", .features = featureSet(&[_]Feature{ @@ -527,7 +528,7 @@ pub const cpu = struct { /// All mips CPUs, sorted alphabetically by name. /// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 /// compiler has inefficient memory and CPU usage, affecting build times. -pub const all_cpus = &[_]*const Cpu{ +pub const all_cpus = &[_]*const CpuModel{ &cpu.generic, &cpu.mips1, &cpu.mips2, diff --git a/lib/std/target/msp430.zig b/lib/std/target/msp430.zig @@ -1,5 +1,6 @@ const std = @import("../std.zig"); -const Cpu = std.Target.Cpu; +const CpuFeature = std.Target.Cpu.Feature; +const CpuModel = std.Target.Cpu.Model; pub const Feature = enum { ext, @@ -8,12 +9,12 @@ pub const Feature = enum { hwmultf5, }; -pub usingnamespace Cpu.Feature.feature_set_fns(Feature); +pub usingnamespace CpuFeature.feature_set_fns(Feature); pub const all_features = blk: { const len = @typeInfo(Feature).Enum.fields.len; - std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); - var result: [len]Cpu.Feature = undefined; + std.debug.assert(len <= CpuFeature.Set.needed_bit_count); + var result: [len]CpuFeature = undefined; result[@enumToInt(Feature.ext)] = .{ .llvm_name = "ext", .description = "Enable MSP430-X extensions", @@ -43,17 +44,17 @@ pub const all_features = blk: { }; pub const cpu = struct { - pub const generic = Cpu{ + pub const generic = CpuModel{ .name = "generic", .llvm_name = "generic", .features = featureSet(&[_]Feature{}), }; - pub const msp430 = Cpu{ + pub const msp430 = CpuModel{ .name = "msp430", .llvm_name = "msp430", .features = featureSet(&[_]Feature{}), }; - pub const msp430x = Cpu{ + pub const msp430x = CpuModel{ .name = "msp430x", .llvm_name = "msp430x", .features = featureSet(&[_]Feature{ @@ -65,7 +66,7 @@ pub const cpu = struct { /// All msp430 CPUs, sorted alphabetically by name. /// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 /// compiler has inefficient memory and CPU usage, affecting build times. -pub const all_cpus = &[_]*const Cpu{ +pub const all_cpus = &[_]*const CpuModel{ &cpu.generic, &cpu.msp430, &cpu.msp430x, diff --git a/lib/std/target/nvptx.zig b/lib/std/target/nvptx.zig @@ -1,5 +1,6 @@ const std = @import("../std.zig"); -const Cpu = std.Target.Cpu; +const CpuFeature = std.Target.Cpu.Feature; +const CpuModel = std.Target.Cpu.Model; pub const Feature = enum { ptx32, @@ -29,12 +30,12 @@ pub const Feature = enum { sm_75, }; -pub usingnamespace Cpu.Feature.feature_set_fns(Feature); +pub usingnamespace CpuFeature.feature_set_fns(Feature); pub const all_features = blk: { const len = @typeInfo(Feature).Enum.fields.len; - std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); - var result: [len]Cpu.Feature = undefined; + std.debug.assert(len <= CpuFeature.Set.needed_bit_count); + var result: [len]CpuFeature = undefined; result[@enumToInt(Feature.ptx32)] = .{ .llvm_name = "ptx32", .description = "Use PTX version 3.2", @@ -169,28 +170,28 @@ pub const all_features = blk: { }; pub const cpu = struct { - pub const sm_20 = Cpu{ + pub const sm_20 = CpuModel{ .name = "sm_20", .llvm_name = "sm_20", .features = featureSet(&[_]Feature{ .sm_20, }), }; - pub const sm_21 = Cpu{ + pub const sm_21 = CpuModel{ .name = "sm_21", .llvm_name = "sm_21", .features = featureSet(&[_]Feature{ .sm_21, }), }; - pub const sm_30 = Cpu{ + pub const sm_30 = CpuModel{ .name = "sm_30", .llvm_name = "sm_30", .features = featureSet(&[_]Feature{ .sm_30, }), }; - pub const sm_32 = Cpu{ + pub const sm_32 = CpuModel{ .name = "sm_32", .llvm_name = "sm_32", .features = featureSet(&[_]Feature{ @@ -198,14 +199,14 @@ pub const cpu = struct { .sm_32, }), }; - pub const sm_35 = Cpu{ + pub const sm_35 = CpuModel{ .name = "sm_35", .llvm_name = "sm_35", .features = featureSet(&[_]Feature{ .sm_35, }), }; - pub const sm_37 = Cpu{ + pub const sm_37 = CpuModel{ .name = "sm_37", .llvm_name = "sm_37", .features = featureSet(&[_]Feature{ @@ -213,7 +214,7 @@ pub const cpu = struct { .sm_37, }), }; - pub const sm_50 = Cpu{ + pub const sm_50 = CpuModel{ .name = "sm_50", .llvm_name = "sm_50", .features = featureSet(&[_]Feature{ @@ -221,7 +222,7 @@ pub const cpu = struct { .sm_50, }), }; - pub const sm_52 = Cpu{ + pub const sm_52 = CpuModel{ .name = "sm_52", .llvm_name = "sm_52", .features = featureSet(&[_]Feature{ @@ -229,7 +230,7 @@ pub const cpu = struct { .sm_52, }), }; - pub const sm_53 = Cpu{ + pub const sm_53 = CpuModel{ .name = "sm_53", .llvm_name = "sm_53", .features = featureSet(&[_]Feature{ @@ -237,7 +238,7 @@ pub const cpu = struct { .sm_53, }), }; - pub const sm_60 = Cpu{ + pub const sm_60 = CpuModel{ .name = "sm_60", .llvm_name = "sm_60", .features = featureSet(&[_]Feature{ @@ -245,7 +246,7 @@ pub const cpu = struct { .sm_60, }), }; - pub const sm_61 = Cpu{ + pub const sm_61 = CpuModel{ .name = "sm_61", .llvm_name = "sm_61", .features = featureSet(&[_]Feature{ @@ -253,7 +254,7 @@ pub const cpu = struct { .sm_61, }), }; - pub const sm_62 = Cpu{ + pub const sm_62 = CpuModel{ .name = "sm_62", .llvm_name = "sm_62", .features = featureSet(&[_]Feature{ @@ -261,7 +262,7 @@ pub const cpu = struct { .sm_62, }), }; - pub const sm_70 = Cpu{ + pub const sm_70 = CpuModel{ .name = "sm_70", .llvm_name = "sm_70", .features = featureSet(&[_]Feature{ @@ -269,7 +270,7 @@ pub const cpu = struct { .sm_70, }), }; - pub const sm_72 = Cpu{ + pub const sm_72 = CpuModel{ .name = "sm_72", .llvm_name = "sm_72", .features = featureSet(&[_]Feature{ @@ -277,7 +278,7 @@ pub const cpu = struct { .sm_72, }), }; - pub const sm_75 = Cpu{ + pub const sm_75 = CpuModel{ .name = "sm_75", .llvm_name = "sm_75", .features = featureSet(&[_]Feature{ @@ -290,7 +291,7 @@ pub const cpu = struct { /// All nvptx CPUs, sorted alphabetically by name. /// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 /// compiler has inefficient memory and CPU usage, affecting build times. -pub const all_cpus = &[_]*const Cpu{ +pub const all_cpus = &[_]*const CpuModel{ &cpu.sm_20, &cpu.sm_21, &cpu.sm_30, diff --git a/lib/std/target/powerpc.zig b/lib/std/target/powerpc.zig @@ -1,5 +1,6 @@ const std = @import("../std.zig"); -const Cpu = std.Target.Cpu; +const CpuFeature = std.Target.Cpu.Feature; +const CpuModel = std.Target.Cpu.Model; pub const Feature = enum { @"64bit", @@ -56,12 +57,12 @@ pub const Feature = enum { vsx, }; -pub usingnamespace Cpu.Feature.feature_set_fns(Feature); +pub usingnamespace CpuFeature.feature_set_fns(Feature); pub const all_features = blk: { const len = @typeInfo(Feature).Enum.fields.len; - std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); - var result: [len]Cpu.Feature = undefined; + std.debug.assert(len <= CpuFeature.Set.needed_bit_count); + var result: [len]CpuFeature = undefined; result[@enumToInt(Feature.@"64bit")] = .{ .llvm_name = "64bit", .description = "Enable 64-bit instructions", @@ -383,7 +384,7 @@ pub const all_features = blk: { }; pub const cpu = struct { - pub const @"440" = Cpu{ + pub const @"440" = CpuModel{ .name = "440", .llvm_name = "440", .features = featureSet(&[_]Feature{ @@ -395,7 +396,7 @@ pub const cpu = struct { .msync, }), }; - pub const @"450" = Cpu{ + pub const @"450" = CpuModel{ .name = "450", .llvm_name = "450", .features = featureSet(&[_]Feature{ @@ -407,21 +408,21 @@ pub const cpu = struct { .msync, }), }; - pub const @"601" = Cpu{ + pub const @"601" = CpuModel{ .name = "601", .llvm_name = "601", .features = featureSet(&[_]Feature{ .fpu, }), }; - pub const @"602" = Cpu{ + pub const @"602" = CpuModel{ .name = "602", .llvm_name = "602", .features = featureSet(&[_]Feature{ .fpu, }), }; - pub const @"603" = Cpu{ + pub const @"603" = CpuModel{ .name = "603", .llvm_name = "603", .features = featureSet(&[_]Feature{ @@ -429,7 +430,7 @@ pub const cpu = struct { .frsqrte, }), }; - pub const @"603e" = Cpu{ + pub const @"603e" = CpuModel{ .name = "603e", .llvm_name = "603e", .features = featureSet(&[_]Feature{ @@ -437,7 +438,7 @@ pub const cpu = struct { .frsqrte, }), }; - pub const @"603ev" = Cpu{ + pub const @"603ev" = CpuModel{ .name = "603ev", .llvm_name = "603ev", .features = featureSet(&[_]Feature{ @@ -445,7 +446,7 @@ pub const cpu = struct { .frsqrte, }), }; - pub const @"604" = Cpu{ + pub const @"604" = CpuModel{ .name = "604", .llvm_name = "604", .features = featureSet(&[_]Feature{ @@ -453,7 +454,7 @@ pub const cpu = struct { .frsqrte, }), }; - pub const @"604e" = Cpu{ + pub const @"604e" = CpuModel{ .name = "604e", .llvm_name = "604e", .features = featureSet(&[_]Feature{ @@ -461,7 +462,7 @@ pub const cpu = struct { .frsqrte, }), }; - pub const @"620" = Cpu{ + pub const @"620" = CpuModel{ .name = "620", .llvm_name = "620", .features = featureSet(&[_]Feature{ @@ -469,7 +470,7 @@ pub const cpu = struct { .frsqrte, }), }; - pub const @"7400" = Cpu{ + pub const @"7400" = CpuModel{ .name = "7400", .llvm_name = "7400", .features = featureSet(&[_]Feature{ @@ -478,7 +479,7 @@ pub const cpu = struct { .frsqrte, }), }; - pub const @"7450" = Cpu{ + pub const @"7450" = CpuModel{ .name = "7450", .llvm_name = "7450", .features = featureSet(&[_]Feature{ @@ -487,7 +488,7 @@ pub const cpu = struct { .frsqrte, }), }; - pub const @"750" = Cpu{ + pub const @"750" = CpuModel{ .name = "750", .llvm_name = "750", .features = featureSet(&[_]Feature{ @@ -495,7 +496,7 @@ pub const cpu = struct { .frsqrte, }), }; - pub const @"970" = Cpu{ + pub const @"970" = CpuModel{ .name = "970", .llvm_name = "970", .features = featureSet(&[_]Feature{ @@ -508,7 +509,7 @@ pub const cpu = struct { .stfiwx, }), }; - pub const a2 = Cpu{ + pub const a2 = CpuModel{ .name = "a2", .llvm_name = "a2", .features = featureSet(&[_]Feature{ @@ -533,7 +534,7 @@ pub const cpu = struct { .stfiwx, }), }; - pub const a2q = Cpu{ + pub const a2q = CpuModel{ .name = "a2q", .llvm_name = "a2q", .features = featureSet(&[_]Feature{ @@ -559,7 +560,7 @@ pub const cpu = struct { .stfiwx, }), }; - pub const e500 = Cpu{ + pub const e500 = CpuModel{ .name = "e500", .llvm_name = "e500", .features = featureSet(&[_]Feature{ @@ -569,7 +570,7 @@ pub const cpu = struct { .spe, }), }; - pub const e500mc = Cpu{ + pub const e500mc = CpuModel{ .name = "e500mc", .llvm_name = "e500mc", .features = featureSet(&[_]Feature{ @@ -579,7 +580,7 @@ pub const cpu = struct { .stfiwx, }), }; - pub const e5500 = Cpu{ + pub const e5500 = CpuModel{ .name = "e5500", .llvm_name = "e5500", .features = featureSet(&[_]Feature{ @@ -591,7 +592,7 @@ pub const cpu = struct { .stfiwx, }), }; - pub const future = Cpu{ + pub const future = CpuModel{ .name = "future", .llvm_name = "future", .features = featureSet(&[_]Feature{ @@ -630,7 +631,7 @@ pub const cpu = struct { .vsx, }), }; - pub const g3 = Cpu{ + pub const g3 = CpuModel{ .name = "g3", .llvm_name = "g3", .features = featureSet(&[_]Feature{ @@ -638,7 +639,7 @@ pub const cpu = struct { .frsqrte, }), }; - pub const g4 = Cpu{ + pub const g4 = CpuModel{ .name = "g4", .llvm_name = "g4", .features = featureSet(&[_]Feature{ @@ -647,7 +648,7 @@ pub const cpu = struct { .frsqrte, }), }; - pub const @"g4+" = Cpu{ + pub const @"g4+" = CpuModel{ .name = "g4+", .llvm_name = "g4+", .features = featureSet(&[_]Feature{ @@ -656,7 +657,7 @@ pub const cpu = struct { .frsqrte, }), }; - pub const g5 = Cpu{ + pub const g5 = CpuModel{ .name = "g5", .llvm_name = "g5", .features = featureSet(&[_]Feature{ @@ -669,28 +670,28 @@ pub const cpu = struct { .stfiwx, }), }; - pub const generic = Cpu{ + pub const generic = CpuModel{ .name = "generic", .llvm_name = "generic", .features = featureSet(&[_]Feature{ .hard_float, }), }; - pub const ppc = Cpu{ + pub const ppc = CpuModel{ .name = "ppc", .llvm_name = "ppc", .features = featureSet(&[_]Feature{ .hard_float, }), }; - pub const ppc32 = Cpu{ + pub const ppc32 = CpuModel{ .name = "ppc32", .llvm_name = "ppc32", .features = featureSet(&[_]Feature{ .hard_float, }), }; - pub const ppc64 = Cpu{ + pub const ppc64 = CpuModel{ .name = "ppc64", .llvm_name = "ppc64", .features = featureSet(&[_]Feature{ @@ -703,7 +704,7 @@ pub const cpu = struct { .stfiwx, }), }; - pub const ppc64le = Cpu{ + pub const ppc64le = CpuModel{ .name = "ppc64le", .llvm_name = "ppc64le", .features = featureSet(&[_]Feature{ @@ -739,7 +740,7 @@ pub const cpu = struct { .vsx, }), }; - pub const pwr3 = Cpu{ + pub const pwr3 = CpuModel{ .name = "pwr3", .llvm_name = "pwr3", .features = featureSet(&[_]Feature{ @@ -751,7 +752,7 @@ pub const cpu = struct { .stfiwx, }), }; - pub const pwr4 = Cpu{ + pub const pwr4 = CpuModel{ .name = "pwr4", .llvm_name = "pwr4", .features = featureSet(&[_]Feature{ @@ -764,7 +765,7 @@ pub const cpu = struct { .stfiwx, }), }; - pub const pwr5 = Cpu{ + pub const pwr5 = CpuModel{ .name = "pwr5", .llvm_name = "pwr5", .features = featureSet(&[_]Feature{ @@ -779,7 +780,7 @@ pub const cpu = struct { .stfiwx, }), }; - pub const pwr5x = Cpu{ + pub const pwr5x = CpuModel{ .name = "pwr5x", .llvm_name = "pwr5x", .features = featureSet(&[_]Feature{ @@ -795,7 +796,7 @@ pub const cpu = struct { .stfiwx, }), }; - pub const pwr6 = Cpu{ + pub const pwr6 = CpuModel{ .name = "pwr6", .llvm_name = "pwr6", .features = featureSet(&[_]Feature{ @@ -815,7 +816,7 @@ pub const cpu = struct { .stfiwx, }), }; - pub const pwr6x = Cpu{ + pub const pwr6x = CpuModel{ .name = "pwr6x", .llvm_name = "pwr6x", .features = featureSet(&[_]Feature{ @@ -835,7 +836,7 @@ pub const cpu = struct { .stfiwx, }), }; - pub const pwr7 = Cpu{ + pub const pwr7 = CpuModel{ .name = "pwr7", .llvm_name = "pwr7", .features = featureSet(&[_]Feature{ @@ -864,7 +865,7 @@ pub const cpu = struct { .vsx, }), }; - pub const pwr8 = Cpu{ + pub const pwr8 = CpuModel{ .name = "pwr8", .llvm_name = "pwr8", .features = featureSet(&[_]Feature{ @@ -900,7 +901,7 @@ pub const cpu = struct { .vsx, }), }; - pub const pwr9 = Cpu{ + pub const pwr9 = CpuModel{ .name = "pwr9", .llvm_name = "pwr9", .features = featureSet(&[_]Feature{ @@ -947,7 +948,7 @@ pub const cpu = struct { /// All powerpc CPUs, sorted alphabetically by name. /// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 /// compiler has inefficient memory and CPU usage, affecting build times. -pub const all_cpus = &[_]*const Cpu{ +pub const all_cpus = &[_]*const CpuModel{ &cpu.@"440", &cpu.@"450", &cpu.@"601", diff --git a/lib/std/target/riscv.zig b/lib/std/target/riscv.zig @@ -1,5 +1,6 @@ const std = @import("../std.zig"); -const Cpu = std.Target.Cpu; +const CpuFeature = std.Target.Cpu.Feature; +const CpuModel = std.Target.Cpu.Model; pub const Feature = enum { @"64bit", @@ -44,12 +45,12 @@ pub const Feature = enum { rvc_hints, }; -pub usingnamespace Cpu.Feature.feature_set_fns(Feature); +pub usingnamespace CpuFeature.feature_set_fns(Feature); pub const all_features = blk: { const len = @typeInfo(Feature).Enum.fields.len; - std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); - var result: [len]Cpu.Feature = undefined; + std.debug.assert(len <= CpuFeature.Set.needed_bit_count); + var result: [len]CpuFeature = undefined; result[@enumToInt(Feature.@"64bit")] = .{ .llvm_name = "64bit", .description = "Implements RV64", @@ -261,7 +262,7 @@ pub const all_features = blk: { }; pub const cpu = struct { - pub const baseline_rv32 = Cpu{ + pub const baseline_rv32 = CpuModel{ .name = "baseline_rv32", .llvm_name = null, .features = featureSet(&[_]Feature{ @@ -273,7 +274,7 @@ pub const cpu = struct { }), }; - pub const baseline_rv64 = Cpu{ + pub const baseline_rv64 = CpuModel{ .name = "baseline_rv64", .llvm_name = null, .features = featureSet(&[_]Feature{ @@ -286,14 +287,14 @@ pub const cpu = struct { }), }; - pub const generic_rv32 = Cpu{ + pub const generic_rv32 = CpuModel{ .name = "generic_rv32", .llvm_name = null, .features = featureSet(&[_]Feature{ .rvc_hints, }), }; - pub const generic_rv64 = Cpu{ + pub const generic_rv64 = CpuModel{ .name = "generic_rv64", .llvm_name = null, .features = featureSet(&[_]Feature{ @@ -306,7 +307,7 @@ pub const cpu = struct { /// All riscv CPUs, sorted alphabetically by name. /// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 /// compiler has inefficient memory and CPU usage, affecting build times. -pub const all_cpus = &[_]*const Cpu{ +pub const all_cpus = &[_]*const CpuModel{ &cpu.baseline_rv32, &cpu.baseline_rv64, &cpu.generic_rv32, diff --git a/lib/std/target/sparc.zig b/lib/std/target/sparc.zig @@ -1,5 +1,6 @@ const std = @import("../std.zig"); -const Cpu = std.Target.Cpu; +const CpuFeature = std.Target.Cpu.Feature; +const CpuModel = std.Target.Cpu.Model; pub const Feature = enum { deprecated_v8, @@ -23,12 +24,12 @@ pub const Feature = enum { vis3, }; -pub usingnamespace Cpu.Feature.feature_set_fns(Feature); +pub usingnamespace CpuFeature.feature_set_fns(Feature); pub const all_features = blk: { const len = @typeInfo(Feature).Enum.fields.len; - std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); - var result: [len]Cpu.Feature = undefined; + std.debug.assert(len <= CpuFeature.Set.needed_bit_count); + var result: [len]CpuFeature = undefined; result[@enumToInt(Feature.deprecated_v8)] = .{ .llvm_name = "deprecated-v8", .description = "Enable deprecated V8 instructions in V9 mode", @@ -133,7 +134,7 @@ pub const all_features = blk: { }; pub const cpu = struct { - pub const at697e = Cpu{ + pub const at697e = CpuModel{ .name = "at697e", .llvm_name = "at697e", .features = featureSet(&[_]Feature{ @@ -141,7 +142,7 @@ pub const cpu = struct { .leon, }), }; - pub const at697f = Cpu{ + pub const at697f = CpuModel{ .name = "at697f", .llvm_name = "at697f", .features = featureSet(&[_]Feature{ @@ -149,17 +150,17 @@ pub const cpu = struct { .leon, }), }; - pub const f934 = Cpu{ + pub const f934 = CpuModel{ .name = "f934", .llvm_name = "f934", .features = featureSet(&[_]Feature{}), }; - pub const generic = Cpu{ + pub const generic = CpuModel{ .name = "generic", .llvm_name = "generic", .features = featureSet(&[_]Feature{}), }; - pub const gr712rc = Cpu{ + pub const gr712rc = CpuModel{ .name = "gr712rc", .llvm_name = "gr712rc", .features = featureSet(&[_]Feature{ @@ -167,7 +168,7 @@ pub const cpu = struct { .leon, }), }; - pub const gr740 = Cpu{ + pub const gr740 = CpuModel{ .name = "gr740", .llvm_name = "gr740", .features = featureSet(&[_]Feature{ @@ -178,19 +179,19 @@ pub const cpu = struct { .leonpwrpsr, }), }; - pub const hypersparc = Cpu{ + pub const hypersparc = CpuModel{ .name = "hypersparc", .llvm_name = "hypersparc", .features = featureSet(&[_]Feature{}), }; - pub const leon2 = Cpu{ + pub const leon2 = CpuModel{ .name = "leon2", .llvm_name = "leon2", .features = featureSet(&[_]Feature{ .leon, }), }; - pub const leon3 = Cpu{ + pub const leon3 = CpuModel{ .name = "leon3", .llvm_name = "leon3", .features = featureSet(&[_]Feature{ @@ -198,7 +199,7 @@ pub const cpu = struct { .leon, }), }; - pub const leon4 = Cpu{ + pub const leon4 = CpuModel{ .name = "leon4", .llvm_name = "leon4", .features = featureSet(&[_]Feature{ @@ -207,7 +208,7 @@ pub const cpu = struct { .leon, }), }; - pub const ma2080 = Cpu{ + pub const ma2080 = CpuModel{ .name = "ma2080", .llvm_name = "ma2080", .features = featureSet(&[_]Feature{ @@ -215,7 +216,7 @@ pub const cpu = struct { .leon, }), }; - pub const ma2085 = Cpu{ + pub const ma2085 = CpuModel{ .name = "ma2085", .llvm_name = "ma2085", .features = featureSet(&[_]Feature{ @@ -223,7 +224,7 @@ pub const cpu = struct { .leon, }), }; - pub const ma2100 = Cpu{ + pub const ma2100 = CpuModel{ .name = "ma2100", .llvm_name = "ma2100", .features = featureSet(&[_]Feature{ @@ -231,7 +232,7 @@ pub const cpu = struct { .leon, }), }; - pub const ma2150 = Cpu{ + pub const ma2150 = CpuModel{ .name = "ma2150", .llvm_name = "ma2150", .features = featureSet(&[_]Feature{ @@ -239,7 +240,7 @@ pub const cpu = struct { .leon, }), }; - pub const ma2155 = Cpu{ + pub const ma2155 = CpuModel{ .name = "ma2155", .llvm_name = "ma2155", .features = featureSet(&[_]Feature{ @@ -247,7 +248,7 @@ pub const cpu = struct { .leon, }), }; - pub const ma2450 = Cpu{ + pub const ma2450 = CpuModel{ .name = "ma2450", .llvm_name = "ma2450", .features = featureSet(&[_]Feature{ @@ -255,7 +256,7 @@ pub const cpu = struct { .leon, }), }; - pub const ma2455 = Cpu{ + pub const ma2455 = CpuModel{ .name = "ma2455", .llvm_name = "ma2455", .features = featureSet(&[_]Feature{ @@ -263,7 +264,7 @@ pub const cpu = struct { .leon, }), }; - pub const ma2480 = Cpu{ + pub const ma2480 = CpuModel{ .name = "ma2480", .llvm_name = "ma2480", .features = featureSet(&[_]Feature{ @@ -271,7 +272,7 @@ pub const cpu = struct { .leon, }), }; - pub const ma2485 = Cpu{ + pub const ma2485 = CpuModel{ .name = "ma2485", .llvm_name = "ma2485", .features = featureSet(&[_]Feature{ @@ -279,7 +280,7 @@ pub const cpu = struct { .leon, }), }; - pub const ma2x5x = Cpu{ + pub const ma2x5x = CpuModel{ .name = "ma2x5x", .llvm_name = "ma2x5x", .features = featureSet(&[_]Feature{ @@ -287,7 +288,7 @@ pub const cpu = struct { .leon, }), }; - pub const ma2x8x = Cpu{ + pub const ma2x8x = CpuModel{ .name = "ma2x8x", .llvm_name = "ma2x8x", .features = featureSet(&[_]Feature{ @@ -295,7 +296,7 @@ pub const cpu = struct { .leon, }), }; - pub const myriad2 = Cpu{ + pub const myriad2 = CpuModel{ .name = "myriad2", .llvm_name = "myriad2", .features = featureSet(&[_]Feature{ @@ -303,7 +304,7 @@ pub const cpu = struct { .leon, }), }; - pub const myriad2_1 = Cpu{ + pub const myriad2_1 = CpuModel{ .name = "myriad2_1", .llvm_name = "myriad2.1", .features = featureSet(&[_]Feature{ @@ -311,7 +312,7 @@ pub const cpu = struct { .leon, }), }; - pub const myriad2_2 = Cpu{ + pub const myriad2_2 = CpuModel{ .name = "myriad2_2", .llvm_name = "myriad2.2", .features = featureSet(&[_]Feature{ @@ -319,7 +320,7 @@ pub const cpu = struct { .leon, }), }; - pub const myriad2_3 = Cpu{ + pub const myriad2_3 = CpuModel{ .name = "myriad2_3", .llvm_name = "myriad2.3", .features = featureSet(&[_]Feature{ @@ -327,7 +328,7 @@ pub const cpu = struct { .leon, }), }; - pub const niagara = Cpu{ + pub const niagara = CpuModel{ .name = "niagara", .llvm_name = "niagara", .features = featureSet(&[_]Feature{ @@ -337,7 +338,7 @@ pub const cpu = struct { .vis2, }), }; - pub const niagara2 = Cpu{ + pub const niagara2 = CpuModel{ .name = "niagara2", .llvm_name = "niagara2", .features = featureSet(&[_]Feature{ @@ -348,7 +349,7 @@ pub const cpu = struct { .vis2, }), }; - pub const niagara3 = Cpu{ + pub const niagara3 = CpuModel{ .name = "niagara3", .llvm_name = "niagara3", .features = featureSet(&[_]Feature{ @@ -359,7 +360,7 @@ pub const cpu = struct { .vis2, }), }; - pub const niagara4 = Cpu{ + pub const niagara4 = CpuModel{ .name = "niagara4", .llvm_name = "niagara4", .features = featureSet(&[_]Feature{ @@ -371,32 +372,32 @@ pub const cpu = struct { .vis3, }), }; - pub const sparclet = Cpu{ + pub const sparclet = CpuModel{ .name = "sparclet", .llvm_name = "sparclet", .features = featureSet(&[_]Feature{}), }; - pub const sparclite = Cpu{ + pub const sparclite = CpuModel{ .name = "sparclite", .llvm_name = "sparclite", .features = featureSet(&[_]Feature{}), }; - pub const sparclite86x = Cpu{ + pub const sparclite86x = CpuModel{ .name = "sparclite86x", .llvm_name = "sparclite86x", .features = featureSet(&[_]Feature{}), }; - pub const supersparc = Cpu{ + pub const supersparc = CpuModel{ .name = "supersparc", .llvm_name = "supersparc", .features = featureSet(&[_]Feature{}), }; - pub const tsc701 = Cpu{ + pub const tsc701 = CpuModel{ .name = "tsc701", .llvm_name = "tsc701", .features = featureSet(&[_]Feature{}), }; - pub const ultrasparc = Cpu{ + pub const ultrasparc = CpuModel{ .name = "ultrasparc", .llvm_name = "ultrasparc", .features = featureSet(&[_]Feature{ @@ -405,7 +406,7 @@ pub const cpu = struct { .vis, }), }; - pub const ultrasparc3 = Cpu{ + pub const ultrasparc3 = CpuModel{ .name = "ultrasparc3", .llvm_name = "ultrasparc3", .features = featureSet(&[_]Feature{ @@ -415,7 +416,7 @@ pub const cpu = struct { .vis2, }), }; - pub const ut699 = Cpu{ + pub const ut699 = CpuModel{ .name = "ut699", .llvm_name = "ut699", .features = featureSet(&[_]Feature{ @@ -426,7 +427,7 @@ pub const cpu = struct { .no_fsmuld, }), }; - pub const v7 = Cpu{ + pub const v7 = CpuModel{ .name = "v7", .llvm_name = "v7", .features = featureSet(&[_]Feature{ @@ -434,12 +435,12 @@ pub const cpu = struct { .soft_mul_div, }), }; - pub const v8 = Cpu{ + pub const v8 = CpuModel{ .name = "v8", .llvm_name = "v8", .features = featureSet(&[_]Feature{}), }; - pub const v9 = Cpu{ + pub const v9 = CpuModel{ .name = "v9", .llvm_name = "v9", .features = featureSet(&[_]Feature{ @@ -451,7 +452,7 @@ pub const cpu = struct { /// All sparc CPUs, sorted alphabetically by name. /// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 /// compiler has inefficient memory and CPU usage, affecting build times. -pub const all_cpus = &[_]*const Cpu{ +pub const all_cpus = &[_]*const CpuModel{ &cpu.at697e, &cpu.at697f, &cpu.f934, diff --git a/lib/std/target/systemz.zig b/lib/std/target/systemz.zig @@ -1,5 +1,6 @@ const std = @import("../std.zig"); -const Cpu = std.Target.Cpu; +const CpuFeature = std.Target.Cpu.Feature; +const CpuModel = std.Target.Cpu.Model; pub const Feature = enum { deflate_conversion, @@ -39,12 +40,12 @@ pub const Feature = enum { vector_packed_decimal_enhancement, }; -pub usingnamespace Cpu.Feature.feature_set_fns(Feature); +pub usingnamespace CpuFeature.feature_set_fns(Feature); pub const all_features = blk: { const len = @typeInfo(Feature).Enum.fields.len; - std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); - var result: [len]Cpu.Feature = undefined; + std.debug.assert(len <= CpuFeature.Set.needed_bit_count); + var result: [len]CpuFeature = undefined; result[@enumToInt(Feature.deflate_conversion)] = .{ .llvm_name = "deflate-conversion", .description = "Assume that the deflate-conversion facility is installed", @@ -229,7 +230,7 @@ pub const all_features = blk: { }; pub const cpu = struct { - pub const arch10 = Cpu{ + pub const arch10 = CpuModel{ .name = "arch10", .llvm_name = "arch10", .features = featureSet(&[_]Feature{ @@ -252,7 +253,7 @@ pub const cpu = struct { .transactional_execution, }), }; - pub const arch11 = Cpu{ + pub const arch11 = CpuModel{ .name = "arch11", .llvm_name = "arch11", .features = featureSet(&[_]Feature{ @@ -280,7 +281,7 @@ pub const cpu = struct { .vector, }), }; - pub const arch12 = Cpu{ + pub const arch12 = CpuModel{ .name = "arch12", .llvm_name = "arch12", .features = featureSet(&[_]Feature{ @@ -315,7 +316,7 @@ pub const cpu = struct { .vector_packed_decimal, }), }; - pub const arch13 = Cpu{ + pub const arch13 = CpuModel{ .name = "arch13", .llvm_name = "arch13", .features = featureSet(&[_]Feature{ @@ -356,12 +357,12 @@ pub const cpu = struct { .vector_packed_decimal_enhancement, }), }; - pub const arch8 = Cpu{ + pub const arch8 = CpuModel{ .name = "arch8", .llvm_name = "arch8", .features = featureSet(&[_]Feature{}), }; - pub const arch9 = Cpu{ + pub const arch9 = CpuModel{ .name = "arch9", .llvm_name = "arch9", .features = featureSet(&[_]Feature{ @@ -377,17 +378,17 @@ pub const cpu = struct { .reset_reference_bits_multiple, }), }; - pub const generic = Cpu{ + pub const generic = CpuModel{ .name = "generic", .llvm_name = "generic", .features = featureSet(&[_]Feature{}), }; - pub const z10 = Cpu{ + pub const z10 = CpuModel{ .name = "z10", .llvm_name = "z10", .features = featureSet(&[_]Feature{}), }; - pub const z13 = Cpu{ + pub const z13 = CpuModel{ .name = "z13", .llvm_name = "z13", .features = featureSet(&[_]Feature{ @@ -415,7 +416,7 @@ pub const cpu = struct { .vector, }), }; - pub const z14 = Cpu{ + pub const z14 = CpuModel{ .name = "z14", .llvm_name = "z14", .features = featureSet(&[_]Feature{ @@ -450,7 +451,7 @@ pub const cpu = struct { .vector_packed_decimal, }), }; - pub const z15 = Cpu{ + pub const z15 = CpuModel{ .name = "z15", .llvm_name = "z15", .features = featureSet(&[_]Feature{ @@ -491,7 +492,7 @@ pub const cpu = struct { .vector_packed_decimal_enhancement, }), }; - pub const z196 = Cpu{ + pub const z196 = CpuModel{ .name = "z196", .llvm_name = "z196", .features = featureSet(&[_]Feature{ @@ -507,7 +508,7 @@ pub const cpu = struct { .reset_reference_bits_multiple, }), }; - pub const zEC12 = Cpu{ + pub const zEC12 = CpuModel{ .name = "zEC12", .llvm_name = "zEC12", .features = featureSet(&[_]Feature{ @@ -535,7 +536,7 @@ pub const cpu = struct { /// All systemz CPUs, sorted alphabetically by name. /// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 /// compiler has inefficient memory and CPU usage, affecting build times. -pub const all_cpus = &[_]*const Cpu{ +pub const all_cpus = &[_]*const CpuModel{ &cpu.arch10, &cpu.arch11, &cpu.arch12, diff --git a/lib/std/target/wasm.zig b/lib/std/target/wasm.zig @@ -1,5 +1,6 @@ const std = @import("../std.zig"); -const Cpu = std.Target.Cpu; +const CpuFeature = std.Target.Cpu.Feature; +const CpuModel = std.Target.Cpu.Model; pub const Feature = enum { atomics, @@ -14,12 +15,12 @@ pub const Feature = enum { unimplemented_simd128, }; -pub usingnamespace Cpu.Feature.feature_set_fns(Feature); +pub usingnamespace CpuFeature.feature_set_fns(Feature); pub const all_features = blk: { const len = @typeInfo(Feature).Enum.fields.len; - std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); - var result: [len]Cpu.Feature = undefined; + std.debug.assert(len <= CpuFeature.Set.needed_bit_count); + var result: [len]CpuFeature = undefined; result[@enumToInt(Feature.atomics)] = .{ .llvm_name = "atomics", .description = "Enable Atomics", @@ -81,7 +82,7 @@ pub const all_features = blk: { }; pub const cpu = struct { - pub const bleeding_edge = Cpu{ + pub const bleeding_edge = CpuModel{ .name = "bleeding_edge", .llvm_name = "bleeding-edge", .features = featureSet(&[_]Feature{ @@ -92,12 +93,12 @@ pub const cpu = struct { .simd128, }), }; - pub const generic = Cpu{ + pub const generic = CpuModel{ .name = "generic", .llvm_name = "generic", .features = featureSet(&[_]Feature{}), }; - pub const mvp = Cpu{ + pub const mvp = CpuModel{ .name = "mvp", .llvm_name = "mvp", .features = featureSet(&[_]Feature{}), @@ -107,7 +108,7 @@ pub const cpu = struct { /// All wasm CPUs, sorted alphabetically by name. /// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 /// compiler has inefficient memory and CPU usage, affecting build times. -pub const all_cpus = &[_]*const Cpu{ +pub const all_cpus = &[_]*const CpuModel{ &cpu.bleeding_edge, &cpu.generic, &cpu.mvp, diff --git a/lib/std/target/x86.zig b/lib/std/target/x86.zig @@ -1,5 +1,6 @@ const std = @import("../std.zig"); -const Cpu = std.Target.Cpu; +const CpuFeature = std.Target.Cpu.Feature; +const CpuModel = std.Target.Cpu.Model; pub const Feature = enum { @"3dnow", @@ -129,12 +130,12 @@ pub const Feature = enum { xsaves, }; -pub usingnamespace Cpu.Feature.feature_set_fns(Feature); +pub usingnamespace CpuFeature.feature_set_fns(Feature); pub const all_features = blk: { const len = @typeInfo(Feature).Enum.fields.len; - std.debug.assert(len <= Cpu.Feature.Set.needed_bit_count); - var result: [len]Cpu.Feature = undefined; + std.debug.assert(len <= CpuFeature.Set.needed_bit_count); + var result: [len]CpuFeature = undefined; result[@enumToInt(Feature.@"3dnow")] = .{ .llvm_name = "3dnow", .description = "Enable 3DNow! instructions", @@ -851,7 +852,7 @@ pub const all_features = blk: { }; pub const cpu = struct { - pub const amdfam10 = Cpu{ + pub const amdfam10 = CpuModel{ .name = "amdfam10", .llvm_name = "amdfam10", .features = featureSet(&[_]Feature{ @@ -872,7 +873,7 @@ pub const cpu = struct { .x87, }), }; - pub const athlon = Cpu{ + pub const athlon = CpuModel{ .name = "athlon", .llvm_name = "athlon", .features = featureSet(&[_]Feature{ @@ -886,7 +887,7 @@ pub const cpu = struct { .x87, }), }; - pub const athlon_4 = Cpu{ + pub const athlon_4 = CpuModel{ .name = "athlon_4", .llvm_name = "athlon-4", .features = featureSet(&[_]Feature{ @@ -902,7 +903,7 @@ pub const cpu = struct { .x87, }), }; - pub const athlon_fx = Cpu{ + pub const athlon_fx = CpuModel{ .name = "athlon_fx", .llvm_name = "athlon-fx", .features = featureSet(&[_]Feature{ @@ -920,7 +921,7 @@ pub const cpu = struct { .x87, }), }; - pub const athlon_mp = Cpu{ + pub const athlon_mp = CpuModel{ .name = "athlon_mp", .llvm_name = "athlon-mp", .features = featureSet(&[_]Feature{ @@ -936,7 +937,7 @@ pub const cpu = struct { .x87, }), }; - pub const athlon_tbird = Cpu{ + pub const athlon_tbird = CpuModel{ .name = "athlon_tbird", .llvm_name = "athlon-tbird", .features = featureSet(&[_]Feature{ @@ -950,7 +951,7 @@ pub const cpu = struct { .x87, }), }; - pub const athlon_xp = Cpu{ + pub const athlon_xp = CpuModel{ .name = "athlon_xp", .llvm_name = "athlon-xp", .features = featureSet(&[_]Feature{ @@ -966,7 +967,7 @@ pub const cpu = struct { .x87, }), }; - pub const athlon64 = Cpu{ + pub const athlon64 = CpuModel{ .name = "athlon64", .llvm_name = "athlon64", .features = featureSet(&[_]Feature{ @@ -984,7 +985,7 @@ pub const cpu = struct { .x87, }), }; - pub const athlon64_sse3 = Cpu{ + pub const athlon64_sse3 = CpuModel{ .name = "athlon64_sse3", .llvm_name = "athlon64-sse3", .features = featureSet(&[_]Feature{ @@ -1003,7 +1004,7 @@ pub const cpu = struct { .x87, }), }; - pub const atom = Cpu{ + pub const atom = CpuModel{ .name = "atom", .llvm_name = "atom", .features = featureSet(&[_]Feature{ @@ -1028,7 +1029,7 @@ pub const cpu = struct { .x87, }), }; - pub const barcelona = Cpu{ + pub const barcelona = CpuModel{ .name = "barcelona", .llvm_name = "barcelona", .features = featureSet(&[_]Feature{ @@ -1049,7 +1050,7 @@ pub const cpu = struct { .x87, }), }; - pub const bdver1 = Cpu{ + pub const bdver1 = CpuModel{ .name = "bdver1", .llvm_name = "bdver1", .features = featureSet(&[_]Feature{ @@ -1077,7 +1078,7 @@ pub const cpu = struct { .xsave, }), }; - pub const bdver2 = Cpu{ + pub const bdver2 = CpuModel{ .name = "bdver2", .llvm_name = "bdver2", .features = featureSet(&[_]Feature{ @@ -1110,7 +1111,7 @@ pub const cpu = struct { .xsave, }), }; - pub const bdver3 = Cpu{ + pub const bdver3 = CpuModel{ .name = "bdver3", .llvm_name = "bdver3", .features = featureSet(&[_]Feature{ @@ -1145,7 +1146,7 @@ pub const cpu = struct { .xsaveopt, }), }; - pub const bdver4 = Cpu{ + pub const bdver4 = CpuModel{ .name = "bdver4", .llvm_name = "bdver4", .features = featureSet(&[_]Feature{ @@ -1183,7 +1184,7 @@ pub const cpu = struct { .xsaveopt, }), }; - pub const bonnell = Cpu{ + pub const bonnell = CpuModel{ .name = "bonnell", .llvm_name = "bonnell", .features = featureSet(&[_]Feature{ @@ -1208,7 +1209,7 @@ pub const cpu = struct { .x87, }), }; - pub const broadwell = Cpu{ + pub const broadwell = CpuModel{ .name = "broadwell", .llvm_name = "broadwell", .features = featureSet(&[_]Feature{ @@ -1253,7 +1254,7 @@ pub const cpu = struct { .xsaveopt, }), }; - pub const btver1 = Cpu{ + pub const btver1 = CpuModel{ .name = "btver1", .llvm_name = "btver1", .features = featureSet(&[_]Feature{ @@ -1278,7 +1279,7 @@ pub const cpu = struct { .x87, }), }; - pub const btver2 = Cpu{ + pub const btver2 = CpuModel{ .name = "btver2", .llvm_name = "btver2", .features = featureSet(&[_]Feature{ @@ -1313,7 +1314,7 @@ pub const cpu = struct { .xsaveopt, }), }; - pub const c3 = Cpu{ + pub const c3 = CpuModel{ .name = "c3", .llvm_name = "c3", .features = featureSet(&[_]Feature{ @@ -1323,7 +1324,7 @@ pub const cpu = struct { .x87, }), }; - pub const c3_2 = Cpu{ + pub const c3_2 = CpuModel{ .name = "c3_2", .llvm_name = "c3-2", .features = featureSet(&[_]Feature{ @@ -1337,7 +1338,7 @@ pub const cpu = struct { .x87, }), }; - pub const cannonlake = Cpu{ + pub const cannonlake = CpuModel{ .name = "cannonlake", .llvm_name = "cannonlake", .features = featureSet(&[_]Feature{ @@ -1397,7 +1398,7 @@ pub const cpu = struct { .xsaves, }), }; - pub const cascadelake = Cpu{ + pub const cascadelake = CpuModel{ .name = "cascadelake", .llvm_name = "cascadelake", .features = featureSet(&[_]Feature{ @@ -1456,7 +1457,7 @@ pub const cpu = struct { .xsaves, }), }; - pub const cooperlake = Cpu{ + pub const cooperlake = CpuModel{ .name = "cooperlake", .llvm_name = "cooperlake", .features = featureSet(&[_]Feature{ @@ -1516,7 +1517,7 @@ pub const cpu = struct { .xsaves, }), }; - pub const core_avx_i = Cpu{ + pub const core_avx_i = CpuModel{ .name = "core_avx_i", .llvm_name = "core-avx-i", .features = featureSet(&[_]Feature{ @@ -1549,7 +1550,7 @@ pub const cpu = struct { .xsaveopt, }), }; - pub const core_avx2 = Cpu{ + pub const core_avx2 = CpuModel{ .name = "core_avx2", .llvm_name = "core-avx2", .features = featureSet(&[_]Feature{ @@ -1591,7 +1592,7 @@ pub const cpu = struct { .xsaveopt, }), }; - pub const core2 = Cpu{ + pub const core2 = CpuModel{ .name = "core2", .llvm_name = "core2", .features = featureSet(&[_]Feature{ @@ -1610,7 +1611,7 @@ pub const cpu = struct { .x87, }), }; - pub const corei7 = Cpu{ + pub const corei7 = CpuModel{ .name = "corei7", .llvm_name = "corei7", .features = featureSet(&[_]Feature{ @@ -1629,7 +1630,7 @@ pub const cpu = struct { .x87, }), }; - pub const corei7_avx = Cpu{ + pub const corei7_avx = CpuModel{ .name = "corei7_avx", .llvm_name = "corei7-avx", .features = featureSet(&[_]Feature{ @@ -1659,7 +1660,7 @@ pub const cpu = struct { .xsaveopt, }), }; - pub const generic = Cpu{ + pub const generic = CpuModel{ .name = "generic", .llvm_name = "generic", .features = featureSet(&[_]Feature{ @@ -1669,7 +1670,7 @@ pub const cpu = struct { .x87, }), }; - pub const geode = Cpu{ + pub const geode = CpuModel{ .name = "geode", .llvm_name = "geode", .features = featureSet(&[_]Feature{ @@ -1680,7 +1681,7 @@ pub const cpu = struct { .x87, }), }; - pub const goldmont = Cpu{ + pub const goldmont = CpuModel{ .name = "goldmont", .llvm_name = "goldmont", .features = featureSet(&[_]Feature{ @@ -1717,7 +1718,7 @@ pub const cpu = struct { .xsaves, }), }; - pub const goldmont_plus = Cpu{ + pub const goldmont_plus = CpuModel{ .name = "goldmont_plus", .llvm_name = "goldmont-plus", .features = featureSet(&[_]Feature{ @@ -1756,7 +1757,7 @@ pub const cpu = struct { .xsaves, }), }; - pub const haswell = Cpu{ + pub const haswell = CpuModel{ .name = "haswell", .llvm_name = "haswell", .features = featureSet(&[_]Feature{ @@ -1798,7 +1799,7 @@ pub const cpu = struct { .xsaveopt, }), }; - pub const _i386 = Cpu{ + pub const _i386 = CpuModel{ .name = "_i386", .llvm_name = "i386", .features = featureSet(&[_]Feature{ @@ -1807,7 +1808,7 @@ pub const cpu = struct { .x87, }), }; - pub const _i486 = Cpu{ + pub const _i486 = CpuModel{ .name = "_i486", .llvm_name = "i486", .features = featureSet(&[_]Feature{ @@ -1816,7 +1817,7 @@ pub const cpu = struct { .x87, }), }; - pub const _i586 = Cpu{ + pub const _i586 = CpuModel{ .name = "_i586", .llvm_name = "i586", .features = featureSet(&[_]Feature{ @@ -1826,7 +1827,7 @@ pub const cpu = struct { .x87, }), }; - pub const _i686 = Cpu{ + pub const _i686 = CpuModel{ .name = "_i686", .llvm_name = "i686", .features = featureSet(&[_]Feature{ @@ -1837,7 +1838,7 @@ pub const cpu = struct { .x87, }), }; - pub const icelake_client = Cpu{ + pub const icelake_client = CpuModel{ .name = "icelake_client", .llvm_name = "icelake-client", .features = featureSet(&[_]Feature{ @@ -1906,7 +1907,7 @@ pub const cpu = struct { .xsaves, }), }; - pub const icelake_server = Cpu{ + pub const icelake_server = CpuModel{ .name = "icelake_server", .llvm_name = "icelake-server", .features = featureSet(&[_]Feature{ @@ -1977,7 +1978,7 @@ pub const cpu = struct { .xsaves, }), }; - pub const ivybridge = Cpu{ + pub const ivybridge = CpuModel{ .name = "ivybridge", .llvm_name = "ivybridge", .features = featureSet(&[_]Feature{ @@ -2010,7 +2011,7 @@ pub const cpu = struct { .xsaveopt, }), }; - pub const k6 = Cpu{ + pub const k6 = CpuModel{ .name = "k6", .llvm_name = "k6", .features = featureSet(&[_]Feature{ @@ -2021,7 +2022,7 @@ pub const cpu = struct { .x87, }), }; - pub const k6_2 = Cpu{ + pub const k6_2 = CpuModel{ .name = "k6_2", .llvm_name = "k6-2", .features = featureSet(&[_]Feature{ @@ -2032,7 +2033,7 @@ pub const cpu = struct { .x87, }), }; - pub const k6_3 = Cpu{ + pub const k6_3 = CpuModel{ .name = "k6_3", .llvm_name = "k6-3", .features = featureSet(&[_]Feature{ @@ -2043,7 +2044,7 @@ pub const cpu = struct { .x87, }), }; - pub const k8 = Cpu{ + pub const k8 = CpuModel{ .name = "k8", .llvm_name = "k8", .features = featureSet(&[_]Feature{ @@ -2061,7 +2062,7 @@ pub const cpu = struct { .x87, }), }; - pub const k8_sse3 = Cpu{ + pub const k8_sse3 = CpuModel{ .name = "k8_sse3", .llvm_name = "k8-sse3", .features = featureSet(&[_]Feature{ @@ -2080,7 +2081,7 @@ pub const cpu = struct { .x87, }), }; - pub const knl = Cpu{ + pub const knl = CpuModel{ .name = "knl", .llvm_name = "knl", .features = featureSet(&[_]Feature{ @@ -2123,7 +2124,7 @@ pub const cpu = struct { .xsaveopt, }), }; - pub const knm = Cpu{ + pub const knm = CpuModel{ .name = "knm", .llvm_name = "knm", .features = featureSet(&[_]Feature{ @@ -2167,14 +2168,14 @@ pub const cpu = struct { .xsaveopt, }), }; - pub const lakemont = Cpu{ + pub const lakemont = CpuModel{ .name = "lakemont", .llvm_name = "lakemont", .features = featureSet(&[_]Feature{ .vzeroupper, }), }; - pub const nehalem = Cpu{ + pub const nehalem = CpuModel{ .name = "nehalem", .llvm_name = "nehalem", .features = featureSet(&[_]Feature{ @@ -2193,7 +2194,7 @@ pub const cpu = struct { .x87, }), }; - pub const nocona = Cpu{ + pub const nocona = CpuModel{ .name = "nocona", .llvm_name = "nocona", .features = featureSet(&[_]Feature{ @@ -2210,7 +2211,7 @@ pub const cpu = struct { .x87, }), }; - pub const opteron = Cpu{ + pub const opteron = CpuModel{ .name = "opteron", .llvm_name = "opteron", .features = featureSet(&[_]Feature{ @@ -2228,7 +2229,7 @@ pub const cpu = struct { .x87, }), }; - pub const opteron_sse3 = Cpu{ + pub const opteron_sse3 = CpuModel{ .name = "opteron_sse3", .llvm_name = "opteron-sse3", .features = featureSet(&[_]Feature{ @@ -2247,7 +2248,7 @@ pub const cpu = struct { .x87, }), }; - pub const penryn = Cpu{ + pub const penryn = CpuModel{ .name = "penryn", .llvm_name = "penryn", .features = featureSet(&[_]Feature{ @@ -2266,7 +2267,7 @@ pub const cpu = struct { .x87, }), }; - pub const pentium = Cpu{ + pub const pentium = CpuModel{ .name = "pentium", .llvm_name = "pentium", .features = featureSet(&[_]Feature{ @@ -2276,7 +2277,7 @@ pub const cpu = struct { .x87, }), }; - pub const pentium_m = Cpu{ + pub const pentium_m = CpuModel{ .name = "pentium_m", .llvm_name = "pentium-m", .features = featureSet(&[_]Feature{ @@ -2291,7 +2292,7 @@ pub const cpu = struct { .x87, }), }; - pub const pentium_mmx = Cpu{ + pub const pentium_mmx = CpuModel{ .name = "pentium_mmx", .llvm_name = "pentium-mmx", .features = featureSet(&[_]Feature{ @@ -2302,7 +2303,7 @@ pub const cpu = struct { .x87, }), }; - pub const pentium2 = Cpu{ + pub const pentium2 = CpuModel{ .name = "pentium2", .llvm_name = "pentium2", .features = featureSet(&[_]Feature{ @@ -2316,7 +2317,7 @@ pub const cpu = struct { .x87, }), }; - pub const pentium3 = Cpu{ + pub const pentium3 = CpuModel{ .name = "pentium3", .llvm_name = "pentium3", .features = featureSet(&[_]Feature{ @@ -2331,7 +2332,7 @@ pub const cpu = struct { .x87, }), }; - pub const pentium3m = Cpu{ + pub const pentium3m = CpuModel{ .name = "pentium3m", .llvm_name = "pentium3m", .features = featureSet(&[_]Feature{ @@ -2346,7 +2347,7 @@ pub const cpu = struct { .x87, }), }; - pub const pentium4 = Cpu{ + pub const pentium4 = CpuModel{ .name = "pentium4", .llvm_name = "pentium4", .features = featureSet(&[_]Feature{ @@ -2361,7 +2362,7 @@ pub const cpu = struct { .x87, }), }; - pub const pentium4m = Cpu{ + pub const pentium4m = CpuModel{ .name = "pentium4m", .llvm_name = "pentium4m", .features = featureSet(&[_]Feature{ @@ -2376,7 +2377,7 @@ pub const cpu = struct { .x87, }), }; - pub const pentiumpro = Cpu{ + pub const pentiumpro = CpuModel{ .name = "pentiumpro", .llvm_name = "pentiumpro", .features = featureSet(&[_]Feature{ @@ -2388,7 +2389,7 @@ pub const cpu = struct { .x87, }), }; - pub const prescott = Cpu{ + pub const prescott = CpuModel{ .name = "prescott", .llvm_name = "prescott", .features = featureSet(&[_]Feature{ @@ -2403,7 +2404,7 @@ pub const cpu = struct { .x87, }), }; - pub const sandybridge = Cpu{ + pub const sandybridge = CpuModel{ .name = "sandybridge", .llvm_name = "sandybridge", .features = featureSet(&[_]Feature{ @@ -2433,7 +2434,7 @@ pub const cpu = struct { .xsaveopt, }), }; - pub const silvermont = Cpu{ + pub const silvermont = CpuModel{ .name = "silvermont", .llvm_name = "silvermont", .features = featureSet(&[_]Feature{ @@ -2462,7 +2463,7 @@ pub const cpu = struct { .x87, }), }; - pub const skx = Cpu{ + pub const skx = CpuModel{ .name = "skx", .llvm_name = "skx", .features = featureSet(&[_]Feature{ @@ -2520,7 +2521,7 @@ pub const cpu = struct { .xsaves, }), }; - pub const skylake = Cpu{ + pub const skylake = CpuModel{ .name = "skylake", .llvm_name = "skylake", .features = featureSet(&[_]Feature{ @@ -2571,7 +2572,7 @@ pub const cpu = struct { .xsaves, }), }; - pub const skylake_avx512 = Cpu{ + pub const skylake_avx512 = CpuModel{ .name = "skylake_avx512", .llvm_name = "skylake-avx512", .features = featureSet(&[_]Feature{ @@ -2629,7 +2630,7 @@ pub const cpu = struct { .xsaves, }), }; - pub const slm = Cpu{ + pub const slm = CpuModel{ .name = "slm", .llvm_name = "slm", .features = featureSet(&[_]Feature{ @@ -2658,7 +2659,7 @@ pub const cpu = struct { .x87, }), }; - pub const tigerlake = Cpu{ + pub const tigerlake = CpuModel{ .name = "tigerlake", .llvm_name = "tigerlake", .features = featureSet(&[_]Feature{ @@ -2731,7 +2732,7 @@ pub const cpu = struct { .xsaves, }), }; - pub const tremont = Cpu{ + pub const tremont = CpuModel{ .name = "tremont", .llvm_name = "tremont", .features = featureSet(&[_]Feature{ @@ -2775,7 +2776,7 @@ pub const cpu = struct { .xsaves, }), }; - pub const westmere = Cpu{ + pub const westmere = CpuModel{ .name = "westmere", .llvm_name = "westmere", .features = featureSet(&[_]Feature{ @@ -2795,7 +2796,7 @@ pub const cpu = struct { .x87, }), }; - pub const winchip_c6 = Cpu{ + pub const winchip_c6 = CpuModel{ .name = "winchip_c6", .llvm_name = "winchip-c6", .features = featureSet(&[_]Feature{ @@ -2805,7 +2806,7 @@ pub const cpu = struct { .x87, }), }; - pub const winchip2 = Cpu{ + pub const winchip2 = CpuModel{ .name = "winchip2", .llvm_name = "winchip2", .features = featureSet(&[_]Feature{ @@ -2815,7 +2816,7 @@ pub const cpu = struct { .x87, }), }; - pub const x86_64 = Cpu{ + pub const x86_64 = CpuModel{ .name = "x86_64", .llvm_name = "x86-64", .features = featureSet(&[_]Feature{ @@ -2833,7 +2834,7 @@ pub const cpu = struct { .x87, }), }; - pub const yonah = Cpu{ + pub const yonah = CpuModel{ .name = "yonah", .llvm_name = "yonah", .features = featureSet(&[_]Feature{ @@ -2848,7 +2849,7 @@ pub const cpu = struct { .x87, }), }; - pub const znver1 = Cpu{ + pub const znver1 = CpuModel{ .name = "znver1", .llvm_name = "znver1", .features = featureSet(&[_]Feature{ @@ -2893,7 +2894,7 @@ pub const cpu = struct { .xsaves, }), }; - pub const znver2 = Cpu{ + pub const znver2 = CpuModel{ .name = "znver2", .llvm_name = "znver2", .features = featureSet(&[_]Feature{ @@ -2946,7 +2947,7 @@ pub const cpu = struct { /// All x86 CPUs, sorted alphabetically by name. /// TODO: Replace this with usage of `std.meta.declList`. It does work, but stage1 /// compiler has inefficient memory and CPU usage, affecting build times. -pub const all_cpus = &[_]*const Cpu{ +pub const all_cpus = &[_]*const CpuModel{ &cpu.amdfam10, &cpu.athlon, &cpu.athlon_4, diff --git a/lib/std/thread.zig b/lib/std/thread.zig @@ -148,7 +148,7 @@ pub const Thread = struct { const default_stack_size = 16 * 1024 * 1024; const Context = @TypeOf(context); - comptime assert(@ArgType(@TypeOf(startFn), 0) == Context); + comptime assert(@typeInfo(@TypeOf(startFn)).Fn.args[0].arg_type.? == Context); if (builtin.os == builtin.Os.windows) { const WinThread = struct { @@ -158,7 +158,7 @@ pub const Thread = struct { }; fn threadMain(raw_arg: windows.LPVOID) callconv(.C) windows.DWORD { const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*; - switch (@typeId(@TypeOf(startFn).ReturnType)) { + switch (@typeInfo(@TypeOf(startFn).ReturnType)) { .Int => { return startFn(arg); }, @@ -201,7 +201,7 @@ pub const Thread = struct { fn linuxThreadMain(ctx_addr: usize) callconv(.C) u8 { const arg = if (@sizeOf(Context) == 0) {} else @intToPtr(*const Context, ctx_addr).*; - switch (@typeId(@TypeOf(startFn).ReturnType)) { + switch (@typeInfo(@TypeOf(startFn).ReturnType)) { .Int => { return startFn(arg); }, diff --git a/lib/std/time.zig b/lib/std/time.zig @@ -8,6 +8,7 @@ const math = std.math; pub const epoch = @import("time/epoch.zig"); /// Spurious wakeups are possible and no precision of timing is guaranteed. +/// TODO integrate with evented I/O pub fn sleep(nanoseconds: u64) void { if (builtin.os == .windows) { const ns_per_ms = ns_per_s / ms_per_s; @@ -152,15 +153,9 @@ pub const Timer = struct { } /// Reads the timer value since start or the last reset in nanoseconds - pub fn read(self: *Timer) u64 { + pub fn read(self: Timer) u64 { var clock = clockNative() - self.start_time; - if (builtin.os == .windows) { - return @divFloor(clock * ns_per_s, self.frequency); - } - if (comptime std.Target.current.isDarwin()) { - return @divFloor(clock * self.frequency.numer, self.frequency.denom); - } - return clock; + return self.nativeDurationToNanos(clock); } /// Resets the timer value to 0/now. @@ -171,7 +166,7 @@ pub const Timer = struct { /// Returns the current value of the timer in nanoseconds, then resets it pub fn lap(self: *Timer) u64 { var now = clockNative(); - var lap_time = self.read(); + var lap_time = self.nativeDurationToNanos(now - self.start_time); self.start_time = now; return lap_time; } @@ -187,6 +182,16 @@ pub const Timer = struct { os.clock_gettime(monotonic_clock_id, &ts) catch unreachable; return @intCast(u64, ts.tv_sec) * @as(u64, ns_per_s) + @intCast(u64, ts.tv_nsec); } + + fn nativeDurationToNanos(self: Timer, duration: u64) u64 { + if (builtin.os == .windows) { + return @divFloor(duration * ns_per_s, self.frequency); + } + if (comptime std.Target.current.isDarwin()) { + return @divFloor(duration * self.frequency.numer, self.frequency.denom); + } + return duration; + } }; test "sleep" { diff --git a/lib/std/unicode.zig b/lib/std/unicode.zig @@ -243,7 +243,7 @@ pub const Utf16LeIterator = struct { pub fn init(s: []const u16) Utf16LeIterator { return Utf16LeIterator{ - .bytes = @sliceToBytes(s), + .bytes = mem.sliceAsBytes(s), .i = 0, }; } @@ -496,7 +496,7 @@ pub fn utf16leToUtf8(utf8: []u8, utf16le: []const u16) !usize { test "utf16leToUtf8" { var utf16le: [2]u16 = undefined; - const utf16le_as_bytes = @sliceToBytes(utf16le[0..]); + const utf16le_as_bytes = mem.sliceAsBytes(utf16le[0..]); { mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 'A'); @@ -606,12 +606,12 @@ test "utf8ToUtf16Le" { { const length = try utf8ToUtf16Le(utf16le[0..], "𐐷"); testing.expectEqual(@as(usize, 2), length); - testing.expectEqualSlices(u8, "\x01\xd8\x37\xdc", @sliceToBytes(utf16le[0..])); + testing.expectEqualSlices(u8, "\x01\xd8\x37\xdc", mem.sliceAsBytes(utf16le[0..])); } { const length = try utf8ToUtf16Le(utf16le[0..], "\u{10FFFF}"); testing.expectEqual(@as(usize, 2), length); - testing.expectEqualSlices(u8, "\xff\xdb\xff\xdf", @sliceToBytes(utf16le[0..])); + testing.expectEqualSlices(u8, "\xff\xdb\xff\xdf", mem.sliceAsBytes(utf16le[0..])); } } @@ -619,13 +619,13 @@ test "utf8ToUtf16LeWithNull" { { const utf16 = try utf8ToUtf16LeWithNull(testing.allocator, "𐐷"); defer testing.allocator.free(utf16); - testing.expectEqualSlices(u8, "\x01\xd8\x37\xdc", @sliceToBytes(utf16[0..])); + testing.expectEqualSlices(u8, "\x01\xd8\x37\xdc", mem.sliceAsBytes(utf16[0..])); testing.expect(utf16[2] == 0); } { const utf16 = try utf8ToUtf16LeWithNull(testing.allocator, "\u{10FFFF}"); defer testing.allocator.free(utf16); - testing.expectEqualSlices(u8, "\xff\xdb\xff\xdf", @sliceToBytes(utf16[0..])); + testing.expectEqualSlices(u8, "\xff\xdb\xff\xdf", mem.sliceAsBytes(utf16[0..])); testing.expect(utf16[2] == 0); } } diff --git a/lib/std/zig.zig b/lib/std/zig.zig @@ -5,6 +5,7 @@ pub const parse = @import("zig/parse.zig").parse; pub const parseStringLiteral = @import("zig/parse_string_literal.zig").parseStringLiteral; pub const render = @import("zig/render.zig").render; pub const ast = @import("zig/ast.zig"); +pub const system = @import("zig/system.zig"); test "std.zig tests" { _ = @import("zig/ast.zig"); diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig @@ -460,10 +460,9 @@ pub const Node = struct { } pub fn iterate(base: *Node, index: usize) ?*Node { - comptime var i = 0; - inline while (i < @memberCount(Id)) : (i += 1) { - if (base.id == @field(Id, @memberName(Id, i))) { - const T = @field(Node, @memberName(Id, i)); + inline for (@typeInfo(Id).Enum.fields) |f| { + if (base.id == @field(Id, f.name)) { + const T = @field(Node, f.name); return @fieldParentPtr(T, "base", base).iterate(index); } } @@ -471,10 +470,9 @@ pub const Node = struct { } pub fn firstToken(base: *const Node) TokenIndex { - comptime var i = 0; - inline while (i < @memberCount(Id)) : (i += 1) { - if (base.id == @field(Id, @memberName(Id, i))) { - const T = @field(Node, @memberName(Id, i)); + inline for (@typeInfo(Id).Enum.fields) |f| { + if (base.id == @field(Id, f.name)) { + const T = @field(Node, f.name); return @fieldParentPtr(T, "base", base).firstToken(); } } @@ -482,10 +480,9 @@ pub const Node = struct { } pub fn lastToken(base: *const Node) TokenIndex { - comptime var i = 0; - inline while (i < @memberCount(Id)) : (i += 1) { - if (base.id == @field(Id, @memberName(Id, i))) { - const T = @field(Node, @memberName(Id, i)); + inline for (@typeInfo(Id).Enum.fields) |f| { + if (base.id == @field(Id, f.name)) { + const T = @field(Node, f.name); return @fieldParentPtr(T, "base", base).lastToken(); } } @@ -493,10 +490,9 @@ pub const Node = struct { } pub fn typeToId(comptime T: type) Id { - comptime var i = 0; - inline while (i < @memberCount(Id)) : (i += 1) { - if (T == @field(Node, @memberName(Id, i))) { - return @field(Id, @memberName(Id, i)); + inline for (@typeInfo(Id).Enum.fields) |f| { + if (T == @field(Node, f.name)) { + return @field(Id, f.name); } } unreachable; @@ -1567,7 +1563,9 @@ pub const Node = struct { pub const Op = union(enum) { AddressOf, ArrayType: ArrayInfo, - Await, + Await: struct { + noasync_token: ?TokenIndex = null, + }, BitNot, BoolNot, Cancel, @@ -2184,10 +2182,10 @@ pub const Node = struct { pub fn iterate(self: *Asm, index: usize) ?*Node { var i = index; - if (i < self.outputs.len) return &self.outputs.at(index).*.base; + if (i < self.outputs.len) return &self.outputs.at(i).*.base; i -= self.outputs.len; - if (i < self.inputs.len) return &self.inputs.at(index).*.base; + if (i < self.inputs.len) return &self.inputs.at(i).*.base; i -= self.inputs.len; return null; diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig @@ -1129,7 +1129,7 @@ fn parseErrorUnionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No /// / KEYWORD_noasync PrimaryTypeExpr SuffixOp* FnCallArguments /// / PrimaryTypeExpr (SuffixOp / FnCallArguments)* fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { - var maybe_async = eatAnnotatedToken(it, .Keyword_async) orelse eatAnnotatedToken(it, .Keyword_noasync); + const maybe_async = eatAnnotatedToken(it, .Keyword_async) orelse eatAnnotatedToken(it, .Keyword_noasync); if (maybe_async) |async_token| { const token_fn = eatToken(it, .Keyword_fn); if (async_token.ptr.id == .Keyword_async and token_fn != null) { @@ -2179,7 +2179,19 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { .MinusPercent => ops{ .NegationWrap = {} }, .Ampersand => ops{ .AddressOf = {} }, .Keyword_try => ops{ .Try = {} }, - .Keyword_await => ops{ .Await = {} }, + .Keyword_await => ops{ .Await = .{} }, + .Keyword_noasync => if (eatToken(it, .Keyword_await)) |await_tok| { + const node = try arena.create(Node.PrefixOp); + node.* = Node.PrefixOp{ + .op_token = await_tok, + .op = .{ .Await = .{ .noasync_token = token.index } }, + .rhs = undefined, // set by caller + }; + return &node.base; + } else { + putBackToken(it, token.index); + return null; + }, else => { putBackToken(it, token.index); return null; diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig @@ -1,3 +1,12 @@ +test "zig fmt: noasync await" { + try testCanonical( + \\fn foo() void { + \\ x = noasync await y; + \\} + \\ + ); +} + test "zig fmt: trailing comma in container declaration" { try testCanonical( \\const X = struct { foo: i32 }; @@ -83,10 +92,12 @@ test "zig fmt: convert extern/nakedcc/stdcallcc into callconv(...)" { \\nakedcc fn foo1() void {} \\stdcallcc fn foo2() void {} \\extern fn foo3() void {} + \\extern "mylib" fn foo4() void {} , \\fn foo1() callconv(.Naked) void {} \\fn foo2() callconv(.Stdcall) void {} \\fn foo3() callconv(.C) void {} + \\fn foo4() callconv(.C) void {} \\ ); } @@ -1399,7 +1410,7 @@ test "zig fmt: same-line comment after non-block if expression" { test "zig fmt: same-line comment on comptime expression" { try testCanonical( \\test "" { - \\ comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt + \\ comptime assert(@typeInfo(T) == .Int); // must pass an integer to absInt \\} \\ ); diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig @@ -1,5 +1,4 @@ const std = @import("../std.zig"); -const builtin = @import("builtin"); const assert = std.debug.assert; const mem = std.mem; const ast = std.zig.ast; @@ -14,7 +13,7 @@ pub const Error = error{ /// Returns whether anything changed pub fn render(allocator: *mem.Allocator, stream: var, tree: *ast.Tree) (@TypeOf(stream).Child.Error || Error)!bool { - comptime assert(@typeId(@TypeOf(stream)) == builtin.TypeId.Pointer); + comptime assert(@typeInfo(@TypeOf(stream)) == .Pointer); var anything_changed: bool = false; @@ -584,12 +583,18 @@ fn renderExpression( }, .Try, - .Await, .Cancel, .Resume, => { try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.Space); }, + + .Await => |await_info| { + if (await_info.noasync_token) |tok| { + try renderToken(tree, stream, tok, indent, start_col, Space.Space); + } + try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.Space); + }, } return renderExpression(allocator, stream, tree, indent, start_col, prefix_op_node.rhs, space); @@ -1390,6 +1395,7 @@ fn renderExpression( try renderToken(tree, stream, extern_export_inline_token, indent, start_col, Space.Space); // extern/export } else { cc_rewrite_str = ".C"; + fn_proto.lib_name = null; } } diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig @@ -0,0 +1,163 @@ +const std = @import("../std.zig"); +const mem = std.mem; +const Allocator = std.mem.Allocator; +const ArrayList = std.ArrayList; +const assert = std.debug.assert; +const process = std.process; + +const is_windows = std.Target.current.isWindows(); + +pub const NativePaths = struct { + include_dirs: ArrayList([:0]u8), + lib_dirs: ArrayList([:0]u8), + rpaths: ArrayList([:0]u8), + warnings: ArrayList([:0]u8), + + pub fn detect(allocator: *Allocator) !NativePaths { + var self: NativePaths = .{ + .include_dirs = ArrayList([:0]u8).init(allocator), + .lib_dirs = ArrayList([:0]u8).init(allocator), + .rpaths = ArrayList([:0]u8).init(allocator), + .warnings = ArrayList([:0]u8).init(allocator), + }; + errdefer self.deinit(); + + var is_nix = false; + if (process.getEnvVarOwned(allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| { + defer allocator.free(nix_cflags_compile); + + is_nix = true; + var it = mem.tokenize(nix_cflags_compile, " "); + while (true) { + const word = it.next() orelse break; + if (mem.eql(u8, word, "-isystem")) { + const include_path = it.next() orelse { + try self.addWarning("Expected argument after -isystem in NIX_CFLAGS_COMPILE"); + break; + }; + try self.addIncludeDir(include_path); + } else { + try self.addWarningFmt("Unrecognized C flag from NIX_CFLAGS_COMPILE: {}", .{word}); + break; + } + } + } else |err| switch (err) { + error.InvalidUtf8 => {}, + error.EnvironmentVariableNotFound => {}, + error.OutOfMemory => |e| return e, + } + if (process.getEnvVarOwned(allocator, "NIX_LDFLAGS")) |nix_ldflags| { + defer allocator.free(nix_ldflags); + + is_nix = true; + var it = mem.tokenize(nix_ldflags, " "); + while (true) { + const word = it.next() orelse break; + if (mem.eql(u8, word, "-rpath")) { + const rpath = it.next() orelse { + try self.addWarning("Expected argument after -rpath in NIX_LDFLAGS"); + break; + }; + try self.addRPath(rpath); + } else if (word.len > 2 and word[0] == '-' and word[1] == 'L') { + const lib_path = word[2..]; + try self.addLibDir(lib_path); + } else { + try self.addWarningFmt("Unrecognized C flag from NIX_LDFLAGS: {}", .{word}); + break; + } + } + } else |err| switch (err) { + error.InvalidUtf8 => {}, + error.EnvironmentVariableNotFound => {}, + error.OutOfMemory => |e| return e, + } + if (is_nix) { + return self; + } + + if (!is_windows) { + const triple = try std.Target.current.linuxTriple(allocator); + + // TODO: $ ld --verbose | grep SEARCH_DIR + // the output contains some paths that end with lib64, maybe include them too? + // TODO: what is the best possible order of things? + // TODO: some of these are suspect and should only be added on some systems. audit needed. + + try self.addIncludeDir("/usr/local/include"); + try self.addLibDir("/usr/local/lib"); + try self.addLibDir("/usr/local/lib64"); + + try self.addIncludeDirFmt("/usr/include/{}", .{triple}); + try self.addLibDirFmt("/usr/lib/{}", .{triple}); + + try self.addIncludeDir("/usr/include"); + try self.addLibDir("/lib"); + try self.addLibDir("/lib64"); + try self.addLibDir("/usr/lib"); + try self.addLibDir("/usr/lib64"); + + // example: on a 64-bit debian-based linux distro, with zlib installed from apt: + // zlib.h is in /usr/include (added above) + // libz.so.1 is in /lib/x86_64-linux-gnu (added here) + try self.addLibDirFmt("/lib/{}", .{triple}); + } + + return self; + } + + pub fn deinit(self: *NativePaths) void { + deinitArray(&self.include_dirs); + deinitArray(&self.lib_dirs); + deinitArray(&self.rpaths); + deinitArray(&self.warnings); + self.* = undefined; + } + + fn deinitArray(array: *ArrayList([:0]u8)) void { + for (array.toSlice()) |item| { + array.allocator.free(item); + } + array.deinit(); + } + + pub fn addIncludeDir(self: *NativePaths, s: []const u8) !void { + return self.appendArray(&self.include_dirs, s); + } + + pub fn addIncludeDirFmt(self: *NativePaths, comptime fmt: []const u8, args: var) !void { + const item = try std.fmt.allocPrint0(self.include_dirs.allocator, fmt, args); + errdefer self.include_dirs.allocator.free(item); + try self.include_dirs.append(item); + } + + pub fn addLibDir(self: *NativePaths, s: []const u8) !void { + return self.appendArray(&self.lib_dirs, s); + } + + pub fn addLibDirFmt(self: *NativePaths, comptime fmt: []const u8, args: var) !void { + const item = try std.fmt.allocPrint0(self.lib_dirs.allocator, fmt, args); + errdefer self.lib_dirs.allocator.free(item); + try self.lib_dirs.append(item); + } + + pub fn addWarning(self: *NativePaths, s: []const u8) !void { + return self.appendArray(&self.warnings, s); + } + + pub fn addWarningFmt(self: *NativePaths, comptime fmt: []const u8, args: var) !void { + const item = try std.fmt.allocPrint0(self.warnings.allocator, fmt, args); + errdefer self.warnings.allocator.free(item); + try self.warnings.append(item); + } + + pub fn addRPath(self: *NativePaths, s: []const u8) !void { + return self.appendArray(&self.rpaths, s); + } + + fn appendArray(self: *NativePaths, array: *ArrayList([:0]u8), s: []const u8) !void { + const item = try std.mem.dupeZ(array.allocator, u8, s); + errdefer array.allocator.free(item); + try array.append(item); + } +}; diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig @@ -414,10 +414,8 @@ pub const Tokenizer = struct { pub fn next(self: *Tokenizer) Token { if (self.pending_invalid_token) |token| { - // TODO: Audit this pattern once #2915 is closed - const copy = token; self.pending_invalid_token = null; - return copy; + return token; } const start_index = self.index; var state = State.Start; @@ -1270,10 +1268,8 @@ pub const Tokenizer = struct { if (result.id == Token.Id.Eof) { if (self.pending_invalid_token) |token| { - // TODO: Audit this pattern once #2915 is closed - const copy = token; self.pending_invalid_token = null; - return copy; + return token; } } diff --git a/src-self-hosted/c.zig b/src-self-hosted/c.zig @@ -4,5 +4,4 @@ pub usingnamespace @cImport({ @cInclude("inttypes.h"); @cInclude("config.h"); @cInclude("zig_llvm.h"); - @cInclude("windows_sdk.h"); }); diff --git a/src-self-hosted/introspect.zig b/src-self-hosted/introspect.zig @@ -6,6 +6,14 @@ const fs = std.fs; const warn = std.debug.warn; +pub fn detectDynamicLinker(allocator: *mem.Allocator, target: std.Target) ![:0]u8 { + if (target == .Native) { + return @import("libc_installation.zig").detectNativeDynamicLinker(allocator); + } else { + return target.getStandardDynamicLinkerPath(allocator); + } +} + /// Caller must free result pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 { const test_zig_dir = try fs.path.join(allocator, &[_][]const u8{ test_path, "lib", "zig" }); diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig @@ -76,20 +76,18 @@ pub const Inst = struct { } pub fn typeToId(comptime T: type) Id { - comptime var i = 0; - inline while (i < @memberCount(Id)) : (i += 1) { - if (T == @field(Inst, @memberName(Id, i))) { - return @field(Id, @memberName(Id, i)); + inline for (@typeInfo(Id).Enum.fields) |f| { + if (T == @field(Inst, f.name)) { + return @field(Id, f.name); } } unreachable; } pub fn dump(base: *const Inst) void { - comptime var i = 0; - inline while (i < @memberCount(Id)) : (i += 1) { - if (base.id == @field(Id, @memberName(Id, i))) { - const T = @field(Inst, @memberName(Id, i)); + inline for (@typeInfo(Id).Enum.fields) |f| { + if (base.id == @field(Id, f.name)) { + const T = @field(Inst, f.name); std.debug.warn("#{} = {}(", .{ base.debug_id, @tagName(base.id) }); @fieldParentPtr(T, "base", base).dump(); std.debug.warn(")", .{}); @@ -100,10 +98,9 @@ pub const Inst = struct { } pub fn hasSideEffects(base: *const Inst) bool { - comptime var i = 0; - inline while (i < @memberCount(Id)) : (i += 1) { - if (base.id == @field(Id, @memberName(Id, i))) { - const T = @field(Inst, @memberName(Id, i)); + inline for (@typeInfo(Id).Enum.fields) |f| { + if (base.id == @field(Id, f.name)) { + const T = @field(Inst, f.name); return @fieldParentPtr(T, "base", base).hasSideEffects(); } } @@ -1805,21 +1802,19 @@ pub const Builder = struct { }; // Look at the params and ref() other instructions - comptime var i = 0; - inline while (i < @memberCount(I.Params)) : (i += 1) { - const FieldType = comptime @TypeOf(@field(@as(I.Params, undefined), @memberName(I.Params, i))); - switch (FieldType) { - *Inst => @field(inst.params, @memberName(I.Params, i)).ref(self), - *BasicBlock => @field(inst.params, @memberName(I.Params, i)).ref(self), - ?*Inst => if (@field(inst.params, @memberName(I.Params, i))) |other| other.ref(self), + inline for (@typeInfo(I.Params).Struct.fields) |f| { + switch (f.fiedl_type) { + *Inst => @field(inst.params, f.name).ref(self), + *BasicBlock => @field(inst.params, f.name).ref(self), + ?*Inst => if (@field(inst.params, f.name)) |other| other.ref(self), []*Inst => { // TODO https://github.com/ziglang/zig/issues/1269 - for (@field(inst.params, @memberName(I.Params, i))) |other| + for (@field(inst.params, f.name)) |other| other.ref(self); }, []*BasicBlock => { // TODO https://github.com/ziglang/zig/issues/1269 - for (@field(inst.params, @memberName(I.Params, i))) |other| + for (@field(inst.params, f.name)) |other| other.ref(self); }, Type.Pointer.Mut, @@ -1831,7 +1826,7 @@ pub const Builder = struct { => {}, // it's ok to add more types here, just make sure that // any instructions and basic blocks are ref'd appropriately - else => @compileError("unrecognized type in Params: " ++ @typeName(FieldType)), + else => @compileError("unrecognized type in Params: " ++ @typeName(f.field_type)), } } diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig @@ -1,20 +1,29 @@ const std = @import("std"); const builtin = @import("builtin"); -const event = std.event; const util = @import("util.zig"); const Target = std.Target; -const c = @import("c.zig"); const fs = std.fs; const Allocator = std.mem.Allocator; +const Batch = std.event.Batch; + +const is_darwin = Target.current.isDarwin(); +const is_windows = Target.current.isWindows(); +const is_freebsd = Target.current.isFreeBSD(); +const is_netbsd = Target.current.isNetBSD(); +const is_linux = Target.current.isLinux(); +const is_dragonfly = Target.current.isDragonFlyBSD(); +const is_gnu = Target.current.isGnu(); + +usingnamespace @import("windows_sdk.zig"); /// See the render function implementation for documentation of the fields. pub const LibCInstallation = struct { - include_dir: []const u8, - lib_dir: ?[]const u8, - static_lib_dir: ?[]const u8, - msvc_lib_dir: ?[]const u8, - kernel32_lib_dir: ?[]const u8, - dynamic_linker_path: ?[]const u8, + include_dir: ?[:0]const u8 = null, + sys_include_dir: ?[:0]const u8 = null, + crt_dir: ?[:0]const u8 = null, + static_crt_dir: ?[:0]const u8 = null, + msvc_lib_dir: ?[:0]const u8 = null, + kernel32_lib_dir: ?[:0]const u8 = null, pub const FindError = error{ OutOfMemory, @@ -27,31 +36,24 @@ pub const LibCInstallation = struct { LibCStdLibHeaderNotFound, LibCKernel32LibNotFound, UnsupportedArchitecture, + WindowsSdkNotFound, }; pub fn parse( - self: *LibCInstallation, allocator: *Allocator, libc_file: []const u8, stderr: *std.io.OutStream(fs.File.WriteError), - ) !void { - self.initEmpty(); - - const keys = [_][]const u8{ - "include_dir", - "lib_dir", - "static_lib_dir", - "msvc_lib_dir", - "kernel32_lib_dir", - "dynamic_linker_path", - }; + ) !LibCInstallation { + var self: LibCInstallation = .{}; + + const fields = std.meta.fields(LibCInstallation); const FoundKey = struct { found: bool, - allocated: ?[]u8, + allocated: ?[:0]u8, }; - var found_keys = [1]FoundKey{FoundKey{ .found = false, .allocated = null }} ** keys.len; + var found_keys = [1]FoundKey{FoundKey{ .found = false, .allocated = null }} ** fields.len; errdefer { - self.initEmpty(); + self = .{}; for (found_keys) |found_key| { if (found_key.allocated) |s| allocator.free(s); } @@ -69,152 +71,216 @@ pub const LibCInstallation = struct { return error.ParseError; }; const value = line_it.rest(); - inline for (keys) |key, i| { - if (std.mem.eql(u8, name, key)) { + inline for (fields) |field, i| { + if (std.mem.eql(u8, name, field.name)) { found_keys[i].found = true; - switch (@typeInfo(@TypeOf(@field(self, key)))) { - .Optional => { - if (value.len == 0) { - @field(self, key) = null; - } else { - found_keys[i].allocated = try std.mem.dupe(allocator, u8, value); - @field(self, key) = found_keys[i].allocated; - } - }, - else => { - if (value.len == 0) { - try stderr.print("field cannot be empty: {}\n", .{key}); - return error.ParseError; - } - const dupe = try std.mem.dupe(allocator, u8, value); - found_keys[i].allocated = dupe; - @field(self, key) = dupe; - }, + if (value.len == 0) { + @field(self, field.name) = null; + } else { + found_keys[i].allocated = try std.mem.dupeZ(allocator, u8, value); + @field(self, field.name) = found_keys[i].allocated; } break; } } } - for (found_keys) |found_key, i| { - if (!found_key.found) { - try stderr.print("missing field: {}\n", .{keys[i]}); + inline for (fields) |field, i| { + if (!found_keys[i].found) { + try stderr.print("missing field: {}\n", .{field.name}); return error.ParseError; } } + if (self.include_dir == null) { + try stderr.print("include_dir may not be empty\n", .{}); + return error.ParseError; + } + if (self.sys_include_dir == null) { + try stderr.print("sys_include_dir may not be empty\n", .{}); + return error.ParseError; + } + if (self.crt_dir == null and !is_darwin) { + try stderr.print("crt_dir may not be empty for {}\n", .{@tagName(Target.current.getOs())}); + return error.ParseError; + } + if (self.static_crt_dir == null and is_windows and is_gnu) { + try stderr.print("static_crt_dir may not be empty for {}-{}\n", .{ + @tagName(Target.current.getOs()), + @tagName(Target.current.getAbi()), + }); + return error.ParseError; + } + if (self.msvc_lib_dir == null and is_windows and !is_gnu) { + try stderr.print("msvc_lib_dir may not be empty for {}-{}\n", .{ + @tagName(Target.current.getOs()), + @tagName(Target.current.getAbi()), + }); + return error.ParseError; + } + if (self.kernel32_lib_dir == null and is_windows and !is_gnu) { + try stderr.print("kernel32_lib_dir may not be empty for {}-{}\n", .{ + @tagName(Target.current.getOs()), + @tagName(Target.current.getAbi()), + }); + return error.ParseError; + } + + return self; } - pub fn render(self: *const LibCInstallation, out: *std.io.OutStream(fs.File.WriteError)) !void { + pub fn render(self: LibCInstallation, out: *std.io.OutStream(fs.File.WriteError)) !void { @setEvalBranchQuota(4000); - const lib_dir = self.lib_dir orelse ""; - const static_lib_dir = self.static_lib_dir orelse ""; + const include_dir = self.include_dir orelse ""; + const sys_include_dir = self.sys_include_dir orelse ""; + const crt_dir = self.crt_dir orelse ""; + const static_crt_dir = self.static_crt_dir orelse ""; const msvc_lib_dir = self.msvc_lib_dir orelse ""; const kernel32_lib_dir = self.kernel32_lib_dir orelse ""; - const dynamic_linker_path = self.dynamic_linker_path orelse util.getDynamicLinkerPath(Target{ .Native = {} }); + try out.print( \\# The directory that contains `stdlib.h`. - \\# On Linux, can be found with: `cc -E -Wp,-v -xc /dev/null` + \\# On POSIX-like systems, include directories be found with: `cc -E -Wp,-v -xc /dev/null` \\include_dir={} \\ - \\# The directory that contains `crt1.o`. - \\# On Linux, can be found with `cc -print-file-name=crt1.o`. + \\# The system-specific include directory. May be the same as `include_dir`. + \\# On Windows it's the directory that includes `vcruntime.h`. + \\# On POSIX it's the directory that includes `sys/errno.h`. + \\sys_include_dir={} + \\ + \\# The directory that contains `crt1.o` or `crt2.o`. + \\# On POSIX, can be found with `cc -print-file-name=crt1.o`. \\# Not needed when targeting MacOS. - \\lib_dir={} + \\crt_dir={} \\ \\# The directory that contains `crtbegin.o`. - \\# On Linux, can be found with `cc -print-file-name=crtbegin.o`. - \\# Not needed when targeting MacOS or Windows. - \\static_lib_dir={} + \\# On POSIX, can be found with `cc -print-file-name=crtbegin.o`. + \\# Only needed when targeting MinGW-w64 on Windows. + \\static_crt_dir={} \\ \\# The directory that contains `vcruntime.lib`. - \\# Only needed when targeting Windows. + \\# Only needed when targeting MSVC on Windows. \\msvc_lib_dir={} \\ \\# The directory that contains `kernel32.lib`. - \\# Only needed when targeting Windows. + \\# Only needed when targeting MSVC on Windows. \\kernel32_lib_dir={} \\ - \\# The full path to the dynamic linker, on the target system. - \\# Only needed when targeting Linux. - \\dynamic_linker_path={} - \\ - , .{ self.include_dir, lib_dir, static_lib_dir, msvc_lib_dir, kernel32_lib_dir, dynamic_linker_path }); + , .{ + include_dir, + sys_include_dir, + crt_dir, + static_crt_dir, + msvc_lib_dir, + kernel32_lib_dir, + }); } + pub const FindNativeOptions = struct { + allocator: *Allocator, + + /// If enabled, will print human-friendly errors to stderr. + verbose: bool = false, + }; + /// Finds the default, native libc. - pub fn findNative(self: *LibCInstallation, allocator: *Allocator) !void { - self.initEmpty(); - var group = event.Group(FindError!void).init(allocator); - errdefer group.wait() catch {}; - var windows_sdk: ?*c.ZigWindowsSDK = null; - errdefer if (windows_sdk) |sdk| c.zig_free_windows_sdk(@ptrCast(?[*]c.ZigWindowsSDK, sdk)); - - switch (builtin.os) { - .windows => { - var sdk: *c.ZigWindowsSDK = undefined; - switch (c.zig_find_windows_sdk(@ptrCast(?[*]?[*]c.ZigWindowsSDK, &sdk))) { - c.ZigFindWindowsSdkError.None => { - windows_sdk = sdk; - - if (sdk.msvc_lib_dir_ptr != 0) { - self.msvc_lib_dir = try std.mem.dupe(allocator, u8, sdk.msvc_lib_dir_ptr[0..sdk.msvc_lib_dir_len]); - } - try group.call(findNativeKernel32LibDir, .{ allocator, self, sdk }); - try group.call(findNativeIncludeDirWindows, .{ self, allocator, sdk }); - try group.call(findNativeLibDirWindows, .{ self, allocator, sdk }); + pub fn findNative(args: FindNativeOptions) FindError!LibCInstallation { + var self: LibCInstallation = .{}; + + if (is_windows) { + if (is_gnu) { + var batch = Batch(FindError!void, 3, .auto_async).init(); + batch.add(&async self.findNativeIncludeDirPosix(args)); + batch.add(&async self.findNativeCrtDirPosix(args)); + batch.add(&async self.findNativeStaticCrtDirPosix(args)); + try batch.wait(); + } else { + var sdk: *ZigWindowsSDK = undefined; + switch (zig_find_windows_sdk(&sdk)) { + .None => { + defer zig_free_windows_sdk(sdk); + + var batch = Batch(FindError!void, 5, .auto_async).init(); + batch.add(&async self.findNativeMsvcIncludeDir(args, sdk)); + batch.add(&async self.findNativeMsvcLibDir(args, sdk)); + batch.add(&async self.findNativeKernel32LibDir(args, sdk)); + batch.add(&async self.findNativeIncludeDirWindows(args, sdk)); + batch.add(&async self.findNativeCrtDirWindows(args, sdk)); + try batch.wait(); }, - c.ZigFindWindowsSdkError.OutOfMemory => return error.OutOfMemory, - c.ZigFindWindowsSdkError.NotFound => return error.NotFound, - c.ZigFindWindowsSdkError.PathTooLong => return error.NotFound, + .OutOfMemory => return error.OutOfMemory, + .NotFound => return error.WindowsSdkNotFound, + .PathTooLong => return error.WindowsSdkNotFound, } - }, - .linux => { - try group.call(findNativeIncludeDirLinux, .{ self, allocator }); - try group.call(findNativeLibDirLinux, .{ self, allocator }); - try group.call(findNativeStaticLibDir, .{ self, allocator }); - try group.call(findNativeDynamicLinker, .{ self, allocator }); - }, - .macosx, .freebsd, .netbsd => { - self.include_dir = try std.mem.dupe(allocator, u8, "/usr/include"); - }, - else => @compileError("unimplemented: find libc for this OS"), + } + } else { + try blk: { + var batch = Batch(FindError!void, 2, .auto_async).init(); + errdefer batch.wait() catch {}; + batch.add(&async self.findNativeIncludeDirPosix(args)); + if (is_freebsd or is_netbsd) { + self.crt_dir = try std.mem.dupeZ(args.allocator, u8, "/usr/lib"); + } else if (is_linux or is_dragonfly) { + batch.add(&async self.findNativeCrtDirPosix(args)); + } + break :blk batch.wait(); + }; + } + return self; + } + + /// Must be the same allocator passed to `parse` or `findNative`. + pub fn deinit(self: *LibCInstallation, allocator: *Allocator) void { + const fields = std.meta.fields(LibCInstallation); + inline for (fields) |field| { + if (@field(self, field.name)) |payload| { + allocator.free(payload); + } } - return group.wait(); + self.* = undefined; } - async fn findNativeIncludeDirLinux(self: *LibCInstallation, allocator: *Allocator) FindError!void { - const cc_exe = std.os.getenv("CC") orelse "cc"; + fn findNativeIncludeDirPosix(self: *LibCInstallation, args: FindNativeOptions) FindError!void { + const allocator = args.allocator; + const dev_null = if (is_windows) "nul" else "/dev/null"; + const cc_exe = std.os.getenvZ("CC") orelse default_cc_exe; const argv = [_][]const u8{ cc_exe, "-E", "-Wp,-v", "-xc", - "/dev/null", + dev_null, }; - // TODO make this use event loop - const errorable_result = std.ChildProcess.exec(allocator, &argv, null, null, 1024 * 1024); - const exec_result = if (std.debug.runtime_safety) blk: { - break :blk errorable_result catch unreachable; - } else blk: { - break :blk errorable_result catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - else => return error.UnableToSpawnCCompiler, - }; + const exec_res = std.ChildProcess.exec2(.{ + .allocator = allocator, + .argv = &argv, + .max_output_bytes = 1024 * 1024, + // Some C compilers, such as Clang, are known to rely on argv[0] to find the path + // to their own executable, without even bothering to resolve PATH. This results in the message: + // error: unable to execute command: Executable "" doesn't exist! + // So we use the expandArg0 variant of ChildProcess to give them a helping hand. + .expand_arg0 = .expand, + }) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + else => { + printVerboseInvocation(&argv, null, args.verbose, null); + return error.UnableToSpawnCCompiler; + }, }; defer { - allocator.free(exec_result.stdout); - allocator.free(exec_result.stderr); + allocator.free(exec_res.stdout); + allocator.free(exec_res.stderr); } - - switch (exec_result.term) { - .Exited => |code| { - if (code != 0) return error.CCompilerExitCode; + switch (exec_res.term) { + .Exited => |code| if (code != 0) { + printVerboseInvocation(&argv, null, args.verbose, exec_res.stderr); + return error.CCompilerExitCode; }, else => { + printVerboseInvocation(&argv, null, args.verbose, exec_res.stderr); return error.CCompilerCrashed; }, } - var it = std.mem.tokenize(exec_result.stderr, "\n\r"); + var it = std.mem.tokenize(exec_res.stderr, "\n\r"); var search_paths = std.ArrayList([]const u8).init(allocator); defer search_paths.deinit(); while (it.next()) |line| { @@ -226,16 +292,44 @@ pub const LibCInstallation = struct { return error.CCompilerCannotFindHeaders; } - // search in reverse order + const include_dir_example_file = "stdlib.h"; + const sys_include_dir_example_file = if (is_windows) "sys\\types.h" else "sys/errno.h"; + var path_i: usize = 0; while (path_i < search_paths.len) : (path_i += 1) { + // search in reverse order const search_path_untrimmed = search_paths.at(search_paths.len - path_i - 1); const search_path = std.mem.trimLeft(u8, search_path_untrimmed, " "); - const stdlib_path = try fs.path.join(allocator, &[_][]const u8{ search_path, "stdlib.h" }); - defer allocator.free(stdlib_path); + var search_dir = fs.cwd().openDirList(search_path) catch |err| switch (err) { + error.FileNotFound, + error.NotDir, + error.NoDevice, + => continue, + + else => return error.FileSystem, + }; + defer search_dir.close(); + + if (self.include_dir == null) { + if (search_dir.accessZ(include_dir_example_file, .{})) |_| { + self.include_dir = try std.mem.dupeZ(allocator, u8, search_path); + } else |err| switch (err) { + error.FileNotFound => {}, + else => return error.FileSystem, + } + } + + if (self.sys_include_dir == null) { + if (search_dir.accessZ(sys_include_dir_example_file, .{})) |_| { + self.sys_include_dir = try std.mem.dupeZ(allocator, u8, search_path); + } else |err| switch (err) { + error.FileNotFound => {}, + else => return error.FileSystem, + } + } - if (try fileExists(stdlib_path)) { - self.include_dir = try std.mem.dupe(allocator, u8, search_path); + if (self.include_dir != null and self.sys_include_dir != null) { + // Success. return; } } @@ -243,7 +337,13 @@ pub const LibCInstallation = struct { return error.LibCStdLibHeaderNotFound; } - async fn findNativeIncludeDirWindows(self: *LibCInstallation, allocator: *Allocator, sdk: *c.ZigWindowsSDK) !void { + fn findNativeIncludeDirWindows( + self: *LibCInstallation, + args: FindNativeOptions, + sdk: *ZigWindowsSDK, + ) FindError!void { + const allocator = args.allocator; + var search_buf: [2]Search = undefined; const searches = fillSearch(&search_buf, sdk); @@ -255,180 +355,363 @@ pub const LibCInstallation = struct { const stream = &std.io.BufferOutStream.init(&result_buf).stream; try stream.print("{}\\Include\\{}\\ucrt", .{ search.path, search.version }); - const stdlib_path = try fs.path.join( - allocator, - [_][]const u8{ result_buf.toSliceConst(), "stdlib.h" }, - ); - defer allocator.free(stdlib_path); + var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) { + error.FileNotFound, + error.NotDir, + error.NoDevice, + => continue, - if (try fileExists(stdlib_path)) { - self.include_dir = result_buf.toOwnedSlice(); - return; - } + else => return error.FileSystem, + }; + defer dir.close(); + + dir.accessZ("stdlib.h", .{}) catch |err| switch (err) { + error.FileNotFound => continue, + else => return error.FileSystem, + }; + + self.include_dir = result_buf.toOwnedSlice(); + return; } return error.LibCStdLibHeaderNotFound; } - async fn findNativeLibDirWindows(self: *LibCInstallation, allocator: *Allocator, sdk: *c.ZigWindowsSDK) FindError!void { + fn findNativeCrtDirWindows( + self: *LibCInstallation, + args: FindNativeOptions, + sdk: *ZigWindowsSDK, + ) FindError!void { + const allocator = args.allocator; + var search_buf: [2]Search = undefined; const searches = fillSearch(&search_buf, sdk); var result_buf = try std.Buffer.initSize(allocator, 0); defer result_buf.deinit(); + const arch_sub_dir = switch (builtin.arch) { + .i386 => "x86", + .x86_64 => "x64", + .arm, .armeb => "arm", + else => return error.UnsupportedArchitecture, + }; + for (searches) |search| { result_buf.shrink(0); const stream = &std.io.BufferOutStream.init(&result_buf).stream; - try stream.print("{}\\Lib\\{}\\ucrt\\", .{ search.path, search.version }); - switch (builtin.arch) { - .i386 => try stream.write("x86"), - .x86_64 => try stream.write("x64"), - .aarch64 => try stream.write("arm"), - else => return error.UnsupportedArchitecture, - } - const ucrt_lib_path = try fs.path.join( - allocator, - [_][]const u8{ result_buf.toSliceConst(), "ucrt.lib" }, - ); - defer allocator.free(ucrt_lib_path); - if (try fileExists(ucrt_lib_path)) { - self.lib_dir = result_buf.toOwnedSlice(); - return; - } - } - return error.LibCRuntimeNotFound; - } + try stream.print("{}\\Lib\\{}\\ucrt\\{}", .{ search.path, search.version, arch_sub_dir }); - async fn findNativeLibDirLinux(self: *LibCInstallation, allocator: *Allocator) FindError!void { - self.lib_dir = try ccPrintFileName(allocator, "crt1.o", true); - } + var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) { + error.FileNotFound, + error.NotDir, + error.NoDevice, + => continue, - async fn findNativeStaticLibDir(self: *LibCInstallation, allocator: *Allocator) FindError!void { - self.static_lib_dir = try ccPrintFileName(allocator, "crtbegin.o", true); - } + else => return error.FileSystem, + }; + defer dir.close(); - async fn findNativeDynamicLinker(self: *LibCInstallation, allocator: *Allocator) FindError!void { - var dyn_tests = [_]DynTest{ - DynTest{ - .name = "ld-linux-x86-64.so.2", - .result = null, - }, - DynTest{ - .name = "ld-musl-x86_64.so.1", - .result = null, - }, - }; - var group = event.Group(FindError!void).init(allocator); - errdefer group.wait() catch {}; - for (dyn_tests) |*dyn_test| { - try group.call(testNativeDynamicLinker, .{ self, allocator, dyn_test }); - } - try group.wait(); - for (dyn_tests) |*dyn_test| { - if (dyn_test.result) |result| { - self.dynamic_linker_path = result; - return; - } + dir.accessZ("ucrt.lib", .{}) catch |err| switch (err) { + error.FileNotFound => continue, + else => return error.FileSystem, + }; + + self.crt_dir = result_buf.toOwnedSlice(); + return; } + return error.LibCRuntimeNotFound; } - const DynTest = struct { - name: []const u8, - result: ?[]const u8, - }; + fn findNativeCrtDirPosix(self: *LibCInstallation, args: FindNativeOptions) FindError!void { + self.crt_dir = try ccPrintFileName(.{ + .allocator = args.allocator, + .search_basename = "crt1.o", + .want_dirname = .only_dir, + .verbose = args.verbose, + }); + } - async fn testNativeDynamicLinker(self: *LibCInstallation, allocator: *Allocator, dyn_test: *DynTest) FindError!void { - if (ccPrintFileName(allocator, dyn_test.name, false)) |result| { - dyn_test.result = result; - return; - } else |err| switch (err) { - error.LibCRuntimeNotFound => return, - else => return err, - } + fn findNativeStaticCrtDirPosix(self: *LibCInstallation, args: FindNativeOptions) FindError!void { + self.static_crt_dir = try ccPrintFileName(.{ + .allocator = args.allocator, + .search_basename = "crtbegin.o", + .want_dirname = .only_dir, + .verbose = args.verbose, + }); } - async fn findNativeKernel32LibDir(self: *LibCInstallation, allocator: *Allocator, sdk: *c.ZigWindowsSDK) FindError!void { + fn findNativeKernel32LibDir( + self: *LibCInstallation, + args: FindNativeOptions, + sdk: *ZigWindowsSDK, + ) FindError!void { + const allocator = args.allocator; + var search_buf: [2]Search = undefined; const searches = fillSearch(&search_buf, sdk); var result_buf = try std.Buffer.initSize(allocator, 0); defer result_buf.deinit(); + const arch_sub_dir = switch (builtin.arch) { + .i386 => "x86", + .x86_64 => "x64", + .arm, .armeb => "arm", + else => return error.UnsupportedArchitecture, + }; + for (searches) |search| { result_buf.shrink(0); const stream = &std.io.BufferOutStream.init(&result_buf).stream; - try stream.print("{}\\Lib\\{}\\um\\", .{ search.path, search.version }); - switch (builtin.arch) { - .i386 => try stream.write("x86\\"), - .x86_64 => try stream.write("x64\\"), - .aarch64 => try stream.write("arm\\"), - else => return error.UnsupportedArchitecture, - } - const kernel32_path = try fs.path.join( - allocator, - [_][]const u8{ result_buf.toSliceConst(), "kernel32.lib" }, - ); - defer allocator.free(kernel32_path); - if (try fileExists(kernel32_path)) { - self.kernel32_lib_dir = result_buf.toOwnedSlice(); - return; - } + try stream.print("{}\\Lib\\{}\\um\\{}", .{ search.path, search.version, arch_sub_dir }); + + var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) { + error.FileNotFound, + error.NotDir, + error.NoDevice, + => continue, + + else => return error.FileSystem, + }; + defer dir.close(); + + dir.accessZ("kernel32.lib", .{}) catch |err| switch (err) { + error.FileNotFound => continue, + else => return error.FileSystem, + }; + + self.kernel32_lib_dir = result_buf.toOwnedSlice(); + return; } return error.LibCKernel32LibNotFound; } - fn initEmpty(self: *LibCInstallation) void { - self.* = LibCInstallation{ - .include_dir = @as([*]const u8, undefined)[0..0], - .lib_dir = null, - .static_lib_dir = null, - .msvc_lib_dir = null, - .kernel32_lib_dir = null, - .dynamic_linker_path = null, + fn findNativeMsvcIncludeDir( + self: *LibCInstallation, + args: FindNativeOptions, + sdk: *ZigWindowsSDK, + ) FindError!void { + const allocator = args.allocator; + + const msvc_lib_dir_ptr = sdk.msvc_lib_dir_ptr orelse return error.LibCStdLibHeaderNotFound; + const msvc_lib_dir = msvc_lib_dir_ptr[0..sdk.msvc_lib_dir_len]; + const up1 = fs.path.dirname(msvc_lib_dir) orelse return error.LibCStdLibHeaderNotFound; + const up2 = fs.path.dirname(up1) orelse return error.LibCStdLibHeaderNotFound; + + var result_buf = try std.Buffer.init(allocator, up2); + defer result_buf.deinit(); + + try result_buf.append("\\include"); + + var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) { + error.FileNotFound, + error.NotDir, + error.NoDevice, + => return error.LibCStdLibHeaderNotFound, + + else => return error.FileSystem, + }; + defer dir.close(); + + dir.accessZ("vcruntime.h", .{}) catch |err| switch (err) { + error.FileNotFound => return error.LibCStdLibHeaderNotFound, + else => return error.FileSystem, }; + + self.sys_include_dir = result_buf.toOwnedSlice(); + } + + fn findNativeMsvcLibDir( + self: *LibCInstallation, + args: FindNativeOptions, + sdk: *ZigWindowsSDK, + ) FindError!void { + const allocator = args.allocator; + const msvc_lib_dir_ptr = sdk.msvc_lib_dir_ptr orelse return error.LibCRuntimeNotFound; + self.msvc_lib_dir = try std.mem.dupeZ(allocator, u8, msvc_lib_dir_ptr[0..sdk.msvc_lib_dir_len]); } }; +const default_cc_exe = if (is_windows) "cc.exe" else "cc"; + +pub const CCPrintFileNameOptions = struct { + allocator: *Allocator, + search_basename: []const u8, + want_dirname: enum { full_path, only_dir }, + verbose: bool = false, +}; + /// caller owns returned memory -fn ccPrintFileName(allocator: *Allocator, o_file: []const u8, want_dirname: bool) ![]u8 { - const cc_exe = std.os.getenv("CC") orelse "cc"; - const arg1 = try std.fmt.allocPrint(allocator, "-print-file-name={}", .{o_file}); +fn ccPrintFileName(args: CCPrintFileNameOptions) ![:0]u8 { + const allocator = args.allocator; + + const cc_exe = std.os.getenvZ("CC") orelse default_cc_exe; + const arg1 = try std.fmt.allocPrint(allocator, "-print-file-name={}", .{args.search_basename}); defer allocator.free(arg1); const argv = [_][]const u8{ cc_exe, arg1 }; - // TODO This simulates evented I/O for the child process exec - event.Loop.startCpuBoundOperation(); - const errorable_result = std.ChildProcess.exec(allocator, &argv, null, null, 1024 * 1024); - const exec_result = if (std.debug.runtime_safety) blk: { - break :blk errorable_result catch unreachable; - } else blk: { - break :blk errorable_result catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - else => return error.UnableToSpawnCCompiler, - }; + const exec_res = std.ChildProcess.exec2(.{ + .allocator = allocator, + .argv = &argv, + .max_output_bytes = 1024 * 1024, + // Some C compilers, such as Clang, are known to rely on argv[0] to find the path + // to their own executable, without even bothering to resolve PATH. This results in the message: + // error: unable to execute command: Executable "" doesn't exist! + // So we use the expandArg0 variant of ChildProcess to give them a helping hand. + .expand_arg0 = .expand, + }) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + else => return error.UnableToSpawnCCompiler, }; defer { - allocator.free(exec_result.stdout); - allocator.free(exec_result.stderr); + allocator.free(exec_res.stdout); + allocator.free(exec_res.stderr); } - switch (exec_result.term) { - .Exited => |code| { - if (code != 0) return error.CCompilerExitCode; + switch (exec_res.term) { + .Exited => |code| if (code != 0) { + printVerboseInvocation(&argv, args.search_basename, args.verbose, exec_res.stderr); + return error.CCompilerExitCode; }, else => { + printVerboseInvocation(&argv, args.search_basename, args.verbose, exec_res.stderr); return error.CCompilerCrashed; }, } - var it = std.mem.tokenize(exec_result.stdout, "\n\r"); + + var it = std.mem.tokenize(exec_res.stdout, "\n\r"); const line = it.next() orelse return error.LibCRuntimeNotFound; - const dirname = fs.path.dirname(line) orelse return error.LibCRuntimeNotFound; + // When this command fails, it returns exit code 0 and duplicates the input file name. + // So we detect failure by checking if the output matches exactly the input. + if (std.mem.eql(u8, line, args.search_basename)) return error.LibCRuntimeNotFound; + switch (args.want_dirname) { + .full_path => return std.mem.dupeZ(allocator, u8, line), + .only_dir => { + const dirname = fs.path.dirname(line) orelse return error.LibCRuntimeNotFound; + return std.mem.dupeZ(allocator, u8, dirname); + }, + } +} + +fn printVerboseInvocation( + argv: []const []const u8, + search_basename: ?[]const u8, + verbose: bool, + stderr: ?[]const u8, +) void { + if (!verbose) return; - if (want_dirname) { - return std.mem.dupe(allocator, u8, dirname); + if (search_basename) |s| { + std.debug.warn("Zig attempted to find the file '{}' by executing this command:\n", .{s}); } else { - return std.mem.dupe(allocator, u8, line); + std.debug.warn("Zig attempted to find the path to native system libc headers by executing this command:\n", .{}); + } + for (argv) |arg, i| { + if (i != 0) std.debug.warn(" ", .{}); + std.debug.warn("{}", .{arg}); + } + std.debug.warn("\n", .{}); + if (stderr) |s| { + std.debug.warn("Output:\n==========\n{}\n==========\n", .{s}); + } +} + +/// Caller owns returned memory. +pub fn detectNativeDynamicLinker(allocator: *Allocator) error{ + OutOfMemory, + TargetHasNoDynamicLinker, + UnknownDynamicLinkerPath, +}![:0]u8 { + if (!comptime Target.current.hasDynamicLinker()) { + return error.TargetHasNoDynamicLinker; + } + + // The current target's ABI cannot be relied on for this. For example, we may build the zig + // compiler for target riscv64-linux-musl and provide a tarball for users to download. + // A user could then run that zig compiler on riscv64-linux-gnu. This use case is well-defined + // and supported by Zig. But that means that we must detect the system ABI here rather than + // relying on `std.Target.current`. + + const LdInfo = struct { + ld_path: []u8, + abi: Target.Abi, + }; + var ld_info_list = std.ArrayList(LdInfo).init(allocator); + defer { + for (ld_info_list.toSlice()) |ld_info| allocator.free(ld_info.ld_path); + ld_info_list.deinit(); + } + + const all_abis = comptime blk: { + const fields = std.meta.fields(Target.Abi); + var array: [fields.len]Target.Abi = undefined; + inline for (fields) |field, i| { + array[i] = @field(Target.Abi, field.name); + } + break :blk array; + }; + for (all_abis) |abi| { + // This may be a nonsensical parameter. We detect this with error.UnknownDynamicLinkerPath and + // skip adding it to `ld_info_list`. + const target: Target = .{ + .Cross = .{ + .cpu = Target.Cpu.baseline(Target.current.getArch()), + .os = Target.current.getOs(), + .abi = abi, + }, + }; + const standard_ld_path = target.getStandardDynamicLinkerPath(allocator) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.UnknownDynamicLinkerPath, error.TargetHasNoDynamicLinker => continue, + }; + errdefer allocator.free(standard_ld_path); + try ld_info_list.append(.{ + .ld_path = standard_ld_path, + .abi = abi, + }); + } + + // Best case scenario: the zig compiler is dynamically linked, and we can iterate + // over our own shared objects and find a dynamic linker. + { + const lib_paths = try std.process.getSelfExeSharedLibPaths(allocator); + defer allocator.free(lib_paths); + + // This is O(N^M) but typical case here is N=2 and M=10. + for (lib_paths) |lib_path| { + for (ld_info_list.toSlice()) |ld_info| { + const standard_ld_basename = fs.path.basename(ld_info.ld_path); + if (std.mem.endsWith(u8, lib_path, standard_ld_basename)) { + return std.mem.dupeZ(allocator, u8, lib_path); + } + } + } + } + + // If Zig is statically linked, such as via distributed binary static builds, the above + // trick won't work. What are we left with? Try to run the system C compiler and get + // it to tell us the dynamic linker path. + // TODO: instead of this, look at the shared libs of /usr/bin/env. + for (ld_info_list.toSlice()) |ld_info| { + const standard_ld_basename = fs.path.basename(ld_info.ld_path); + + const full_ld_path = ccPrintFileName(.{ + .allocator = allocator, + .search_basename = standard_ld_basename, + .want_dirname = .full_path, + }) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.LibCRuntimeNotFound, + error.CCompilerExitCode, + error.CCompilerCrashed, + error.UnableToSpawnCCompiler, + => continue, + }; + return full_ld_path; } + + // Finally, we fall back on the standard path. + return Target.current.getStandardDynamicLinkerPath(allocator); } const Search = struct { @@ -436,34 +719,25 @@ const Search = struct { version: []const u8, }; -fn fillSearch(search_buf: *[2]Search, sdk: *c.ZigWindowsSDK) []Search { +fn fillSearch(search_buf: *[2]Search, sdk: *ZigWindowsSDK) []Search { var search_end: usize = 0; - if (sdk.path10_ptr != 0) { - if (sdk.version10_ptr != 0) { + if (sdk.path10_ptr) |path10_ptr| { + if (sdk.version10_ptr) |version10_ptr| { search_buf[search_end] = Search{ - .path = sdk.path10_ptr[0..sdk.path10_len], - .version = sdk.version10_ptr[0..sdk.version10_len], + .path = path10_ptr[0..sdk.path10_len], + .version = version10_ptr[0..sdk.version10_len], }; search_end += 1; } } - if (sdk.path81_ptr != 0) { - if (sdk.version81_ptr != 0) { + if (sdk.path81_ptr) |path81_ptr| { + if (sdk.version81_ptr) |version81_ptr| { search_buf[search_end] = Search{ - .path = sdk.path81_ptr[0..sdk.path81_len], - .version = sdk.version81_ptr[0..sdk.version81_len], + .path = path81_ptr[0..sdk.path81_len], + .version = version81_ptr[0..sdk.version81_len], }; search_end += 1; } } return search_buf[0..search_end]; } - -fn fileExists(path: []const u8) !bool { - if (fs.File.access(path)) |_| { - return true; - } else |err| switch (err) { - error.FileNotFound => return false, - else => return error.FileSystem, - } -} diff --git a/src-self-hosted/print_targets.zig b/src-self-hosted/print_targets.zig @@ -113,37 +113,14 @@ pub fn cmdTargets( try jws.beginObject(); try jws.objectField("arch"); - try jws.beginObject(); + try jws.beginArray(); { - inline for (@typeInfo(Target.Arch).Union.fields) |field| { - try jws.objectField(field.name); - if (field.field_type == void) { - try jws.emitNull(); - } else { - try jws.emitString(@typeName(field.field_type)); - } - } - } - try jws.endObject(); - - try jws.objectField("subArch"); - try jws.beginObject(); - const sub_arch_list = [_]type{ - Target.Arch.Arm32, - Target.Arch.Arm64, - Target.Arch.Kalimba, - Target.Arch.Mips, - }; - inline for (sub_arch_list) |SubArch| { - try jws.objectField(@typeName(SubArch)); - try jws.beginArray(); - inline for (@typeInfo(SubArch).Enum.fields) |field| { + inline for (@typeInfo(Target.Cpu.Arch).Enum.fields) |field| { try jws.arrayElem(); try jws.emitString(field.name); } - try jws.endArray(); } - try jws.endObject(); + try jws.endArray(); try jws.objectField("os"); try jws.beginArray(); @@ -179,15 +156,15 @@ pub fn cmdTargets( try jws.objectField("cpus"); try jws.beginObject(); - inline for (@typeInfo(Target.Arch).Union.fields) |field| { + inline for (@typeInfo(Target.Cpu.Arch).Enum.fields) |field| { try jws.objectField(field.name); try jws.beginObject(); - const arch = @unionInit(Target.Arch, field.name, undefined); - for (arch.allCpus()) |cpu| { - try jws.objectField(cpu.name); + const arch = @field(Target.Cpu.Arch, field.name); + for (arch.allCpuModels()) |model| { + try jws.objectField(model.name); try jws.beginArray(); for (arch.allFeaturesList()) |feature, i| { - if (cpu.features.isEnabled(@intCast(u8, i))) { + if (model.features.isEnabled(@intCast(u8, i))) { try jws.arrayElem(); try jws.emitString(feature.name); } @@ -200,10 +177,10 @@ pub fn cmdTargets( try jws.objectField("cpuFeatures"); try jws.beginObject(); - inline for (@typeInfo(Target.Arch).Union.fields) |field| { + inline for (@typeInfo(Target.Cpu.Arch).Enum.fields) |field| { try jws.objectField(field.name); try jws.beginArray(); - const arch = @unionInit(Target.Arch, field.name, undefined); + const arch = @field(Target.Cpu.Arch, field.name); for (arch.allFeaturesList()) |feature| { try jws.arrayElem(); try jws.emitString(feature.name); @@ -220,27 +197,34 @@ pub fn cmdTargets( try jws.objectField("triple"); try jws.emitString(triple); } - try jws.objectField("arch"); - try jws.emitString(@tagName(native_target.getArch())); - try jws.objectField("os"); - try jws.emitString(@tagName(native_target.getOs())); - try jws.objectField("abi"); - try jws.emitString(@tagName(native_target.getAbi())); - try jws.objectField("cpuName"); - const cpu_features = native_target.getCpuFeatures(); - try jws.emitString(cpu_features.cpu.name); { - try jws.objectField("cpuFeatures"); - try jws.beginArray(); - for (native_target.getArch().allFeaturesList()) |feature, i_usize| { - const index = @intCast(Target.Cpu.Feature.Set.Index, i_usize); - if (cpu_features.features.isEnabled(index)) { - try jws.arrayElem(); - try jws.emitString(feature.name); + try jws.objectField("cpu"); + try jws.beginObject(); + try jws.objectField("arch"); + try jws.emitString(@tagName(native_target.getArch())); + + try jws.objectField("name"); + const cpu = native_target.getCpu(); + try jws.emitString(cpu.model.name); + + { + try jws.objectField("features"); + try jws.beginArray(); + for (native_target.getArch().allFeaturesList()) |feature, i_usize| { + const index = @intCast(Target.Cpu.Feature.Set.Index, i_usize); + if (cpu.features.isEnabled(index)) { + try jws.arrayElem(); + try jws.emitString(feature.name); + } } + try jws.endArray(); } - try jws.endArray(); + try jws.endObject(); } + try jws.objectField("os"); + try jws.emitString(@tagName(native_target.getOs())); + try jws.objectField("abi"); + try jws.emitString(@tagName(native_target.getAbi())); // TODO implement native glibc version detection in self-hosted try jws.endObject(); diff --git a/src-self-hosted/stage1.zig b/src-self-hosted/stage1.zig @@ -1,832 +0,0 @@ -// This is Zig code that is used by both stage1 and stage2. -// The prototypes in src/userland.h must match these definitions. - -const std = @import("std"); -const io = std.io; -const mem = std.mem; -const fs = std.fs; -const process = std.process; -const Allocator = mem.Allocator; -const ArrayList = std.ArrayList; -const Buffer = std.Buffer; -const Target = std.Target; -const self_hosted_main = @import("main.zig"); -const errmsg = @import("errmsg.zig"); -const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer; -const assert = std.debug.assert; - -var stderr_file: fs.File = undefined; -var stderr: *io.OutStream(fs.File.WriteError) = undefined; -var stdout: *io.OutStream(fs.File.WriteError) = undefined; - -comptime { - _ = @import("dep_tokenizer.zig"); -} - -// ABI warning -export fn stage2_zen(ptr: *[*]const u8, len: *usize) void { - const info_zen = @import("main.zig").info_zen; - ptr.* = info_zen; - len.* = info_zen.len; -} - -// ABI warning -export fn stage2_panic(ptr: [*]const u8, len: usize) void { - @panic(ptr[0..len]); -} - -// ABI warning -const Error = extern enum { - None, - OutOfMemory, - InvalidFormat, - SemanticAnalyzeFail, - AccessDenied, - Interrupted, - SystemResources, - FileNotFound, - FileSystem, - FileTooBig, - DivByZero, - Overflow, - PathAlreadyExists, - Unexpected, - ExactDivRemainder, - NegativeDenominator, - ShiftedOutOneBits, - CCompileErrors, - EndOfFile, - IsDir, - NotDir, - UnsupportedOperatingSystem, - SharingViolation, - PipeBusy, - PrimitiveTypeNotFound, - CacheUnavailable, - PathTooLong, - CCompilerCannotFindFile, - NoCCompilerInstalled, - ReadingDepFile, - InvalidDepFile, - MissingArchitecture, - MissingOperatingSystem, - UnknownArchitecture, - UnknownOperatingSystem, - UnknownABI, - InvalidFilename, - DiskQuota, - DiskSpace, - UnexpectedWriteFailure, - UnexpectedSeekFailure, - UnexpectedFileTruncationFailure, - Unimplemented, - OperationAborted, - BrokenPipe, - NoSpaceLeft, - NotLazy, - IsAsync, - ImportOutsidePkgPath, - UnknownCpu, - UnknownSubArchitecture, - UnknownCpuFeature, - InvalidCpuFeatures, - InvalidLlvmCpuFeaturesFormat, - UnknownApplicationBinaryInterface, -}; - -const FILE = std.c.FILE; -const ast = std.zig.ast; -const translate_c = @import("translate_c.zig"); - -/// Args should have a null terminating last arg. -export fn stage2_translate_c( - out_ast: **ast.Tree, - out_errors_ptr: *[*]translate_c.ClangErrMsg, - out_errors_len: *usize, - args_begin: [*]?[*]const u8, - args_end: [*]?[*]const u8, - resources_path: [*:0]const u8, -) Error { - var errors = @as([*]translate_c.ClangErrMsg, undefined)[0..0]; - out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, &errors, resources_path) catch |err| switch (err) { - error.SemanticAnalyzeFail => { - out_errors_ptr.* = errors.ptr; - out_errors_len.* = errors.len; - return Error.CCompileErrors; - }, - error.OutOfMemory => return Error.OutOfMemory, - }; - return Error.None; -} - -export fn stage2_free_clang_errors(errors_ptr: [*]translate_c.ClangErrMsg, errors_len: usize) void { - translate_c.freeErrors(errors_ptr[0..errors_len]); -} - -export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error { - const c_out_stream = &std.io.COutStream.init(output_file).stream; - _ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) { - error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode - error.SystemResources => return Error.SystemResources, - error.OperationAborted => return Error.OperationAborted, - error.BrokenPipe => return Error.BrokenPipe, - error.DiskQuota => return Error.DiskQuota, - error.FileTooBig => return Error.FileTooBig, - error.NoSpaceLeft => return Error.NoSpaceLeft, - error.AccessDenied => return Error.AccessDenied, - error.OutOfMemory => return Error.OutOfMemory, - error.Unexpected => return Error.Unexpected, - error.InputOutput => return Error.FileSystem, - }; - return Error.None; -} - -// TODO: just use the actual self-hosted zig fmt. Until https://github.com/ziglang/zig/issues/2377, -// we use a blocking implementation. -export fn stage2_fmt(argc: c_int, argv: [*]const [*:0]const u8) c_int { - if (std.debug.runtime_safety) { - fmtMain(argc, argv) catch unreachable; - } else { - fmtMain(argc, argv) catch |e| { - std.debug.warn("{}\n", .{@errorName(e)}); - return -1; - }; - } - return 0; -} - -fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void { - const allocator = std.heap.c_allocator; - var args_list = std.ArrayList([]const u8).init(allocator); - const argc_usize = @intCast(usize, argc); - var arg_i: usize = 0; - while (arg_i < argc_usize) : (arg_i += 1) { - try args_list.append(mem.toSliceConst(u8, argv[arg_i])); - } - - stdout = &std.io.getStdOut().outStream().stream; - stderr_file = std.io.getStdErr(); - stderr = &stderr_file.outStream().stream; - - const args = args_list.toSliceConst()[2..]; - - var color: errmsg.Color = .Auto; - var stdin_flag: bool = false; - var check_flag: bool = false; - var input_files = ArrayList([]const u8).init(allocator); - - { - var i: usize = 0; - while (i < args.len) : (i += 1) { - const arg = args[i]; - if (mem.startsWith(u8, arg, "-")) { - if (mem.eql(u8, arg, "--help")) { - try stdout.write(self_hosted_main.usage_fmt); - process.exit(0); - } else if (mem.eql(u8, arg, "--color")) { - if (i + 1 >= args.len) { - try stderr.write("expected [auto|on|off] after --color\n"); - process.exit(1); - } - i += 1; - const next_arg = args[i]; - if (mem.eql(u8, next_arg, "auto")) { - color = .Auto; - } else if (mem.eql(u8, next_arg, "on")) { - color = .On; - } else if (mem.eql(u8, next_arg, "off")) { - color = .Off; - } else { - try stderr.print("expected [auto|on|off] after --color, found '{}'\n", .{next_arg}); - process.exit(1); - } - } else if (mem.eql(u8, arg, "--stdin")) { - stdin_flag = true; - } else if (mem.eql(u8, arg, "--check")) { - check_flag = true; - } else { - try stderr.print("unrecognized parameter: '{}'", .{arg}); - process.exit(1); - } - } else { - try input_files.append(arg); - } - } - } - - if (stdin_flag) { - if (input_files.len != 0) { - try stderr.write("cannot use --stdin with positional arguments\n"); - process.exit(1); - } - - const stdin_file = io.getStdIn(); - var stdin = stdin_file.inStream(); - - const source_code = try stdin.stream.readAllAlloc(allocator, self_hosted_main.max_src_size); - defer allocator.free(source_code); - - const tree = std.zig.parse(allocator, source_code) catch |err| { - try stderr.print("error parsing stdin: {}\n", .{err}); - process.exit(1); - }; - defer tree.deinit(); - - var error_it = tree.errors.iterator(0); - while (error_it.next()) |parse_error| { - try printErrMsgToFile(allocator, parse_error, tree, "<stdin>", stderr_file, color); - } - if (tree.errors.len != 0) { - process.exit(1); - } - if (check_flag) { - const anything_changed = try std.zig.render(allocator, io.null_out_stream, tree); - const code = if (anything_changed) @as(u8, 1) else @as(u8, 0); - process.exit(code); - } - - _ = try std.zig.render(allocator, stdout, tree); - return; - } - - if (input_files.len == 0) { - try stderr.write("expected at least one source file argument\n"); - process.exit(1); - } - - var fmt = Fmt{ - .seen = Fmt.SeenMap.init(allocator), - .any_error = false, - .color = color, - .allocator = allocator, - }; - - for (input_files.toSliceConst()) |file_path| { - try fmtPath(&fmt, file_path, check_flag); - } - if (fmt.any_error) { - process.exit(1); - } -} - -const FmtError = error{ - SystemResources, - OperationAborted, - IoPending, - BrokenPipe, - Unexpected, - WouldBlock, - FileClosed, - DestinationAddressRequired, - DiskQuota, - FileTooBig, - InputOutput, - NoSpaceLeft, - AccessDenied, - OutOfMemory, - RenameAcrossMountPoints, - ReadOnlyFileSystem, - LinkQuotaExceeded, - FileBusy, -} || fs.File.OpenError; - -fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void { - if (fmt.seen.exists(file_path)) return; - try fmt.seen.put(file_path); - - const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) { - error.IsDir, error.AccessDenied => { - // TODO make event based (and dir.next()) - var dir = try fs.cwd().openDirList(file_path); - defer dir.close(); - - var dir_it = dir.iterate(); - - while (try dir_it.next()) |entry| { - if (entry.kind == .Directory or mem.endsWith(u8, entry.name, ".zig")) { - const full_path = try fs.path.join(fmt.allocator, &[_][]const u8{ file_path, entry.name }); - try fmtPath(fmt, full_path, check_mode); - } - } - return; - }, - else => { - // TODO lock stderr printing - try stderr.print("unable to open '{}': {}\n", .{ file_path, err }); - fmt.any_error = true; - return; - }, - }; - defer fmt.allocator.free(source_code); - - const tree = std.zig.parse(fmt.allocator, source_code) catch |err| { - try stderr.print("error parsing file '{}': {}\n", .{ file_path, err }); - fmt.any_error = true; - return; - }; - defer tree.deinit(); - - var error_it = tree.errors.iterator(0); - while (error_it.next()) |parse_error| { - try printErrMsgToFile(fmt.allocator, parse_error, tree, file_path, stderr_file, fmt.color); - } - if (tree.errors.len != 0) { - fmt.any_error = true; - return; - } - - if (check_mode) { - const anything_changed = try std.zig.render(fmt.allocator, io.null_out_stream, tree); - if (anything_changed) { - try stderr.print("{}\n", .{file_path}); - fmt.any_error = true; - } - } else { - const baf = try io.BufferedAtomicFile.create(fmt.allocator, file_path); - defer baf.destroy(); - - const anything_changed = try std.zig.render(fmt.allocator, baf.stream(), tree); - if (anything_changed) { - try stderr.print("{}\n", .{file_path}); - try baf.finish(); - } - } -} - -const Fmt = struct { - seen: SeenMap, - any_error: bool, - color: errmsg.Color, - allocator: *mem.Allocator, - - const SeenMap = std.BufSet; -}; - -fn printErrMsgToFile( - allocator: *mem.Allocator, - parse_error: *const ast.Error, - tree: *ast.Tree, - path: []const u8, - file: fs.File, - color: errmsg.Color, -) !void { - const color_on = switch (color) { - .Auto => file.isTty(), - .On => true, - .Off => false, - }; - const lok_token = parse_error.loc(); - const span = errmsg.Span{ - .first = lok_token, - .last = lok_token, - }; - - const first_token = tree.tokens.at(span.first); - const last_token = tree.tokens.at(span.last); - const start_loc = tree.tokenLocationPtr(0, first_token); - const end_loc = tree.tokenLocationPtr(first_token.end, last_token); - - var text_buf = try std.Buffer.initSize(allocator, 0); - var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; - try parse_error.render(&tree.tokens, out_stream); - const text = text_buf.toOwnedSlice(); - - const stream = &file.outStream().stream; - try stream.print("{}:{}:{}: error: {}\n", .{ path, start_loc.line + 1, start_loc.column + 1, text }); - - if (!color_on) return; - - // Print \r and \t as one space each so that column counts line up - for (tree.source[start_loc.line_start..start_loc.line_end]) |byte| { - try stream.writeByte(switch (byte) { - '\r', '\t' => ' ', - else => byte, - }); - } - try stream.writeByte('\n'); - try stream.writeByteNTimes(' ', start_loc.column); - try stream.writeByteNTimes('~', last_token.end - first_token.start); - try stream.writeByte('\n'); -} - -export fn stage2_DepTokenizer_init(input: [*]const u8, len: usize) stage2_DepTokenizer { - const t = std.heap.c_allocator.create(DepTokenizer) catch @panic("failed to create .d tokenizer"); - t.* = DepTokenizer.init(std.heap.c_allocator, input[0..len]); - return stage2_DepTokenizer{ - .handle = t, - }; -} - -export fn stage2_DepTokenizer_deinit(self: *stage2_DepTokenizer) void { - self.handle.deinit(); -} - -export fn stage2_DepTokenizer_next(self: *stage2_DepTokenizer) stage2_DepNextResult { - const otoken = self.handle.next() catch { - const textz = std.Buffer.init(&self.handle.arena.allocator, self.handle.error_text) catch @panic("failed to create .d tokenizer error text"); - return stage2_DepNextResult{ - .type_id = .error_, - .textz = textz.toSlice().ptr, - }; - }; - const token = otoken orelse { - return stage2_DepNextResult{ - .type_id = .null_, - .textz = undefined, - }; - }; - const textz = std.Buffer.init(&self.handle.arena.allocator, token.bytes) catch @panic("failed to create .d tokenizer token text"); - return stage2_DepNextResult{ - .type_id = switch (token.id) { - .target => .target, - .prereq => .prereq, - }, - .textz = textz.toSlice().ptr, - }; -} - -const stage2_DepTokenizer = extern struct { - handle: *DepTokenizer, -}; - -const stage2_DepNextResult = extern struct { - type_id: TypeId, - - // when type_id == error --> error text - // when type_id == null --> undefined - // when type_id == target --> target pathname - // when type_id == prereq --> prereq pathname - textz: [*]const u8, - - const TypeId = extern enum { - error_, - null_, - target, - prereq, - }; -}; - -// ABI warning -export fn stage2_attach_segfault_handler() void { - if (std.debug.runtime_safety and std.debug.have_segfault_handling_support) { - std.debug.attachSegfaultHandler(); - } -} - -// ABI warning -export fn stage2_progress_create() *std.Progress { - const ptr = std.heap.c_allocator.create(std.Progress) catch @panic("out of memory"); - ptr.* = std.Progress{}; - return ptr; -} - -// ABI warning -export fn stage2_progress_destroy(progress: *std.Progress) void { - std.heap.c_allocator.destroy(progress); -} - -// ABI warning -export fn stage2_progress_start_root( - progress: *std.Progress, - name_ptr: [*]const u8, - name_len: usize, - estimated_total_items: usize, -) *std.Progress.Node { - return progress.start( - name_ptr[0..name_len], - if (estimated_total_items == 0) null else estimated_total_items, - ) catch @panic("timer unsupported"); -} - -// ABI warning -export fn stage2_progress_disable_tty(progress: *std.Progress) void { - progress.terminal = null; -} - -// ABI warning -export fn stage2_progress_start( - node: *std.Progress.Node, - name_ptr: [*]const u8, - name_len: usize, - estimated_total_items: usize, -) *std.Progress.Node { - const child_node = std.heap.c_allocator.create(std.Progress.Node) catch @panic("out of memory"); - child_node.* = node.start( - name_ptr[0..name_len], - if (estimated_total_items == 0) null else estimated_total_items, - ); - child_node.activate(); - return child_node; -} - -// ABI warning -export fn stage2_progress_end(node: *std.Progress.Node) void { - node.end(); - if (&node.context.root != node) { - std.heap.c_allocator.destroy(node); - } -} - -// ABI warning -export fn stage2_progress_complete_one(node: *std.Progress.Node) void { - node.completeOne(); -} - -// ABI warning -export fn stage2_progress_update_node(node: *std.Progress.Node, done_count: usize, total_count: usize) void { - node.completed_items = done_count; - node.estimated_total_items = total_count; - node.activate(); - node.context.maybeRefresh(); -} - -fn cpuFeaturesFromLLVM( - arch: Target.Arch, - llvm_cpu_name_z: ?[*:0]const u8, - llvm_cpu_features_opt: ?[*:0]const u8, -) !Target.CpuFeatures { - var result = arch.getBaselineCpuFeatures(); - - if (llvm_cpu_name_z) |cpu_name_z| { - const llvm_cpu_name = mem.toSliceConst(u8, cpu_name_z); - - for (arch.allCpus()) |cpu| { - const this_llvm_name = cpu.llvm_name orelse continue; - if (mem.eql(u8, this_llvm_name, llvm_cpu_name)) { - // Here we use the non-dependencies-populated set, - // so that subtracting features later in this function - // affect the prepopulated set. - result = Target.CpuFeatures{ - .cpu = cpu, - .features = cpu.features, - }; - break; - } - } - } - - const all_features = arch.allFeaturesList(); - - if (llvm_cpu_features_opt) |llvm_cpu_features| { - var it = mem.tokenize(mem.toSliceConst(u8, llvm_cpu_features), ","); - while (it.next()) |decorated_llvm_feat| { - var op: enum { - add, - sub, - } = undefined; - var llvm_feat: []const u8 = undefined; - if (mem.startsWith(u8, decorated_llvm_feat, "+")) { - op = .add; - llvm_feat = decorated_llvm_feat[1..]; - } else if (mem.startsWith(u8, decorated_llvm_feat, "-")) { - op = .sub; - llvm_feat = decorated_llvm_feat[1..]; - } else { - return error.InvalidLlvmCpuFeaturesFormat; - } - for (all_features) |feature, index_usize| { - const this_llvm_name = feature.llvm_name orelse continue; - if (mem.eql(u8, llvm_feat, this_llvm_name)) { - const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize); - switch (op) { - .add => result.features.addFeature(index), - .sub => result.features.removeFeature(index), - } - break; - } - } - } - } - - result.features.populateDependencies(all_features); - return result; -} - -// ABI warning -export fn stage2_cmd_targets(zig_triple: [*:0]const u8) c_int { - cmdTargets(zig_triple) catch |err| { - std.debug.warn("unable to list targets: {}\n", .{@errorName(err)}); - return -1; - }; - return 0; -} - -fn cmdTargets(zig_triple: [*:0]const u8) !void { - var target = try Target.parse(mem.toSliceConst(u8, zig_triple)); - target.Cross.cpu_features = blk: { - const llvm = @import("llvm.zig"); - const llvm_cpu_name = llvm.GetHostCPUName(); - const llvm_cpu_features = llvm.GetNativeFeatures(); - break :blk try cpuFeaturesFromLLVM(target.Cross.arch, llvm_cpu_name, llvm_cpu_features); - }; - return @import("print_targets.zig").cmdTargets( - std.heap.c_allocator, - &[0][]u8{}, - &std.io.getStdOut().outStream().stream, - target, - ); -} - -const Stage2CpuFeatures = struct { - allocator: *mem.Allocator, - cpu_features: Target.CpuFeatures, - - llvm_features_str: ?[*:0]const u8, - - builtin_str: [:0]const u8, - cache_hash: [:0]const u8, - - const Self = @This(); - - fn createFromNative(allocator: *mem.Allocator) !*Self { - const arch = Target.current.getArch(); - const llvm = @import("llvm.zig"); - const llvm_cpu_name = llvm.GetHostCPUName(); - const llvm_cpu_features = llvm.GetNativeFeatures(); - const cpu_features = try cpuFeaturesFromLLVM(arch, llvm_cpu_name, llvm_cpu_features); - return createFromCpuFeatures(allocator, arch, cpu_features); - } - - fn createFromCpuFeatures( - allocator: *mem.Allocator, - arch: Target.Arch, - cpu_features: Target.CpuFeatures, - ) !*Self { - const self = try allocator.create(Self); - errdefer allocator.destroy(self); - - const cache_hash = try std.fmt.allocPrint0(allocator, "{}\n{}", .{ - cpu_features.cpu.name, - cpu_features.features.asBytes(), - }); - errdefer allocator.free(cache_hash); - - const generic_arch_name = arch.genericName(); - var builtin_str_buffer = try std.Buffer.allocPrint(allocator, - \\CpuFeatures{{ - \\ .cpu = &Target.{}.cpu.{}, - \\ .features = Target.{}.featureSet(&[_]Target.{}.Feature{{ - \\ - , .{ - generic_arch_name, - cpu_features.cpu.name, - generic_arch_name, - generic_arch_name, - }); - defer builtin_str_buffer.deinit(); - - var llvm_features_buffer = try std.Buffer.initSize(allocator, 0); - defer llvm_features_buffer.deinit(); - - for (arch.allFeaturesList()) |feature, index_usize| { - const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize); - const is_enabled = cpu_features.features.isEnabled(index); - - if (feature.llvm_name) |llvm_name| { - const plus_or_minus = "-+"[@boolToInt(is_enabled)]; - try llvm_features_buffer.appendByte(plus_or_minus); - try llvm_features_buffer.append(llvm_name); - try llvm_features_buffer.append(","); - } - - if (is_enabled) { - // TODO some kind of "zig identifier escape" function rather than - // unconditionally using @"" syntax - try builtin_str_buffer.append(" .@\""); - try builtin_str_buffer.append(feature.name); - try builtin_str_buffer.append("\",\n"); - } - } - - try builtin_str_buffer.append( - \\ }), - \\}; - \\ - ); - - assert(mem.endsWith(u8, llvm_features_buffer.toSliceConst(), ",")); - llvm_features_buffer.shrink(llvm_features_buffer.len() - 1); - - self.* = Self{ - .allocator = allocator, - .cpu_features = cpu_features, - .llvm_features_str = llvm_features_buffer.toOwnedSlice().ptr, - .builtin_str = builtin_str_buffer.toOwnedSlice(), - .cache_hash = cache_hash, - }; - return self; - } - - fn destroy(self: *Self) void { - self.allocator.free(self.cache_hash); - self.allocator.free(self.builtin_str); - // TODO if (self.llvm_features_str) |llvm_features_str| self.allocator.free(llvm_features_str); - self.allocator.destroy(self); - } -}; - -// ABI warning -export fn stage2_cpu_features_parse( - result: **Stage2CpuFeatures, - zig_triple: ?[*:0]const u8, - cpu_name: ?[*:0]const u8, - cpu_features: ?[*:0]const u8, -) Error { - result.* = stage2ParseCpuFeatures(zig_triple, cpu_name, cpu_features) catch |err| switch (err) { - error.OutOfMemory => return .OutOfMemory, - error.UnknownArchitecture => return .UnknownArchitecture, - error.UnknownSubArchitecture => return .UnknownSubArchitecture, - error.UnknownOperatingSystem => return .UnknownOperatingSystem, - error.UnknownApplicationBinaryInterface => return .UnknownApplicationBinaryInterface, - error.MissingOperatingSystem => return .MissingOperatingSystem, - error.MissingArchitecture => return .MissingArchitecture, - error.InvalidLlvmCpuFeaturesFormat => return .InvalidLlvmCpuFeaturesFormat, - error.InvalidCpuFeatures => return .InvalidCpuFeatures, - }; - return .None; -} - -fn stage2ParseCpuFeatures( - zig_triple_oz: ?[*:0]const u8, - cpu_name_oz: ?[*:0]const u8, - cpu_features_oz: ?[*:0]const u8, -) !*Stage2CpuFeatures { - const zig_triple_z = zig_triple_oz orelse return Stage2CpuFeatures.createFromNative(std.heap.c_allocator); - const target = try Target.parse(mem.toSliceConst(u8, zig_triple_z)); - const arch = target.Cross.arch; - - const cpu = if (cpu_name_oz) |cpu_name_z| blk: { - const cpu_name = mem.toSliceConst(u8, cpu_name_z); - break :blk arch.parseCpu(cpu_name) catch |err| switch (err) { - error.UnknownCpu => { - std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{ - cpu_name, - @tagName(arch), - }); - for (arch.allCpus()) |cpu| { - std.debug.warn(" {}\n", .{cpu.name}); - } - process.exit(1); - }, - else => |e| return e, - }; - } else target.Cross.cpu_features.cpu; - - var set = if (cpu_features_oz) |cpu_features_z| blk: { - const cpu_features = mem.toSliceConst(u8, cpu_features_z); - break :blk arch.parseCpuFeatureSet(cpu, cpu_features) catch |err| switch (err) { - error.UnknownCpuFeature => { - std.debug.warn( - \\Unknown CPU features specified. - \\Available CPU features for architecture '{}': - \\ - , .{@tagName(arch)}); - for (arch.allFeaturesList()) |feature| { - std.debug.warn(" {}\n", .{feature.name}); - } - process.exit(1); - }, - else => |e| return e, - }; - } else cpu.features; - - if (arch.subArchFeature()) |index| { - set.addFeature(index); - } - set.populateDependencies(arch.allFeaturesList()); - - return Stage2CpuFeatures.createFromCpuFeatures(std.heap.c_allocator, arch, .{ - .cpu = cpu, - .features = set, - }); -} - -// ABI warning -export fn stage2_cpu_features_get_cache_hash( - cpu_features: *const Stage2CpuFeatures, - ptr: *[*:0]const u8, - len: *usize, -) void { - ptr.* = cpu_features.cache_hash.ptr; - len.* = cpu_features.cache_hash.len; -} - -// ABI warning -export fn stage2_cpu_features_get_builtin_str( - cpu_features: *const Stage2CpuFeatures, - ptr: *[*:0]const u8, - len: *usize, -) void { - ptr.* = cpu_features.builtin_str.ptr; - len.* = cpu_features.builtin_str.len; -} - -// ABI warning -export fn stage2_cpu_features_get_llvm_cpu(cpu_features: *const Stage2CpuFeatures) ?[*:0]const u8 { - return if (cpu_features.cpu_features.cpu.llvm_name) |s| s.ptr else null; -} - -// ABI warning -export fn stage2_cpu_features_get_llvm_features(cpu_features: *const Stage2CpuFeatures) ?[*:0]const u8 { - return cpu_features.llvm_features_str; -} diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig @@ -0,0 +1,1064 @@ +// This is Zig code that is used by both stage1 and stage2. +// The prototypes in src/userland.h must match these definitions. + +const std = @import("std"); +const io = std.io; +const mem = std.mem; +const fs = std.fs; +const process = std.process; +const Allocator = mem.Allocator; +const ArrayList = std.ArrayList; +const Buffer = std.Buffer; +const Target = std.Target; +const self_hosted_main = @import("main.zig"); +const errmsg = @import("errmsg.zig"); +const DepTokenizer = @import("dep_tokenizer.zig").Tokenizer; +const assert = std.debug.assert; +const LibCInstallation = @import("libc_installation.zig").LibCInstallation; + +var stderr_file: fs.File = undefined; +var stderr: *io.OutStream(fs.File.WriteError) = undefined; +var stdout: *io.OutStream(fs.File.WriteError) = undefined; + +comptime { + _ = @import("dep_tokenizer.zig"); +} + +// ABI warning +export fn stage2_zen(ptr: *[*]const u8, len: *usize) void { + const info_zen = @import("main.zig").info_zen; + ptr.* = info_zen; + len.* = info_zen.len; +} + +// ABI warning +export fn stage2_panic(ptr: [*]const u8, len: usize) void { + @panic(ptr[0..len]); +} + +// ABI warning +const Error = extern enum { + None, + OutOfMemory, + InvalidFormat, + SemanticAnalyzeFail, + AccessDenied, + Interrupted, + SystemResources, + FileNotFound, + FileSystem, + FileTooBig, + DivByZero, + Overflow, + PathAlreadyExists, + Unexpected, + ExactDivRemainder, + NegativeDenominator, + ShiftedOutOneBits, + CCompileErrors, + EndOfFile, + IsDir, + NotDir, + UnsupportedOperatingSystem, + SharingViolation, + PipeBusy, + PrimitiveTypeNotFound, + CacheUnavailable, + PathTooLong, + CCompilerCannotFindFile, + NoCCompilerInstalled, + ReadingDepFile, + InvalidDepFile, + MissingArchitecture, + MissingOperatingSystem, + UnknownArchitecture, + UnknownOperatingSystem, + UnknownABI, + InvalidFilename, + DiskQuota, + DiskSpace, + UnexpectedWriteFailure, + UnexpectedSeekFailure, + UnexpectedFileTruncationFailure, + Unimplemented, + OperationAborted, + BrokenPipe, + NoSpaceLeft, + NotLazy, + IsAsync, + ImportOutsidePkgPath, + UnknownCpu, + UnknownCpuFeature, + InvalidCpuFeatures, + InvalidLlvmCpuFeaturesFormat, + UnknownApplicationBinaryInterface, + ASTUnitFailure, + BadPathName, + SymLinkLoop, + ProcessFdQuotaExceeded, + SystemFdQuotaExceeded, + NoDevice, + DeviceBusy, + UnableToSpawnCCompiler, + CCompilerExitCode, + CCompilerCrashed, + CCompilerCannotFindHeaders, + LibCRuntimeNotFound, + LibCStdLibHeaderNotFound, + LibCKernel32LibNotFound, + UnsupportedArchitecture, + WindowsSdkNotFound, + UnknownDynamicLinkerPath, + TargetHasNoDynamicLinker, +}; + +const FILE = std.c.FILE; +const ast = std.zig.ast; +const translate_c = @import("translate_c.zig"); + +/// Args should have a null terminating last arg. +export fn stage2_translate_c( + out_ast: **ast.Tree, + out_errors_ptr: *[*]translate_c.ClangErrMsg, + out_errors_len: *usize, + args_begin: [*]?[*]const u8, + args_end: [*]?[*]const u8, + resources_path: [*:0]const u8, +) Error { + var errors = @as([*]translate_c.ClangErrMsg, undefined)[0..0]; + out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, &errors, resources_path) catch |err| switch (err) { + error.SemanticAnalyzeFail => { + out_errors_ptr.* = errors.ptr; + out_errors_len.* = errors.len; + return .CCompileErrors; + }, + error.ASTUnitFailure => return .ASTUnitFailure, + error.OutOfMemory => return .OutOfMemory, + }; + return .None; +} + +export fn stage2_free_clang_errors(errors_ptr: [*]translate_c.ClangErrMsg, errors_len: usize) void { + translate_c.freeErrors(errors_ptr[0..errors_len]); +} + +export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error { + const c_out_stream = &std.io.COutStream.init(output_file).stream; + _ = std.zig.render(std.heap.c_allocator, c_out_stream, tree) catch |e| switch (e) { + error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode + error.SystemResources => return .SystemResources, + error.OperationAborted => return .OperationAborted, + error.BrokenPipe => return .BrokenPipe, + error.DiskQuota => return .DiskQuota, + error.FileTooBig => return .FileTooBig, + error.NoSpaceLeft => return .NoSpaceLeft, + error.AccessDenied => return .AccessDenied, + error.OutOfMemory => return .OutOfMemory, + error.Unexpected => return .Unexpected, + error.InputOutput => return .FileSystem, + }; + return .None; +} + +// TODO: just use the actual self-hosted zig fmt. Until https://github.com/ziglang/zig/issues/2377, +// we use a blocking implementation. +export fn stage2_fmt(argc: c_int, argv: [*]const [*:0]const u8) c_int { + if (std.debug.runtime_safety) { + fmtMain(argc, argv) catch unreachable; + } else { + fmtMain(argc, argv) catch |e| { + std.debug.warn("{}\n", .{@errorName(e)}); + return -1; + }; + } + return 0; +} + +fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void { + const allocator = std.heap.c_allocator; + var args_list = std.ArrayList([]const u8).init(allocator); + const argc_usize = @intCast(usize, argc); + var arg_i: usize = 0; + while (arg_i < argc_usize) : (arg_i += 1) { + try args_list.append(mem.toSliceConst(u8, argv[arg_i])); + } + + stdout = &std.io.getStdOut().outStream().stream; + stderr_file = std.io.getStdErr(); + stderr = &stderr_file.outStream().stream; + + const args = args_list.toSliceConst()[2..]; + + var color: errmsg.Color = .Auto; + var stdin_flag: bool = false; + var check_flag: bool = false; + var input_files = ArrayList([]const u8).init(allocator); + + { + var i: usize = 0; + while (i < args.len) : (i += 1) { + const arg = args[i]; + if (mem.startsWith(u8, arg, "-")) { + if (mem.eql(u8, arg, "--help")) { + try stdout.write(self_hosted_main.usage_fmt); + process.exit(0); + } else if (mem.eql(u8, arg, "--color")) { + if (i + 1 >= args.len) { + try stderr.write("expected [auto|on|off] after --color\n"); + process.exit(1); + } + i += 1; + const next_arg = args[i]; + if (mem.eql(u8, next_arg, "auto")) { + color = .Auto; + } else if (mem.eql(u8, next_arg, "on")) { + color = .On; + } else if (mem.eql(u8, next_arg, "off")) { + color = .Off; + } else { + try stderr.print("expected [auto|on|off] after --color, found '{}'\n", .{next_arg}); + process.exit(1); + } + } else if (mem.eql(u8, arg, "--stdin")) { + stdin_flag = true; + } else if (mem.eql(u8, arg, "--check")) { + check_flag = true; + } else { + try stderr.print("unrecognized parameter: '{}'", .{arg}); + process.exit(1); + } + } else { + try input_files.append(arg); + } + } + } + + if (stdin_flag) { + if (input_files.len != 0) { + try stderr.write("cannot use --stdin with positional arguments\n"); + process.exit(1); + } + + const stdin_file = io.getStdIn(); + var stdin = stdin_file.inStream(); + + const source_code = try stdin.stream.readAllAlloc(allocator, self_hosted_main.max_src_size); + defer allocator.free(source_code); + + const tree = std.zig.parse(allocator, source_code) catch |err| { + try stderr.print("error parsing stdin: {}\n", .{err}); + process.exit(1); + }; + defer tree.deinit(); + + var error_it = tree.errors.iterator(0); + while (error_it.next()) |parse_error| { + try printErrMsgToFile(allocator, parse_error, tree, "<stdin>", stderr_file, color); + } + if (tree.errors.len != 0) { + process.exit(1); + } + if (check_flag) { + const anything_changed = try std.zig.render(allocator, io.null_out_stream, tree); + const code = if (anything_changed) @as(u8, 1) else @as(u8, 0); + process.exit(code); + } + + _ = try std.zig.render(allocator, stdout, tree); + return; + } + + if (input_files.len == 0) { + try stderr.write("expected at least one source file argument\n"); + process.exit(1); + } + + var fmt = Fmt{ + .seen = Fmt.SeenMap.init(allocator), + .any_error = false, + .color = color, + .allocator = allocator, + }; + + for (input_files.toSliceConst()) |file_path| { + try fmtPath(&fmt, file_path, check_flag); + } + if (fmt.any_error) { + process.exit(1); + } +} + +const FmtError = error{ + SystemResources, + OperationAborted, + IoPending, + BrokenPipe, + Unexpected, + WouldBlock, + FileClosed, + DestinationAddressRequired, + DiskQuota, + FileTooBig, + InputOutput, + NoSpaceLeft, + AccessDenied, + OutOfMemory, + RenameAcrossMountPoints, + ReadOnlyFileSystem, + LinkQuotaExceeded, + FileBusy, +} || fs.File.OpenError; + +fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void { + if (fmt.seen.exists(file_path)) return; + try fmt.seen.put(file_path); + + const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) { + error.IsDir, error.AccessDenied => { + // TODO make event based (and dir.next()) + var dir = try fs.cwd().openDirList(file_path); + defer dir.close(); + + var dir_it = dir.iterate(); + + while (try dir_it.next()) |entry| { + if (entry.kind == .Directory or mem.endsWith(u8, entry.name, ".zig")) { + const full_path = try fs.path.join(fmt.allocator, &[_][]const u8{ file_path, entry.name }); + try fmtPath(fmt, full_path, check_mode); + } + } + return; + }, + else => { + // TODO lock stderr printing + try stderr.print("unable to open '{}': {}\n", .{ file_path, err }); + fmt.any_error = true; + return; + }, + }; + defer fmt.allocator.free(source_code); + + const tree = std.zig.parse(fmt.allocator, source_code) catch |err| { + try stderr.print("error parsing file '{}': {}\n", .{ file_path, err }); + fmt.any_error = true; + return; + }; + defer tree.deinit(); + + var error_it = tree.errors.iterator(0); + while (error_it.next()) |parse_error| { + try printErrMsgToFile(fmt.allocator, parse_error, tree, file_path, stderr_file, fmt.color); + } + if (tree.errors.len != 0) { + fmt.any_error = true; + return; + } + + if (check_mode) { + const anything_changed = try std.zig.render(fmt.allocator, io.null_out_stream, tree); + if (anything_changed) { + try stderr.print("{}\n", .{file_path}); + fmt.any_error = true; + } + } else { + const baf = try io.BufferedAtomicFile.create(fmt.allocator, file_path); + defer baf.destroy(); + + const anything_changed = try std.zig.render(fmt.allocator, baf.stream(), tree); + if (anything_changed) { + try stderr.print("{}\n", .{file_path}); + try baf.finish(); + } + } +} + +const Fmt = struct { + seen: SeenMap, + any_error: bool, + color: errmsg.Color, + allocator: *mem.Allocator, + + const SeenMap = std.BufSet; +}; + +fn printErrMsgToFile( + allocator: *mem.Allocator, + parse_error: *const ast.Error, + tree: *ast.Tree, + path: []const u8, + file: fs.File, + color: errmsg.Color, +) !void { + const color_on = switch (color) { + .Auto => file.isTty(), + .On => true, + .Off => false, + }; + const lok_token = parse_error.loc(); + const span = errmsg.Span{ + .first = lok_token, + .last = lok_token, + }; + + const first_token = tree.tokens.at(span.first); + const last_token = tree.tokens.at(span.last); + const start_loc = tree.tokenLocationPtr(0, first_token); + const end_loc = tree.tokenLocationPtr(first_token.end, last_token); + + var text_buf = try std.Buffer.initSize(allocator, 0); + var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; + try parse_error.render(&tree.tokens, out_stream); + const text = text_buf.toOwnedSlice(); + + const stream = &file.outStream().stream; + try stream.print("{}:{}:{}: error: {}\n", .{ path, start_loc.line + 1, start_loc.column + 1, text }); + + if (!color_on) return; + + // Print \r and \t as one space each so that column counts line up + for (tree.source[start_loc.line_start..start_loc.line_end]) |byte| { + try stream.writeByte(switch (byte) { + '\r', '\t' => ' ', + else => byte, + }); + } + try stream.writeByte('\n'); + try stream.writeByteNTimes(' ', start_loc.column); + try stream.writeByteNTimes('~', last_token.end - first_token.start); + try stream.writeByte('\n'); +} + +export fn stage2_DepTokenizer_init(input: [*]const u8, len: usize) stage2_DepTokenizer { + const t = std.heap.c_allocator.create(DepTokenizer) catch @panic("failed to create .d tokenizer"); + t.* = DepTokenizer.init(std.heap.c_allocator, input[0..len]); + return stage2_DepTokenizer{ + .handle = t, + }; +} + +export fn stage2_DepTokenizer_deinit(self: *stage2_DepTokenizer) void { + self.handle.deinit(); +} + +export fn stage2_DepTokenizer_next(self: *stage2_DepTokenizer) stage2_DepNextResult { + const otoken = self.handle.next() catch { + const textz = std.Buffer.init(&self.handle.arena.allocator, self.handle.error_text) catch @panic("failed to create .d tokenizer error text"); + return stage2_DepNextResult{ + .type_id = .error_, + .textz = textz.toSlice().ptr, + }; + }; + const token = otoken orelse { + return stage2_DepNextResult{ + .type_id = .null_, + .textz = undefined, + }; + }; + const textz = std.Buffer.init(&self.handle.arena.allocator, token.bytes) catch @panic("failed to create .d tokenizer token text"); + return stage2_DepNextResult{ + .type_id = switch (token.id) { + .target => .target, + .prereq => .prereq, + }, + .textz = textz.toSlice().ptr, + }; +} + +const stage2_DepTokenizer = extern struct { + handle: *DepTokenizer, +}; + +const stage2_DepNextResult = extern struct { + type_id: TypeId, + + // when type_id == error --> error text + // when type_id == null --> undefined + // when type_id == target --> target pathname + // when type_id == prereq --> prereq pathname + textz: [*]const u8, + + const TypeId = extern enum { + error_, + null_, + target, + prereq, + }; +}; + +// ABI warning +export fn stage2_attach_segfault_handler() void { + if (std.debug.runtime_safety and std.debug.have_segfault_handling_support) { + std.debug.attachSegfaultHandler(); + } +} + +// ABI warning +export fn stage2_progress_create() *std.Progress { + const ptr = std.heap.c_allocator.create(std.Progress) catch @panic("out of memory"); + ptr.* = std.Progress{}; + return ptr; +} + +// ABI warning +export fn stage2_progress_destroy(progress: *std.Progress) void { + std.heap.c_allocator.destroy(progress); +} + +// ABI warning +export fn stage2_progress_start_root( + progress: *std.Progress, + name_ptr: [*]const u8, + name_len: usize, + estimated_total_items: usize, +) *std.Progress.Node { + return progress.start( + name_ptr[0..name_len], + if (estimated_total_items == 0) null else estimated_total_items, + ) catch @panic("timer unsupported"); +} + +// ABI warning +export fn stage2_progress_disable_tty(progress: *std.Progress) void { + progress.terminal = null; +} + +// ABI warning +export fn stage2_progress_start( + node: *std.Progress.Node, + name_ptr: [*]const u8, + name_len: usize, + estimated_total_items: usize, +) *std.Progress.Node { + const child_node = std.heap.c_allocator.create(std.Progress.Node) catch @panic("out of memory"); + child_node.* = node.start( + name_ptr[0..name_len], + if (estimated_total_items == 0) null else estimated_total_items, + ); + child_node.activate(); + return child_node; +} + +// ABI warning +export fn stage2_progress_end(node: *std.Progress.Node) void { + node.end(); + if (&node.context.root != node) { + std.heap.c_allocator.destroy(node); + } +} + +// ABI warning +export fn stage2_progress_complete_one(node: *std.Progress.Node) void { + node.completeOne(); +} + +// ABI warning +export fn stage2_progress_update_node(node: *std.Progress.Node, done_count: usize, total_count: usize) void { + node.completed_items = done_count; + node.estimated_total_items = total_count; + node.activate(); + node.context.maybeRefresh(); +} + +fn detectNativeCpuWithLLVM( + arch: Target.Cpu.Arch, + llvm_cpu_name_z: ?[*:0]const u8, + llvm_cpu_features_opt: ?[*:0]const u8, +) !Target.Cpu { + var result = Target.Cpu.baseline(arch); + + if (llvm_cpu_name_z) |cpu_name_z| { + const llvm_cpu_name = mem.toSliceConst(u8, cpu_name_z); + + for (arch.allCpuModels()) |model| { + const this_llvm_name = model.llvm_name orelse continue; + if (mem.eql(u8, this_llvm_name, llvm_cpu_name)) { + // Here we use the non-dependencies-populated set, + // so that subtracting features later in this function + // affect the prepopulated set. + result = Target.Cpu{ + .arch = arch, + .model = model, + .features = model.features, + }; + break; + } + } + } + + const all_features = arch.allFeaturesList(); + + if (llvm_cpu_features_opt) |llvm_cpu_features| { + var it = mem.tokenize(mem.toSliceConst(u8, llvm_cpu_features), ","); + while (it.next()) |decorated_llvm_feat| { + var op: enum { + add, + sub, + } = undefined; + var llvm_feat: []const u8 = undefined; + if (mem.startsWith(u8, decorated_llvm_feat, "+")) { + op = .add; + llvm_feat = decorated_llvm_feat[1..]; + } else if (mem.startsWith(u8, decorated_llvm_feat, "-")) { + op = .sub; + llvm_feat = decorated_llvm_feat[1..]; + } else { + return error.InvalidLlvmCpuFeaturesFormat; + } + for (all_features) |feature, index_usize| { + const this_llvm_name = feature.llvm_name orelse continue; + if (mem.eql(u8, llvm_feat, this_llvm_name)) { + const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize); + switch (op) { + .add => result.features.addFeature(index), + .sub => result.features.removeFeature(index), + } + break; + } + } + } + } + + result.features.populateDependencies(all_features); + return result; +} + +// ABI warning +export fn stage2_cmd_targets(zig_triple: [*:0]const u8) c_int { + cmdTargets(zig_triple) catch |err| { + std.debug.warn("unable to list targets: {}\n", .{@errorName(err)}); + return -1; + }; + return 0; +} + +fn cmdTargets(zig_triple: [*:0]const u8) !void { + var target = try Target.parse(.{ .arch_os_abi = mem.toSliceConst(u8, zig_triple) }); + target.Cross.cpu = blk: { + const llvm = @import("llvm.zig"); + const llvm_cpu_name = llvm.GetHostCPUName(); + const llvm_cpu_features = llvm.GetNativeFeatures(); + break :blk try detectNativeCpuWithLLVM(target.getArch(), llvm_cpu_name, llvm_cpu_features); + }; + return @import("print_targets.zig").cmdTargets( + std.heap.c_allocator, + &[0][]u8{}, + &std.io.getStdOut().outStream().stream, + target, + ); +} + +// ABI warning +export fn stage2_target_parse( + target: *Stage2Target, + zig_triple: ?[*:0]const u8, + mcpu: ?[*:0]const u8, +) Error { + stage2TargetParse(target, zig_triple, mcpu) catch |err| switch (err) { + error.OutOfMemory => return .OutOfMemory, + error.UnknownArchitecture => return .UnknownArchitecture, + error.UnknownOperatingSystem => return .UnknownOperatingSystem, + error.UnknownApplicationBinaryInterface => return .UnknownApplicationBinaryInterface, + error.MissingOperatingSystem => return .MissingOperatingSystem, + error.MissingArchitecture => return .MissingArchitecture, + error.InvalidLlvmCpuFeaturesFormat => return .InvalidLlvmCpuFeaturesFormat, + error.UnexpectedExtraField => return .SemanticAnalyzeFail, + }; + return .None; +} + +fn stage2TargetParse( + stage1_target: *Stage2Target, + zig_triple_oz: ?[*:0]const u8, + mcpu_oz: ?[*:0]const u8, +) !void { + const target: Target = if (zig_triple_oz) |zig_triple_z| blk: { + const zig_triple = mem.toSliceConst(u8, zig_triple_z); + const mcpu = if (mcpu_oz) |mcpu_z| mem.toSliceConst(u8, mcpu_z) else "baseline"; + var diags: std.Target.ParseOptions.Diagnostics = .{}; + break :blk Target.parse(.{ + .arch_os_abi = zig_triple, + .cpu_features = mcpu, + .diagnostics = &diags, + }) catch |err| switch (err) { + error.UnknownCpu => { + std.debug.warn("Unknown CPU: '{}'\nAvailable CPUs for architecture '{}':\n", .{ + diags.cpu_name.?, + @tagName(diags.arch.?), + }); + for (diags.arch.?.allCpuModels()) |cpu| { + std.debug.warn(" {}\n", .{cpu.name}); + } + process.exit(1); + }, + error.UnknownCpuFeature => { + std.debug.warn( + \\Unknown CPU feature: '{}' + \\Available CPU features for architecture '{}': + \\ + , .{ + diags.unknown_feature_name, + @tagName(diags.arch.?), + }); + for (diags.arch.?.allFeaturesList()) |feature| { + std.debug.warn(" {}: {}\n", .{ feature.name, feature.description }); + } + process.exit(1); + }, + else => |e| return e, + }; + } else Target.Native; + + try stage1_target.fromTarget(target); +} + +fn initStage1TargetCpuFeatures(stage1_target: *Stage2Target, cpu: Target.Cpu) !void { + const allocator = std.heap.c_allocator; + const cache_hash = try std.fmt.allocPrint0(allocator, "{}\n{}", .{ + cpu.model.name, + cpu.features.asBytes(), + }); + errdefer allocator.free(cache_hash); + + const generic_arch_name = cpu.arch.genericName(); + var builtin_str_buffer = try std.Buffer.allocPrint(allocator, + \\Cpu{{ + \\ .arch = .{}, + \\ .model = &Target.{}.cpu.{}, + \\ .features = Target.{}.featureSet(&[_]Target.{}.Feature{{ + \\ + , .{ + @tagName(cpu.arch), + generic_arch_name, + cpu.model.name, + generic_arch_name, + generic_arch_name, + }); + defer builtin_str_buffer.deinit(); + + var llvm_features_buffer = try std.Buffer.initSize(allocator, 0); + defer llvm_features_buffer.deinit(); + + for (cpu.arch.allFeaturesList()) |feature, index_usize| { + const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize); + const is_enabled = cpu.features.isEnabled(index); + + if (feature.llvm_name) |llvm_name| { + const plus_or_minus = "-+"[@boolToInt(is_enabled)]; + try llvm_features_buffer.appendByte(plus_or_minus); + try llvm_features_buffer.append(llvm_name); + try llvm_features_buffer.append(","); + } + + if (is_enabled) { + // TODO some kind of "zig identifier escape" function rather than + // unconditionally using @"" syntax + try builtin_str_buffer.append(" .@\""); + try builtin_str_buffer.append(feature.name); + try builtin_str_buffer.append("\",\n"); + } + } + + try builtin_str_buffer.append( + \\ }), + \\}; + \\ + ); + + assert(mem.endsWith(u8, llvm_features_buffer.toSliceConst(), ",")); + llvm_features_buffer.shrink(llvm_features_buffer.len() - 1); + + stage1_target.llvm_cpu_name = if (cpu.model.llvm_name) |s| s.ptr else null; + stage1_target.llvm_cpu_features = llvm_features_buffer.toOwnedSlice().ptr; + stage1_target.builtin_str = builtin_str_buffer.toOwnedSlice().ptr; + stage1_target.cache_hash = cache_hash.ptr; +} + +// ABI warning +const Stage2LibCInstallation = extern struct { + include_dir: [*:0]const u8, + include_dir_len: usize, + sys_include_dir: [*:0]const u8, + sys_include_dir_len: usize, + crt_dir: [*:0]const u8, + crt_dir_len: usize, + static_crt_dir: [*:0]const u8, + static_crt_dir_len: usize, + msvc_lib_dir: [*:0]const u8, + msvc_lib_dir_len: usize, + kernel32_lib_dir: [*:0]const u8, + kernel32_lib_dir_len: usize, + + fn initFromStage2(self: *Stage2LibCInstallation, libc: LibCInstallation) void { + if (libc.include_dir) |s| { + self.include_dir = s.ptr; + self.include_dir_len = s.len; + } else { + self.include_dir = ""; + self.include_dir_len = 0; + } + if (libc.sys_include_dir) |s| { + self.sys_include_dir = s.ptr; + self.sys_include_dir_len = s.len; + } else { + self.sys_include_dir = ""; + self.sys_include_dir_len = 0; + } + if (libc.crt_dir) |s| { + self.crt_dir = s.ptr; + self.crt_dir_len = s.len; + } else { + self.crt_dir = ""; + self.crt_dir_len = 0; + } + if (libc.static_crt_dir) |s| { + self.static_crt_dir = s.ptr; + self.static_crt_dir_len = s.len; + } else { + self.static_crt_dir = ""; + self.static_crt_dir_len = 0; + } + if (libc.msvc_lib_dir) |s| { + self.msvc_lib_dir = s.ptr; + self.msvc_lib_dir_len = s.len; + } else { + self.msvc_lib_dir = ""; + self.msvc_lib_dir_len = 0; + } + if (libc.kernel32_lib_dir) |s| { + self.kernel32_lib_dir = s.ptr; + self.kernel32_lib_dir_len = s.len; + } else { + self.kernel32_lib_dir = ""; + self.kernel32_lib_dir_len = 0; + } + } + + fn toStage2(self: Stage2LibCInstallation) LibCInstallation { + var libc: LibCInstallation = .{}; + if (self.include_dir_len != 0) { + libc.include_dir = self.include_dir[0..self.include_dir_len :0]; + } + if (self.sys_include_dir_len != 0) { + libc.sys_include_dir = self.sys_include_dir[0..self.sys_include_dir_len :0]; + } + if (self.crt_dir_len != 0) { + libc.crt_dir = self.crt_dir[0..self.crt_dir_len :0]; + } + if (self.static_crt_dir_len != 0) { + libc.static_crt_dir = self.static_crt_dir[0..self.static_crt_dir_len :0]; + } + if (self.msvc_lib_dir_len != 0) { + libc.msvc_lib_dir = self.msvc_lib_dir[0..self.msvc_lib_dir_len :0]; + } + if (self.kernel32_lib_dir_len != 0) { + libc.kernel32_lib_dir = self.kernel32_lib_dir[0..self.kernel32_lib_dir_len :0]; + } + return libc; + } +}; + +// ABI warning +export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [*:0]const u8) Error { + stderr_file = std.io.getStdErr(); + stderr = &stderr_file.outStream().stream; + const libc_file = mem.toSliceConst(u8, libc_file_z); + var libc = LibCInstallation.parse(std.heap.c_allocator, libc_file, stderr) catch |err| switch (err) { + error.ParseError => return .SemanticAnalyzeFail, + error.DiskQuota => return .DiskQuota, + error.FileTooBig => return .FileTooBig, + error.InputOutput => return .FileSystem, + error.NoSpaceLeft => return .NoSpaceLeft, + error.AccessDenied => return .AccessDenied, + error.BrokenPipe => return .BrokenPipe, + error.SystemResources => return .SystemResources, + error.OperationAborted => return .OperationAborted, + error.WouldBlock => unreachable, + error.Unexpected => return .Unexpected, + error.EndOfStream => return .EndOfFile, + error.IsDir => return .IsDir, + error.ConnectionResetByPeer => unreachable, + error.OutOfMemory => return .OutOfMemory, + error.Unseekable => unreachable, + error.SharingViolation => return .SharingViolation, + error.PathAlreadyExists => unreachable, + error.FileNotFound => return .FileNotFound, + error.PipeBusy => return .PipeBusy, + error.NameTooLong => return .PathTooLong, + error.InvalidUtf8 => return .BadPathName, + error.BadPathName => return .BadPathName, + error.SymLinkLoop => return .SymLinkLoop, + error.ProcessFdQuotaExceeded => return .ProcessFdQuotaExceeded, + error.SystemFdQuotaExceeded => return .SystemFdQuotaExceeded, + error.NoDevice => return .NoDevice, + error.NotDir => return .NotDir, + error.DeviceBusy => return .DeviceBusy, + }; + stage1_libc.initFromStage2(libc); + return .None; +} + +// ABI warning +export fn stage2_libc_find_native(stage1_libc: *Stage2LibCInstallation) Error { + var libc = LibCInstallation.findNative(.{ + .allocator = std.heap.c_allocator, + .verbose = true, + }) catch |err| switch (err) { + error.OutOfMemory => return .OutOfMemory, + error.FileSystem => return .FileSystem, + error.UnableToSpawnCCompiler => return .UnableToSpawnCCompiler, + error.CCompilerExitCode => return .CCompilerExitCode, + error.CCompilerCrashed => return .CCompilerCrashed, + error.CCompilerCannotFindHeaders => return .CCompilerCannotFindHeaders, + error.LibCRuntimeNotFound => return .LibCRuntimeNotFound, + error.LibCStdLibHeaderNotFound => return .LibCStdLibHeaderNotFound, + error.LibCKernel32LibNotFound => return .LibCKernel32LibNotFound, + error.UnsupportedArchitecture => return .UnsupportedArchitecture, + error.WindowsSdkNotFound => return .WindowsSdkNotFound, + }; + stage1_libc.initFromStage2(libc); + return .None; +} + +// ABI warning +export fn stage2_libc_render(stage1_libc: *Stage2LibCInstallation, output_file: *FILE) Error { + var libc = stage1_libc.toStage2(); + const c_out_stream = &std.io.COutStream.init(output_file).stream; + libc.render(c_out_stream) catch |err| switch (err) { + error.WouldBlock => unreachable, // stage1 opens stuff in exclusively blocking mode + error.SystemResources => return .SystemResources, + error.OperationAborted => return .OperationAborted, + error.BrokenPipe => return .BrokenPipe, + error.DiskQuota => return .DiskQuota, + error.FileTooBig => return .FileTooBig, + error.NoSpaceLeft => return .NoSpaceLeft, + error.AccessDenied => return .AccessDenied, + error.Unexpected => return .Unexpected, + error.InputOutput => return .FileSystem, + }; + return .None; +} + +// ABI warning +const Stage2Target = extern struct { + arch: c_int, + vendor: c_int, + + abi: c_int, + os: c_int, + + is_native: bool, + + glibc_version: ?*Stage2GLibCVersion, // null means default + + llvm_cpu_name: ?[*:0]const u8, + llvm_cpu_features: ?[*:0]const u8, + builtin_str: ?[*:0]const u8, + cache_hash: ?[*:0]const u8, + + fn toTarget(in_target: Stage2Target) Target { + if (in_target.is_native) return .Native; + + const in_arch = in_target.arch - 1; // skip over ZigLLVM_UnknownArch + const in_os = in_target.os; + const in_abi = in_target.abi; + + return .{ + .Cross = .{ + .cpu = Target.Cpu.baseline(enumInt(Target.Cpu.Arch, in_arch)), + .os = enumInt(Target.Os, in_os), + .abi = enumInt(Target.Abi, in_abi), + }, + }; + } + + fn fromTarget(self: *Stage2Target, target: Target) !void { + const cpu = switch (target) { + .Native => blk: { + // TODO self-host CPU model and feature detection instead of relying on LLVM + const llvm = @import("llvm.zig"); + const llvm_cpu_name = llvm.GetHostCPUName(); + const llvm_cpu_features = llvm.GetNativeFeatures(); + break :blk try detectNativeCpuWithLLVM(target.getArch(), llvm_cpu_name, llvm_cpu_features); + }, + .Cross => target.getCpu(), + }; + self.* = .{ + .arch = @enumToInt(target.getArch()) + 1, // skip over ZigLLVM_UnknownArch + .vendor = 0, + .os = @enumToInt(target.getOs()), + .abi = @enumToInt(target.getAbi()), + .llvm_cpu_name = null, + .llvm_cpu_features = null, + .builtin_str = null, + .cache_hash = null, + .is_native = target == .Native, + .glibc_version = null, + }; + try initStage1TargetCpuFeatures(self, cpu); + } +}; + +// ABI warning +const Stage2GLibCVersion = extern struct { + major: u32, + minor: u32, + patch: u32, +}; + +// ABI warning +export fn stage2_detect_dynamic_linker(in_target: *const Stage2Target, out_ptr: *[*:0]u8, out_len: *usize) Error { + const target = in_target.toTarget(); + const result = @import("introspect.zig").detectDynamicLinker( + std.heap.c_allocator, + target, + ) catch |err| switch (err) { + error.OutOfMemory => return .OutOfMemory, + error.UnknownDynamicLinkerPath => return .UnknownDynamicLinkerPath, + error.TargetHasNoDynamicLinker => return .TargetHasNoDynamicLinker, + }; + out_ptr.* = result.ptr; + out_len.* = result.len; + return .None; +} + +fn enumInt(comptime Enum: type, int: c_int) Enum { + return @intToEnum(Enum, @intCast(@TagType(Enum), int)); +} + +// ABI warning +const Stage2NativePaths = extern struct { + include_dirs_ptr: [*][*:0]u8, + include_dirs_len: usize, + lib_dirs_ptr: [*][*:0]u8, + lib_dirs_len: usize, + rpaths_ptr: [*][*:0]u8, + rpaths_len: usize, + warnings_ptr: [*][*:0]u8, + warnings_len: usize, +}; +// ABI warning +export fn stage2_detect_native_paths(stage1_paths: *Stage2NativePaths) Error { + stage2DetectNativePaths(stage1_paths) catch |err| switch (err) { + error.OutOfMemory => return .OutOfMemory, + }; + return .None; +} + +fn stage2DetectNativePaths(stage1_paths: *Stage2NativePaths) !void { + var paths = try std.zig.system.NativePaths.detect(std.heap.c_allocator); + errdefer paths.deinit(); + + try convertSlice(paths.include_dirs.toSlice(), &stage1_paths.include_dirs_ptr, &stage1_paths.include_dirs_len); + try convertSlice(paths.lib_dirs.toSlice(), &stage1_paths.lib_dirs_ptr, &stage1_paths.lib_dirs_len); + try convertSlice(paths.rpaths.toSlice(), &stage1_paths.rpaths_ptr, &stage1_paths.rpaths_len); + try convertSlice(paths.warnings.toSlice(), &stage1_paths.warnings_ptr, &stage1_paths.warnings_len); +} + +fn convertSlice(slice: [][:0]u8, ptr: *[*][*:0]u8, len: *usize) !void { + len.* = slice.len; + const new_slice = try std.heap.c_allocator.alloc([*:0]u8, slice.len); + for (slice) |item, i| { + new_slice[i] = item.ptr; + } + ptr.* = new_slice.ptr; +} diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig @@ -264,7 +264,7 @@ pub fn translate( &errors.len, resources_path, ) orelse { - if (errors.len == 0) return error.OutOfMemory; + if (errors.len == 0) return error.ASTUnitFailure; return error.SemanticAnalyzeFail; }; defer ZigClangASTUnit_delete(ast_unit); @@ -5382,15 +5382,15 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, return error.ParseError; } - //if (@typeId(@TypeOf(x)) == .Pointer) + //if (@typeInfo(@TypeOf(x)) == .Pointer) // @ptrCast(dest, x) - //else if (@typeId(@TypeOf(x)) == .Integer) + //else if (@typeInfo(@TypeOf(x)) == .Integer) // @intToPtr(dest, x) //else // @as(dest, x) const if_1 = try transCreateNodeIf(c); - const type_id_1 = try transCreateNodeBuiltinFnCall(c, "@typeId"); + const type_id_1 = try transCreateNodeBuiltinFnCall(c, "@typeInfo"); const type_of_1 = try transCreateNodeBuiltinFnCall(c, "@TypeOf"); try type_id_1.params.push(&type_of_1.base); try type_of_1.params.push(node_to_cast); @@ -5417,7 +5417,7 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, if_1.@"else" = else_1; const if_2 = try transCreateNodeIf(c); - const type_id_2 = try transCreateNodeBuiltinFnCall(c, "@typeId"); + const type_id_2 = try transCreateNodeBuiltinFnCall(c, "@typeInfo"); const type_of_2 = try transCreateNodeBuiltinFnCall(c, "@TypeOf"); try type_id_2.params.push(&type_of_2.base); try type_of_2.params.push(node_to_cast); diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig @@ -1042,7 +1042,7 @@ fn hashAny(x: var, comptime seed: u64) u32 { switch (@typeInfo(@TypeOf(x))) { .Int => |info| { comptime var rng = comptime std.rand.DefaultPrng.init(seed); - const unsigned_x = @bitCast(@IntType(false, info.bits), x); + const unsigned_x = @bitCast(std.meta.IntType(false, info.bits), x); if (info.bits <= 32) { return @as(u32, unsigned_x) *% comptime rng.random.scalar(u32); } else { diff --git a/src-self-hosted/util.zig b/src-self-hosted/util.zig @@ -2,144 +2,6 @@ const std = @import("std"); const Target = std.Target; const llvm = @import("llvm.zig"); -pub const FloatAbi = enum { - Hard, - Soft, - SoftFp, -}; - -/// TODO expose the arch and subarch separately -pub fn isArmOrThumb(self: Target) bool { - return switch (self.getArch()) { - .arm, - .armeb, - .aarch64, - .aarch64_be, - .thumb, - .thumbeb, - => true, - else => false, - }; -} - -pub fn getFloatAbi(self: Target) FloatAbi { - return switch (self.getAbi()) { - .gnueabihf, - .eabihf, - .musleabihf, - => .Hard, - else => .Soft, - }; -} - -pub fn getDynamicLinkerPath(self: Target) ?[]const u8 { - const env = self.getAbi(); - const arch = self.getArch(); - const os = self.getOs(); - switch (os) { - .freebsd => { - return "/libexec/ld-elf.so.1"; - }, - .linux => { - switch (env) { - .android => { - if (self.getArchPtrBitWidth() == 64) { - return "/system/bin/linker64"; - } else { - return "/system/bin/linker"; - } - }, - .gnux32 => { - if (arch == .x86_64) { - return "/libx32/ld-linux-x32.so.2"; - } - }, - .musl, - .musleabi, - .musleabihf, - => { - if (arch == .x86_64) { - return "/lib/ld-musl-x86_64.so.1"; - } - }, - else => {}, - } - switch (arch) { - .i386, - .sparc, - .sparcel, - => return "/lib/ld-linux.so.2", - - .aarch64 => return "/lib/ld-linux-aarch64.so.1", - - .aarch64_be => return "/lib/ld-linux-aarch64_be.so.1", - - .arm, - .thumb, - => return switch (getFloatAbi(self)) { - .Hard => return "/lib/ld-linux-armhf.so.3", - else => return "/lib/ld-linux.so.3", - }, - - .armeb, - .thumbeb, - => return switch (getFloatAbi(self)) { - .Hard => return "/lib/ld-linux-armhf.so.3", - else => return "/lib/ld-linux.so.3", - }, - - .mips, - .mipsel, - .mips64, - .mips64el, - => return null, - - .powerpc => return "/lib/ld.so.1", - .powerpc64 => return "/lib64/ld64.so.2", - .powerpc64le => return "/lib64/ld64.so.2", - .s390x => return "/lib64/ld64.so.1", - .sparcv9 => return "/lib64/ld-linux.so.2", - .x86_64 => return "/lib64/ld-linux-x86-64.so.2", - - .arc, - .avr, - .bpfel, - .bpfeb, - .hexagon, - .msp430, - .r600, - .amdgcn, - .riscv32, - .riscv64, - .tce, - .tcele, - .xcore, - .nvptx, - .nvptx64, - .le32, - .le64, - .amdil, - .amdil64, - .hsail, - .hsail64, - .spir, - .spir64, - .kalimba, - .shave, - .lanai, - .wasm32, - .wasm64, - .renderscript32, - .renderscript64, - .aarch64_32, - .ve, - => return null, - } - }, - else => return null, - } -} - pub fn getDarwinArchString(self: Target) [:0]const u8 { const arch = self.getArch(); switch (arch) { diff --git a/src-self-hosted/windows_sdk.zig b/src-self-hosted/windows_sdk.zig @@ -0,0 +1,22 @@ +// C API bindings for src/windows_sdk.h + +pub const ZigWindowsSDK = extern struct { + path10_ptr: ?[*]const u8, + path10_len: usize, + version10_ptr: ?[*]const u8, + version10_len: usize, + path81_ptr: ?[*]const u8, + path81_len: usize, + version81_ptr: ?[*]const u8, + version81_len: usize, + msvc_lib_dir_ptr: ?[*]const u8, + msvc_lib_dir_len: usize, +}; +pub const ZigFindWindowsSdkError = extern enum { + None, + OutOfMemory, + NotFound, + PathTooLong, +}; +pub extern fn zig_find_windows_sdk(out_sdk: **ZigWindowsSDK) ZigFindWindowsSdkError; +pub extern fn zig_free_windows_sdk(sdk: *ZigWindowsSDK) void; diff --git a/src/all_types.hpp b/src/all_types.hpp @@ -18,7 +18,6 @@ #include "bigfloat.hpp" #include "target.hpp" #include "tokenizer.hpp" -#include "libc_installation.hpp" struct AstNode; struct ZigFn; @@ -370,12 +369,22 @@ enum LazyValueId { LazyValueIdFnType, LazyValueIdErrUnionType, LazyValueIdArrayType, + LazyValueIdTypeInfoDecls, }; struct LazyValue { LazyValueId id; }; +struct LazyValueTypeInfoDecls { + LazyValue base; + + IrAnalyze *ira; + + ScopeDecls *decls_scope; + IrInst *source_instr; +}; + struct LazyValueAlignOf { LazyValue base; @@ -1139,6 +1148,7 @@ struct AstNodeErrorType { }; struct AstNodeAwaitExpr { + Token *noasync_token; AstNode *expr; }; @@ -1685,9 +1695,6 @@ enum BuiltinFnId { BuiltinFnIdMemset, BuiltinFnIdSizeof, BuiltinFnIdAlignOf, - BuiltinFnIdMemberCount, - BuiltinFnIdMemberType, - BuiltinFnIdMemberName, BuiltinFnIdField, BuiltinFnIdTypeInfo, BuiltinFnIdType, @@ -1740,8 +1747,6 @@ enum BuiltinFnId { BuiltinFnIdIntCast, BuiltinFnIdFloatCast, BuiltinFnIdErrSetCast, - BuiltinFnIdToBytes, - BuiltinFnIdFromBytes, BuiltinFnIdIntToFloat, BuiltinFnIdFloatToInt, BuiltinFnIdBoolToInt, @@ -1749,7 +1754,6 @@ enum BuiltinFnId { BuiltinFnIdIntToErr, BuiltinFnIdEnumToInt, BuiltinFnIdIntToEnum, - BuiltinFnIdIntType, BuiltinFnIdVectorType, BuiltinFnIdShuffle, BuiltinFnIdSplat, @@ -1768,7 +1772,6 @@ enum BuiltinFnId { BuiltinFnIdByteOffsetOf, BuiltinFnIdBitOffsetOf, BuiltinFnIdAsyncCall, - BuiltinFnIdTypeId, BuiltinFnIdShlExact, BuiltinFnIdShrExact, BuiltinFnIdSetEvalBranchQuota, @@ -1776,7 +1779,6 @@ enum BuiltinFnId { BuiltinFnIdOpaqueType, BuiltinFnIdThis, BuiltinFnIdSetAlignStack, - BuiltinFnIdArgType, BuiltinFnIdExport, BuiltinFnIdErrorReturnTrace, BuiltinFnIdAtomicRmw, @@ -1810,7 +1812,6 @@ enum PanicMsgId { PanicMsgIdDivisionByZero, PanicMsgIdRemainderDivisionByZero, PanicMsgIdExactDivisionRemainder, - PanicMsgIdSliceWidenRemainder, PanicMsgIdUnwrapOptionalFail, PanicMsgIdInvalidErrorCode, PanicMsgIdIncorrectAlignment, @@ -1955,12 +1956,6 @@ enum CodeModel { CodeModelLarge, }; -enum EmitFileType { - EmitFileTypeBinary, - EmitFileTypeAssembly, - EmitFileTypeLLVMIr, -}; - struct LinkLib { Buf *name; Buf *path; @@ -2131,13 +2126,15 @@ struct CodeGen { Buf llvm_triple_str; Buf global_asm; - Buf output_file_path; Buf o_file_output_path; + Buf bin_file_output_path; + Buf asm_file_output_path; + Buf llvm_ir_file_output_path; Buf *cache_dir; // As an input parameter, mutually exclusive with enable_cache. But it gets // populated in codegen_build_and_link. Buf *output_dir; - Buf **libc_include_dir_list; + const char **libc_include_dir_list; size_t libc_include_dir_len; Buf *zig_c_headers_dir; // Cannot be overridden; derived from zig_lib_dir. @@ -2218,14 +2215,13 @@ struct CodeGen { ZigList<const char *> lib_dirs; ZigList<const char *> framework_dirs; - ZigLibCInstallation *libc; + Stage2LibCInstallation *libc; size_t version_major; size_t version_minor; size_t version_patch; const char *linker_script; - EmitFileType emit_file_type; BuildMode build_mode; OutType out_type; const ZigTarget *zig_target; @@ -2247,7 +2243,9 @@ struct CodeGen { bool function_sections; bool enable_dump_analysis; bool enable_doc_generation; - bool disable_bin_generation; + bool emit_bin; + bool emit_asm; + bool emit_llvm_ir; bool test_is_evented; CodeModel code_model; @@ -2625,7 +2623,6 @@ enum IrInstSrcId { IrInstSrcIdIntToFloat, IrInstSrcIdFloatToInt, IrInstSrcIdBoolToInt, - IrInstSrcIdIntType, IrInstSrcIdVectorType, IrInstSrcIdShuffleVector, IrInstSrcIdSplat, @@ -2633,9 +2630,6 @@ enum IrInstSrcId { IrInstSrcIdMemset, IrInstSrcIdMemcpy, IrInstSrcIdSlice, - IrInstSrcIdMemberCount, - IrInstSrcIdMemberType, - IrInstSrcIdMemberName, IrInstSrcIdBreakpoint, IrInstSrcIdReturnAddress, IrInstSrcIdFrameAddress, @@ -2672,7 +2666,6 @@ enum IrInstSrcId { IrInstSrcIdTypeInfo, IrInstSrcIdType, IrInstSrcIdHasField, - IrInstSrcIdTypeId, IrInstSrcIdSetEvalBranchQuota, IrInstSrcIdPtrType, IrInstSrcIdAlignCast, @@ -2691,8 +2684,6 @@ enum IrInstSrcId { IrInstSrcIdSaveErrRetAddr, IrInstSrcIdAddImplicitReturnType, IrInstSrcIdErrSetCast, - IrInstSrcIdToBytes, - IrInstSrcIdFromBytes, IrInstSrcIdCheckRuntimeScope, IrInstSrcIdHasDecl, IrInstSrcIdUndeclaredIdent, @@ -2731,7 +2722,6 @@ enum IrInstGenId { IrInstGenIdCall, IrInstGenIdReturn, IrInstGenIdCast, - IrInstGenIdResizeSlice, IrInstGenIdUnreachable, IrInstGenIdAsm, IrInstGenIdTestNonNull, @@ -3263,13 +3253,6 @@ struct IrInstGenCast { CastOp cast_op; }; -struct IrInstGenResizeSlice { - IrInstGen base; - - IrInstGen *operand; - IrInstGen *result_loc; -}; - struct IrInstSrcContainerInitList { IrInstSrc base; @@ -3621,21 +3604,6 @@ struct IrInstSrcErrSetCast { IrInstSrc *target; }; -struct IrInstSrcToBytes { - IrInstSrc base; - - IrInstSrc *target; - ResultLoc *result_loc; -}; - -struct IrInstSrcFromBytes { - IrInstSrc base; - - IrInstSrc *dest_child_type; - IrInstSrc *target; - ResultLoc *result_loc; -}; - struct IrInstSrcIntToFloat { IrInstSrc base; @@ -3656,13 +3624,6 @@ struct IrInstSrcBoolToInt { IrInstSrc *target; }; -struct IrInstSrcIntType { - IrInstSrc base; - - IrInstSrc *is_signed; - IrInstSrc *bit_count; -}; - struct IrInstSrcVectorType { IrInstSrc base; @@ -3735,26 +3696,6 @@ struct IrInstGenSlice { bool safety_check_on; }; -struct IrInstSrcMemberCount { - IrInstSrc base; - - IrInstSrc *container; -}; - -struct IrInstSrcMemberType { - IrInstSrc base; - - IrInstSrc *container_type; - IrInstSrc *member_index; -}; - -struct IrInstSrcMemberName { - IrInstSrc base; - - IrInstSrc *container_type; - IrInstSrc *member_index; -}; - struct IrInstSrcBreakpoint { IrInstSrc base; }; @@ -4162,12 +4103,6 @@ struct IrInstSrcHasField { IrInstSrc *field_name; }; -struct IrInstSrcTypeId { - IrInstSrc base; - - IrInstSrc *type_value; -}; - struct IrInstSrcSetEvalBranchQuota { IrInstSrc base; @@ -4499,6 +4434,7 @@ struct IrInstSrcAwait { IrInstSrc *frame; ResultLoc *result_loc; + bool is_noasync; }; struct IrInstGenAwait { @@ -4507,6 +4443,7 @@ struct IrInstGenAwait { IrInstGen *frame; IrInstGen *result_loc; ZigFn *target_fn; + bool is_noasync; }; struct IrInstSrcResume { diff --git a/src/analyze.cpp b/src/analyze.cpp @@ -1150,6 +1150,7 @@ Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent case LazyValueIdInvalid: case LazyValueIdAlignOf: case LazyValueIdSizeOf: + case LazyValueIdTypeInfoDecls: zig_unreachable(); case LazyValueIdPtrType: { LazyValuePtrType *lazy_ptr_type = reinterpret_cast<LazyValuePtrType *>(type_val->data.x_lazy); @@ -1209,6 +1210,7 @@ Error type_val_resolve_is_opaque_type(CodeGen *g, ZigValue *type_val, bool *is_o case LazyValueIdInvalid: case LazyValueIdAlignOf: case LazyValueIdSizeOf: + case LazyValueIdTypeInfoDecls: zig_unreachable(); case LazyValueIdSliceType: case LazyValueIdPtrType: @@ -1230,6 +1232,7 @@ static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ZigValue *type case LazyValueIdInvalid: case LazyValueIdAlignOf: case LazyValueIdSizeOf: + case LazyValueIdTypeInfoDecls: zig_unreachable(); case LazyValueIdSliceType: { LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(type_val->data.x_lazy); @@ -1303,6 +1306,7 @@ start_over: case LazyValueIdInvalid: case LazyValueIdAlignOf: case LazyValueIdSizeOf: + case LazyValueIdTypeInfoDecls: zig_unreachable(); case LazyValueIdSliceType: { LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(type_val->data.x_lazy); @@ -1370,6 +1374,7 @@ Error type_val_resolve_abi_align(CodeGen *g, AstNode *source_node, ZigValue *typ case LazyValueIdInvalid: case LazyValueIdAlignOf: case LazyValueIdSizeOf: + case LazyValueIdTypeInfoDecls: zig_unreachable(); case LazyValueIdSliceType: case LazyValueIdPtrType: @@ -1412,6 +1417,7 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, ZigV case LazyValueIdInvalid: case LazyValueIdAlignOf: case LazyValueIdSizeOf: + case LazyValueIdTypeInfoDecls: zig_unreachable(); case LazyValueIdSliceType: // it has the len field case LazyValueIdOptType: // it has the optional bit @@ -4710,8 +4716,7 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) { } for (size_t i = 0; i < fn->await_list.length; i += 1) { IrInstGenAwait *await = fn->await_list.at(i); - // TODO If this is a noasync await, it doesn't count - // https://github.com/ziglang/zig/issues/3157 + if (await->is_noasync) continue; switch (analyze_callee_async(g, fn, await->target_fn, await->base.base.source_node, must_not_be_async, CallModifierNone)) { @@ -6315,8 +6320,9 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { // The funtion call result of foo() must be spilled. for (size_t i = 0; i < fn->await_list.length; i += 1) { IrInstGenAwait *await = fn->await_list.at(i); - // TODO If this is a noasync await, it doesn't suspend - // https://github.com/ziglang/zig/issues/3157 + if (await->is_noasync) { + continue; + } if (await->base.value->special != ConstValSpecialRuntime) { // Known at comptime. No spill, no suspend. continue; diff --git a/src/cache_hash.cpp b/src/cache_hash.cpp @@ -5,7 +5,7 @@ * See http://opensource.org/licenses/MIT */ -#include "userland.h" +#include "stage2.h" #include "cache_hash.hpp" #include "all_types.hpp" #include "buffer.hpp" diff --git a/src/codegen.cpp b/src/codegen.cpp @@ -18,7 +18,7 @@ #include "target.hpp" #include "util.hpp" #include "zig_llvm.h" -#include "userland.h" +#include "stage2.h" #include "dump_analysis.hpp" #include "softfloat.hpp" #include "mem_profile.hpp" @@ -121,10 +121,6 @@ void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patc g->version_patch = patch; } -void codegen_set_emit_file_type(CodeGen *g, EmitFileType emit_file_type) { - g->emit_file_type = emit_file_type; -} - void codegen_set_each_lib_rpath(CodeGen *g, bool each_lib_rpath) { g->each_lib_rpath = each_lib_rpath; } @@ -975,8 +971,6 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) { return buf_create_from_str("remainder division by zero or negative value"); case PanicMsgIdExactDivisionRemainder: return buf_create_from_str("exact division produced remainder"); - case PanicMsgIdSliceWidenRemainder: - return buf_create_from_str("slice widening size mismatch"); case PanicMsgIdUnwrapOptionalFail: return buf_create_from_str("attempt to unwrap null"); case PanicMsgIdUnreachable: @@ -3085,74 +3079,6 @@ static void add_error_range_check(CodeGen *g, ZigType *err_set_type, ZigType *in } } -static LLVMValueRef ir_render_resize_slice(CodeGen *g, IrExecutableGen *executable, - IrInstGenResizeSlice *instruction) -{ - ZigType *actual_type = instruction->operand->value->type; - ZigType *wanted_type = instruction->base.value->type; - LLVMValueRef expr_val = ir_llvm_value(g, instruction->operand); - assert(expr_val); - - LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - assert(wanted_type->id == ZigTypeIdStruct); - assert(wanted_type->data.structure.special == StructSpecialSlice); - assert(actual_type->id == ZigTypeIdStruct); - assert(actual_type->data.structure.special == StructSpecialSlice); - - ZigType *actual_pointer_type = actual_type->data.structure.fields[0]->type_entry; - ZigType *actual_child_type = actual_pointer_type->data.pointer.child_type; - ZigType *wanted_pointer_type = wanted_type->data.structure.fields[0]->type_entry; - ZigType *wanted_child_type = wanted_pointer_type->data.pointer.child_type; - - - size_t actual_ptr_index = actual_type->data.structure.fields[slice_ptr_index]->gen_index; - size_t actual_len_index = actual_type->data.structure.fields[slice_len_index]->gen_index; - size_t wanted_ptr_index = wanted_type->data.structure.fields[slice_ptr_index]->gen_index; - size_t wanted_len_index = wanted_type->data.structure.fields[slice_len_index]->gen_index; - - LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, expr_val, (unsigned)actual_ptr_index, ""); - LLVMValueRef src_ptr = gen_load_untyped(g, src_ptr_ptr, 0, false, ""); - LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr, - get_llvm_type(g, wanted_type->data.structure.fields[0]->type_entry), ""); - LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, result_loc, - (unsigned)wanted_ptr_index, ""); - gen_store_untyped(g, src_ptr_casted, dest_ptr_ptr, 0, false); - - LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, expr_val, (unsigned)actual_len_index, ""); - LLVMValueRef src_len = gen_load_untyped(g, src_len_ptr, 0, false, ""); - uint64_t src_size = type_size(g, actual_child_type); - uint64_t dest_size = type_size(g, wanted_child_type); - - LLVMValueRef new_len; - if (dest_size == 1) { - LLVMValueRef src_size_val = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, src_size, false); - new_len = LLVMBuildMul(g->builder, src_len, src_size_val, ""); - } else if (src_size == 1) { - LLVMValueRef dest_size_val = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, dest_size, false); - if (ir_want_runtime_safety(g, &instruction->base)) { - LLVMValueRef remainder_val = LLVMBuildURem(g->builder, src_len, dest_size_val, ""); - LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_usize->llvm_type); - LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, ""); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SliceWidenOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "SliceWidenFail"); - LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block); - - LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdSliceWidenRemainder); - - LLVMPositionBuilderAtEnd(g->builder, ok_block); - } - new_len = LLVMBuildExactUDiv(g->builder, src_len, dest_size_val, ""); - } else { - zig_unreachable(); - } - - LLVMValueRef dest_len_ptr = LLVMBuildStructGEP(g->builder, result_loc, (unsigned)wanted_len_index, ""); - gen_store_untyped(g, new_len, dest_len_ptr, 0, false); - - return result_loc; -} - static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutableGen *executable, IrInstGenCast *cast_instruction) { @@ -5014,6 +4940,12 @@ static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutableGen *executable, IrIns if (!type_has_bits(instruction->base.value->type)) { return nullptr; } + if (instruction->operand->id == IrInstGenIdCall) { + IrInstGenCall *call = reinterpret_cast<IrInstGenCall *>(instruction->operand); + if (call->result_loc != nullptr) { + return ir_llvm_value(g, call->result_loc); + } + } LLVMValueRef value = ir_llvm_value(g, instruction->operand); if (handle_is_ptr(instruction->operand->value->type)) { return value; @@ -6177,7 +6109,9 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutableGen *executable, IrI LLVMValueRef result_loc = (instruction->result_loc == nullptr) ? nullptr : ir_llvm_value(g, instruction->result_loc); - if (instruction->target_fn != nullptr && !fn_is_async(instruction->target_fn)) { + if (instruction->is_noasync || + (instruction->target_fn != nullptr && !fn_is_async(instruction->target_fn))) + { return gen_await_early_return(g, &instruction->base, target_frame_ptr, result_type, ptr_result_type, result_loc, true); } @@ -6476,8 +6410,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutableGen *executabl return ir_render_assert_zero(g, executable, (IrInstGenAssertZero *)instruction); case IrInstGenIdAssertNonNull: return ir_render_assert_non_null(g, executable, (IrInstGenAssertNonNull *)instruction); - case IrInstGenIdResizeSlice: - return ir_render_resize_slice(g, executable, (IrInstGenResizeSlice *)instruction); case IrInstGenIdPtrOfArrayToSlice: return ir_render_ptr_of_array_to_slice(g, executable, (IrInstGenPtrOfArrayToSlice *)instruction); case IrInstGenIdSuspendBegin: @@ -6528,7 +6460,7 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) { set_debug_location(g, instruction); } instruction->llvm_value = ir_render_instruction(g, executable, instruction); - if (instruction->spill != nullptr) { + if (instruction->spill != nullptr && instruction->llvm_value != nullptr) { LLVMValueRef spill_ptr = ir_llvm_value(g, instruction->spill); gen_assign_raw(g, spill_ptr, instruction->spill->value->type, instruction->llvm_value); instruction->llvm_value = nullptr; @@ -7912,50 +7844,44 @@ static void zig_llvm_emit_output(CodeGen *g) { bool is_small = g->build_mode == BuildModeSmallRelease; - Buf *output_path = &g->o_file_output_path; char *err_msg = nullptr; - switch (g->emit_file_type) { - case EmitFileTypeBinary: - if (g->disable_bin_generation) - return; - if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), - ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug, is_small, - g->enable_time_report)) - { - zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg); - } - validate_inline_fns(g); - g->link_objects.append(output_path); - if (g->bundle_compiler_rt && (g->out_type == OutTypeObj || - (g->out_type == OutTypeLib && !g->is_dynamic))) - { - zig_link_add_compiler_rt(g, g->sub_progress_node); - } - break; + const char *asm_filename = nullptr; + const char *bin_filename = nullptr; + const char *llvm_ir_filename = nullptr; + + if (g->emit_bin) bin_filename = buf_ptr(&g->o_file_output_path); + if (g->emit_asm) asm_filename = buf_ptr(&g->asm_file_output_path); + if (g->emit_llvm_ir) llvm_ir_filename = buf_ptr(&g->llvm_ir_file_output_path); + + // Unfortunately, LLVM shits the bed when we ask for both binary and assembly. So we call the entire + // pipeline multiple times if this is requested. + if (asm_filename != nullptr && bin_filename != nullptr) { + if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg, g->build_mode == BuildModeDebug, + is_small, g->enable_time_report, nullptr, bin_filename, llvm_ir_filename)) + { + fprintf(stderr, "LLVM failed to emit file: %s\n", err_msg); + exit(1); + } + bin_filename = nullptr; + llvm_ir_filename = nullptr; + } - case EmitFileTypeAssembly: - if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), - ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug, is_small, - g->enable_time_report)) - { - zig_panic("unable to write assembly file %s: %s", buf_ptr(output_path), err_msg); - } - validate_inline_fns(g); - break; + if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg, g->build_mode == BuildModeDebug, + is_small, g->enable_time_report, asm_filename, bin_filename, llvm_ir_filename)) + { + fprintf(stderr, "LLVM failed to emit file: %s\n", err_msg); + exit(1); + } - case EmitFileTypeLLVMIr: - if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), - ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug, is_small, - g->enable_time_report)) - { - zig_panic("unable to write llvm-ir file %s: %s", buf_ptr(output_path), err_msg); - } - validate_inline_fns(g); - break; + validate_inline_fns(g); - default: - zig_unreachable(); + if (g->emit_bin) { + g->link_objects.append(&g->o_file_output_path); + if (g->bundle_compiler_rt && (g->out_type == OutTypeObj || (g->out_type == OutTypeLib && !g->is_dynamic))) { + zig_link_add_compiler_rt(g, g->sub_progress_node); + } } + LLVMDisposeModule(g->module); g->module = nullptr; LLVMDisposeTargetData(g->target_data_ref); @@ -8221,9 +8147,6 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdMemset, "memset", 3); create_builtin_fn(g, BuiltinFnIdSizeof, "sizeOf", 1); create_builtin_fn(g, BuiltinFnIdAlignOf, "alignOf", 1); - create_builtin_fn(g, BuiltinFnIdMemberCount, "memberCount", 1); - create_builtin_fn(g, BuiltinFnIdMemberType, "memberType", 2); - create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2); create_builtin_fn(g, BuiltinFnIdField, "field", 2); create_builtin_fn(g, BuiltinFnIdTypeInfo, "typeInfo", 1); create_builtin_fn(g, BuiltinFnIdType, "Type", 1); @@ -8261,7 +8184,6 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdIntToEnum, "intToEnum", 2); create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1); create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX); - create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int create_builtin_fn(g, BuiltinFnIdVectorType, "Vector", 2); create_builtin_fn(g, BuiltinFnIdShuffle, "shuffle", 4); create_builtin_fn(g, BuiltinFnIdSplat, "splat", 2); @@ -8299,22 +8221,18 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdRound, "round", 1); create_builtin_fn(g, BuiltinFnIdMulAdd, "mulAdd", 4); create_builtin_fn(g, BuiltinFnIdAsyncCall, "asyncCall", SIZE_MAX); - create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1); create_builtin_fn(g, BuiltinFnIdShlExact, "shlExact", 2); create_builtin_fn(g, BuiltinFnIdShrExact, "shrExact", 2); create_builtin_fn(g, BuiltinFnIdSetEvalBranchQuota, "setEvalBranchQuota", 1); create_builtin_fn(g, BuiltinFnIdAlignCast, "alignCast", 2); create_builtin_fn(g, BuiltinFnIdOpaqueType, "OpaqueType", 0); create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1); - create_builtin_fn(g, BuiltinFnIdArgType, "ArgType", 2); create_builtin_fn(g, BuiltinFnIdExport, "export", 2); create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0); create_builtin_fn(g, BuiltinFnIdAtomicRmw, "atomicRmw", 5); create_builtin_fn(g, BuiltinFnIdAtomicLoad, "atomicLoad", 3); create_builtin_fn(g, BuiltinFnIdAtomicStore, "atomicStore", 4); create_builtin_fn(g, BuiltinFnIdErrSetCast, "errSetCast", 2); - create_builtin_fn(g, BuiltinFnIdToBytes, "sliceToBytes", 1); - create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2); create_builtin_fn(g, BuiltinFnIdThis, "This", 0); create_builtin_fn(g, BuiltinFnIdHasDecl, "hasDecl", 2); create_builtin_fn(g, BuiltinFnIdUnionInit, "unionInit", 3); @@ -8361,9 +8279,11 @@ static bool detect_dynamic_link(CodeGen *g) { return true; if (g->zig_target->os == OsFreestanding) return false; - if (target_requires_pic(g->zig_target, g->libc_link_lib != nullptr)) + if (target_os_requires_libc(g->zig_target->os)) return true; - // If there are no dynamic libraries then we can disable PIC + if (g->libc_link_lib != nullptr && target_is_glibc(g->zig_target)) + return true; + // If there are no dynamic libraries then we can disable dynamic linking. for (size_t i = 0; i < g->link_libs_list.length; i += 1) { LinkLib *link_lib = g->link_libs_list.at(i); if (target_is_libc_lib_name(g->zig_target, buf_ptr(link_lib->name))) @@ -8498,25 +8418,9 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { for (uint32_t arch_i = 0; arch_i < field_count; arch_i += 1) { ZigLLVM_ArchType arch = target_arch_enum(arch_i); const char *arch_name = target_arch_name(arch); - SubArchList sub_arch_list = target_subarch_list(arch); - if (sub_arch_list == SubArchListNone) { - if (arch == g->zig_target->arch) { - g->target_arch_index = arch_i; - cur_arch = buf_ptr(buf_sprintf("Arch.%s", arch_name)); - } - } else { - const char *sub_arch_list_name = target_subarch_list_name(sub_arch_list); - if (arch == g->zig_target->arch) { - size_t sub_count = target_subarch_count(sub_arch_list); - for (size_t sub_i = 0; sub_i < sub_count; sub_i += 1) { - ZigLLVM_SubArchType sub = target_subarch_enum(sub_arch_list, sub_i); - if (sub == g->zig_target->sub_arch) { - g->target_sub_arch_index = sub_i; - cur_arch = buf_ptr(buf_sprintf("Arch{ .%s = Arch.%s.%s }", - arch_name, sub_arch_list_name, target_subarch_name(sub))); - } - } - } + if (arch == g->zig_target->arch) { + g->target_arch_index = arch_i; + cur_arch = arch_name; } } } @@ -8610,22 +8514,19 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { break; } buf_appendf(contents, "pub const output_mode = OutputMode.%s;\n", out_type); - const char *link_type = g->is_dynamic ? "Dynamic" : "Static"; + const char *link_type = g->have_dynamic_link ? "Dynamic" : "Static"; buf_appendf(contents, "pub const link_mode = LinkMode.%s;\n", link_type); buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build)); buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded)); buf_appendf(contents, "pub const os = Os.%s;\n", cur_os); - buf_appendf(contents, "pub const arch = %s;\n", cur_arch); + buf_appendf(contents, "pub const arch = Arch.%s;\n", cur_arch); buf_appendf(contents, "pub const abi = Abi.%s;\n", cur_abi); { - buf_append_str(contents, "pub const cpu_features: CpuFeatures = "); - if (g->zig_target->cpu_features != nullptr) { - const char *ptr; - size_t len; - stage2_cpu_features_get_builtin_str(g->zig_target->cpu_features, &ptr, &len); - buf_append_mem(contents, ptr, len); + buf_append_str(contents, "pub const cpu: Cpu = "); + if (g->zig_target->builtin_str != nullptr) { + buf_append_str(contents, g->zig_target->builtin_str); } else { - buf_append_str(contents, "arch.getBaselineCpuFeatures();\n"); + buf_append_str(contents, "Target.Cpu.baseline(arch);\n"); } } if (g->libc_link_lib != nullptr && g->zig_target->glibc_version != nullptr) { @@ -8717,22 +8618,18 @@ static Error define_builtin_compile_vars(CodeGen *g) { cache_int(&cache_hash, g->build_mode); cache_bool(&cache_hash, g->strip_debug_symbols); cache_int(&cache_hash, g->out_type); - cache_bool(&cache_hash, g->is_dynamic); + cache_bool(&cache_hash, detect_dynamic_link(g)); cache_bool(&cache_hash, g->is_test_build); cache_bool(&cache_hash, g->is_single_threaded); cache_bool(&cache_hash, g->test_is_evented); cache_int(&cache_hash, g->code_model); cache_int(&cache_hash, g->zig_target->is_native); cache_int(&cache_hash, g->zig_target->arch); - cache_int(&cache_hash, g->zig_target->sub_arch); cache_int(&cache_hash, g->zig_target->vendor); cache_int(&cache_hash, g->zig_target->os); cache_int(&cache_hash, g->zig_target->abi); - if (g->zig_target->cpu_features != nullptr) { - const char *ptr; - size_t len; - stage2_cpu_features_get_cache_hash(g->zig_target->cpu_features, &ptr, &len); - cache_str(&cache_hash, ptr); + if (g->zig_target->cache_hash != nullptr) { + cache_str(&cache_hash, g->zig_target->cache_hash); } if (g->zig_target->glibc_version != nullptr) { cache_int(&cache_hash, g->zig_target->glibc_version->major); @@ -8867,9 +8764,11 @@ static void init(CodeGen *g) { } // Override CPU and features if defined by user. - if (g->zig_target->cpu_features != nullptr) { - target_specific_cpu_args = stage2_cpu_features_get_llvm_cpu(g->zig_target->cpu_features); - target_specific_features = stage2_cpu_features_get_llvm_features(g->zig_target->cpu_features); + if (g->zig_target->llvm_cpu_name != nullptr) { + target_specific_cpu_args = g->zig_target->llvm_cpu_name; + } + if (g->zig_target->llvm_cpu_features != nullptr) { + target_specific_features = g->zig_target->llvm_cpu_features; } if (g->verbose_llvm_cpu_features) { fprintf(stderr, "name=%s triple=%s\n", buf_ptr(g->root_out_name), buf_ptr(&g->llvm_triple_str)); @@ -8943,6 +8842,8 @@ static void init(CodeGen *g) { } static void detect_dynamic_linker(CodeGen *g) { + Error err; + if (g->dynamic_linker_path != nullptr) return; if (!g->have_dynamic_link) @@ -8950,42 +8851,16 @@ static void detect_dynamic_linker(CodeGen *g) { if (g->out_type == OutTypeObj || (g->out_type == OutTypeLib && !g->is_dynamic)) return; - const char *standard_ld_path = target_dynamic_linker(g->zig_target); - if (standard_ld_path == nullptr) - return; - - if (g->zig_target->is_native) { - // target_dynamic_linker is usually correct. However on some systems, such as NixOS - // it will be incorrect. See if we can do better by looking at what zig's own - // dynamic linker path is. - g->dynamic_linker_path = get_self_dynamic_linker_path(); - if (g->dynamic_linker_path != nullptr) - return; - - // If Zig is statically linked, such as via distributed binary static builds, the above - // trick won't work. What are we left with? Try to run the system C compiler and get - // it to tell us the dynamic linker path -#if defined(ZIG_OS_LINUX) - { - Error err; - Buf *result = buf_alloc(); - for (size_t i = 0; possible_ld_names[i] != NULL; i += 1) { - const char *lib_name = possible_ld_names[i]; - if ((err = zig_libc_cc_print_file_name(lib_name, result, false, true))) { - if (err != ErrorCCompilerCannotFindFile && err != ErrorNoCCompilerInstalled) { - fprintf(stderr, "Unable to detect native dynamic linker: %s\n", err_str(err)); - exit(1); - } - continue; - } - g->dynamic_linker_path = result; - return; - } - } -#endif + char *dynamic_linker_ptr; + size_t dynamic_linker_len; + if ((err = stage2_detect_dynamic_linker(g->zig_target, &dynamic_linker_ptr, &dynamic_linker_len))) { + if (err == ErrorTargetHasNoDynamicLinker) return; + fprintf(stderr, "Unable to detect dynamic linker: %s\n", err_str(err)); + exit(1); } - - g->dynamic_linker_path = buf_create_from_str(standard_ld_path); + g->dynamic_linker_path = buf_create_from_mem(dynamic_linker_ptr, dynamic_linker_len); + // Skips heap::c_allocator because the memory is allocated by stage2 library. + free(dynamic_linker_ptr); } static void detect_libc(CodeGen *g) { @@ -9014,16 +8889,16 @@ static void detect_libc(CodeGen *g) { buf_ptr(g->zig_lib_dir), target_os_name(g->zig_target->os)); g->libc_include_dir_len = 4; - g->libc_include_dir_list = heap::c_allocator.allocate<Buf*>(g->libc_include_dir_len); - g->libc_include_dir_list[0] = arch_include_dir; - g->libc_include_dir_list[1] = generic_include_dir; - g->libc_include_dir_list[2] = arch_os_include_dir; - g->libc_include_dir_list[3] = generic_os_include_dir; + g->libc_include_dir_list = heap::c_allocator.allocate<const char*>(g->libc_include_dir_len); + g->libc_include_dir_list[0] = buf_ptr(arch_include_dir); + g->libc_include_dir_list[1] = buf_ptr(generic_include_dir); + g->libc_include_dir_list[2] = buf_ptr(arch_os_include_dir); + g->libc_include_dir_list[3] = buf_ptr(generic_os_include_dir); return; } if (g->zig_target->is_native) { - g->libc = heap::c_allocator.create<ZigLibCInstallation>(); + g->libc = heap::c_allocator.create<Stage2LibCInstallation>(); // search for native_libc.txt in following dirs: // - LOCAL_CACHE_DIR @@ -9068,8 +8943,8 @@ static void detect_libc(CodeGen *g) { if (libc_txt == nullptr) libc_txt = &global_libc_txt; - if ((err = zig_libc_parse(g->libc, libc_txt, g->zig_target, false))) { - if ((err = zig_libc_find_native(g->libc, true))) { + if ((err = stage2_libc_parse(g->libc, buf_ptr(libc_txt)))) { + if ((err = stage2_libc_find_native(g->libc))) { fprintf(stderr, "Unable to link against libc: Unable to find libc installation: %s\n" "See `zig libc --help` for more details.\n", err_str(err)); @@ -9089,7 +8964,7 @@ static void detect_libc(CodeGen *g) { fprintf(stderr, "Unable to open %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno)); exit(1); } - zig_libc_render(g->libc, file); + stage2_libc_render(g->libc, file); if (fclose(file) != 0) { fprintf(stderr, "Unable to save %s: %s\n", buf_ptr(native_libc_tmp), strerror(errno)); exit(1); @@ -9099,27 +8974,28 @@ static void detect_libc(CodeGen *g) { exit(1); } } - bool want_sys_dir = !buf_eql_buf(&g->libc->include_dir, &g->libc->sys_include_dir); + bool want_sys_dir = !mem_eql_mem(g->libc->include_dir, g->libc->include_dir_len, + g->libc->sys_include_dir, g->libc->sys_include_dir_len); size_t want_um_and_shared_dirs = (g->zig_target->os == OsWindows) ? 2 : 0; size_t dir_count = 1 + want_sys_dir + want_um_and_shared_dirs; g->libc_include_dir_len = 0; - g->libc_include_dir_list = heap::c_allocator.allocate<Buf*>(dir_count); + g->libc_include_dir_list = heap::c_allocator.allocate<const char *>(dir_count); - g->libc_include_dir_list[g->libc_include_dir_len] = &g->libc->include_dir; + g->libc_include_dir_list[g->libc_include_dir_len] = g->libc->include_dir; g->libc_include_dir_len += 1; if (want_sys_dir) { - g->libc_include_dir_list[g->libc_include_dir_len] = &g->libc->sys_include_dir; + g->libc_include_dir_list[g->libc_include_dir_len] = g->libc->sys_include_dir; g->libc_include_dir_len += 1; } if (want_um_and_shared_dirs != 0) { - g->libc_include_dir_list[g->libc_include_dir_len] = buf_sprintf("%s" OS_SEP ".." OS_SEP "um", - buf_ptr(&g->libc->include_dir)); + g->libc_include_dir_list[g->libc_include_dir_len] = buf_ptr(buf_sprintf( + "%s" OS_SEP ".." OS_SEP "um", g->libc->include_dir)); g->libc_include_dir_len += 1; - g->libc_include_dir_list[g->libc_include_dir_len] = buf_sprintf("%s" OS_SEP ".." OS_SEP "shared", - buf_ptr(&g->libc->include_dir)); + g->libc_include_dir_list[g->libc_include_dir_len] = buf_ptr(buf_sprintf( + "%s" OS_SEP ".." OS_SEP "shared", g->libc->include_dir)); g->libc_include_dir_len += 1; } assert(g->libc_include_dir_len == dir_count); @@ -9194,9 +9070,9 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa args.append(buf_ptr(g->zig_c_headers_dir)); for (size_t i = 0; i < g->libc_include_dir_len; i += 1) { - Buf *include_dir = g->libc_include_dir_list[i]; + const char *include_dir = g->libc_include_dir_list[i]; args.append("-isystem"); - args.append(buf_ptr(include_dir)); + args.append(include_dir); } if (g->zig_target->is_native) { @@ -9207,19 +9083,17 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa args.append("-target"); args.append(buf_ptr(&g->llvm_triple_str)); - const char *llvm_cpu = stage2_cpu_features_get_llvm_cpu(g->zig_target->cpu_features); - if (llvm_cpu != nullptr) { + if (g->zig_target->llvm_cpu_name != nullptr) { args.append("-Xclang"); args.append("-target-cpu"); args.append("-Xclang"); - args.append(llvm_cpu); + args.append(g->zig_target->llvm_cpu_name); } - const char *llvm_target_features = stage2_cpu_features_get_llvm_features(g->zig_target->cpu_features); - if (llvm_target_features != nullptr) { + if (g->zig_target->llvm_cpu_features != nullptr) { args.append("-Xclang"); args.append("-target-feature"); args.append("-Xclang"); - args.append(llvm_target_features); + args.append(g->zig_target->llvm_cpu_features); } } @@ -9652,10 +9526,9 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose cache_buf(cache_hash, compiler_id); cache_int(cache_hash, g->err_color); cache_buf(cache_hash, g->zig_c_headers_dir); - cache_list_of_buf(cache_hash, g->libc_include_dir_list, g->libc_include_dir_len); + cache_list_of_str(cache_hash, g->libc_include_dir_list, g->libc_include_dir_len); cache_int(cache_hash, g->zig_target->is_native); cache_int(cache_hash, g->zig_target->arch); - cache_int(cache_hash, g->zig_target->sub_arch); cache_int(cache_hash, g->zig_target->vendor); cache_int(cache_hash, g->zig_target->os); cache_int(cache_hash, g->zig_target->abi); @@ -10419,15 +10292,11 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_int(ch, g->out_type); cache_bool(ch, g->zig_target->is_native); cache_int(ch, g->zig_target->arch); - cache_int(ch, g->zig_target->sub_arch); cache_int(ch, g->zig_target->vendor); cache_int(ch, g->zig_target->os); cache_int(ch, g->zig_target->abi); - if (g->zig_target->cpu_features != nullptr) { - const char *ptr; - size_t len; - stage2_cpu_features_get_cache_hash(g->zig_target->cpu_features, &ptr, &len); - cache_str(ch, ptr); + if (g->zig_target->cache_hash != nullptr) { + cache_str(ch, g->zig_target->cache_hash); } if (g->zig_target->glibc_version != nullptr) { cache_int(ch, g->zig_target->glibc_version->major); @@ -10457,7 +10326,9 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_bool(ch, g->function_sections); cache_bool(ch, g->enable_dump_analysis); cache_bool(ch, g->enable_doc_generation); - cache_bool(ch, g->disable_bin_generation); + cache_bool(ch, g->emit_bin); + cache_bool(ch, g->emit_llvm_ir); + cache_bool(ch, g->emit_asm); cache_buf_opt(ch, g->mmacosx_version_min); cache_buf_opt(ch, g->mios_version_min); cache_usize(ch, g->version_major); @@ -10468,11 +10339,11 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_list_of_str(ch, g->lib_dirs.items, g->lib_dirs.length); cache_list_of_str(ch, g->framework_dirs.items, g->framework_dirs.length); if (g->libc) { - cache_buf(ch, &g->libc->include_dir); - cache_buf(ch, &g->libc->sys_include_dir); - cache_buf(ch, &g->libc->crt_dir); - cache_buf(ch, &g->libc->msvc_lib_dir); - cache_buf(ch, &g->libc->kernel32_lib_dir); + cache_str(ch, g->libc->include_dir); + cache_str(ch, g->libc->sys_include_dir); + cache_str(ch, g->libc->crt_dir); + cache_str(ch, g->libc->msvc_lib_dir); + cache_str(ch, g->libc->kernel32_lib_dir); } cache_buf_opt(ch, g->dynamic_linker_path); cache_buf_opt(ch, g->version_script_path); @@ -10502,58 +10373,54 @@ static void resolve_out_paths(CodeGen *g) { assert(g->output_dir != nullptr); assert(g->root_out_name != nullptr); - Buf *out_basename = buf_create_from_buf(g->root_out_name); - Buf *o_basename = buf_create_from_buf(g->root_out_name); - switch (g->emit_file_type) { - case EmitFileTypeBinary: { - switch (g->out_type) { - case OutTypeUnknown: - zig_unreachable(); - case OutTypeObj: - if (g->enable_cache && g->link_objects.length == 1 && !need_llvm_module(g)) { - buf_init_from_buf(&g->output_file_path, g->link_objects.at(0)); - return; - } - if (need_llvm_module(g) && g->link_objects.length != 0 && !g->enable_cache && - buf_eql_buf(o_basename, out_basename)) - { - // make it not collide with main output object - buf_append_str(o_basename, ".root"); - } - buf_append_str(o_basename, target_o_file_ext(g->zig_target)); - buf_append_str(out_basename, target_o_file_ext(g->zig_target)); - break; - case OutTypeExe: - buf_append_str(o_basename, target_o_file_ext(g->zig_target)); - buf_append_str(out_basename, target_exe_file_ext(g->zig_target)); - break; - case OutTypeLib: - buf_append_str(o_basename, target_o_file_ext(g->zig_target)); - buf_resize(out_basename, 0); - buf_append_str(out_basename, target_lib_file_prefix(g->zig_target)); - buf_append_buf(out_basename, g->root_out_name); - buf_append_str(out_basename, target_lib_file_ext(g->zig_target, !g->is_dynamic, - g->version_major, g->version_minor, g->version_patch)); - break; - } - break; - } - case EmitFileTypeAssembly: { - const char *asm_ext = target_asm_file_ext(g->zig_target); - buf_append_str(o_basename, asm_ext); - buf_append_str(out_basename, asm_ext); - break; - } - case EmitFileTypeLLVMIr: { - const char *llvm_ir_ext = target_llvm_ir_file_ext(g->zig_target); - buf_append_str(o_basename, llvm_ir_ext); - buf_append_str(out_basename, llvm_ir_ext); - break; + if (g->emit_bin) { + Buf *out_basename = buf_create_from_buf(g->root_out_name); + Buf *o_basename = buf_create_from_buf(g->root_out_name); + switch (g->out_type) { + case OutTypeUnknown: + zig_unreachable(); + case OutTypeObj: + if (g->enable_cache && g->link_objects.length == 1 && !need_llvm_module(g)) { + buf_init_from_buf(&g->bin_file_output_path, g->link_objects.at(0)); + return; + } + if (need_llvm_module(g) && g->link_objects.length != 0 && !g->enable_cache && + buf_eql_buf(o_basename, out_basename)) + { + // make it not collide with main output object + buf_append_str(o_basename, ".root"); + } + buf_append_str(o_basename, target_o_file_ext(g->zig_target)); + buf_append_str(out_basename, target_o_file_ext(g->zig_target)); + break; + case OutTypeExe: + buf_append_str(o_basename, target_o_file_ext(g->zig_target)); + buf_append_str(out_basename, target_exe_file_ext(g->zig_target)); + break; + case OutTypeLib: + buf_append_str(o_basename, target_o_file_ext(g->zig_target)); + buf_resize(out_basename, 0); + buf_append_str(out_basename, target_lib_file_prefix(g->zig_target)); + buf_append_buf(out_basename, g->root_out_name); + buf_append_str(out_basename, target_lib_file_ext(g->zig_target, !g->is_dynamic, + g->version_major, g->version_minor, g->version_patch)); + break; } + os_path_join(g->output_dir, o_basename, &g->o_file_output_path); + os_path_join(g->output_dir, out_basename, &g->bin_file_output_path); + } + if (g->emit_asm) { + Buf *asm_basename = buf_create_from_buf(g->root_out_name); + const char *asm_ext = target_asm_file_ext(g->zig_target); + buf_append_str(asm_basename, asm_ext); + os_path_join(g->output_dir, asm_basename, &g->asm_file_output_path); + } + if (g->emit_llvm_ir) { + Buf *llvm_ir_basename = buf_create_from_buf(g->root_out_name); + const char *llvm_ir_ext = target_llvm_ir_file_ext(g->zig_target); + buf_append_str(llvm_ir_basename, llvm_ir_ext); + os_path_join(g->output_dir, llvm_ir_basename, &g->llvm_ir_file_output_path); } - - os_path_join(g->output_dir, o_basename, &g->o_file_output_path); - os_path_join(g->output_dir, out_basename, &g->output_file_path); } void codegen_build_and_link(CodeGen *g) { @@ -10715,7 +10582,7 @@ void codegen_build_and_link(CodeGen *g) { // If there is more than one object, we have to link them (with -r). // Finally, if we didn't make an object from zig source, and we don't have caching enabled, // then we have an object from C source that we must copy to the output dir which we do with a -r link. - if (!g->disable_bin_generation && g->emit_file_type == EmitFileTypeBinary && + if (g->emit_bin && (g->out_type != OutTypeObj || g->link_objects.length > 1 || (!need_llvm_module(g) && !g->enable_cache))) { @@ -10751,7 +10618,7 @@ ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const c } CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type, - ZigLibCInstallation *libc, const char *name, Stage2ProgressNode *parent_progress_node) + Stage2LibCInstallation *libc, const char *name, Stage2ProgressNode *parent_progress_node) { Stage2ProgressNode *child_progress_node = stage2_progress_start( parent_progress_node ? parent_progress_node : parent_gen->sub_progress_node, @@ -10790,9 +10657,10 @@ CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType o CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode, Buf *override_lib_dir, - ZigLibCInstallation *libc, Buf *cache_dir, bool is_test_build, Stage2ProgressNode *progress_node) + Stage2LibCInstallation *libc, Buf *cache_dir, bool is_test_build, Stage2ProgressNode *progress_node) { CodeGen *g = heap::c_allocator.create<CodeGen>(); + g->emit_bin = true; g->pass1_arena = heap::ArenaAllocator::construct(&heap::c_allocator, &heap::c_allocator, "pass1"); g->main_progress_node = progress_node; diff --git a/src/codegen.hpp b/src/codegen.hpp @@ -11,23 +11,21 @@ #include "parser.hpp" #include "errmsg.hpp" #include "target.hpp" -#include "libc_installation.hpp" -#include "userland.h" +#include "stage2.h" #include <stdio.h> CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget *target, OutType out_type, BuildMode build_mode, Buf *zig_lib_dir, - ZigLibCInstallation *libc, Buf *cache_dir, bool is_test_build, Stage2ProgressNode *progress_node); + Stage2LibCInstallation *libc, Buf *cache_dir, bool is_test_build, Stage2ProgressNode *progress_node); CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type, - ZigLibCInstallation *libc, const char *name, Stage2ProgressNode *progress_node); + Stage2LibCInstallation *libc, const char *name, Stage2ProgressNode *progress_node); void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len); void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len); void codegen_set_each_lib_rpath(CodeGen *codegen, bool each_lib_rpath); -void codegen_set_emit_file_type(CodeGen *g, EmitFileType emit_file_type); void codegen_set_strip(CodeGen *codegen, bool strip); void codegen_set_errmsg_color(CodeGen *codegen, ErrColor err_color); void codegen_set_out_name(CodeGen *codegen, Buf *out_name); diff --git a/src/compiler.cpp b/src/compiler.cpp @@ -4,20 +4,6 @@ #include <stdio.h> -static Buf saved_dynamic_linker_path = BUF_INIT; -static bool searched_for_dyn_linker = false; - -static void detect_dynamic_linker(Buf *lib_path) { -#if defined(ZIG_OS_LINUX) - for (size_t i = 0; possible_ld_names[i] != NULL; i += 1) { - if (buf_ends_with_str(lib_path, possible_ld_names[i])) { - buf_init_from_buf(&saved_dynamic_linker_path, lib_path); - break; - } - } -#endif -} - Buf *get_self_libc_path(void) { static Buf saved_libc_path = BUF_INIT; static bool searched_for_libc = false; @@ -43,25 +29,6 @@ Buf *get_self_libc_path(void) { } } -Buf *get_self_dynamic_linker_path(void) { - for (;;) { - if (saved_dynamic_linker_path.list.length != 0) { - return &saved_dynamic_linker_path; - } - if (searched_for_dyn_linker) - return nullptr; - ZigList<Buf *> lib_paths = {}; - Error err; - if ((err = os_self_exe_shared_libs(lib_paths))) - return nullptr; - for (size_t i = 0; i < lib_paths.length; i += 1) { - Buf *lib_path = lib_paths.at(i); - detect_dynamic_linker(lib_path); - } - searched_for_dyn_linker = true; - } -} - Error get_compiler_id(Buf **result) { static Buf saved_compiler_id = BUF_INIT; @@ -98,7 +65,6 @@ Error get_compiler_id(Buf **result) { return err; for (size_t i = 0; i < lib_paths.length; i += 1) { Buf *lib_path = lib_paths.at(i); - detect_dynamic_linker(lib_path); if ((err = cache_add_file(ch, lib_path))) return err; } diff --git a/src/compiler.hpp b/src/compiler.hpp @@ -12,7 +12,6 @@ #include "error.hpp" Error get_compiler_id(Buf **result); -Buf *get_self_dynamic_linker_path(void); Buf *get_self_libc_path(void); Buf *get_zig_lib_dir(void); diff --git a/src/error.cpp b/src/error.cpp @@ -59,11 +59,28 @@ const char *err_str(Error err) { case ErrorIsAsync: return "is async"; case ErrorImportOutsidePkgPath: return "import of file outside package path"; case ErrorUnknownCpu: return "unknown CPU"; - case ErrorUnknownSubArchitecture: return "unknown sub-architecture"; case ErrorUnknownCpuFeature: return "unknown CPU feature"; case ErrorInvalidCpuFeatures: return "invalid CPU features"; case ErrorInvalidLlvmCpuFeaturesFormat: return "invalid LLVM CPU features format"; case ErrorUnknownApplicationBinaryInterface: return "unknown application binary interface"; + case ErrorASTUnitFailure: return "compiler bug: clang encountered a compile error, but the libclang API does not expose the error. See https://github.com/ziglang/zig/issues/4455 for more details"; + case ErrorBadPathName: return "bad path name"; + case ErrorSymLinkLoop: return "sym link loop"; + case ErrorProcessFdQuotaExceeded: return "process fd quota exceeded"; + case ErrorSystemFdQuotaExceeded: return "system fd quota exceeded"; + case ErrorNoDevice: return "no device"; + case ErrorDeviceBusy: return "device busy"; + case ErrorUnableToSpawnCCompiler: return "unable to spawn system C compiler"; + case ErrorCCompilerExitCode: return "system C compiler exited with failure code"; + case ErrorCCompilerCrashed: return "system C compiler crashed"; + case ErrorCCompilerCannotFindHeaders: return "system C compiler cannot find libc headers"; + case ErrorLibCRuntimeNotFound: return "libc runtime not found"; + case ErrorLibCStdLibHeaderNotFound: return "libc std lib headers not found"; + case ErrorLibCKernel32LibNotFound: return "kernel32 library not found"; + case ErrorUnsupportedArchitecture: return "unsupported architecture"; + case ErrorWindowsSdkNotFound: return "Windows SDK not found"; + case ErrorUnknownDynamicLinkerPath: return "unknown dynamic linker path"; + case ErrorTargetHasNoDynamicLinker: return "target has no dynamic linker"; } return "(invalid error)"; } diff --git a/src/error.hpp b/src/error.hpp @@ -8,7 +8,7 @@ #ifndef ERROR_HPP #define ERROR_HPP -#include "userland.h" +#include "stage2.h" const char *err_str(Error err); diff --git a/src/glibc.cpp b/src/glibc.cpp @@ -116,10 +116,8 @@ Error glibc_load_metadata(ZigGLibCAbi **out_result, Buf *zig_lib_dir, bool verbo assert(opt_abi.is_some); - err = target_parse_archsub(&target->arch, &target->sub_arch, - (char*)opt_arch.value.ptr, opt_arch.value.len); - // there's no sub arch so we might get an error, but the arch is still populated - assert(err == ErrorNone || err == ErrorUnknownArchitecture); + err = target_parse_arch(&target->arch, (char*)opt_arch.value.ptr, opt_arch.value.len); + assert(err == ErrorNone); target->os = OsLinux; diff --git a/src/ir.cpp b/src/ir.cpp @@ -14,6 +14,7 @@ #include "range_set.hpp" #include "softfloat.hpp" #include "util.hpp" +#include "mem_list.hpp" #include <errno.h> @@ -28,6 +29,9 @@ struct IrBuilderGen { CodeGen *codegen; IrExecutableGen *exec; IrBasicBlockGen *current_basic_block; + + // track for immediate post-analysis destruction + mem::List<IrInstGenConst *> constants; }; struct IrAnalyze { @@ -383,18 +387,12 @@ static void destroy_instruction_src(IrInstSrc *inst) { return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFloatCast *>(inst)); case IrInstSrcIdErrSetCast: return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcErrSetCast *>(inst)); - case IrInstSrcIdFromBytes: - return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFromBytes *>(inst)); - case IrInstSrcIdToBytes: - return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcToBytes *>(inst)); case IrInstSrcIdIntToFloat: return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcIntToFloat *>(inst)); case IrInstSrcIdFloatToInt: return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFloatToInt *>(inst)); case IrInstSrcIdBoolToInt: return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcBoolToInt *>(inst)); - case IrInstSrcIdIntType: - return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcIntType *>(inst)); case IrInstSrcIdVectorType: return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcVectorType *>(inst)); case IrInstSrcIdShuffleVector: @@ -409,12 +407,6 @@ static void destroy_instruction_src(IrInstSrc *inst) { return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcMemcpy *>(inst)); case IrInstSrcIdSlice: return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSlice *>(inst)); - case IrInstSrcIdMemberCount: - return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcMemberCount *>(inst)); - case IrInstSrcIdMemberType: - return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcMemberType *>(inst)); - case IrInstSrcIdMemberName: - return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcMemberName *>(inst)); case IrInstSrcIdBreakpoint: return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcBreakpoint *>(inst)); case IrInstSrcIdReturnAddress: @@ -481,8 +473,6 @@ static void destroy_instruction_src(IrInstSrc *inst) { return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcType *>(inst)); case IrInstSrcIdHasField: return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcHasField *>(inst)); - case IrInstSrcIdTypeId: - return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTypeId *>(inst)); case IrInstSrcIdSetEvalBranchQuota: return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSetEvalBranchQuota *>(inst)); case IrInstSrcIdAlignCast: @@ -707,8 +697,6 @@ void destroy_instruction_gen(IrInstGen *inst) { return heap::c_allocator.destroy(reinterpret_cast<IrInstGenAssertZero *>(inst)); case IrInstGenIdAssertNonNull: return heap::c_allocator.destroy(reinterpret_cast<IrInstGenAssertNonNull *>(inst)); - case IrInstGenIdResizeSlice: - return heap::c_allocator.destroy(reinterpret_cast<IrInstGenResizeSlice *>(inst)); case IrInstGenIdAlloca: return heap::c_allocator.destroy(reinterpret_cast<IrInstGenAlloca *>(inst)); case IrInstGenIdSuspendBegin: @@ -741,6 +729,10 @@ static void ira_ref(IrAnalyze *ira) { static void ira_deref(IrAnalyze *ira) { if (ira->ref_count > 1) { ira->ref_count -= 1; + + // immediate destruction of dangling IrInstGenConst is not possible + // free tracking memory because it will never be used + ira->new_irb.constants.deinit(&heap::c_allocator); return; } assert(ira->ref_count != 0); @@ -758,6 +750,15 @@ static void ira_deref(IrAnalyze *ira) { heap::c_allocator.destroy(ira->old_irb.exec); ira->src_implicit_return_type_list.deinit(); ira->resume_stack.deinit(); + + // destroy dangling IrInstGenConst + for (size_t i = 0; i < ira->new_irb.constants.length; i += 1) { + auto constant = ira->new_irb.constants.items[i]; + if (constant->base.base.ref_count == 0 && !ir_inst_gen_has_side_effects(&constant->base)) + destroy_instruction_gen(&constant->base); + } + ira->new_irb.constants.deinit(&heap::c_allocator); + heap::c_allocator.destroy(ira); } @@ -1299,10 +1300,6 @@ static constexpr IrInstSrcId ir_inst_id(IrInstSrcBoolToInt *) { return IrInstSrcIdBoolToInt; } -static constexpr IrInstSrcId ir_inst_id(IrInstSrcIntType *) { - return IrInstSrcIdIntType; -} - static constexpr IrInstSrcId ir_inst_id(IrInstSrcVectorType *) { return IrInstSrcIdVectorType; } @@ -1331,18 +1328,6 @@ static constexpr IrInstSrcId ir_inst_id(IrInstSrcSlice *) { return IrInstSrcIdSlice; } -static constexpr IrInstSrcId ir_inst_id(IrInstSrcMemberCount *) { - return IrInstSrcIdMemberCount; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcMemberType *) { - return IrInstSrcIdMemberType; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcMemberName *) { - return IrInstSrcIdMemberName; -} - static constexpr IrInstSrcId ir_inst_id(IrInstSrcBreakpoint *) { return IrInstSrcIdBreakpoint; } @@ -1487,10 +1472,6 @@ static constexpr IrInstSrcId ir_inst_id(IrInstSrcHasField *) { return IrInstSrcIdHasField; } -static constexpr IrInstSrcId ir_inst_id(IrInstSrcTypeId *) { - return IrInstSrcIdTypeId; -} - static constexpr IrInstSrcId ir_inst_id(IrInstSrcSetEvalBranchQuota *) { return IrInstSrcIdSetEvalBranchQuota; } @@ -1563,14 +1544,6 @@ static constexpr IrInstSrcId ir_inst_id(IrInstSrcErrSetCast *) { return IrInstSrcIdErrSetCast; } -static constexpr IrInstSrcId ir_inst_id(IrInstSrcToBytes *) { - return IrInstSrcIdToBytes; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcFromBytes *) { - return IrInstSrcIdFromBytes; -} - static constexpr IrInstSrcId ir_inst_id(IrInstSrcCheckRuntimeScope *) { return IrInstSrcIdCheckRuntimeScope; } @@ -1700,10 +1673,6 @@ static constexpr IrInstGenId ir_inst_id(IrInstGenCast *) { return IrInstGenIdCast; } -static constexpr IrInstGenId ir_inst_id(IrInstGenResizeSlice *) { - return IrInstGenIdResizeSlice; -} - static constexpr IrInstGenId ir_inst_id(IrInstGenUnreachable *) { return IrInstGenIdUnreachable; } @@ -2759,21 +2728,6 @@ static IrInstGen *ir_build_var_decl_gen(IrAnalyze *ira, IrInst *source_instructi return &inst->base; } -static IrInstGen *ir_build_resize_slice(IrAnalyze *ira, IrInst *source_instruction, - IrInstGen *operand, ZigType *ty, IrInstGen *result_loc) -{ - IrInstGenResizeSlice *instruction = ir_build_inst_gen<IrInstGenResizeSlice>(&ira->new_irb, - source_instruction->scope, source_instruction->source_node); - instruction->base.value->type = ty; - instruction->operand = operand; - instruction->result_loc = result_loc; - - ir_ref_inst_gen(operand, ira->new_irb.current_basic_block); - if (result_loc != nullptr) ir_ref_inst_gen(result_loc, ira->new_irb.current_basic_block); - - return &instruction->base; -} - static IrInstSrc *ir_build_export(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *target, IrInstSrc *options) { @@ -3540,32 +3494,6 @@ static IrInstSrc *ir_build_err_set_cast(IrBuilderSrc *irb, Scope *scope, AstNode return &instruction->base; } -static IrInstSrc *ir_build_to_bytes(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *target, - ResultLoc *result_loc) -{ - IrInstSrcToBytes *instruction = ir_build_instruction<IrInstSrcToBytes>(irb, scope, source_node); - instruction->target = target; - instruction->result_loc = result_loc; - - ir_ref_instruction(target, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_from_bytes(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *dest_child_type, IrInstSrc *target, ResultLoc *result_loc) -{ - IrInstSrcFromBytes *instruction = ir_build_instruction<IrInstSrcFromBytes>(irb, scope, source_node); - instruction->dest_child_type = dest_child_type; - instruction->target = target; - instruction->result_loc = result_loc; - - ir_ref_instruction(dest_child_type, irb->current_basic_block); - ir_ref_instruction(target, irb->current_basic_block); - - return &instruction->base; -} - static IrInstSrc *ir_build_int_to_float(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *dest_type, IrInstSrc *target) { @@ -3601,19 +3529,6 @@ static IrInstSrc *ir_build_bool_to_int(IrBuilderSrc *irb, Scope *scope, AstNode return &instruction->base; } -static IrInstSrc *ir_build_int_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *is_signed, - IrInstSrc *bit_count) -{ - IrInstSrcIntType *instruction = ir_build_instruction<IrInstSrcIntType>(irb, scope, source_node); - instruction->is_signed = is_signed; - instruction->bit_count = bit_count; - - ir_ref_instruction(is_signed, irb->current_basic_block); - ir_ref_instruction(bit_count, irb->current_basic_block); - - return &instruction->base; -} - static IrInstSrc *ir_build_vector_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *len, IrInstSrc *elem_type) { @@ -3808,41 +3723,6 @@ static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction, return &instruction->base; } -static IrInstSrc *ir_build_member_count(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *container) { - IrInstSrcMemberCount *instruction = ir_build_instruction<IrInstSrcMemberCount>(irb, scope, source_node); - instruction->container = container; - - ir_ref_instruction(container, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_member_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *container_type, IrInstSrc *member_index) -{ - IrInstSrcMemberType *instruction = ir_build_instruction<IrInstSrcMemberType>(irb, scope, source_node); - instruction->container_type = container_type; - instruction->member_index = member_index; - - ir_ref_instruction(container_type, irb->current_basic_block); - ir_ref_instruction(member_index, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_member_name(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *container_type, IrInstSrc *member_index) -{ - IrInstSrcMemberName *instruction = ir_build_instruction<IrInstSrcMemberName>(irb, scope, source_node); - instruction->container_type = container_type; - instruction->member_index = member_index; - - ir_ref_instruction(container_type, irb->current_basic_block); - ir_ref_instruction(member_index, irb->current_basic_block); - - return &instruction->base; -} - static IrInstSrc *ir_build_breakpoint(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { IrInstSrcBreakpoint *instruction = ir_build_instruction<IrInstSrcBreakpoint>(irb, scope, source_node); return &instruction->base; @@ -4517,15 +4397,6 @@ static IrInstSrc *ir_build_type(IrBuilderSrc *irb, Scope *scope, AstNode *source return &instruction->base; } -static IrInstSrc *ir_build_type_id(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type_value) { - IrInstSrcTypeId *instruction = ir_build_instruction<IrInstSrcTypeId>(irb, scope, source_node); - instruction->type_value = type_value; - - ir_ref_instruction(type_value, irb->current_basic_block); - - return &instruction->base; -} - static IrInstSrc *ir_build_set_eval_branch_quota(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *new_quota) { @@ -4956,11 +4827,12 @@ static IrInstGen *ir_build_suspend_finish_gen(IrAnalyze *ira, IrInst *source_ins } static IrInstSrc *ir_build_await_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *frame, ResultLoc *result_loc) + IrInstSrc *frame, ResultLoc *result_loc, bool is_noasync) { IrInstSrcAwait *instruction = ir_build_instruction<IrInstSrcAwait>(irb, scope, source_node); instruction->frame = frame; instruction->result_loc = result_loc; + instruction->is_noasync = is_noasync; ir_ref_instruction(frame, irb->current_basic_block); @@ -4968,13 +4840,14 @@ static IrInstSrc *ir_build_await_src(IrBuilderSrc *irb, Scope *scope, AstNode *s } static IrInstGenAwait *ir_build_await_gen(IrAnalyze *ira, IrInst *source_instruction, - IrInstGen *frame, ZigType *result_type, IrInstGen *result_loc) + IrInstGen *frame, ZigType *result_type, IrInstGen *result_loc, bool is_noasync) { IrInstGenAwait *instruction = ir_build_inst_gen<IrInstGenAwait>(&ira->new_irb, source_instruction->scope, source_instruction->source_node); instruction->base.value->type = result_type; instruction->frame = frame; instruction->result_loc = result_loc; + instruction->is_noasync = is_noasync; ir_ref_inst_gen(frame, ira->new_irb.current_basic_block); if (result_loc != nullptr) ir_ref_inst_gen(result_loc, ira->new_irb.current_basic_block); @@ -6595,31 +6468,6 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod IrInstSrc *result = ir_build_err_set_cast(irb, scope, node, arg0_value, arg1_value); return ir_lval_wrap(irb, scope, result, lval, result_loc); } - case BuiltinFnIdFromBytes: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *result = ir_build_from_bytes(irb, scope, node, arg0_value, arg1_value, result_loc); - return ir_lval_wrap(irb, scope, result, lval, result_loc); - } - case BuiltinFnIdToBytes: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *result = ir_build_to_bytes(irb, scope, node, arg0_value, result_loc); - return ir_lval_wrap(irb, scope, result, lval, result_loc); - } case BuiltinFnIdIntToFloat: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); @@ -6680,21 +6528,6 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod IrInstSrc *result = ir_build_bool_to_int(irb, scope, node, arg0_value); return ir_lval_wrap(irb, scope, result, lval, result_loc); } - case BuiltinFnIdIntType: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *int_type = ir_build_int_type(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, int_type, lval, result_loc); - } case BuiltinFnIdVectorType: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); @@ -6792,48 +6625,6 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod IrInstSrc *ir_memset = ir_build_memset_src(irb, scope, node, arg0_value, arg1_value, arg2_value); return ir_lval_wrap(irb, scope, ir_memset, lval, result_loc); } - case BuiltinFnIdMemberCount: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *member_count = ir_build_member_count(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, member_count, lval, result_loc); - } - case BuiltinFnIdMemberType: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - - IrInstSrc *member_type = ir_build_member_type(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, member_type, lval, result_loc); - } - case BuiltinFnIdMemberName: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - - IrInstSrc *member_name = ir_build_member_name(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, member_name, lval, result_loc); - } case BuiltinFnIdField: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); @@ -7158,16 +6949,6 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod } case BuiltinFnIdAsyncCall: return ir_gen_async_call(irb, scope, nullptr, node, lval, result_loc); - case BuiltinFnIdTypeId: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *type_id = ir_build_type_id(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, type_id, lval, result_loc); - } case BuiltinFnIdShlExact: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); @@ -7243,21 +7024,6 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod IrInstSrc *set_align_stack = ir_build_set_align_stack(irb, scope, node, arg0_value); return ir_lval_wrap(irb, scope, set_align_stack, lval, result_loc); } - case BuiltinFnIdArgType: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *arg_type = ir_build_arg_type(irb, scope, node, arg0_value, arg1_value, false); - return ir_lval_wrap(irb, scope, arg_type, lval, result_loc); - } case BuiltinFnIdExport: { // Cast the options parameter to the options type @@ -8073,9 +7839,9 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no if (var_symbol) { IrInstSrc *payload_ptr = ir_build_unwrap_err_payload_src(irb, &spill_scope->base, symbol_node, err_val_ptr, false, false); - IrInstSrc *var_ptr = node->data.while_expr.var_is_ptr ? - ir_build_ref_src(irb, &spill_scope->base, symbol_node, payload_ptr, true, false) : payload_ptr; - ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, var_ptr); + IrInstSrc *var_value = node->data.while_expr.var_is_ptr ? + payload_ptr : ir_build_load_ptr(irb, &spill_scope->base, symbol_node, payload_ptr); + build_decl_var_and_init(irb, payload_scope, symbol_node, payload_var, var_value, buf_ptr(var_symbol), is_comptime); } ZigList<IrInstSrc *> incoming_values = {0}; @@ -8123,7 +7889,8 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no true, false, false, is_comptime); Scope *err_scope = err_var->child_scope; IrInstSrc *err_ptr = ir_build_unwrap_err_code_src(irb, err_scope, err_symbol_node, err_val_ptr); - ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, err_ptr); + IrInstSrc *err_value = ir_build_load_ptr(irb, err_scope, err_symbol_node, err_ptr); + build_decl_var_and_init(irb, err_scope, err_symbol_node, err_var, err_value, buf_ptr(err_symbol), is_comptime); if (peer_parent->peers.length != 0) { peer_parent->peers.last()->next_bb = else_block; @@ -8184,9 +7951,9 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no ir_set_cursor_at_end_and_append_block(irb, body_block); IrInstSrc *payload_ptr = ir_build_optional_unwrap_ptr(irb, &spill_scope->base, symbol_node, maybe_val_ptr, false, false); - IrInstSrc *var_ptr = node->data.while_expr.var_is_ptr ? - ir_build_ref_src(irb, &spill_scope->base, symbol_node, payload_ptr, true, false) : payload_ptr; - ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, var_ptr); + IrInstSrc *var_value = node->data.while_expr.var_is_ptr ? + payload_ptr : ir_build_load_ptr(irb, &spill_scope->base, symbol_node, payload_ptr); + build_decl_var_and_init(irb, child_scope, symbol_node, payload_var, var_value, buf_ptr(var_symbol), is_comptime); ZigList<IrInstSrc *> incoming_values = {0}; ZigList<IrBasicBlockSrc *> incoming_blocks = {0}; @@ -8425,9 +8192,9 @@ static IrInstSrc *ir_gen_for_expr(IrBuilderSrc *irb, Scope *parent_scope, AstNod ZigVar *elem_var = ir_create_var(irb, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime); Scope *child_scope = elem_var->child_scope; - IrInstSrc *var_ptr = node->data.for_expr.elem_is_ptr ? - ir_build_ref_src(irb, &spill_scope->base, elem_node, elem_ptr, true, false) : elem_ptr; - ir_build_var_decl_src(irb, parent_scope, elem_node, elem_var, nullptr, var_ptr); + IrInstSrc *elem_value = node->data.for_expr.elem_is_ptr ? + elem_ptr : ir_build_load_ptr(irb, &spill_scope->base, elem_node, elem_ptr); + build_decl_var_and_init(irb, parent_scope, elem_node, elem_var, elem_value, buf_ptr(elem_var_name), is_comptime); ZigList<IrInstSrc *> incoming_values = {0}; ZigList<IrBasicBlockSrc *> incoming_blocks = {0}; @@ -8847,8 +8614,9 @@ static IrInstSrc *ir_gen_if_optional_expr(IrBuilderSrc *irb, Scope *scope, AstNo var_symbol, is_const, is_const, is_shadowable, is_comptime); IrInstSrc *payload_ptr = ir_build_optional_unwrap_ptr(irb, subexpr_scope, node, maybe_val_ptr, false, false); - IrInstSrc *var_ptr = var_is_ptr ? ir_build_ref_src(irb, subexpr_scope, node, payload_ptr, true, false) : payload_ptr; - ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, var_ptr); + IrInstSrc *var_value = var_is_ptr ? + payload_ptr : ir_build_load_ptr(irb, &spill_scope->base, node, payload_ptr); + build_decl_var_and_init(irb, subexpr_scope, node, var, var_value, buf_ptr(var_symbol), is_comptime); var_scope = var->child_scope; } else { var_scope = subexpr_scope; @@ -8929,9 +8697,9 @@ static IrInstSrc *ir_gen_if_err_expr(IrBuilderSrc *irb, Scope *scope, AstNode *n var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime); IrInstSrc *payload_ptr = ir_build_unwrap_err_payload_src(irb, subexpr_scope, node, err_val_ptr, false, false); - IrInstSrc *var_ptr = var_is_ptr ? - ir_build_ref_src(irb, subexpr_scope, node, payload_ptr, true, false) : payload_ptr; - ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, var_ptr); + IrInstSrc *var_value = var_is_ptr ? + payload_ptr : ir_build_load_ptr(irb, subexpr_scope, node, payload_ptr); + build_decl_var_and_init(irb, subexpr_scope, node, var, var_value, buf_ptr(var_symbol), var_is_comptime); var_scope = var->child_scope; } else { var_scope = subexpr_scope; @@ -8956,7 +8724,8 @@ static IrInstSrc *ir_gen_if_err_expr(IrBuilderSrc *irb, Scope *scope, AstNode *n err_symbol, is_const, is_const, is_shadowable, is_comptime); IrInstSrc *err_ptr = ir_build_unwrap_err_code_src(irb, subexpr_scope, node, err_val_ptr); - ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, err_ptr); + IrInstSrc *err_value = ir_build_load_ptr(irb, subexpr_scope, node, err_ptr); + build_decl_var_and_init(irb, subexpr_scope, node, var, err_value, buf_ptr(err_symbol), is_comptime); err_var_scope = var->child_scope; } else { err_var_scope = subexpr_scope; @@ -9006,22 +8775,24 @@ static bool ir_gen_switch_prong_expr(IrBuilderSrc *irb, Scope *scope, AstNode *s ZigVar *var = ir_create_var(irb, var_symbol_node, scope, var_name, is_const, is_const, is_shadowable, var_is_comptime); child_scope = var->child_scope; - IrInstSrc *var_ptr; + IrInstSrc *var_value; if (out_switch_else_var != nullptr) { IrInstSrcSwitchElseVar *switch_else_var = ir_build_switch_else_var(irb, scope, var_symbol_node, target_value_ptr); *out_switch_else_var = switch_else_var; IrInstSrc *payload_ptr = &switch_else_var->base; - var_ptr = var_is_ptr ? ir_build_ref_src(irb, scope, var_symbol_node, payload_ptr, true, false) : payload_ptr; + var_value = var_is_ptr ? + payload_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, payload_ptr); } else if (prong_values != nullptr) { IrInstSrc *payload_ptr = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, prong_values, prong_values_len); - var_ptr = var_is_ptr ? ir_build_ref_src(irb, scope, var_symbol_node, payload_ptr, true, false) : payload_ptr; + var_value = var_is_ptr ? + payload_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, payload_ptr); } else { - var_ptr = var_is_ptr ? - ir_build_ref_src(irb, scope, var_symbol_node, target_value_ptr, true, false) : target_value_ptr; + var_value = var_is_ptr ? + target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr); } - ir_build_var_decl_src(irb, scope, var_symbol_node, var, nullptr, var_ptr); + build_decl_var_and_init(irb, scope, var_symbol_node, var, var_value, buf_ptr(var_name), var_is_comptime); } else { child_scope = scope; } @@ -9594,7 +9365,8 @@ static IrInstSrc *ir_gen_catch(IrBuilderSrc *irb, Scope *parent_scope, AstNode * is_const, is_const, is_shadowable, is_comptime); err_scope = var->child_scope; IrInstSrc *err_ptr = ir_build_unwrap_err_code_src(irb, err_scope, node, err_union_ptr); - ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, err_ptr); + IrInstSrc *err_value = ir_build_load_ptr(irb, err_scope, var_node, err_ptr); + build_decl_var_and_init(irb, err_scope, var_node, var, err_value, buf_ptr(var_name), is_comptime); } else { err_scope = subexpr_scope; } @@ -9914,6 +9686,8 @@ static IrInstSrc *ir_gen_await_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no { assert(node->type == NodeTypeAwaitExpr); + bool is_noasync = node->data.await_expr.noasync_token != nullptr; + AstNode *expr_node = node->data.await_expr.expr; if (expr_node->type == NodeTypeFnCallExpr && expr_node->data.fn_call_expr.modifier == CallModifierBuiltin) { AstNode *fn_ref_expr = expr_node->data.fn_call_expr.fn_ref_expr; @@ -9946,7 +9720,7 @@ static IrInstSrc *ir_gen_await_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no if (target_inst == irb->codegen->invalid_inst_src) return irb->codegen->invalid_inst_src; - IrInstSrc *await_inst = ir_build_await_src(irb, scope, node, target_inst, result_loc); + IrInstSrc *await_inst = ir_build_await_src(irb, scope, node, target_inst, result_loc, is_noasync); return ir_lval_wrap(irb, scope, await_inst, lval, result_loc); } @@ -12703,12 +12477,14 @@ static IrInstGen *ir_const(IrAnalyze *ira, IrInst *inst, ZigType *ty) { IrInstGen *new_instruction = &const_instruction->base; new_instruction->value->type = ty; new_instruction->value->special = ConstValSpecialStatic; + ira->new_irb.constants.append(&heap::c_allocator, const_instruction); return new_instruction; } static IrInstGen *ir_const_noval(IrAnalyze *ira, IrInst *old_instruction) { IrInstGenConst *const_instruction = ir_create_inst_noval<IrInstGenConst>(&ira->new_irb, old_instruction->scope, old_instruction->source_node); + ira->new_irb.constants.append(&heap::c_allocator, const_instruction); return &const_instruction->base; } @@ -20599,12 +20375,12 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP if (type_is_invalid(array_ptr->value->type)) return ira->codegen->invalid_inst_gen; - ZigValue *orig_array_ptr_val = array_ptr->value; - IrInstGen *elem_index = elem_ptr_instruction->elem_index->child; if (type_is_invalid(elem_index->value->type)) return ira->codegen->invalid_inst_gen; + ZigValue *orig_array_ptr_val = array_ptr->value; + ZigType *ptr_type = orig_array_ptr_val->type; assert(ptr_type->id == ZigTypeIdPointer); @@ -20614,23 +20390,25 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP // We will adjust return_type's alignment before returning it. ZigType *return_type; - if (type_is_invalid(array_type)) { + if (type_is_invalid(array_type)) return ira->codegen->invalid_inst_gen; - } else if (array_type->id == ZigTypeIdArray || - (array_type->id == ZigTypeIdPointer && - array_type->data.pointer.ptr_len == PtrLenSingle && - array_type->data.pointer.child_type->id == ZigTypeIdArray)) + + if (array_type->id == ZigTypeIdPointer && + array_type->data.pointer.ptr_len == PtrLenSingle && + array_type->data.pointer.child_type->id == ZigTypeIdArray) { - if (array_type->id == ZigTypeIdPointer) { - array_type = array_type->data.pointer.child_type; - ptr_type = ptr_type->data.pointer.child_type; - if (orig_array_ptr_val->special != ConstValSpecialRuntime) { - orig_array_ptr_val = const_ptr_pointee(ira, ira->codegen, orig_array_ptr_val, - elem_ptr_instruction->base.base.source_node); - if (orig_array_ptr_val == nullptr) - return ira->codegen->invalid_inst_gen; - } - } + IrInstGen *ptr_value = ir_get_deref(ira, &elem_ptr_instruction->base.base, + array_ptr, nullptr); + if (type_is_invalid(ptr_value->value->type)) + return ira->codegen->invalid_inst_gen; + + array_type = array_type->data.pointer.child_type; + ptr_type = ptr_type->data.pointer.child_type; + + orig_array_ptr_val = ptr_value->value; + } + + if (array_type->id == ZigTypeIdArray) { if (array_type->data.array.len == 0) { ir_add_error_node(ira, elem_ptr_instruction->base.base.source_node, buf_sprintf("index 0 outside array of size 0")); @@ -20768,8 +20546,14 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP orig_array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr && (orig_array_ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar || array_type->id == ZigTypeIdArray)) { + if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, + elem_ptr_instruction->base.base.source_node, orig_array_ptr_val, UndefBad))) + { + return ira->codegen->invalid_inst_gen; + } + ZigValue *array_ptr_val = const_ptr_pointee(ira, ira->codegen, orig_array_ptr_val, - elem_ptr_instruction->base.base.source_node); + elem_ptr_instruction->base.base.source_node); if (array_ptr_val == nullptr) return ira->codegen->invalid_inst_gen; @@ -21178,6 +20962,13 @@ static IrInstGen *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInst* source_ins return ira->codegen->invalid_inst_gen; if (type_is_invalid(struct_val->type)) return ira->codegen->invalid_inst_gen; + + // This to allow lazy values to be resolved. + if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, + source_instr->source_node, struct_val, UndefOk))) + { + return ira->codegen->invalid_inst_gen; + } if (initializing && struct_val->special == ConstValSpecialUndef) { struct_val->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, struct_type->data.structure.src_field_count); struct_val->special = ConstValSpecialStatic; @@ -23583,7 +23374,7 @@ static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, Zig } static Error ir_make_type_info_decls(IrAnalyze *ira, IrInst* source_instr, ZigValue *out_val, - ScopeDecls *decls_scope) + ScopeDecls *decls_scope, bool resolve_types) { Error err; ZigType *type_info_declaration_type = ir_type_info_get_type(ira, "Declaration", nullptr); @@ -23594,6 +23385,24 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInst* source_instr, ZigVa ensure_field_index(type_info_declaration_type, "is_pub", 1); ensure_field_index(type_info_declaration_type, "data", 2); + if (!resolve_types) { + ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, type_info_declaration_type, + false, false, PtrLenUnknown, 0, 0, 0, false); + + out_val->special = ConstValSpecialLazy; + out_val->type = get_slice_type(ira->codegen, ptr_type); + + LazyValueTypeInfoDecls *lazy_type_info_decls = heap::c_allocator.create<LazyValueTypeInfoDecls>(); + lazy_type_info_decls->ira = ira; ira_ref(ira); + out_val->data.x_lazy = &lazy_type_info_decls->base; + lazy_type_info_decls->base.id = LazyValueIdTypeInfoDecls; + + lazy_type_info_decls->source_instr = source_instr; + lazy_type_info_decls->decls_scope = decls_scope; + + return ErrorNone; + } + ZigType *type_info_declaration_data_type = ir_type_info_get_type(ira, "Data", type_info_declaration_type); if ((err = type_resolve(ira->codegen, type_info_declaration_data_type, ResolveStatusSizeKnown))) return err; @@ -23606,14 +23415,13 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInst* source_instr, ZigVa if ((err = type_resolve(ira->codegen, type_info_fn_decl_inline_type, ResolveStatusSizeKnown))) return err; - // Loop through our declarations once to figure out how many declarations we will generate info for. + // The unresolved declarations are collected in a separate queue to avoid + // modifying decl_table while iterating over it + ZigList<Tld*> resolve_decl_queue{}; + auto decl_it = decls_scope->decl_table.entry_iterator(); decltype(decls_scope->decl_table)::Entry *curr_entry = nullptr; - int declaration_count = 0; - while ((curr_entry = decl_it.next()) != nullptr) { - // If the declaration is unresolved, force it to be resolved again. - resolve_top_level_decl(ira->codegen, curr_entry->value, curr_entry->value->source_node, false); if (curr_entry->value->resolution == TldResolutionInvalid) { return ErrorSemanticAnalyzeFail; } @@ -23623,16 +23431,36 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInst* source_instr, ZigVa return ErrorSemanticAnalyzeFail; } + // If the declaration is unresolved, force it to be resolved again. + if (curr_entry->value->resolution == TldResolutionUnresolved) + resolve_decl_queue.append(curr_entry->value); + } + + for (size_t i = 0; i < resolve_decl_queue.length; i++) { + Tld *decl = resolve_decl_queue.at(i); + resolve_top_level_decl(ira->codegen, decl, decl->source_node, false); + if (decl->resolution == TldResolutionInvalid) { + return ErrorSemanticAnalyzeFail; + } + } + + resolve_decl_queue.deinit(); + + // Loop through our declarations once to figure out how many declarations we will generate info for. + int declaration_count = 0; + decl_it = decls_scope->decl_table.entry_iterator(); + while ((curr_entry = decl_it.next()) != nullptr) { // Skip comptime blocks and test functions. - if (curr_entry->value->id != TldIdCompTime) { - if (curr_entry->value->id == TldIdFn) { - ZigFn *fn_entry = ((TldFn *)curr_entry->value)->fn_entry; - if (fn_entry->is_test) - continue; - } + if (curr_entry->value->id == TldIdCompTime) + continue; - declaration_count += 1; + if (curr_entry->value->id == TldIdFn) { + ZigFn *fn_entry = ((TldFn *)curr_entry->value)->fn_entry; + if (fn_entry->is_test) + continue; } + + declaration_count += 1; } ZigValue *declaration_array = ira->codegen->pass1_arena->create<ZigValue>(); @@ -24146,7 +23974,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy // decls: []TypeInfo.Declaration ensure_field_index(result->type, "decls", 3); if ((err = ir_make_type_info_decls(ira, source_instr, fields[3], - type_entry->data.enumeration.decls_scope))) + type_entry->data.enumeration.decls_scope, false))) { return err; } @@ -24318,7 +24146,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy // decls: []TypeInfo.Declaration ensure_field_index(result->type, "decls", 3); if ((err = ir_make_type_info_decls(ira, source_instr, fields[3], - type_entry->data.unionation.decls_scope))) + type_entry->data.unionation.decls_scope, false))) { return err; } @@ -24410,7 +24238,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy // decls: []TypeInfo.Declaration ensure_field_index(result->type, "decls", 2); if ((err = ir_make_type_info_decls(ira, source_instr, fields[2], - type_entry->data.structure.decls_scope))) + type_entry->data.structure.decls_scope, false))) { return err; } @@ -24784,19 +24612,6 @@ static IrInstGen *ir_analyze_instruction_type(IrAnalyze *ira, IrInstSrcType *ins return ir_const_type(ira, &instruction->base.base, type); } -static IrInstGen *ir_analyze_instruction_type_id(IrAnalyze *ira, IrInstSrcTypeId *instruction) { - IrInstGen *type_value = instruction->type_value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value); - if (type_is_invalid(type_entry)) - return ira->codegen->invalid_inst_gen; - - ZigType *result_type = get_builtin_type(ira->codegen, "TypeId"); - - IrInstGen *result = ir_const(ira, &instruction->base.base, result_type); - bigint_init_unsigned(&result->value->data.x_enum_tag, type_id_index(type_entry)); - return result; -} - static IrInstGen *ir_analyze_instruction_set_eval_branch_quota(IrAnalyze *ira, IrInstSrcSetEvalBranchQuota *instruction) { @@ -25394,171 +25209,6 @@ static IrInstGen *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstSrcE return ir_analyze_err_set_cast(ira, &instruction->base.base, target, dest_type); } -static IrInstGen *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstSrcFromBytes *instruction) { - Error err; - - ZigType *dest_child_type = ir_resolve_type(ira, instruction->dest_child_type->child); - if (type_is_invalid(dest_child_type)) - return ira->codegen->invalid_inst_gen; - - IrInstGen *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - bool src_ptr_const; - bool src_ptr_volatile; - uint32_t src_ptr_align; - if (target->value->type->id == ZigTypeIdPointer) { - src_ptr_const = target->value->type->data.pointer.is_const; - src_ptr_volatile = target->value->type->data.pointer.is_volatile; - - if ((err = resolve_ptr_align(ira, target->value->type, &src_ptr_align))) - return ira->codegen->invalid_inst_gen; - } else if (is_slice(target->value->type)) { - ZigType *src_ptr_type = target->value->type->data.structure.fields[slice_ptr_index]->type_entry; - src_ptr_const = src_ptr_type->data.pointer.is_const; - src_ptr_volatile = src_ptr_type->data.pointer.is_volatile; - - if ((err = resolve_ptr_align(ira, src_ptr_type, &src_ptr_align))) - return ira->codegen->invalid_inst_gen; - } else { - src_ptr_const = true; - src_ptr_volatile = false; - - if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_inst_gen; - - src_ptr_align = get_abi_alignment(ira->codegen, target->value->type); - } - - if (src_ptr_align != 0) { - if ((err = type_resolve(ira->codegen, dest_child_type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_inst_gen; - } - - ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_child_type, - src_ptr_const, src_ptr_volatile, PtrLenUnknown, - src_ptr_align, 0, 0, false); - ZigType *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type); - - ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, - src_ptr_const, src_ptr_volatile, PtrLenUnknown, - src_ptr_align, 0, 0, false); - ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); - - IrInstGen *casted_value = ir_implicit_cast2(ira, &instruction->target->base, target, u8_slice); - if (type_is_invalid(casted_value->value->type)) - return ira->codegen->invalid_inst_gen; - - bool have_known_len = false; - uint64_t known_len; - - if (instr_is_comptime(casted_value)) { - ZigValue *val = ir_resolve_const(ira, casted_value, UndefBad); - if (!val) - return ira->codegen->invalid_inst_gen; - - ZigValue *len_val = val->data.x_struct.fields[slice_len_index]; - if (value_is_comptime(len_val)) { - known_len = bigint_as_u64(&len_val->data.x_bigint); - have_known_len = true; - } - } - - IrInstGen *result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc, - dest_slice_type, nullptr, true, true); - if (result_loc != nullptr && (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable)) { - return result_loc; - } - - if (target->value->type->id == ZigTypeIdPointer && - target->value->type->data.pointer.ptr_len == PtrLenSingle && - target->value->type->data.pointer.child_type->id == ZigTypeIdArray) - { - known_len = target->value->type->data.pointer.child_type->data.array.len; - have_known_len = true; - } else if (casted_value->value->data.rh_slice.id == RuntimeHintSliceIdLen) { - known_len = casted_value->value->data.rh_slice.len; - have_known_len = true; - } - - if (have_known_len) { - if ((err = type_resolve(ira->codegen, dest_child_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - uint64_t child_type_size = type_size(ira->codegen, dest_child_type); - uint64_t remainder = known_len % child_type_size; - if (remainder != 0) { - ErrorMsg *msg = ir_add_error(ira, &instruction->base.base, - buf_sprintf("unable to convert [%" ZIG_PRI_u64 "]u8 to %s: size mismatch", - known_len, buf_ptr(&dest_slice_type->name))); - add_error_note(ira->codegen, msg, instruction->dest_child_type->base.source_node, - buf_sprintf("%s has size %" ZIG_PRI_u64 "; remaining bytes: %" ZIG_PRI_u64, - buf_ptr(&dest_child_type->name), child_type_size, remainder)); - return ira->codegen->invalid_inst_gen; - } - } - - return ir_build_resize_slice(ira, &instruction->base.base, casted_value, dest_slice_type, result_loc); -} - -static IrInstGen *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstSrcToBytes *instruction) { - Error err; - - IrInstGen *target = instruction->target->child; - if (type_is_invalid(target->value->type)) - return ira->codegen->invalid_inst_gen; - - if (!is_slice(target->value->type)) { - ir_add_error(ira, &instruction->target->base, - buf_sprintf("expected slice, found '%s'", buf_ptr(&target->value->type->name))); - return ira->codegen->invalid_inst_gen; - } - - ZigType *src_ptr_type = target->value->type->data.structure.fields[slice_ptr_index]->type_entry; - - uint32_t alignment; - if ((err = resolve_ptr_align(ira, src_ptr_type, &alignment))) - return ira->codegen->invalid_inst_gen; - - ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, - src_ptr_type->data.pointer.is_const, src_ptr_type->data.pointer.is_volatile, PtrLenUnknown, - alignment, 0, 0, false); - ZigType *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type); - - if (instr_is_comptime(target)) { - ZigValue *target_val = ir_resolve_const(ira, target, UndefBad); - if (target_val == nullptr) - return ira->codegen->invalid_inst_gen; - - IrInstGen *result = ir_const(ira, &instruction->base.base, dest_slice_type); - result->value->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, 2); - - ZigValue *ptr_val = result->value->data.x_struct.fields[slice_ptr_index]; - ZigValue *target_ptr_val = target_val->data.x_struct.fields[slice_ptr_index]; - copy_const_val(ira->codegen, ptr_val, target_ptr_val); - ptr_val->type = dest_ptr_type; - - ZigValue *len_val = result->value->data.x_struct.fields[slice_len_index]; - len_val->special = ConstValSpecialStatic; - len_val->type = ira->codegen->builtin_types.entry_usize; - ZigValue *target_len_val = target_val->data.x_struct.fields[slice_len_index]; - ZigType *elem_type = src_ptr_type->data.pointer.child_type; - BigInt elem_size_bigint; - bigint_init_unsigned(&elem_size_bigint, type_size(ira->codegen, elem_type)); - bigint_mul(&len_val->data.x_bigint, &target_len_val->data.x_bigint, &elem_size_bigint); - - return result; - } - - IrInstGen *result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc, - dest_slice_type, nullptr, true, true); - if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { - return result_loc; - } - - return ir_build_resize_slice(ira, &instruction->base.base, target, dest_slice_type, result_loc); -} - static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) { Error err; @@ -25672,20 +25322,6 @@ static IrInstGen *ir_analyze_instruction_bool_to_int(IrAnalyze *ira, IrInstSrcBo return ir_resolve_cast(ira, &instruction->base.base, target, u1_type, CastOpBoolToInt); } -static IrInstGen *ir_analyze_instruction_int_type(IrAnalyze *ira, IrInstSrcIntType *instruction) { - IrInstGen *is_signed_value = instruction->is_signed->child; - bool is_signed; - if (!ir_resolve_bool(ira, is_signed_value, &is_signed)) - return ira->codegen->invalid_inst_gen; - - IrInstGen *bit_count_value = instruction->bit_count->child; - uint64_t bit_count; - if (!ir_resolve_unsigned(ira, bit_count_value, ira->codegen->builtin_types.entry_u16, &bit_count)) - return ira->codegen->invalid_inst_gen; - - return ir_const_type(ira, &instruction->base.base, get_int_type(ira->codegen, is_signed, (uint32_t)bit_count)); -} - static IrInstGen *ir_analyze_instruction_vector_type(IrAnalyze *ira, IrInstSrcVectorType *instruction) { uint64_t len; if (!ir_resolve_unsigned(ira, instruction->len->child, ira->codegen->builtin_types.entry_u32, &len)) @@ -26582,148 +26218,21 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i IrInstGen *result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc, return_type, nullptr, true, true); - if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { - return result_loc; - } - return ir_build_slice_gen(ira, &instruction->base.base, return_type, - ptr_ptr, casted_start, end, instruction->safety_check_on, result_loc); -} - -static IrInstGen *ir_analyze_instruction_member_count(IrAnalyze *ira, IrInstSrcMemberCount *instruction) { - Error err; - IrInstGen *container = instruction->container->child; - if (type_is_invalid(container->value->type)) - return ira->codegen->invalid_inst_gen; - ZigType *container_type = ir_resolve_type(ira, container); - - if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - uint64_t result; - if (type_is_invalid(container_type)) { - return ira->codegen->invalid_inst_gen; - } else if (container_type->id == ZigTypeIdEnum) { - result = container_type->data.enumeration.src_field_count; - } else if (container_type->id == ZigTypeIdStruct) { - result = container_type->data.structure.src_field_count; - } else if (container_type->id == ZigTypeIdUnion) { - result = container_type->data.unionation.src_field_count; - } else if (container_type->id == ZigTypeIdErrorSet) { - if (!resolve_inferred_error_set(ira->codegen, container_type, instruction->base.base.source_node)) { - return ira->codegen->invalid_inst_gen; - } - if (type_is_global_error_set(container_type)) { - ir_add_error(ira, &instruction->base.base, buf_sprintf("global error set member count not available at comptime")); - return ira->codegen->invalid_inst_gen; - } - result = container_type->data.error_set.err_count; - } else { - ir_add_error(ira, &instruction->base.base, buf_sprintf("no value count available for type '%s'", buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } - - return ir_const_unsigned(ira, &instruction->base.base, result); -} - -static IrInstGen *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstSrcMemberType *instruction) { - Error err; - IrInstGen *container_type_value = instruction->container_type->child; - ZigType *container_type = ir_resolve_type(ira, container_type_value); - if (type_is_invalid(container_type)) - return ira->codegen->invalid_inst_gen; - - if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - - uint64_t member_index; - IrInstGen *index_value = instruction->member_index->child; - if (!ir_resolve_usize(ira, index_value, &member_index)) - return ira->codegen->invalid_inst_gen; - if (container_type->id == ZigTypeIdStruct) { - if (member_index >= container_type->data.structure.src_field_count) { - ir_add_error(ira, &index_value->base, - buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members", - member_index, buf_ptr(&container_type->name), container_type->data.structure.src_field_count)); - return ira->codegen->invalid_inst_gen; + if (result_loc != nullptr) { + if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { + return result_loc; } - TypeStructField *field = container_type->data.structure.fields[member_index]; - - return ir_const_type(ira, &instruction->base.base, field->type_entry); - } else if (container_type->id == ZigTypeIdUnion) { - if (member_index >= container_type->data.unionation.src_field_count) { - ir_add_error(ira, &index_value->base, - buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members", - member_index, buf_ptr(&container_type->name), container_type->data.unionation.src_field_count)); + IrInstGen *dummy_value = ir_const(ira, &instruction->base.base, return_type); + dummy_value->value->special = ConstValSpecialRuntime; + IrInstGen *dummy_result = ir_implicit_cast2(ira, &instruction->base.base, + dummy_value, result_loc->value->type->data.pointer.child_type); + if (type_is_invalid(dummy_result->value->type)) return ira->codegen->invalid_inst_gen; - } - TypeUnionField *field = &container_type->data.unionation.fields[member_index]; - - return ir_const_type(ira, &instruction->base.base, field->type_entry); - } else { - ir_add_error(ira, &container_type_value->base, - buf_sprintf("type '%s' does not support @memberType", buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; } -} - -static IrInstGen *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInstSrcMemberName *instruction) { - Error err; - IrInstGen *container_type_value = instruction->container_type->child; - ZigType *container_type = ir_resolve_type(ira, container_type_value); - if (type_is_invalid(container_type)) - return ira->codegen->invalid_inst_gen; - if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_inst_gen; - - uint64_t member_index; - IrInstGen *index_value = instruction->member_index->child; - if (!ir_resolve_usize(ira, index_value, &member_index)) - return ira->codegen->invalid_inst_gen; - - if (container_type->id == ZigTypeIdStruct) { - if (member_index >= container_type->data.structure.src_field_count) { - ir_add_error(ira, &index_value->base, - buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members", - member_index, buf_ptr(&container_type->name), container_type->data.structure.src_field_count)); - return ira->codegen->invalid_inst_gen; - } - TypeStructField *field = container_type->data.structure.fields[member_index]; - - IrInstGen *result = ir_const(ira, &instruction->base.base, nullptr); - init_const_str_lit(ira->codegen, result->value, field->name); - return result; - } else if (container_type->id == ZigTypeIdEnum) { - if (member_index >= container_type->data.enumeration.src_field_count) { - ir_add_error(ira, &index_value->base, - buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members", - member_index, buf_ptr(&container_type->name), container_type->data.enumeration.src_field_count)); - return ira->codegen->invalid_inst_gen; - } - TypeEnumField *field = &container_type->data.enumeration.fields[member_index]; - - IrInstGen *result = ir_const(ira, &instruction->base.base, nullptr); - init_const_str_lit(ira->codegen, result->value, field->name); - return result; - } else if (container_type->id == ZigTypeIdUnion) { - if (member_index >= container_type->data.unionation.src_field_count) { - ir_add_error(ira, &index_value->base, - buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members", - member_index, buf_ptr(&container_type->name), container_type->data.unionation.src_field_count)); - return ira->codegen->invalid_inst_gen; - } - TypeUnionField *field = &container_type->data.unionation.fields[member_index]; - - IrInstGen *result = ir_const(ira, &instruction->base.base, nullptr); - init_const_str_lit(ira->codegen, result->value, field->name); - return result; - } else { - ir_add_error(ira, &container_type_value->base, - buf_sprintf("type '%s' does not support @memberName", buf_ptr(&container_type->name))); - return ira->codegen->invalid_inst_gen; - } + return ir_build_slice_gen(ira, &instruction->base.base, return_type, + ptr_ptr, casted_start, end, instruction->safety_check_on, result_loc); } static IrInstGen *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstSrcHasField *instruction) { @@ -29466,7 +28975,7 @@ static IrInstGen *ir_analyze_instruction_await(IrAnalyze *ira, IrInstSrcAwait *i ir_assert(fn_entry != nullptr, &instruction->base.base); // If it's not @Frame(func) then it's definitely a suspend point - if (target_fn == nullptr) { + if (target_fn == nullptr && !instruction->is_noasync) { if (fn_entry->inferred_async_node == nullptr) { fn_entry->inferred_async_node = instruction->base.base.source_node; } @@ -29489,7 +28998,8 @@ static IrInstGen *ir_analyze_instruction_await(IrAnalyze *ira, IrInstSrcAwait *i result_loc = nullptr; } - IrInstGenAwait *result = ir_build_await_gen(ira, &instruction->base.base, frame, result_type, result_loc); + IrInstGenAwait *result = ir_build_await_gen(ira, &instruction->base.base, frame, result_type, result_loc, + instruction->is_noasync); result->target_fn = target_fn; fn_entry->await_list.append(result); return ir_finish_anal(ira, &result->base); @@ -29677,18 +29187,12 @@ static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruc return ir_analyze_instruction_float_cast(ira, (IrInstSrcFloatCast *)instruction); case IrInstSrcIdErrSetCast: return ir_analyze_instruction_err_set_cast(ira, (IrInstSrcErrSetCast *)instruction); - case IrInstSrcIdFromBytes: - return ir_analyze_instruction_from_bytes(ira, (IrInstSrcFromBytes *)instruction); - case IrInstSrcIdToBytes: - return ir_analyze_instruction_to_bytes(ira, (IrInstSrcToBytes *)instruction); case IrInstSrcIdIntToFloat: return ir_analyze_instruction_int_to_float(ira, (IrInstSrcIntToFloat *)instruction); case IrInstSrcIdFloatToInt: return ir_analyze_instruction_float_to_int(ira, (IrInstSrcFloatToInt *)instruction); case IrInstSrcIdBoolToInt: return ir_analyze_instruction_bool_to_int(ira, (IrInstSrcBoolToInt *)instruction); - case IrInstSrcIdIntType: - return ir_analyze_instruction_int_type(ira, (IrInstSrcIntType *)instruction); case IrInstSrcIdVectorType: return ir_analyze_instruction_vector_type(ira, (IrInstSrcVectorType *)instruction); case IrInstSrcIdShuffleVector: @@ -29703,12 +29207,6 @@ static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruc return ir_analyze_instruction_memcpy(ira, (IrInstSrcMemcpy *)instruction); case IrInstSrcIdSlice: return ir_analyze_instruction_slice(ira, (IrInstSrcSlice *)instruction); - case IrInstSrcIdMemberCount: - return ir_analyze_instruction_member_count(ira, (IrInstSrcMemberCount *)instruction); - case IrInstSrcIdMemberType: - return ir_analyze_instruction_member_type(ira, (IrInstSrcMemberType *)instruction); - case IrInstSrcIdMemberName: - return ir_analyze_instruction_member_name(ira, (IrInstSrcMemberName *)instruction); case IrInstSrcIdBreakpoint: return ir_analyze_instruction_breakpoint(ira, (IrInstSrcBreakpoint *)instruction); case IrInstSrcIdReturnAddress: @@ -29763,8 +29261,6 @@ static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruc return ir_analyze_instruction_type(ira, (IrInstSrcType *)instruction); case IrInstSrcIdHasField: return ir_analyze_instruction_has_field(ira, (IrInstSrcHasField *) instruction); - case IrInstSrcIdTypeId: - return ir_analyze_instruction_type_id(ira, (IrInstSrcTypeId *)instruction); case IrInstSrcIdSetEvalBranchQuota: return ir_analyze_instruction_set_eval_branch_quota(ira, (IrInstSrcSetEvalBranchQuota *)instruction); case IrInstSrcIdPtrType: @@ -30007,7 +29503,6 @@ bool ir_inst_gen_has_side_effects(IrInstGen *instruction) { case IrInstGenIdCmpxchg: case IrInstGenIdAssertZero: case IrInstGenIdAssertNonNull: - case IrInstGenIdResizeSlice: case IrInstGenIdPtrOfArrayToSlice: case IrInstGenIdSlice: case IrInstGenIdOptionalWrap: @@ -30180,15 +29675,11 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) { case IrInstSrcIdRef: case IrInstSrcIdEmbedFile: case IrInstSrcIdTruncate: - case IrInstSrcIdIntType: case IrInstSrcIdVectorType: case IrInstSrcIdShuffleVector: case IrInstSrcIdSplat: case IrInstSrcIdBoolNot: case IrInstSrcIdSlice: - case IrInstSrcIdMemberCount: - case IrInstSrcIdMemberType: - case IrInstSrcIdMemberName: case IrInstSrcIdAlignOf: case IrInstSrcIdReturnAddress: case IrInstSrcIdFrameAddress: @@ -30215,7 +29706,6 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) { case IrInstSrcIdTypeInfo: case IrInstSrcIdType: case IrInstSrcIdHasField: - case IrInstSrcIdTypeId: case IrInstSrcIdAlignCast: case IrInstSrcIdImplicitCast: case IrInstSrcIdResolveResult: @@ -30233,8 +29723,6 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) { case IrInstSrcIdIntToFloat: case IrInstSrcIdFloatToInt: case IrInstSrcIdBoolToInt: - case IrInstSrcIdFromBytes: - case IrInstSrcIdToBytes: case IrInstSrcIdEnumToInt: case IrInstSrcIdHasDecl: case IrInstSrcIdAlloca: @@ -30347,6 +29835,18 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { switch (val->data.x_lazy->id) { case LazyValueIdInvalid: zig_unreachable(); + case LazyValueIdTypeInfoDecls: { + LazyValueTypeInfoDecls *type_info_decls = reinterpret_cast<LazyValueTypeInfoDecls *>(val->data.x_lazy); + IrAnalyze *ira = type_info_decls->ira; + + if ((err = ir_make_type_info_decls(ira, type_info_decls->source_instr, val, type_info_decls->decls_scope, true))) + { + return err; + }; + + // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. + return ErrorNone; + } case LazyValueIdAlignOf: { LazyValueAlignOf *lazy_align_of = reinterpret_cast<LazyValueAlignOf *>(val->data.x_lazy); IrAnalyze *ira = lazy_align_of->ira; diff --git a/src/ir_print.cpp b/src/ir_print.cpp @@ -179,8 +179,6 @@ const char* ir_inst_src_type_str(IrInstSrcId id) { return "SrcFloatToInt"; case IrInstSrcIdBoolToInt: return "SrcBoolToInt"; - case IrInstSrcIdIntType: - return "SrcIntType"; case IrInstSrcIdVectorType: return "SrcVectorType"; case IrInstSrcIdBoolNot: @@ -191,12 +189,6 @@ const char* ir_inst_src_type_str(IrInstSrcId id) { return "SrcMemcpy"; case IrInstSrcIdSlice: return "SrcSlice"; - case IrInstSrcIdMemberCount: - return "SrcMemberCount"; - case IrInstSrcIdMemberType: - return "SrcMemberType"; - case IrInstSrcIdMemberName: - return "SrcMemberName"; case IrInstSrcIdBreakpoint: return "SrcBreakpoint"; case IrInstSrcIdReturnAddress: @@ -269,8 +261,6 @@ const char* ir_inst_src_type_str(IrInstSrcId id) { return "SrcType"; case IrInstSrcIdHasField: return "SrcHasField"; - case IrInstSrcIdTypeId: - return "SrcTypeId"; case IrInstSrcIdSetEvalBranchQuota: return "SrcSetEvalBranchQuota"; case IrInstSrcIdPtrType: @@ -307,10 +297,6 @@ const char* ir_inst_src_type_str(IrInstSrcId id) { return "SrcAddImplicitReturnType"; case IrInstSrcIdErrSetCast: return "SrcErrSetCast"; - case IrInstSrcIdToBytes: - return "SrcToBytes"; - case IrInstSrcIdFromBytes: - return "SrcFromBytes"; case IrInstSrcIdCheckRuntimeScope: return "SrcCheckRuntimeScope"; case IrInstSrcIdHasDecl: @@ -383,8 +369,6 @@ const char* ir_inst_gen_type_str(IrInstGenId id) { return "GenReturn"; case IrInstGenIdCast: return "GenCast"; - case IrInstGenIdResizeSlice: - return "GenResizeSlice"; case IrInstGenIdUnreachable: return "GenUnreachable"; case IrInstGenIdAsm: @@ -590,11 +574,6 @@ static void ir_print_const_value(CodeGen *g, FILE *f, ZigValue *const_val) { static void ir_print_other_inst_gen(IrPrintGen *irp, IrInstGen *inst) { if (inst == nullptr) { fprintf(irp->f, "(null)"); - return; - } - - if (inst->value->special != ConstValSpecialRuntime) { - ir_print_const_value(irp->codegen, irp->f, inst->value); } else { ir_print_var_gen(irp, inst); } @@ -1649,20 +1628,6 @@ static void ir_print_err_set_cast(IrPrintSrc *irp, IrInstSrcErrSetCast *instruct fprintf(irp->f, ")"); } -static void ir_print_from_bytes(IrPrintSrc *irp, IrInstSrcFromBytes *instruction) { - fprintf(irp->f, "@bytesToSlice("); - ir_print_other_inst_src(irp, instruction->dest_child_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - -static void ir_print_to_bytes(IrPrintSrc *irp, IrInstSrcToBytes *instruction) { - fprintf(irp->f, "@sliceToBytes("); - ir_print_other_inst_src(irp, instruction->target); - fprintf(irp->f, ")"); -} - static void ir_print_int_to_float(IrPrintSrc *irp, IrInstSrcIntToFloat *instruction) { fprintf(irp->f, "@intToFloat("); ir_print_other_inst_src(irp, instruction->dest_type); @@ -1685,14 +1650,6 @@ static void ir_print_bool_to_int(IrPrintSrc *irp, IrInstSrcBoolToInt *instructio fprintf(irp->f, ")"); } -static void ir_print_int_type(IrPrintSrc *irp, IrInstSrcIntType *instruction) { - fprintf(irp->f, "@IntType("); - ir_print_other_inst_src(irp, instruction->is_signed); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->bit_count); - fprintf(irp->f, ")"); -} - static void ir_print_vector_type(IrPrintSrc *irp, IrInstSrcVectorType *instruction) { fprintf(irp->f, "@Vector("); ir_print_other_inst_src(irp, instruction->len); @@ -1809,28 +1766,6 @@ static void ir_print_slice_gen(IrPrintGen *irp, IrInstGenSlice *instruction) { ir_print_other_inst_gen(irp, instruction->result_loc); } -static void ir_print_member_count(IrPrintSrc *irp, IrInstSrcMemberCount *instruction) { - fprintf(irp->f, "@memberCount("); - ir_print_other_inst_src(irp, instruction->container); - fprintf(irp->f, ")"); -} - -static void ir_print_member_type(IrPrintSrc *irp, IrInstSrcMemberType *instruction) { - fprintf(irp->f, "@memberType("); - ir_print_other_inst_src(irp, instruction->container_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->member_index); - fprintf(irp->f, ")"); -} - -static void ir_print_member_name(IrPrintSrc *irp, IrInstSrcMemberName *instruction) { - fprintf(irp->f, "@memberName("); - ir_print_other_inst_src(irp, instruction->container_type); - fprintf(irp->f, ", "); - ir_print_other_inst_src(irp, instruction->member_index); - fprintf(irp->f, ")"); -} - static void ir_print_breakpoint(IrPrintSrc *irp, IrInstSrcBreakpoint *instruction) { fprintf(irp->f, "@breakpoint()"); } @@ -2147,13 +2082,6 @@ static void ir_print_assert_non_null(IrPrintGen *irp, IrInstGenAssertNonNull *in fprintf(irp->f, ")"); } -static void ir_print_resize_slice(IrPrintGen *irp, IrInstGenResizeSlice *instruction) { - fprintf(irp->f, "@resizeSlice("); - ir_print_other_inst_gen(irp, instruction->operand); - fprintf(irp->f, ")result="); - ir_print_other_inst_gen(irp, instruction->result_loc); -} - static void ir_print_alloca_src(IrPrintSrc *irp, IrInstSrcAlloca *instruction) { fprintf(irp->f, "Alloca(align="); ir_print_other_inst_src(irp, instruction->align); @@ -2311,12 +2239,6 @@ static void ir_print_has_field(IrPrintSrc *irp, IrInstSrcHasField *instruction) fprintf(irp->f, ")"); } -static void ir_print_type_id(IrPrintSrc *irp, IrInstSrcTypeId *instruction) { - fprintf(irp->f, "@typeId("); - ir_print_other_inst_src(irp, instruction->type_value); - fprintf(irp->f, ")"); -} - static void ir_print_set_eval_branch_quota(IrPrintSrc *irp, IrInstSrcSetEvalBranchQuota *instruction) { fprintf(irp->f, "@setEvalBranchQuota("); ir_print_other_inst_src(irp, instruction->new_quota); @@ -2798,12 +2720,6 @@ static void ir_print_inst_src(IrPrintSrc *irp, IrInstSrc *instruction, bool trai case IrInstSrcIdErrSetCast: ir_print_err_set_cast(irp, (IrInstSrcErrSetCast *)instruction); break; - case IrInstSrcIdFromBytes: - ir_print_from_bytes(irp, (IrInstSrcFromBytes *)instruction); - break; - case IrInstSrcIdToBytes: - ir_print_to_bytes(irp, (IrInstSrcToBytes *)instruction); - break; case IrInstSrcIdIntToFloat: ir_print_int_to_float(irp, (IrInstSrcIntToFloat *)instruction); break; @@ -2813,9 +2729,6 @@ static void ir_print_inst_src(IrPrintSrc *irp, IrInstSrc *instruction, bool trai case IrInstSrcIdBoolToInt: ir_print_bool_to_int(irp, (IrInstSrcBoolToInt *)instruction); break; - case IrInstSrcIdIntType: - ir_print_int_type(irp, (IrInstSrcIntType *)instruction); - break; case IrInstSrcIdVectorType: ir_print_vector_type(irp, (IrInstSrcVectorType *)instruction); break; @@ -2837,15 +2750,6 @@ static void ir_print_inst_src(IrPrintSrc *irp, IrInstSrc *instruction, bool trai case IrInstSrcIdSlice: ir_print_slice_src(irp, (IrInstSrcSlice *)instruction); break; - case IrInstSrcIdMemberCount: - ir_print_member_count(irp, (IrInstSrcMemberCount *)instruction); - break; - case IrInstSrcIdMemberType: - ir_print_member_type(irp, (IrInstSrcMemberType *)instruction); - break; - case IrInstSrcIdMemberName: - ir_print_member_name(irp, (IrInstSrcMemberName *)instruction); - break; case IrInstSrcIdBreakpoint: ir_print_breakpoint(irp, (IrInstSrcBreakpoint *)instruction); break; @@ -2945,9 +2849,6 @@ static void ir_print_inst_src(IrPrintSrc *irp, IrInstSrc *instruction, bool trai case IrInstSrcIdHasField: ir_print_has_field(irp, (IrInstSrcHasField *)instruction); break; - case IrInstSrcIdTypeId: - ir_print_type_id(irp, (IrInstSrcTypeId *)instruction); - break; case IrInstSrcIdSetEvalBranchQuota: ir_print_set_eval_branch_quota(irp, (IrInstSrcSetEvalBranchQuota *)instruction); break; @@ -3278,9 +3179,6 @@ static void ir_print_inst_gen(IrPrintGen *irp, IrInstGen *instruction, bool trai case IrInstGenIdAssertNonNull: ir_print_assert_non_null(irp, (IrInstGenAssertNonNull *)instruction); break; - case IrInstGenIdResizeSlice: - ir_print_resize_slice(irp, (IrInstGenResizeSlice *)instruction); - break; case IrInstGenIdAlloca: ir_print_alloca_gen(irp, (IrInstGenAlloca *)instruction); break; diff --git a/src/libc_installation.cpp b/src/libc_installation.cpp @@ -1,498 +0,0 @@ -/* - * Copyright (c) 2019 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "libc_installation.hpp" -#include "os.hpp" -#include "windows_sdk.h" -#include "target.hpp" - -static const char *zig_libc_keys[] = { - "include_dir", - "sys_include_dir", - "crt_dir", - "static_crt_dir", - "msvc_lib_dir", - "kernel32_lib_dir", -}; - -static const size_t zig_libc_keys_len = array_length(zig_libc_keys); - -static bool zig_libc_match_key(Slice<uint8_t> name, Slice<uint8_t> value, bool *found_keys, - size_t index, Buf *field_ptr) -{ - if (!memEql(name, str(zig_libc_keys[index]))) return false; - buf_init_from_mem(field_ptr, (const char*)value.ptr, value.len); - found_keys[index] = true; - return true; -} - -static void zig_libc_init_empty(ZigLibCInstallation *libc) { - *libc = {}; - buf_init_from_str(&libc->include_dir, ""); - buf_init_from_str(&libc->sys_include_dir, ""); - buf_init_from_str(&libc->crt_dir, ""); - buf_init_from_str(&libc->static_crt_dir, ""); - buf_init_from_str(&libc->msvc_lib_dir, ""); - buf_init_from_str(&libc->kernel32_lib_dir, ""); -} - -Error zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file, const ZigTarget *target, bool verbose) { - Error err; - zig_libc_init_empty(libc); - - bool found_keys[array_length(zig_libc_keys)] = {}; - - Buf *contents = buf_alloc(); - if ((err = os_fetch_file_path(libc_file, contents))) { - if (err != ErrorFileNotFound && verbose) { - fprintf(stderr, "Unable to read '%s': %s\n", buf_ptr(libc_file), err_str(err)); - } - return err; - } - - SplitIterator it = memSplit(buf_to_slice(contents), str("\n")); - for (;;) { - Optional<Slice<uint8_t>> opt_line = SplitIterator_next(&it); - if (!opt_line.is_some) - break; - - if (opt_line.value.len == 0 || opt_line.value.ptr[0] == '#') - continue; - - SplitIterator line_it = memSplit(opt_line.value, str("=")); - Slice<uint8_t> name; - if (!SplitIterator_next(&line_it).unwrap(&name)) { - if (verbose) { - fprintf(stderr, "missing equal sign after field name\n"); - } - return ErrorSemanticAnalyzeFail; - } - Slice<uint8_t> value = SplitIterator_rest(&line_it); - bool match = false; - match = match || zig_libc_match_key(name, value, found_keys, 0, &libc->include_dir); - match = match || zig_libc_match_key(name, value, found_keys, 1, &libc->sys_include_dir); - match = match || zig_libc_match_key(name, value, found_keys, 2, &libc->crt_dir); - match = match || zig_libc_match_key(name, value, found_keys, 3, &libc->static_crt_dir); - match = match || zig_libc_match_key(name, value, found_keys, 4, &libc->msvc_lib_dir); - match = match || zig_libc_match_key(name, value, found_keys, 5, &libc->kernel32_lib_dir); - } - - for (size_t i = 0; i < zig_libc_keys_len; i += 1) { - if (!found_keys[i]) { - if (verbose) { - fprintf(stderr, "missing field: %s\n", zig_libc_keys[i]); - } - return ErrorSemanticAnalyzeFail; - } - } - - if (buf_len(&libc->include_dir) == 0) { - if (verbose) { - fprintf(stderr, "include_dir may not be empty\n"); - } - return ErrorSemanticAnalyzeFail; - } - - if (buf_len(&libc->sys_include_dir) == 0) { - if (verbose) { - fprintf(stderr, "sys_include_dir may not be empty\n"); - } - return ErrorSemanticAnalyzeFail; - } - - if (buf_len(&libc->crt_dir) == 0) { - if (!target_os_is_darwin(target->os)) { - if (verbose) { - fprintf(stderr, "crt_dir may not be empty for %s\n", target_os_name(target->os)); - } - return ErrorSemanticAnalyzeFail; - } - } - - if (buf_len(&libc->static_crt_dir) == 0) { - if (target->os == OsWindows && target_abi_is_gnu(target->abi)) { - if (verbose) { - fprintf(stderr, "static_crt_dir may not be empty for %s\n", target_os_name(target->os)); - } - return ErrorSemanticAnalyzeFail; - } - } - - if (buf_len(&libc->msvc_lib_dir) == 0) { - if (target->os == OsWindows && !target_abi_is_gnu(target->abi)) { - if (verbose) { - fprintf(stderr, "msvc_lib_dir may not be empty for %s\n", target_os_name(target->os)); - } - return ErrorSemanticAnalyzeFail; - } - } - - if (buf_len(&libc->kernel32_lib_dir) == 0) { - if (target->os == OsWindows && !target_abi_is_gnu(target->abi)) { - if (verbose) { - fprintf(stderr, "kernel32_lib_dir may not be empty for %s\n", target_os_name(target->os)); - } - return ErrorSemanticAnalyzeFail; - } - } - - return ErrorNone; -} - -#if defined(ZIG_OS_WINDOWS) -#define CC_EXE "cc.exe" -#else -#define CC_EXE "cc" -#endif - -static Error zig_libc_find_native_include_dir_posix(ZigLibCInstallation *self, bool verbose) { - const char *cc_exe = getenv("CC"); - cc_exe = (cc_exe == nullptr) ? CC_EXE : cc_exe; - ZigList<const char *> args = {}; - args.append(cc_exe); - args.append("-E"); - args.append("-Wp,-v"); - args.append("-xc"); - #if defined(ZIG_OS_WINDOWS) - args.append("nul"); - #else - args.append("/dev/null"); - #endif - - Termination term; - Buf *out_stderr = buf_alloc(); - Buf *out_stdout = buf_alloc(); - Error err; - if ((err = os_exec_process(args, &term, out_stderr, out_stdout))) { - if (verbose) { - fprintf(stderr, "unable to determine libc include path: executing '%s': %s\n", cc_exe, err_str(err)); - } - return err; - } - if (term.how != TerminationIdClean || term.code != 0) { - if (verbose) { - fprintf(stderr, "unable to determine libc include path: executing '%s' failed\n", cc_exe); - } - return ErrorCCompileErrors; - } - char *prev_newline = buf_ptr(out_stderr); - ZigList<const char *> search_paths = {}; - for (;;) { - char *newline = strchr(prev_newline, '\n'); - if (newline == nullptr) { - break; - } - - #if defined(ZIG_OS_WINDOWS) - *(newline - 1) = 0; - #endif - *newline = 0; - - if (prev_newline[0] == ' ') { - search_paths.append(prev_newline); - } - prev_newline = newline + 1; - } - if (search_paths.length == 0) { - if (verbose) { - fprintf(stderr, "unable to determine libc include path: '%s' cannot find libc headers\n", cc_exe); - } - return ErrorCCompileErrors; - } - for (size_t i = 0; i < search_paths.length; i += 1) { - // search in reverse order - const char *search_path = search_paths.items[search_paths.length - i - 1]; - // cut off spaces - while (*search_path == ' ') { - search_path += 1; - } - - #if defined(ZIG_OS_WINDOWS) - if (buf_len(&self->include_dir) == 0) { - Buf *stdlib_path = buf_sprintf("%s\\stdlib.h", search_path); - bool exists; - if ((err = os_file_exists(stdlib_path, &exists))) { - exists = false; - } - if (exists) { - buf_init_from_str(&self->include_dir, search_path); - } - } - if (buf_len(&self->sys_include_dir) == 0) { - Buf *stdlib_path = buf_sprintf("%s\\sys\\types.h", search_path); - bool exists; - if ((err = os_file_exists(stdlib_path, &exists))) { - exists = false; - } - if (exists) { - buf_init_from_str(&self->sys_include_dir, search_path); - } - } - #else - if (buf_len(&self->include_dir) == 0) { - Buf *stdlib_path = buf_sprintf("%s/stdlib.h", search_path); - bool exists; - if ((err = os_file_exists(stdlib_path, &exists))) { - exists = false; - } - if (exists) { - buf_init_from_str(&self->include_dir, search_path); - } - } - if (buf_len(&self->sys_include_dir) == 0) { - Buf *stdlib_path = buf_sprintf("%s/sys/errno.h", search_path); - bool exists; - if ((err = os_file_exists(stdlib_path, &exists))) { - exists = false; - } - if (exists) { - buf_init_from_str(&self->sys_include_dir, search_path); - } - } - #endif - - if (buf_len(&self->include_dir) != 0 && buf_len(&self->sys_include_dir) != 0) { - return ErrorNone; - } - } - if (verbose) { - if (buf_len(&self->include_dir) == 0) { - fprintf(stderr, "unable to determine libc include path: stdlib.h not found in '%s' search paths\n", cc_exe); - } - if (buf_len(&self->sys_include_dir) == 0) { - #if defined(ZIG_OS_WINDOWS) - fprintf(stderr, "unable to determine libc include path: sys/types.h not found in '%s' search paths\n", cc_exe); - #else - fprintf(stderr, "unable to determine libc include path: sys/errno.h not found in '%s' search paths\n", cc_exe); - #endif - } - } - return ErrorFileNotFound; -} - -Error zig_libc_cc_print_file_name(const char *o_file, Buf *out, bool want_dirname, bool verbose) { - const char *cc_exe = getenv("CC"); - cc_exe = (cc_exe == nullptr) ? CC_EXE : cc_exe; - ZigList<const char *> args = {}; - args.append(cc_exe); - args.append(buf_ptr(buf_sprintf("-print-file-name=%s", o_file))); - Termination term; - Buf *out_stderr = buf_alloc(); - Buf *out_stdout = buf_alloc(); - Error err; - if ((err = os_exec_process(args, &term, out_stderr, out_stdout))) { - if (err == ErrorFileNotFound) - return ErrorNoCCompilerInstalled; - if (verbose) { - fprintf(stderr, "unable to determine libc library path: executing '%s': %s\n", cc_exe, err_str(err)); - } - return err; - } - if (term.how != TerminationIdClean || term.code != 0) { - if (verbose) { - fprintf(stderr, "unable to determine libc library path: executing '%s' failed\n", cc_exe); - } - return ErrorCCompileErrors; - } - #if defined(ZIG_OS_WINDOWS) - if (buf_ends_with_str(out_stdout, "\r\n")) { - buf_resize(out_stdout, buf_len(out_stdout) - 2); - } - #else - if (buf_ends_with_str(out_stdout, "\n")) { - buf_resize(out_stdout, buf_len(out_stdout) - 1); - } - #endif - if (buf_len(out_stdout) == 0 || buf_eql_str(out_stdout, o_file)) { - return ErrorCCompilerCannotFindFile; - } - if (want_dirname) { - os_path_dirname(out_stdout, out); - } else { - buf_init_from_buf(out, out_stdout); - } - return ErrorNone; -} - -#undef CC_EXE - -#if defined(ZIG_OS_WINDOWS) || defined(ZIG_OS_LINUX) || defined(ZIG_OS_DRAGONFLY) -static Error zig_libc_find_native_crt_dir_posix(ZigLibCInstallation *self, bool verbose) { - return zig_libc_cc_print_file_name("crt1.o", &self->crt_dir, true, verbose); -} -#endif - -#if defined(ZIG_OS_WINDOWS) -static Error zig_libc_find_native_static_crt_dir_posix(ZigLibCInstallation *self, bool verbose) { - return zig_libc_cc_print_file_name("crtbegin.o", &self->static_crt_dir, true, verbose); -} - -static Error zig_libc_find_native_include_dir_windows(ZigLibCInstallation *self, ZigWindowsSDK *sdk, bool verbose) { - Error err; - if ((err = os_get_win32_ucrt_include_path(sdk, &self->include_dir))) { - if (verbose) { - fprintf(stderr, "Unable to determine libc include path: %s\n", err_str(err)); - } - return err; - } - return ErrorNone; -} - -static Error zig_libc_find_native_crt_dir_windows(ZigLibCInstallation *self, ZigWindowsSDK *sdk, ZigTarget *target, - bool verbose) -{ - Error err; - if ((err = os_get_win32_ucrt_lib_path(sdk, &self->crt_dir, target->arch))) { - if (verbose) { - fprintf(stderr, "Unable to determine ucrt path: %s\n", err_str(err)); - } - return err; - } - return ErrorNone; -} - -static Error zig_libc_find_kernel32_lib_dir(ZigLibCInstallation *self, ZigWindowsSDK *sdk, ZigTarget *target, - bool verbose) -{ - Error err; - if ((err = os_get_win32_kern32_path(sdk, &self->kernel32_lib_dir, target->arch))) { - if (verbose) { - fprintf(stderr, "Unable to determine kernel32 path: %s\n", err_str(err)); - } - return err; - } - return ErrorNone; -} - -static Error zig_libc_find_native_msvc_lib_dir(ZigLibCInstallation *self, ZigWindowsSDK *sdk, bool verbose) { - if (sdk->msvc_lib_dir_ptr == nullptr) { - if (verbose) { - fprintf(stderr, "Unable to determine vcruntime.lib path\n"); - } - return ErrorFileNotFound; - } - buf_init_from_mem(&self->msvc_lib_dir, sdk->msvc_lib_dir_ptr, sdk->msvc_lib_dir_len); - return ErrorNone; -} - -static Error zig_libc_find_native_msvc_include_dir(ZigLibCInstallation *self, ZigWindowsSDK *sdk, bool verbose) { - Error err; - if (sdk->msvc_lib_dir_ptr == nullptr) { - if (verbose) { - fprintf(stderr, "Unable to determine vcruntime.h path\n"); - } - return ErrorFileNotFound; - } - Buf search_path = BUF_INIT; - buf_init_from_mem(&search_path, sdk->msvc_lib_dir_ptr, sdk->msvc_lib_dir_len); - buf_append_str(&search_path, "..\\..\\include"); - - Buf *vcruntime_path = buf_sprintf("%s\\vcruntime.h", buf_ptr(&search_path)); - bool exists; - if ((err = os_file_exists(vcruntime_path, &exists))) { - exists = false; - } - if (exists) { - self->sys_include_dir = search_path; - return ErrorNone; - } - - if (verbose) { - fprintf(stderr, "Unable to determine vcruntime.h path\n"); - } - return ErrorFileNotFound; -} -#endif - -void zig_libc_render(ZigLibCInstallation *self, FILE *file) { - fprintf(file, - "# The directory that contains `stdlib.h`.\n" - "# On POSIX-like systems, include directories be found with: `cc -E -Wp,-v -xc /dev/null`\n" - "include_dir=%s\n" - "\n" - "# The system-specific include directory. May be the same as `include_dir`.\n" - "# On Windows it's the directory that includes `vcruntime.h`.\n" - "# On POSIX it's the directory that includes `sys/errno.h`.\n" - "sys_include_dir=%s\n" - "\n" - "# The directory that contains `crt1.o` or `crt2.o`.\n" - "# On POSIX, can be found with `cc -print-file-name=crt1.o`.\n" - "# Not needed when targeting MacOS.\n" - "crt_dir=%s\n" - "\n" - "# The directory that contains `crtbegin.o`.\n" - "# On POSIX, can be found with `cc -print-file-name=crtbegin.o`.\n" - "# Not needed when targeting MacOS.\n" - "static_crt_dir=%s\n" - "\n" - "# The directory that contains `vcruntime.lib`.\n" - "# Only needed when targeting MSVC on Windows.\n" - "msvc_lib_dir=%s\n" - "\n" - "# The directory that contains `kernel32.lib`.\n" - "# Only needed when targeting MSVC on Windows.\n" - "kernel32_lib_dir=%s\n" - "\n", - buf_ptr(&self->include_dir), - buf_ptr(&self->sys_include_dir), - buf_ptr(&self->crt_dir), - buf_ptr(&self->static_crt_dir), - buf_ptr(&self->msvc_lib_dir), - buf_ptr(&self->kernel32_lib_dir) - ); -} - -Error zig_libc_find_native(ZigLibCInstallation *self, bool verbose) { - Error err; - zig_libc_init_empty(self); -#if defined(ZIG_OS_WINDOWS) - ZigTarget native_target; - get_native_target(&native_target); - if (target_abi_is_gnu(native_target.abi)) { - if ((err = zig_libc_find_native_include_dir_posix(self, verbose))) - return err; - if ((err = zig_libc_find_native_crt_dir_posix(self, verbose))) - return err; - if ((err = zig_libc_find_native_static_crt_dir_posix(self, verbose))) - return err; - return ErrorNone; - } else { - ZigWindowsSDK *sdk; - switch (zig_find_windows_sdk(&sdk)) { - case ZigFindWindowsSdkErrorNone: - if ((err = zig_libc_find_native_msvc_include_dir(self, sdk, verbose))) - return err; - if ((err = zig_libc_find_native_msvc_lib_dir(self, sdk, verbose))) - return err; - if ((err = zig_libc_find_kernel32_lib_dir(self, sdk, &native_target, verbose))) - return err; - if ((err = zig_libc_find_native_include_dir_windows(self, sdk, verbose))) - return err; - if ((err = zig_libc_find_native_crt_dir_windows(self, sdk, &native_target, verbose))) - return err; - return ErrorNone; - case ZigFindWindowsSdkErrorOutOfMemory: - return ErrorNoMem; - case ZigFindWindowsSdkErrorNotFound: - return ErrorFileNotFound; - case ZigFindWindowsSdkErrorPathTooLong: - return ErrorPathTooLong; - } - } - zig_unreachable(); -#else - if ((err = zig_libc_find_native_include_dir_posix(self, verbose))) - return err; -#if defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD) - buf_init_from_str(&self->crt_dir, "/usr/lib"); -#elif defined(ZIG_OS_LINUX) || defined(ZIG_OS_DRAGONFLY) - if ((err = zig_libc_find_native_crt_dir_posix(self, verbose))) - return err; -#endif - return ErrorNone; -#endif -} diff --git a/src/libc_installation.hpp b/src/libc_installation.hpp @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2019 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_LIBC_INSTALLATION_HPP -#define ZIG_LIBC_INSTALLATION_HPP - -#include <stdio.h> - -#include "buffer.hpp" -#include "error.hpp" -#include "target.hpp" - -// Must be synchronized with zig_libc_keys -struct ZigLibCInstallation { - Buf include_dir; - Buf sys_include_dir; - Buf crt_dir; - Buf static_crt_dir; - Buf msvc_lib_dir; - Buf kernel32_lib_dir; -}; - -Error ATTRIBUTE_MUST_USE zig_libc_parse(ZigLibCInstallation *libc, Buf *libc_file, - const ZigTarget *target, bool verbose); -void zig_libc_render(ZigLibCInstallation *self, FILE *file); - -Error ATTRIBUTE_MUST_USE zig_libc_find_native(ZigLibCInstallation *self, bool verbose); - -Error zig_libc_cc_print_file_name(const char *o_file, Buf *out, bool want_dirname, bool verbose); - -#endif diff --git a/src/link.cpp b/src/link.cpp @@ -605,7 +605,7 @@ static const char *build_libc_object(CodeGen *parent_gen, const char *name, CFil c_source_files.append(c_file); child_gen->c_source_files = c_source_files; codegen_build_and_link(child_gen); - return buf_ptr(&child_gen->output_file_path); + return buf_ptr(&child_gen->bin_file_output_path); } static const char *path_from_zig_lib(CodeGen *g, const char *dir, const char *subpath) { @@ -682,7 +682,7 @@ static const char *build_libunwind(CodeGen *parent, Stage2ProgressNode *progress } child_gen->c_source_files = c_source_files; codegen_build_and_link(child_gen); - return buf_ptr(&child_gen->output_file_path); + return buf_ptr(&child_gen->bin_file_output_path); } static void mingw_add_cc_args(CodeGen *parent, CFile *c_file) { @@ -1123,7 +1123,7 @@ static const char *build_musl(CodeGen *parent, Stage2ProgressNode *progress_node child_gen->c_source_files = c_source_files; codegen_build_and_link(child_gen); - return buf_ptr(&child_gen->output_file_path); + return buf_ptr(&child_gen->bin_file_output_path); } static void add_msvcrt_os_dep(CodeGen *parent, CodeGen *child_gen, const char *src_path) { @@ -1253,7 +1253,7 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file, Stage2Pr child_gen->c_source_files.append(c_file); } codegen_build_and_link(child_gen); - return buf_ptr(&child_gen->output_file_path); + return buf_ptr(&child_gen->bin_file_output_path); } else if (strcmp(file, "msvcrt-os.lib") == 0) { CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr, "msvcrt-os", progress_node); @@ -1270,7 +1270,7 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file, Stage2Pr } } codegen_build_and_link(child_gen); - return buf_ptr(&child_gen->output_file_path); + return buf_ptr(&child_gen->bin_file_output_path); } else if (strcmp(file, "mingwex.lib") == 0) { CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr, "mingwex", progress_node); @@ -1295,7 +1295,7 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file, Stage2Pr zig_unreachable(); } codegen_build_and_link(child_gen); - return buf_ptr(&child_gen->output_file_path); + return buf_ptr(&child_gen->bin_file_output_path); } else { zig_unreachable(); } @@ -1365,7 +1365,7 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file, Stage2Pr codegen_add_object(child_gen, buf_create_from_str(start_os)); codegen_add_object(child_gen, buf_create_from_str(abi_note_o)); codegen_build_and_link(child_gen); - return buf_ptr(&child_gen->output_file_path); + return buf_ptr(&child_gen->bin_file_output_path); } else if (strcmp(file, "libc_nonshared.a") == 0) { CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr, "c_nonshared", progress_node); { @@ -1445,7 +1445,7 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file, Stage2Pr build_libc_object(parent, deps[i].name, c_file, progress_node))); } codegen_build_and_link(child_gen); - return buf_ptr(&child_gen->output_file_path); + return buf_ptr(&child_gen->bin_file_output_path); } else { zig_unreachable(); } @@ -1483,7 +1483,7 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file, Stage2Pr } else { assert(parent->libc != nullptr); Buf *out_buf = buf_alloc(); - os_path_join(&parent->libc->crt_dir, buf_create_from_str(file), out_buf); + os_path_join(buf_create_from_str(parent->libc->crt_dir), buf_create_from_str(file), out_buf); return buf_ptr(out_buf); } } @@ -1519,7 +1519,7 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path, child_gen->want_stack_check = WantStackCheckDisabled; codegen_build_and_link(child_gen); - return &child_gen->output_file_path; + return &child_gen->bin_file_output_path; } static Buf *build_compiler_rt(CodeGen *parent_gen, OutType child_out_type, Stage2ProgressNode *progress_node) { @@ -1681,7 +1681,7 @@ static void construct_linker_job_elf(LinkJob *lj) { } else if (is_dyn_lib) { lj->args.append("-shared"); - assert(buf_len(&g->output_file_path) != 0); + assert(buf_len(&g->bin_file_output_path) != 0); soname = buf_sprintf("lib%s.so.%" ZIG_PRI_usize, buf_ptr(g->root_out_name), g->version_major); } @@ -1690,7 +1690,7 @@ static void construct_linker_job_elf(LinkJob *lj) { } lj->args.append("-o"); - lj->args.append(buf_ptr(&g->output_file_path)); + lj->args.append(buf_ptr(&g->bin_file_output_path)); if (lj->link_in_crt) { const char *crt1o; @@ -1747,7 +1747,7 @@ static void construct_linker_job_elf(LinkJob *lj) { if (g->libc_link_lib != nullptr) { if (g->libc != nullptr) { lj->args.append("-L"); - lj->args.append(buf_ptr(&g->libc->crt_dir)); + lj->args.append(g->libc->crt_dir); } if (g->have_dynamic_link && (is_dyn_lib || g->out_type == OutTypeExe)) { @@ -1872,7 +1872,7 @@ static void construct_linker_job_wasm(LinkJob *lj) { } lj->args.append("--allow-undefined"); lj->args.append("-o"); - lj->args.append(buf_ptr(&g->output_file_path)); + lj->args.append(buf_ptr(&g->bin_file_output_path)); // .o files for (size_t i = 0; i < g->link_objects.length; i += 1) { @@ -2253,17 +2253,17 @@ static void construct_linker_job_coff(LinkJob *lj) { lj->args.append("-DLL"); } - lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path)))); + lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->bin_file_output_path)))); if (g->libc_link_lib != nullptr && g->libc != nullptr) { - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->crt_dir)))); + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", g->libc->crt_dir))); if (target_abi_is_gnu(g->zig_target->abi)) { - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->sys_include_dir)))); - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->include_dir)))); + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", g->libc->sys_include_dir))); + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", g->libc->include_dir))); } else { - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->msvc_lib_dir)))); - lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->kernel32_lib_dir)))); + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", g->libc->msvc_lib_dir))); + lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", g->libc->kernel32_lib_dir))); } } @@ -2506,7 +2506,7 @@ static void construct_linker_job_macho(LinkJob *lj) { //lj->args.append("-install_name"); //lj->args.append(buf_ptr(dylib_install_name)); - assert(buf_len(&g->output_file_path) != 0); + assert(buf_len(&g->bin_file_output_path) != 0); } lj->args.append("-arch"); @@ -2537,14 +2537,14 @@ static void construct_linker_job_macho(LinkJob *lj) { } lj->args.append("-o"); - lj->args.append(buf_ptr(&g->output_file_path)); + lj->args.append(buf_ptr(&g->bin_file_output_path)); for (size_t i = 0; i < g->rpath_list.length; i += 1) { Buf *rpath = g->rpath_list.at(i); add_rpath(lj, rpath); } if (is_dyn_lib) { - add_rpath(lj, &g->output_file_path); + add_rpath(lj, &g->bin_file_output_path); } if (is_dyn_lib) { @@ -2664,14 +2664,14 @@ void codegen_link(CodeGen *g) { progress_name, strlen(progress_name), 0)); } if (g->verbose_link) { - fprintf(stderr, "ar rcs %s", buf_ptr(&g->output_file_path)); + fprintf(stderr, "ar rcs %s", buf_ptr(&g->bin_file_output_path)); for (size_t i = 0; i < file_names.length; i += 1) { fprintf(stderr, " %s", file_names.at(i)); } fprintf(stderr, "\n"); } - if (ZigLLVMWriteArchive(buf_ptr(&g->output_file_path), file_names.items, file_names.length, os_type)) { - fprintf(stderr, "Unable to write archive '%s'\n", buf_ptr(&g->output_file_path)); + if (ZigLLVMWriteArchive(buf_ptr(&g->bin_file_output_path), file_names.items, file_names.length, os_type)) { + fprintf(stderr, "Unable to write archive '%s'\n", buf_ptr(&g->bin_file_output_path)); exit(1); } return; diff --git a/src/main.cpp b/src/main.cpp @@ -14,8 +14,7 @@ #include "heap.hpp" #include "os.hpp" #include "target.hpp" -#include "libc_installation.hpp" -#include "userland.h" +#include "stage2.h" #include "glibc.hpp" #include "dump_analysis.hpp" #include "mem_profile.hpp" @@ -63,17 +62,21 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " -fno-stack-check disable stack probing in safe builds\n" " -fsanitize-c enable C undefined behavior detection in unsafe builds\n" " -fno-sanitize-c disable C undefined behavior detection in safe builds\n" - " --emit [asm|bin|llvm-ir] emit a specific file format as compilation output\n" + " --emit [asm|bin|llvm-ir] (deprecated) emit a specific file format as compilation output\n" " -fPIC enable Position Independent Code\n" " -fno-PIC disable Position Independent Code\n" " -ftime-report print timing diagnostics\n" " -fstack-report print stack size diagnostics\n" -#ifdef ZIG_ENABLE_MEM_PROFILE " -fmem-report print memory usage diagnostics\n" -#endif " -fdump-analysis write analysis.json file with type information\n" " -femit-docs create a docs/ dir with html documentation\n" - " -fno-emit-bin skip emitting machine code\n" + " -fno-emit-docs do not produce docs/ dir with html documentation\n" + " -femit-bin (default) output machine code\n" + " -fno-emit-bin do not output machine code\n" + " -femit-asm output .s (assembly code)\n" + " -fno-emit-asm (default) do not output .s (assembly code)\n" + " -femit-llvm-ir produce a .ll file with LLVM IR\n" + " -fno-emit-llvm-ir (default) do not produce a .ll file with LLVM IR\n" " --libc [file] Provide a file which specifies libc paths\n" " --name [name] override output name\n" " --output-dir [dir] override output directory (defaults to cwd)\n" @@ -103,8 +106,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " --override-lib-dir [arg] override path to Zig lib directory\n" " -ffunction-sections places each function in a separate section\n" " -D[macro]=[value] define C [macro] to [value] (1 if [value] omitted)\n" - " -target-cpu [cpu] target one specific CPU by name\n" - " -target-feature [features] specify the set of CPU features to target\n" + " -mcpu [cpu] specify target CPU and feature set\n" " -code-model [default|tiny| set target code model\n" " small|kernel|\n" " medium|large]\n" @@ -235,6 +237,14 @@ static int zig_error_no_build_file(void) { return EXIT_FAILURE; } +static bool str_starts_with(const char *s1, const char *s2) { + size_t s2_len = strlen(s2); + if (strlen(s1) < s2_len) { + return false; + } + return memcmp(s1, s2, s2_len) == 0; +} + extern "C" int ZigClang_main(int argc, char **argv); #ifdef ZIG_ENABLE_MEM_PROFILE @@ -378,7 +388,6 @@ static int main0(int argc, char **argv) { } Cmd cmd = CmdNone; - EmitFileType emit_file_type = EmitFileTypeBinary; const char *in_file = nullptr; Buf *output_dir = nullptr; bool strip = false; @@ -426,7 +435,9 @@ static int main0(int argc, char **argv) { bool stack_report = false; bool enable_dump_analysis = false; bool enable_doc_generation = false; - bool disable_bin_generation = false; + bool emit_bin = true; + bool emit_asm = false; + bool emit_llvm_ir = false; const char *cache_dir = nullptr; CliPkg *cur_pkg = heap::c_allocator.create<CliPkg>(); BuildMode build_mode = BuildModeDebug; @@ -444,8 +455,7 @@ static int main0(int argc, char **argv) { WantStackCheck want_stack_check = WantStackCheckAuto; WantCSanitize want_sanitize_c = WantCSanitizeAuto; bool function_sections = false; - const char *cpu = nullptr; - const char *features = nullptr; + const char *mcpu = nullptr; CodeModel code_model = CodeModelDefault; ZigList<const char *> llvm_argv = {0}; @@ -554,7 +564,7 @@ static int main0(int argc, char **argv) { } Termination term; - args.items[0] = buf_ptr(&g->output_file_path); + args.items[0] = buf_ptr(&g->bin_file_output_path); os_spawn_process(args, &term); if (term.how != TerminationIdClean || term.code != 0) { fprintf(stderr, "\nBuild failed. The following command failed:\n"); @@ -633,8 +643,6 @@ static int main0(int argc, char **argv) { enable_dump_analysis = true; } else if (strcmp(arg, "-femit-docs") == 0) { enable_doc_generation = true; - } else if (strcmp(arg, "-fno-emit-bin") == 0) { - disable_bin_generation = true; } else if (strcmp(arg, "--enable-valgrind") == 0) { valgrind_support = ValgrindSupportEnabled; } else if (strcmp(arg, "--disable-valgrind") == 0) { @@ -703,6 +711,20 @@ static int main0(int argc, char **argv) { function_sections = true; } else if (strcmp(arg, "--test-evented-io") == 0) { test_evented_io = true; + } else if (strcmp(arg, "-femit-bin") == 0) { + emit_bin = true; + } else if (strcmp(arg, "-fno-emit-bin") == 0) { + emit_bin = false; + } else if (strcmp(arg, "-femit-asm") == 0) { + emit_asm = true; + } else if (strcmp(arg, "-fno-emit-asm") == 0) { + emit_asm = false; + } else if (strcmp(arg, "-femit-llvm-ir") == 0) { + emit_llvm_ir = true; + } else if (strcmp(arg, "-fno-emit-llvm-ir") == 0) { + emit_llvm_ir = false; + } else if (str_starts_with(arg, "-mcpu=")) { + mcpu = arg + strlen("-mcpu="); } else if (i + 1 >= argc) { fprintf(stderr, "Expected another argument after %s\n", arg); return print_error_usage(arg0); @@ -734,11 +756,13 @@ static int main0(int argc, char **argv) { } } else if (strcmp(arg, "--emit") == 0) { if (strcmp(argv[i], "asm") == 0) { - emit_file_type = EmitFileTypeAssembly; + emit_asm = true; + emit_bin = false; } else if (strcmp(argv[i], "bin") == 0) { - emit_file_type = EmitFileTypeBinary; + emit_bin = true; } else if (strcmp(argv[i], "llvm-ir") == 0) { - emit_file_type = EmitFileTypeLLVMIr; + emit_llvm_ir = true; + emit_bin = false; } else { fprintf(stderr, "--emit options are 'asm', 'bin', or 'llvm-ir'\n"); return print_error_usage(arg0); @@ -877,10 +901,8 @@ static int main0(int argc, char **argv) { , argv[i]); return EXIT_FAILURE; } - } else if (strcmp(arg, "-target-cpu") == 0) { - cpu = argv[i]; - } else if (strcmp(arg, "-target-feature") == 0) { - features = argv[i]; + } else if (strcmp(arg, "-mcpu") == 0) { + mcpu = argv[i]; } else { fprintf(stderr, "Invalid argument: %s\n", arg); return print_error_usage(arg0); @@ -956,58 +978,54 @@ static int main0(int argc, char **argv) { init_all_targets(); ZigTarget target; - if (target_string == nullptr) { - get_native_target(&target); + if ((err = target_parse_triple(&target, target_string, mcpu))) { + fprintf(stderr, "invalid target: %s\n" + "See `%s targets` to display valid targets.\n", err_str(err), arg0); + return print_error_usage(arg0); + } + if (target_is_glibc(&target)) { + target.glibc_version = heap::c_allocator.create<ZigGLibCVersion>(); + if (target_glibc != nullptr) { - fprintf(stderr, "-target-glibc provided but no -target parameter\n"); - return print_error_usage(arg0); - } - } else { - if ((err = target_parse_triple(&target, target_string))) { - if (err == ErrorUnknownArchitecture && target.arch != ZigLLVM_UnknownArch) { - fprintf(stderr, "'%s' requires a sub-architecture. Try one of these:\n", - target_arch_name(target.arch)); - SubArchList sub_arch_list = target_subarch_list(target.arch); - size_t subarch_count = target_subarch_count(sub_arch_list); - for (size_t sub_i = 0; sub_i < subarch_count; sub_i += 1) { - ZigLLVM_SubArchType sub = target_subarch_enum(sub_arch_list, sub_i); - fprintf(stderr, " %s%s\n", target_arch_name(target.arch), target_subarch_name(sub)); - } - return print_error_usage(arg0); - } else { - fprintf(stderr, "invalid target: %s\n", err_str(err)); + if ((err = target_parse_glibc_version(target.glibc_version, target_glibc))) { + fprintf(stderr, "invalid glibc version '%s': %s\n", target_glibc, err_str(err)); return print_error_usage(arg0); } - } - if (target_is_glibc(&target)) { - target.glibc_version = heap::c_allocator.create<ZigGLibCVersion>(); - - if (target_glibc != nullptr) { - if ((err = target_parse_glibc_version(target.glibc_version, target_glibc))) { - fprintf(stderr, "invalid glibc version '%s': %s\n", target_glibc, err_str(err)); - return print_error_usage(arg0); + } else { + target_init_default_glibc_version(&target); +#if defined(ZIG_OS_LINUX) + if (target.is_native) { + // TODO self-host glibc version detection, and then this logic can go away + if ((err = glibc_detect_native_version(target.glibc_version))) { + // Fall back to the default version. } - } else { - target_init_default_glibc_version(&target); } - } else if (target_glibc != nullptr) { - fprintf(stderr, "'%s' is not a glibc-compatible target", target_string); - return print_error_usage(arg0); +#endif } + } else if (target_glibc != nullptr) { + fprintf(stderr, "'%s' is not a glibc-compatible target", target_string); + return print_error_usage(arg0); } Buf zig_triple_buf = BUF_INIT; target_triple_zig(&zig_triple_buf, &target); - const char *stage2_triple_arg = target.is_native ? nullptr : buf_ptr(&zig_triple_buf); - if ((err = stage2_cpu_features_parse(&target.cpu_features, stage2_triple_arg, cpu, features))) { - fprintf(stderr, "unable to initialize CPU features: %s\n", err_str(err)); - return main_exit(root_progress_node, EXIT_FAILURE); - } - + // If both output_dir and enable_cache are provided, and doing build-lib, we + // will just do a file copy at the end. This helps when bootstrapping zig from zig0 + // because we want to pass something like this: + // zig0 build-lib --cache on --output-dir ${CMAKE_BINARY_DIR} + // And we don't have access to `zig0 build` because that would require detecting native libc + // on systems where we are not able to build a libc from source for them. + // But that's the only reason this works, so otherwise we give an error here. + Buf *final_output_dir_step = nullptr; if (output_dir != nullptr && enable_cache == CacheOptOn) { - fprintf(stderr, "`--output-dir` is incompatible with --cache on.\n"); - return print_error_usage(arg0); + if (cmd == CmdBuild && out_type == OutTypeLib) { + final_output_dir_step = output_dir; + output_dir = nullptr; + } else { + fprintf(stderr, "`--output-dir` is incompatible with --cache on.\n"); + return print_error_usage(arg0); + } } if (target_requires_pic(&target, have_libc) && want_pic == WantPICDisabled) { @@ -1015,8 +1033,8 @@ static int main0(int argc, char **argv) { return print_error_usage(arg0); } - if (emit_file_type != EmitFileTypeBinary && in_file == nullptr) { - fprintf(stderr, "A root source file is required when using `--emit asm` or `--emit llvm-ir`\n"); + if ((emit_asm || emit_llvm_ir) && in_file == nullptr) { + fprintf(stderr, "A root source file is required when using `-femit-asm` or `-femit-llvm-ir`\n"); return print_error_usage(arg0); } @@ -1028,15 +1046,22 @@ static int main0(int argc, char **argv) { switch (cmd) { case CmdLibC: { if (in_file) { - ZigLibCInstallation libc; - if ((err = zig_libc_parse(&libc, buf_create_from_str(in_file), &target, true))) + Stage2LibCInstallation libc; + if ((err = stage2_libc_parse(&libc, in_file))) { + fprintf(stderr, "unable to parse libc file: %s\n", err_str(err)); return main_exit(root_progress_node, EXIT_FAILURE); + } return main_exit(root_progress_node, EXIT_SUCCESS); } - ZigLibCInstallation libc; - if ((err = zig_libc_find_native(&libc, true))) + Stage2LibCInstallation libc; + if ((err = stage2_libc_find_native(&libc))) { + fprintf(stderr, "unable to find native libc file: %s\n", err_str(err)); return main_exit(root_progress_node, EXIT_FAILURE); - zig_libc_render(&libc, stdout); + } + if ((err = stage2_libc_render(&libc, stdout))) { + fprintf(stderr, "unable to print libc file: %s\n", err_str(err)); + return main_exit(root_progress_node, EXIT_FAILURE); + } return main_exit(root_progress_node, EXIT_SUCCESS); } case CmdBuiltin: { @@ -1080,11 +1105,38 @@ static int main0(int argc, char **argv) { { fprintf(stderr, "Expected source file argument.\n"); return print_error_usage(arg0); - } else if (cmd == CmdRun && emit_file_type != EmitFileTypeBinary) { - fprintf(stderr, "Cannot run non-executable file.\n"); + } else if (cmd == CmdRun && !emit_bin) { + fprintf(stderr, "Cannot run without emitting a binary file.\n"); return print_error_usage(arg0); } + if (target.is_native && link_libs.length != 0) { + Error err; + Stage2NativePaths paths; + if ((err = stage2_detect_native_paths(&paths))) { + fprintf(stderr, "unable to detect native system paths: %s\n", err_str(err)); + exit(1); + } + for (size_t i = 0; i < paths.warnings_len; i += 1) { + const char *warning = paths.warnings_ptr[i]; + fprintf(stderr, "warning: %s\n", warning); + } + for (size_t i = 0; i < paths.include_dirs_len; i += 1) { + const char *include_dir = paths.include_dirs_ptr[i]; + clang_argv.append("-I"); + clang_argv.append(include_dir); + } + for (size_t i = 0; i < paths.lib_dirs_len; i += 1) { + const char *lib_dir = paths.lib_dirs_ptr[i]; + lib_dirs.append(lib_dir); + } + for (size_t i = 0; i < paths.rpaths_len; i += 1) { + const char *rpath = paths.rpaths_ptr[i]; + rpath_list.append(rpath); + } + } + + assert(cmd != CmdBuild || out_type != OutTypeUnknown); bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC); @@ -1126,10 +1178,10 @@ static int main0(int argc, char **argv) { if (cmd == CmdRun && buf_out_name == nullptr) { buf_out_name = buf_create_from_str("run"); } - ZigLibCInstallation *libc = nullptr; + Stage2LibCInstallation *libc = nullptr; if (libc_txt != nullptr) { - libc = heap::c_allocator.create<ZigLibCInstallation>(); - if ((err = zig_libc_parse(libc, buf_create_from_str(libc_txt), &target, true))) { + libc = heap::c_allocator.create<Stage2LibCInstallation>(); + if ((err = stage2_libc_parse(libc, libc_txt))) { fprintf(stderr, "Unable to parse --libc text file: %s\n", err_str(err)); return main_exit(root_progress_node, EXIT_FAILURE); } @@ -1158,7 +1210,10 @@ static int main0(int argc, char **argv) { g->enable_stack_report = stack_report; g->enable_dump_analysis = enable_dump_analysis; g->enable_doc_generation = enable_doc_generation; - g->disable_bin_generation = disable_bin_generation; + g->emit_bin = emit_bin; + g->emit_asm = emit_asm; + g->emit_llvm_ir = emit_llvm_ir; + codegen_set_out_name(g, buf_out_name); codegen_set_lib_version(g, ver_major, ver_minor, ver_patch); g->want_single_threaded = want_single_threaded; @@ -1188,7 +1243,6 @@ static int main0(int argc, char **argv) { g->function_sections = function_sections; g->code_model = code_model; - for (size_t i = 0; i < lib_dirs.length; i += 1) { codegen_add_lib_dir(g, lib_dirs.at(i)); } @@ -1244,8 +1298,6 @@ static int main0(int argc, char **argv) { if (cmd == CmdBuild || cmd == CmdRun) { - codegen_set_emit_file_type(g, emit_file_type); - g->enable_cache = get_cache_opt(enable_cache, cmd == CmdRun); codegen_build_and_link(g); if (root_progress_node != nullptr) { @@ -1263,7 +1315,7 @@ static int main0(int argc, char **argv) { mem::print_report(); #endif - const char *exec_path = buf_ptr(&g->output_file_path); + const char *exec_path = buf_ptr(&g->bin_file_output_path); ZigList<const char*> args = {0}; args.append(exec_path); @@ -1283,10 +1335,23 @@ static int main0(int argc, char **argv) { } else if (cmd == CmdBuild) { if (g->enable_cache) { #if defined(ZIG_OS_WINDOWS) - buf_replace(&g->output_file_path, '/', '\\'); + buf_replace(&g->bin_file_output_path, '/', '\\'); #endif - if (printf("%s\n", buf_ptr(&g->output_file_path)) < 0) - return main_exit(root_progress_node, EXIT_FAILURE); + if (final_output_dir_step != nullptr) { + Buf *dest_basename = buf_alloc(); + os_path_split(&g->bin_file_output_path, nullptr, dest_basename); + Buf *dest_path = buf_alloc(); + os_path_join(final_output_dir_step, dest_basename, dest_path); + + if ((err = os_update_file(&g->bin_file_output_path, dest_path))) { + fprintf(stderr, "unable to copy %s to %s: %s\n", buf_ptr(&g->bin_file_output_path), + buf_ptr(dest_path), err_str(err)); + return main_exit(root_progress_node, EXIT_FAILURE); + } + } else { + if (printf("%s\n", buf_ptr(&g->bin_file_output_path)) < 0) + return main_exit(root_progress_node, EXIT_FAILURE); + } } return main_exit(root_progress_node, EXIT_SUCCESS); } else { @@ -1299,8 +1364,6 @@ static int main0(int argc, char **argv) { codegen_print_timing_report(g, stderr); return main_exit(root_progress_node, EXIT_SUCCESS); } else if (cmd == CmdTest) { - codegen_set_emit_file_type(g, emit_file_type); - ZigTarget native; get_native_target(&native); @@ -1319,17 +1382,17 @@ static int main0(int argc, char **argv) { zig_print_stack_report(g, stdout); } - if (g->disable_bin_generation) { + if (!g->emit_bin) { fprintf(stderr, "Semantic analysis complete. No binary produced due to -fno-emit-bin.\n"); return main_exit(root_progress_node, EXIT_SUCCESS); } - Buf *test_exe_path_unresolved = &g->output_file_path; + Buf *test_exe_path_unresolved = &g->bin_file_output_path; Buf *test_exe_path = buf_alloc(); *test_exe_path = os_path_resolve(&test_exe_path_unresolved, 1); - if (emit_file_type != EmitFileTypeBinary) { - fprintf(stderr, "Created %s but skipping execution because it is non executable.\n", + if (!g->emit_bin) { + fprintf(stderr, "Created %s but skipping execution because no binary generated.\n", buf_ptr(test_exe_path)); return main_exit(root_progress_node, EXIT_SUCCESS); } diff --git a/src/mem_list.hpp b/src/mem_list.hpp @@ -14,11 +14,14 @@ namespace mem { template<typename T> struct List { - void deinit(Allocator& allocator) { - allocator.deallocate<T>(items, capacity); + void deinit(Allocator *allocator) { + allocator->deallocate<T>(items, capacity); + items = nullptr; + length = 0; + capacity = 0; } - void append(Allocator& allocator, const T& item) { + void append(Allocator *allocator, const T& item) { ensure_capacity(allocator, length + 1); items[length++] = item; } @@ -57,7 +60,7 @@ struct List { return items[length - 1]; } - void resize(Allocator& allocator, size_t new_length) { + void resize(Allocator *allocator, size_t new_length) { assert(new_length != SIZE_MAX); ensure_capacity(allocator, new_length); length = new_length; @@ -67,7 +70,7 @@ struct List { length = 0; } - void ensure_capacity(Allocator& allocator, size_t new_capacity) { + void ensure_capacity(Allocator *allocator, size_t new_capacity) { if (capacity >= new_capacity) return; @@ -76,7 +79,7 @@ struct List { better_capacity = better_capacity * 5 / 2 + 8; } while (better_capacity < new_capacity); - items = allocator.reallocate_nonzero<T>(items, capacity, better_capacity); + items = allocator->reallocate_nonzero<T>(items, capacity, better_capacity); capacity = better_capacity; } diff --git a/src/mem_profile.cpp b/src/mem_profile.cpp @@ -92,7 +92,7 @@ void Profile::print_report(FILE *file) { auto entry = it.next(); if (!entry) break; - list.append(heap::bootstrap_allocator, &entry->value); + list.append(&heap::bootstrap_allocator, &entry->value); } qsort(list.items, list.length, sizeof(const Entry *), entry_compare); @@ -143,7 +143,7 @@ void Profile::print_report(FILE *file) { fprintf(file, "\n Total calls alloc: %zu, dealloc: %zu, remain: %zu\n", total_calls_alloc, total_calls_dealloc, (total_calls_alloc - total_calls_dealloc)); - list.deinit(heap::bootstrap_allocator); + list.deinit(&heap::bootstrap_allocator); } uint32_t Profile::usage_hash(UsageKey key) { diff --git a/src/os.cpp b/src/os.cpp @@ -81,11 +81,7 @@ static clock_serv_t macos_monotonic_clock; #include <errno.h> #include <time.h> -// Apple doesn't provide the environ global variable -#if defined(__APPLE__) && !defined(environ) -#include <crt_externs.h> -#define environ (*_NSGetEnviron()) -#elif defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD) || defined(ZIG_OS_DRAGONFLY) +#if !defined(environ) extern char **environ; #endif @@ -826,7 +822,9 @@ static Error os_exec_process_posix(ZigList<const char *> &args, if (errno == ENOENT) { report_err = ErrorFileNotFound; } - write(err_pipe[1], &report_err, sizeof(Error)); + if (write(err_pipe[1], &report_err, sizeof(Error)) == -1) { + zig_panic("write failed"); + } exit(1); } else { // parent @@ -851,9 +849,13 @@ static Error os_exec_process_posix(ZigList<const char *> &args, if (err2) return err2; Error child_err = ErrorNone; - write(err_pipe[1], &child_err, sizeof(Error)); + if (write(err_pipe[1], &child_err, sizeof(Error)) == -1) { + zig_panic("write failed"); + } close(err_pipe[1]); - read(err_pipe[0], &child_err, sizeof(Error)); + if (read(err_pipe[0], &child_err, sizeof(Error)) == -1) { + zig_panic("write failed"); + } close(err_pipe[0]); return child_err; } @@ -1029,6 +1031,124 @@ Error os_write_file(Buf *full_path, Buf *contents) { return ErrorNone; } +static Error copy_open_files(FILE *src_f, FILE *dest_f) { + static const size_t buf_size = 2048; + char buf[buf_size]; + for (;;) { + size_t amt_read = fread(buf, 1, buf_size, src_f); + if (amt_read != buf_size) { + if (ferror(src_f)) { + return ErrorFileSystem; + } + } + size_t amt_written = fwrite(buf, 1, amt_read, dest_f); + if (amt_written != amt_read) { + return ErrorFileSystem; + } + if (feof(src_f)) { + return ErrorNone; + } + } +} + +#if defined(ZIG_OS_WINDOWS) +static void windows_filetime_to_os_timestamp(FILETIME *ft, OsTimeStamp *mtime) { + mtime->sec = (((ULONGLONG) ft->dwHighDateTime) << 32) + ft->dwLowDateTime; + mtime->nsec = 0; +} +static FILETIME windows_os_timestamp_to_filetime(OsTimeStamp mtime) { + FILETIME result; + result.dwHighDateTime = mtime.sec >> 32; + result.dwLowDateTime = mtime.sec; + return result; +} +#endif + +static Error set_file_times(OsFile file, OsTimeStamp ts) { +#if defined(ZIG_OS_WINDOWS) + FILETIME ft = windows_os_timestamp_to_filetime(ts); + if (SetFileTime(file, nullptr, &ft, &ft) == 0) { + return ErrorUnexpected; + } + return ErrorNone; +#else + struct timespec times[2] = { + { ts.sec, ts.nsec }, + { ts.sec, ts.nsec }, + }; + if (futimens(file, times) == -1) { + switch (errno) { + case EBADF: + zig_panic("futimens EBADF"); + default: + return ErrorUnexpected; + } + } + return ErrorNone; +#endif +} + +Error os_update_file(Buf *src_path, Buf *dst_path) { + Error err; + + OsFile src_file; + OsFileAttr src_attr; + if ((err = os_file_open_r(src_path, &src_file, &src_attr))) { + return err; + } + + OsFile dst_file; + OsFileAttr dst_attr; + if ((err = os_file_open_w(dst_path, &dst_file, &dst_attr, src_attr.mode))) { + os_file_close(&src_file); + return err; + } + + if (src_attr.size == dst_attr.size && + src_attr.mode == dst_attr.mode && + src_attr.mtime.sec == dst_attr.mtime.sec && + src_attr.mtime.nsec == dst_attr.mtime.nsec) + { + os_file_close(&src_file); + os_file_close(&dst_file); + return ErrorNone; + } +#if defined(ZIG_OS_WINDOWS) + if (SetEndOfFile(dst_file) == 0) { + return ErrorUnexpected; + } +#else + if (ftruncate(dst_file, 0) == -1) { + return ErrorUnexpected; + } +#endif +#if defined(ZIG_OS_WINDOWS) + FILE *src_libc_file = _fdopen(_open_osfhandle((intptr_t)src_file, _O_RDONLY), "rb"); + FILE *dst_libc_file = _fdopen(_open_osfhandle((intptr_t)dst_file, 0), "wb"); +#else + FILE *src_libc_file = fdopen(src_file, "rb"); + FILE *dst_libc_file = fdopen(dst_file, "wb"); +#endif + assert(src_libc_file); + assert(dst_libc_file); + + if ((err = copy_open_files(src_libc_file, dst_libc_file))) { + fclose(src_libc_file); + fclose(dst_libc_file); + return err; + } + if (fflush(src_libc_file) == -1) { + return ErrorUnexpected; + } + if (fflush(dst_libc_file) == -1) { + return ErrorUnexpected; + } + err = set_file_times(dst_file, src_attr.mtime); + fclose(src_libc_file); + fclose(dst_libc_file); + return err; +} + Error os_copy_file(Buf *src_path, Buf *dest_path) { FILE *src_f = fopen(buf_ptr(src_path), "rb"); if (!src_f) { @@ -1055,30 +1175,10 @@ Error os_copy_file(Buf *src_path, Buf *dest_path) { return ErrorFileSystem; } } - - static const size_t buf_size = 2048; - char buf[buf_size]; - for (;;) { - size_t amt_read = fread(buf, 1, buf_size, src_f); - if (amt_read != buf_size) { - if (ferror(src_f)) { - fclose(src_f); - fclose(dest_f); - return ErrorFileSystem; - } - } - size_t amt_written = fwrite(buf, 1, amt_read, dest_f); - if (amt_written != amt_read) { - fclose(src_f); - fclose(dest_f); - return ErrorFileSystem; - } - if (feof(src_f)) { - fclose(src_f); - fclose(dest_f); - return ErrorNone; - } - } + Error err = copy_open_files(src_f, dest_f); + fclose(src_f); + fclose(dest_f); + return err; } Error os_fetch_file_path(Buf *full_path, Buf *out_contents) { @@ -1218,13 +1318,6 @@ Error os_rename(Buf *src_path, Buf *dest_path) { return ErrorNone; } -#if defined(ZIG_OS_WINDOWS) -static void windows_filetime_to_os_timestamp(FILETIME *ft, OsTimeStamp *mtime) { - mtime->sec = (((ULONGLONG) ft->dwHighDateTime) << 32) + ft->dwLowDateTime; - mtime->nsec = 0; -} -#endif - OsTimeStamp os_timestamp_calendar(void) { OsTimeStamp result; #if defined(ZIG_OS_WINDOWS) @@ -1551,108 +1644,6 @@ void os_stderr_set_color(TermColor color) { #endif } -Error os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) { -#if defined(ZIG_OS_WINDOWS) - buf_resize(output_buf, 0); - buf_appendf(output_buf, "%sLib\\%s\\ucrt\\", sdk->path10_ptr, sdk->version10_ptr); - switch (platform_type) { - case ZigLLVM_x86: - buf_append_str(output_buf, "x86\\"); - break; - case ZigLLVM_x86_64: - buf_append_str(output_buf, "x64\\"); - break; - case ZigLLVM_arm: - buf_append_str(output_buf, "arm\\"); - break; - default: - zig_panic("Attempted to use vcruntime for non-supported platform."); - } - Buf* tmp_buf = buf_alloc(); - buf_init_from_buf(tmp_buf, output_buf); - buf_append_str(tmp_buf, "ucrt.lib"); - if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) { - return ErrorNone; - } - else { - buf_resize(output_buf, 0); - return ErrorFileNotFound; - } -#else - return ErrorFileNotFound; -#endif -} - -Error os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) { -#if defined(ZIG_OS_WINDOWS) - buf_resize(output_buf, 0); - buf_appendf(output_buf, "%sInclude\\%s\\ucrt", sdk->path10_ptr, sdk->version10_ptr); - if (GetFileAttributesA(buf_ptr(output_buf)) != INVALID_FILE_ATTRIBUTES) { - return ErrorNone; - } - else { - buf_resize(output_buf, 0); - return ErrorFileNotFound; - } -#else - return ErrorFileNotFound; -#endif -} - -Error os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) { -#if defined(ZIG_OS_WINDOWS) - { - buf_resize(output_buf, 0); - buf_appendf(output_buf, "%sLib\\%s\\um\\", sdk->path10_ptr, sdk->version10_ptr); - switch (platform_type) { - case ZigLLVM_x86: - buf_append_str(output_buf, "x86\\"); - break; - case ZigLLVM_x86_64: - buf_append_str(output_buf, "x64\\"); - break; - case ZigLLVM_arm: - buf_append_str(output_buf, "arm\\"); - break; - default: - zig_panic("Attempted to use vcruntime for non-supported platform."); - } - Buf* tmp_buf = buf_alloc(); - buf_init_from_buf(tmp_buf, output_buf); - buf_append_str(tmp_buf, "kernel32.lib"); - if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) { - return ErrorNone; - } - } - { - buf_resize(output_buf, 0); - buf_appendf(output_buf, "%sLib\\%s\\um\\", sdk->path81_ptr, sdk->version81_ptr); - switch (platform_type) { - case ZigLLVM_x86: - buf_append_str(output_buf, "x86\\"); - break; - case ZigLLVM_x86_64: - buf_append_str(output_buf, "x64\\"); - break; - case ZigLLVM_arm: - buf_append_str(output_buf, "arm\\"); - break; - default: - zig_panic("Attempted to use vcruntime for non-supported platform."); - } - Buf* tmp_buf = buf_alloc(); - buf_init_from_buf(tmp_buf, output_buf); - buf_append_str(tmp_buf, "kernel32.lib"); - if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) { - return ErrorNone; - } - } - return ErrorFileNotFound; -#else - return ErrorFileNotFound; -#endif -} - #if defined(ZIG_OS_WINDOWS) // Ported from std/unicode.zig struct Utf16LeIterator { @@ -1835,10 +1826,15 @@ Error os_self_exe_shared_libs(ZigList<Buf *> &paths) { #endif } -Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) { +Error os_file_open_rw(Buf *full_path, OsFile *out_file, OsFileAttr *attr, bool need_write, uint32_t mode) { #if defined(ZIG_OS_WINDOWS) // TODO use CreateFileW - HANDLE result = CreateFileA(buf_ptr(full_path), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + HANDLE result = CreateFileA(buf_ptr(full_path), + need_write ? (GENERIC_READ|GENERIC_WRITE) : GENERIC_READ, + need_write ? 0 : FILE_SHARE_READ, + nullptr, + need_write ? OPEN_ALWAYS : OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, nullptr); if (result == INVALID_HANDLE_VALUE) { DWORD err = GetLastError(); @@ -1871,12 +1867,15 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) { } windows_filetime_to_os_timestamp(&file_info.ftLastWriteTime, &attr->mtime); attr->inode = (((uint64_t)file_info.nFileIndexHigh) << 32) | file_info.nFileIndexLow; + attr->mode = 0; + attr->size = (((uint64_t)file_info.nFileSizeHigh) << 32) | file_info.nFileSizeLow; } return ErrorNone; #else for (;;) { - int fd = open(buf_ptr(full_path), O_RDONLY|O_CLOEXEC); + int fd = open(buf_ptr(full_path), + need_write ? (O_RDWR|O_CLOEXEC|O_CREAT) : (O_RDONLY|O_CLOEXEC), mode); if (fd == -1) { switch (errno) { case EINTR: @@ -1886,6 +1885,7 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) { case EFAULT: zig_unreachable(); case EACCES: + case EPERM: return ErrorAccess; case EISDIR: return ErrorIsDir; @@ -1915,12 +1915,22 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) { attr->mtime.sec = statbuf.st_mtim.tv_sec; attr->mtime.nsec = statbuf.st_mtim.tv_nsec; #endif + attr->mode = statbuf.st_mode; + attr->size = statbuf.st_size; } return ErrorNone; } #endif } +Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) { + return os_file_open_rw(full_path, out_file, attr, false, 0); +} + +Error os_file_open_w(Buf *full_path, OsFile *out_file, OsFileAttr *attr, uint32_t mode) { + return os_file_open_rw(full_path, out_file, attr, true, mode); +} + Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { #if defined(ZIG_OS_WINDOWS) for (;;) { @@ -1966,6 +1976,7 @@ Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { case EFAULT: zig_unreachable(); case EACCES: + case EPERM: return ErrorAccess; case EISDIR: return ErrorIsDir; @@ -2114,21 +2125,3 @@ void os_file_close(OsFile *file) { *file = -1; #endif } - -#ifdef ZIG_OS_LINUX -const char *possible_ld_names[] = { -#if defined(ZIG_ARCH_X86_64) - "ld-linux-x86-64.so.2", - "ld-musl-x86_64.so.1", -#elif defined(ZIG_ARCH_ARM64) - "ld-linux-aarch64.so.1", - "ld-musl-aarch64.so.1", -#elif defined(ZIG_ARCH_ARM) - "ld-linux-armhf.so.3", - "ld-musl-armhf.so.1", - "ld-linux.so.3", - "ld-musl-arm.so.1", -#endif - NULL, -}; -#endif diff --git a/src/os.hpp b/src/os.hpp @@ -43,10 +43,6 @@ #define ZIG_ARCH_UNKNOWN #endif -#ifdef ZIG_OS_LINUX -extern const char *possible_ld_names[]; -#endif - #if defined(ZIG_OS_WINDOWS) #define ZIG_PRI_usize "I64u" #define ZIG_PRI_i64 "I64d" @@ -93,13 +89,15 @@ struct Termination { #endif struct OsTimeStamp { - uint64_t sec; - uint64_t nsec; + int64_t sec; + int64_t nsec; }; struct OsFileAttr { OsTimeStamp mtime; + uint64_t size; uint64_t inode; + uint32_t mode; }; int os_init(void); @@ -121,6 +119,7 @@ Error ATTRIBUTE_MUST_USE os_make_path(Buf *path); Error ATTRIBUTE_MUST_USE os_make_dir(Buf *path); Error ATTRIBUTE_MUST_USE os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr); +Error ATTRIBUTE_MUST_USE os_file_open_w(Buf *full_path, OsFile *out_file, OsFileAttr *attr, uint32_t mode); Error ATTRIBUTE_MUST_USE os_file_open_lock_rw(Buf *full_path, OsFile *out_file); Error ATTRIBUTE_MUST_USE os_file_read(OsFile file, void *ptr, size_t *len); Error ATTRIBUTE_MUST_USE os_file_read_all(OsFile file, Buf *contents); @@ -129,6 +128,7 @@ void os_file_close(OsFile *file); Error ATTRIBUTE_MUST_USE os_write_file(Buf *full_path, Buf *contents); Error ATTRIBUTE_MUST_USE os_copy_file(Buf *src_path, Buf *dest_path); +Error ATTRIBUTE_MUST_USE os_update_file(Buf *src_path, Buf *dest_path); Error ATTRIBUTE_MUST_USE os_fetch_file(FILE *file, Buf *out_contents); Error ATTRIBUTE_MUST_USE os_fetch_file_path(Buf *full_path, Buf *out_contents); @@ -152,10 +152,6 @@ Error ATTRIBUTE_MUST_USE os_self_exe_path(Buf *out_path); Error ATTRIBUTE_MUST_USE os_get_app_data_dir(Buf *out_path, const char *appname); -Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf); -Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); -Error ATTRIBUTE_MUST_USE os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); - Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths); #endif diff --git a/src/parser.cpp b/src/parser.cpp @@ -689,6 +689,9 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B AstNode *res = fn_proto; if (body != nullptr) { + if (fn_proto->data.fn_proto.is_extern) { + ast_error(pc, first, "extern functions have no body"); + } res = ast_create_node_copy_line_info(pc, NodeTypeFnDef, fn_proto); res->data.fn_def.fn_proto = fn_proto; res->data.fn_def.body = body; @@ -2596,10 +2599,14 @@ static AstNode *ast_parse_prefix_op(ParseContext *pc) { return res; } + Token *noasync_token = eat_token_if(pc, TokenIdKeywordNoAsync); Token *await = eat_token_if(pc, TokenIdKeywordAwait); if (await != nullptr) { AstNode *res = ast_create_node(pc, NodeTypeAwaitExpr, await); + res->data.await_expr.noasync_token = noasync_token; return res; + } else if (noasync_token != nullptr) { + put_back_token(pc); } return nullptr; diff --git a/src/stage2.cpp b/src/stage2.cpp @@ -0,0 +1,208 @@ +// This file is a shim for zig1. The real implementations of these are in +// src-self-hosted/stage1.zig + +#include "stage2.h" +#include "util.hpp" +#include "zig_llvm.h" +#include "target.hpp" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +Error stage2_translate_c(struct Stage2Ast **out_ast, + struct Stage2ErrorMsg **out_errors_ptr, size_t *out_errors_len, + const char **args_begin, const char **args_end, const char *resources_path) +{ + const char *msg = "stage0 called stage2_translate_c"; + stage2_panic(msg, strlen(msg)); +} + +void stage2_free_clang_errors(struct Stage2ErrorMsg *ptr, size_t len) { + const char *msg = "stage0 called stage2_free_clang_errors"; + stage2_panic(msg, strlen(msg)); +} + +void stage2_zen(const char **ptr, size_t *len) { + const char *msg = "stage0 called stage2_zen"; + stage2_panic(msg, strlen(msg)); +} + +void stage2_attach_segfault_handler(void) { } + +void stage2_panic(const char *ptr, size_t len) { + fwrite(ptr, 1, len, stderr); + fprintf(stderr, "\n"); + fflush(stderr); + abort(); +} + +void stage2_render_ast(struct Stage2Ast *ast, FILE *output_file) { + const char *msg = "stage0 called stage2_render_ast"; + stage2_panic(msg, strlen(msg)); +} + +int stage2_fmt(int argc, char **argv) { + const char *msg = "stage0 called stage2_fmt"; + stage2_panic(msg, strlen(msg)); +} + +stage2_DepTokenizer stage2_DepTokenizer_init(const char *input, size_t len) { + const char *msg = "stage0 called stage2_DepTokenizer_init"; + stage2_panic(msg, strlen(msg)); +} + +void stage2_DepTokenizer_deinit(stage2_DepTokenizer *self) { + const char *msg = "stage0 called stage2_DepTokenizer_deinit"; + stage2_panic(msg, strlen(msg)); +} + +stage2_DepNextResult stage2_DepTokenizer_next(stage2_DepTokenizer *self) { + const char *msg = "stage0 called stage2_DepTokenizer_next"; + stage2_panic(msg, strlen(msg)); +} + + +struct Stage2Progress { + int trash; +}; + +struct Stage2ProgressNode { + int trash; +}; + +Stage2Progress *stage2_progress_create(void) { + return nullptr; +} + +void stage2_progress_destroy(Stage2Progress *progress) {} + +Stage2ProgressNode *stage2_progress_start_root(Stage2Progress *progress, + const char *name_ptr, size_t name_len, size_t estimated_total_items) +{ + return nullptr; +} +Stage2ProgressNode *stage2_progress_start(Stage2ProgressNode *node, + const char *name_ptr, size_t name_len, size_t estimated_total_items) +{ + return nullptr; +} +void stage2_progress_end(Stage2ProgressNode *node) {} +void stage2_progress_complete_one(Stage2ProgressNode *node) {} +void stage2_progress_disable_tty(Stage2Progress *progress) {} +void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){} + +Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu) { + Error err; + + if (zig_triple == nullptr) { + get_native_target(target); + + if (mcpu == nullptr) { + target->llvm_cpu_name = ZigLLVMGetHostCPUName(); + target->llvm_cpu_features = ZigLLVMGetNativeFeatures(); + target->builtin_str = "Target.Cpu.baseline(arch);\n"; + target->cache_hash = "native\n\n"; + } else if (strcmp(mcpu, "baseline") == 0) { + target->is_native = false; + target->llvm_cpu_name = ""; + target->llvm_cpu_features = ""; + target->builtin_str = "Target.Cpu.baseline(arch);\n"; + target->cache_hash = "baseline\n\n"; + } else { + const char *msg = "stage0 can't handle CPU/features in the target"; + stage2_panic(msg, strlen(msg)); + } + } else { + // first initialize all to zero + *target = {}; + + SplitIterator it = memSplit(str(zig_triple), str("-")); + + Optional<Slice<uint8_t>> opt_archsub = SplitIterator_next(&it); + Optional<Slice<uint8_t>> opt_os = SplitIterator_next(&it); + Optional<Slice<uint8_t>> opt_abi = SplitIterator_next(&it); + + if (!opt_archsub.is_some) + return ErrorMissingArchitecture; + + if ((err = target_parse_arch(&target->arch, (char*)opt_archsub.value.ptr, opt_archsub.value.len))) { + return err; + } + + if (!opt_os.is_some) + return ErrorMissingOperatingSystem; + + if ((err = target_parse_os(&target->os, (char*)opt_os.value.ptr, opt_os.value.len))) { + return err; + } + + if (opt_abi.is_some) { + if ((err = target_parse_abi(&target->abi, (char*)opt_abi.value.ptr, opt_abi.value.len))) { + return err; + } + } else { + target->abi = target_default_abi(target->arch, target->os); + } + + if (mcpu != nullptr && strcmp(mcpu, "baseline") != 0) { + const char *msg = "stage0 can't handle CPU/features in the target"; + stage2_panic(msg, strlen(msg)); + } + target->builtin_str = "Target.Cpu.baseline(arch);\n"; + target->cache_hash = "\n\n"; + } + + return ErrorNone; +} + +int stage2_cmd_targets(const char *zig_triple) { + const char *msg = "stage0 called stage2_cmd_targets"; + stage2_panic(msg, strlen(msg)); +} + +enum Error stage2_libc_parse(struct Stage2LibCInstallation *libc, const char *libc_file) { + libc->include_dir = "/dummy/include"; + libc->include_dir_len = strlen(libc->include_dir); + libc->sys_include_dir = "/dummy/sys/include"; + libc->sys_include_dir_len = strlen(libc->sys_include_dir); + libc->crt_dir = ""; + libc->crt_dir_len = strlen(libc->crt_dir); + libc->static_crt_dir = ""; + libc->static_crt_dir_len = strlen(libc->static_crt_dir); + libc->msvc_lib_dir = ""; + libc->msvc_lib_dir_len = strlen(libc->msvc_lib_dir); + libc->kernel32_lib_dir = ""; + libc->kernel32_lib_dir_len = strlen(libc->kernel32_lib_dir); + return ErrorNone; +} + +enum Error stage2_libc_render(struct Stage2LibCInstallation *self, FILE *file) { + const char *msg = "stage0 called stage2_libc_render"; + stage2_panic(msg, strlen(msg)); +} + +enum Error stage2_libc_find_native(struct Stage2LibCInstallation *libc) { + const char *msg = "stage0 called stage2_libc_find_native"; + stage2_panic(msg, strlen(msg)); +} + +enum Error stage2_detect_dynamic_linker(const struct ZigTarget *target, char **out_ptr, size_t *out_len) { + const char *msg = "stage0 called stage2_detect_dynamic_linker"; + stage2_panic(msg, strlen(msg)); +} + +enum Error stage2_detect_native_paths(struct Stage2NativePaths *native_paths) { + native_paths->include_dirs_ptr = nullptr; + native_paths->include_dirs_len = 0; + + native_paths->lib_dirs_ptr = nullptr; + native_paths->lib_dirs_len = 0; + + native_paths->rpaths_ptr = nullptr; + native_paths->rpaths_len = 0; + + native_paths->warnings_ptr = nullptr; + native_paths->warnings_len = 0; + + return ErrorNone; +} diff --git a/src/stage2.h b/src/stage2.h @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2019 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + +#ifndef ZIG_STAGE2_H +#define ZIG_STAGE2_H + +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> + +#include "zig_llvm.h" + +#ifdef __cplusplus +#define ZIG_EXTERN_C extern "C" +#else +#define ZIG_EXTERN_C +#endif + +#if defined(_MSC_VER) +#define ZIG_ATTRIBUTE_NORETURN __declspec(noreturn) +#else +#define ZIG_ATTRIBUTE_NORETURN __attribute__((noreturn)) +#endif + +// ABI warning: the types and declarations in this file must match both those in +// stage2.cpp and src-self-hosted/stage2.zig. + +// ABI warning +enum Error { + ErrorNone, + ErrorNoMem, + ErrorInvalidFormat, + ErrorSemanticAnalyzeFail, + ErrorAccess, + ErrorInterrupted, + ErrorSystemResources, + ErrorFileNotFound, + ErrorFileSystem, + ErrorFileTooBig, + ErrorDivByZero, + ErrorOverflow, + ErrorPathAlreadyExists, + ErrorUnexpected, + ErrorExactDivRemainder, + ErrorNegativeDenominator, + ErrorShiftedOutOneBits, + ErrorCCompileErrors, + ErrorEndOfFile, + ErrorIsDir, + ErrorNotDir, + ErrorUnsupportedOperatingSystem, + ErrorSharingViolation, + ErrorPipeBusy, + ErrorPrimitiveTypeNotFound, + ErrorCacheUnavailable, + ErrorPathTooLong, + ErrorCCompilerCannotFindFile, + ErrorNoCCompilerInstalled, + ErrorReadingDepFile, + ErrorInvalidDepFile, + ErrorMissingArchitecture, + ErrorMissingOperatingSystem, + ErrorUnknownArchitecture, + ErrorUnknownOperatingSystem, + ErrorUnknownABI, + ErrorInvalidFilename, + ErrorDiskQuota, + ErrorDiskSpace, + ErrorUnexpectedWriteFailure, + ErrorUnexpectedSeekFailure, + ErrorUnexpectedFileTruncationFailure, + ErrorUnimplemented, + ErrorOperationAborted, + ErrorBrokenPipe, + ErrorNoSpaceLeft, + ErrorNotLazy, + ErrorIsAsync, + ErrorImportOutsidePkgPath, + ErrorUnknownCpu, + ErrorUnknownCpuFeature, + ErrorInvalidCpuFeatures, + ErrorInvalidLlvmCpuFeaturesFormat, + ErrorUnknownApplicationBinaryInterface, + ErrorASTUnitFailure, + ErrorBadPathName, + ErrorSymLinkLoop, + ErrorProcessFdQuotaExceeded, + ErrorSystemFdQuotaExceeded, + ErrorNoDevice, + ErrorDeviceBusy, + ErrorUnableToSpawnCCompiler, + ErrorCCompilerExitCode, + ErrorCCompilerCrashed, + ErrorCCompilerCannotFindHeaders, + ErrorLibCRuntimeNotFound, + ErrorLibCStdLibHeaderNotFound, + ErrorLibCKernel32LibNotFound, + ErrorUnsupportedArchitecture, + ErrorWindowsSdkNotFound, + ErrorUnknownDynamicLinkerPath, + ErrorTargetHasNoDynamicLinker, +}; + +// ABI warning +struct Stage2ErrorMsg { + const char *filename_ptr; // can be null + size_t filename_len; + const char *msg_ptr; + size_t msg_len; + const char *source; // valid until the ASTUnit is freed. can be null + unsigned line; // 0 based + unsigned column; // 0 based + unsigned offset; // byte offset into source +}; + +// ABI warning +struct Stage2Ast; + +// ABI warning +ZIG_EXTERN_C enum Error stage2_translate_c(struct Stage2Ast **out_ast, + struct Stage2ErrorMsg **out_errors_ptr, size_t *out_errors_len, + const char **args_begin, const char **args_end, const char *resources_path); + +// ABI warning +ZIG_EXTERN_C void stage2_free_clang_errors(struct Stage2ErrorMsg *ptr, size_t len); + +// ABI warning +ZIG_EXTERN_C void stage2_render_ast(struct Stage2Ast *ast, FILE *output_file); + +// ABI warning +ZIG_EXTERN_C void stage2_zen(const char **ptr, size_t *len); + +// ABI warning +ZIG_EXTERN_C void stage2_attach_segfault_handler(void); + +// ABI warning +ZIG_EXTERN_C ZIG_ATTRIBUTE_NORETURN void stage2_panic(const char *ptr, size_t len); + +// ABI warning +ZIG_EXTERN_C int stage2_fmt(int argc, char **argv); + +// ABI warning +struct stage2_DepTokenizer { + void *handle; +}; + +// ABI warning +struct stage2_DepNextResult { + enum TypeId { + error, + null, + target, + prereq, + }; + + TypeId type_id; + + // when ent == error --> error text + // when ent == null --> undefined + // when ent == target --> target pathname + // when ent == prereq --> prereq pathname + const char *textz; +}; + +// ABI warning +ZIG_EXTERN_C stage2_DepTokenizer stage2_DepTokenizer_init(const char *input, size_t len); + +// ABI warning +ZIG_EXTERN_C void stage2_DepTokenizer_deinit(stage2_DepTokenizer *self); + +// ABI warning +ZIG_EXTERN_C stage2_DepNextResult stage2_DepTokenizer_next(stage2_DepTokenizer *self); + +// ABI warning +struct Stage2Progress; +// ABI warning +struct Stage2ProgressNode; +// ABI warning +ZIG_EXTERN_C Stage2Progress *stage2_progress_create(void); +// ABI warning +ZIG_EXTERN_C void stage2_progress_disable_tty(Stage2Progress *progress); +// ABI warning +ZIG_EXTERN_C void stage2_progress_destroy(Stage2Progress *progress); +// ABI warning +ZIG_EXTERN_C Stage2ProgressNode *stage2_progress_start_root(Stage2Progress *progress, + const char *name_ptr, size_t name_len, size_t estimated_total_items); +// ABI warning +ZIG_EXTERN_C Stage2ProgressNode *stage2_progress_start(Stage2ProgressNode *node, + const char *name_ptr, size_t name_len, size_t estimated_total_items); +// ABI warning +ZIG_EXTERN_C void stage2_progress_end(Stage2ProgressNode *node); +// ABI warning +ZIG_EXTERN_C void stage2_progress_complete_one(Stage2ProgressNode *node); +// ABI warning +ZIG_EXTERN_C void stage2_progress_update_node(Stage2ProgressNode *node, + size_t completed_count, size_t estimated_total_items); + +// ABI warning +ZIG_EXTERN_C int stage2_cmd_targets(const char *zig_triple); + +// ABI warning +struct Stage2LibCInstallation { + const char *include_dir; + size_t include_dir_len; + const char *sys_include_dir; + size_t sys_include_dir_len; + const char *crt_dir; + size_t crt_dir_len; + const char *static_crt_dir; + size_t static_crt_dir_len; + const char *msvc_lib_dir; + size_t msvc_lib_dir_len; + const char *kernel32_lib_dir; + size_t kernel32_lib_dir_len; +}; + +// ABI warning +ZIG_EXTERN_C enum Error stage2_libc_parse(struct Stage2LibCInstallation *libc, const char *libc_file); +// ABI warning +ZIG_EXTERN_C enum Error stage2_libc_render(struct Stage2LibCInstallation *self, FILE *file); +// ABI warning +ZIG_EXTERN_C enum Error stage2_libc_find_native(struct Stage2LibCInstallation *libc); + +// ABI warning +// Synchronize with target.cpp::os_list +enum Os { + OsFreestanding, + OsAnanas, + OsCloudABI, + OsDragonFly, + OsFreeBSD, + OsFuchsia, + OsIOS, + OsKFreeBSD, + OsLinux, + OsLv2, // PS3 + OsMacOSX, + OsNetBSD, + OsOpenBSD, + OsSolaris, + OsWindows, + OsHaiku, + OsMinix, + OsRTEMS, + OsNaCl, // Native Client + OsCNK, // BG/P Compute-Node Kernel + OsAIX, + OsCUDA, // NVIDIA CUDA + OsNVCL, // NVIDIA OpenCL + OsAMDHSA, // AMD HSA Runtime + OsPS4, + OsELFIAMCU, + OsTvOS, // Apple tvOS + OsWatchOS, // Apple watchOS + OsMesa3D, + OsContiki, + OsAMDPAL, + OsHermitCore, + OsHurd, + OsWASI, + OsEmscripten, + OsUefi, + OsOther, +}; + +// ABI warning +struct ZigGLibCVersion { + uint32_t major; // always 2 + uint32_t minor; + uint32_t patch; +}; + +struct Stage2TargetData; + +// ABI warning +struct ZigTarget { + enum ZigLLVM_ArchType arch; + enum ZigLLVM_VendorType vendor; + + enum ZigLLVM_EnvironmentType abi; + Os os; + + bool is_native; + + struct ZigGLibCVersion *glibc_version; // null means default + + const char *llvm_cpu_name; + const char *llvm_cpu_features; + const char *builtin_str; + const char *cache_hash; +}; + +// ABI warning +ZIG_EXTERN_C enum Error stage2_detect_dynamic_linker(const struct ZigTarget *target, + char **out_ptr, size_t *out_len); + +// ABI warning +ZIG_EXTERN_C enum Error stage2_target_parse(struct ZigTarget *target, const char *zig_triple, const char *mcpu); + + +// ABI warning +struct Stage2NativePaths { + const char **include_dirs_ptr; + size_t include_dirs_len; + const char **lib_dirs_ptr; + size_t lib_dirs_len; + const char **rpaths_ptr; + size_t rpaths_len; + const char **warnings_ptr; + size_t warnings_len; +}; +// ABI warning +ZIG_EXTERN_C enum Error stage2_detect_native_paths(struct Stage2NativePaths *native_paths); + +#endif diff --git a/src/target.cpp b/src/target.cpp @@ -15,65 +15,6 @@ #include <stdio.h> -static const SubArchList subarch_list_list[] = { - SubArchListNone, - SubArchListArm32, - SubArchListArm64, - SubArchListKalimba, - SubArchListMips, - SubArchListPPC, -}; - -static const ZigLLVM_SubArchType subarch_list_arm32[] = { - ZigLLVM_ARMSubArch_v8_5a, - ZigLLVM_ARMSubArch_v8_4a, - ZigLLVM_ARMSubArch_v8_3a, - ZigLLVM_ARMSubArch_v8_2a, - ZigLLVM_ARMSubArch_v8_1a, - ZigLLVM_ARMSubArch_v8, - ZigLLVM_ARMSubArch_v8r, - ZigLLVM_ARMSubArch_v8m_baseline, - ZigLLVM_ARMSubArch_v8m_mainline, - ZigLLVM_ARMSubArch_v8_1m_mainline, - ZigLLVM_ARMSubArch_v7, - ZigLLVM_ARMSubArch_v7em, - ZigLLVM_ARMSubArch_v7m, - ZigLLVM_ARMSubArch_v7s, - ZigLLVM_ARMSubArch_v7k, - ZigLLVM_ARMSubArch_v7ve, - ZigLLVM_ARMSubArch_v6, - ZigLLVM_ARMSubArch_v6m, - ZigLLVM_ARMSubArch_v6k, - ZigLLVM_ARMSubArch_v6t2, - ZigLLVM_ARMSubArch_v5, - ZigLLVM_ARMSubArch_v5te, - ZigLLVM_ARMSubArch_v4t, - -}; - -static const ZigLLVM_SubArchType subarch_list_arm64[] = { - ZigLLVM_ARMSubArch_v8_5a, - ZigLLVM_ARMSubArch_v8_4a, - ZigLLVM_ARMSubArch_v8_3a, - ZigLLVM_ARMSubArch_v8_2a, - ZigLLVM_ARMSubArch_v8_1a, - ZigLLVM_ARMSubArch_v8, -}; - -static const ZigLLVM_SubArchType subarch_list_kalimba[] = { - ZigLLVM_KalimbaSubArch_v5, - ZigLLVM_KalimbaSubArch_v4, - ZigLLVM_KalimbaSubArch_v3, -}; - -static const ZigLLVM_SubArchType subarch_list_mips[] = { - ZigLLVM_MipsSubArch_r6, -}; - -static const ZigLLVM_SubArchType subarch_list_ppc[] = { - ZigLLVM_PPCSubArch_spe, -}; - static const ZigLLVM_ArchType arch_list[] = { ZigLLVM_arm, // ARM (little endian): arm, armv.*, xscale ZigLLVM_armeb, // ARM (big endian): armeb @@ -513,7 +454,6 @@ void get_native_target(ZigTarget *target) { ZigLLVM_ObjectFormatType oformat; // ignored; based on arch/os ZigLLVMGetNativeTarget( &target->arch, - &target->sub_arch, &target->vendor, &os_type, &target->abi, @@ -526,12 +466,6 @@ void get_native_target(ZigTarget *target) { if (target_is_glibc(target)) { target->glibc_version = heap::c_allocator.create<ZigGLibCVersion>(); target_init_default_glibc_version(target); -#ifdef ZIG_OS_LINUX - Error err; - if ((err = glibc_detect_native_version(target->glibc_version))) { - // Fall back to the default version. - } -#endif } } @@ -539,233 +473,18 @@ void target_init_default_glibc_version(ZigTarget *target) { *target->glibc_version = {2, 17, 0}; } -Error target_parse_archsub(ZigLLVM_ArchType *out_arch, ZigLLVM_SubArchType *out_sub, - const char *archsub_ptr, size_t archsub_len) -{ +Error target_parse_arch(ZigLLVM_ArchType *out_arch, const char *arch_ptr, size_t arch_len) { *out_arch = ZigLLVM_UnknownArch; - *out_sub = ZigLLVM_NoSubArch; for (size_t arch_i = 0; arch_i < array_length(arch_list); arch_i += 1) { ZigLLVM_ArchType arch = arch_list[arch_i]; - SubArchList sub_arch_list = target_subarch_list(arch); - size_t subarch_count = target_subarch_count(sub_arch_list); - if (mem_eql_str(archsub_ptr, archsub_len, target_arch_name(arch))) { + if (mem_eql_str(arch_ptr, arch_len, target_arch_name(arch))) { *out_arch = arch; - if (subarch_count == 0) { - return ErrorNone; - } - } - for (size_t sub_i = 0; sub_i < subarch_count; sub_i += 1) { - ZigLLVM_SubArchType sub = target_subarch_enum(sub_arch_list, sub_i); - char arch_name[64]; - int n = sprintf(arch_name, "%s%s", target_arch_name(arch), target_subarch_name(sub)); - if (mem_eql_mem(arch_name, n, archsub_ptr, archsub_len)) { - *out_arch = arch; - *out_sub = sub; - return ErrorNone; - } + return ErrorNone; } } return ErrorUnknownArchitecture; } -SubArchList target_subarch_list(ZigLLVM_ArchType arch) { - switch (arch) { - case ZigLLVM_UnknownArch: - zig_unreachable(); - case ZigLLVM_arm: - case ZigLLVM_armeb: - case ZigLLVM_thumb: - case ZigLLVM_thumbeb: - return SubArchListArm32; - - case ZigLLVM_aarch64: - case ZigLLVM_aarch64_be: - case ZigLLVM_aarch64_32: - return SubArchListArm64; - - case ZigLLVM_kalimba: - return SubArchListKalimba; - - case ZigLLVM_arc: - case ZigLLVM_avr: - case ZigLLVM_bpfel: - case ZigLLVM_bpfeb: - case ZigLLVM_hexagon: - case ZigLLVM_mips: - case ZigLLVM_mipsel: - case ZigLLVM_mips64: - case ZigLLVM_mips64el: - case ZigLLVM_msp430: - case ZigLLVM_ppc: - case ZigLLVM_ppc64: - case ZigLLVM_ppc64le: - case ZigLLVM_r600: - case ZigLLVM_amdgcn: - case ZigLLVM_riscv32: - case ZigLLVM_riscv64: - case ZigLLVM_sparc: - case ZigLLVM_sparcv9: - case ZigLLVM_sparcel: - case ZigLLVM_systemz: - case ZigLLVM_tce: - case ZigLLVM_tcele: - case ZigLLVM_x86: - case ZigLLVM_x86_64: - case ZigLLVM_xcore: - case ZigLLVM_nvptx: - case ZigLLVM_nvptx64: - case ZigLLVM_le32: - case ZigLLVM_le64: - case ZigLLVM_amdil: - case ZigLLVM_amdil64: - case ZigLLVM_hsail: - case ZigLLVM_hsail64: - case ZigLLVM_spir: - case ZigLLVM_spir64: - case ZigLLVM_shave: - case ZigLLVM_lanai: - case ZigLLVM_wasm32: - case ZigLLVM_wasm64: - case ZigLLVM_renderscript32: - case ZigLLVM_renderscript64: - case ZigLLVM_ve: - return SubArchListNone; - } - zig_unreachable(); -} - -size_t target_subarch_count(SubArchList sub_arch_list) { - switch (sub_arch_list) { - case SubArchListNone: - return 0; - case SubArchListArm32: - return array_length(subarch_list_arm32); - case SubArchListArm64: - return array_length(subarch_list_arm64); - case SubArchListKalimba: - return array_length(subarch_list_kalimba); - case SubArchListMips: - return array_length(subarch_list_mips); - case SubArchListPPC: - return array_length(subarch_list_ppc); - } - zig_unreachable(); -} - -ZigLLVM_SubArchType target_subarch_enum(SubArchList sub_arch_list, size_t i) { - switch (sub_arch_list) { - case SubArchListNone: - zig_unreachable(); - case SubArchListArm32: - assert(i < array_length(subarch_list_arm32)); - return subarch_list_arm32[i]; - case SubArchListArm64: - assert(i < array_length(subarch_list_arm64)); - return subarch_list_arm64[i]; - case SubArchListKalimba: - assert(i < array_length(subarch_list_kalimba)); - return subarch_list_kalimba[i]; - case SubArchListMips: - assert(i < array_length(subarch_list_mips)); - return subarch_list_mips[i]; - case SubArchListPPC: - assert(i < array_length(subarch_list_ppc)); - return subarch_list_ppc[i]; - } - zig_unreachable(); -} - -const char *target_subarch_name(ZigLLVM_SubArchType subarch) { - switch (subarch) { - case ZigLLVM_NoSubArch: - return ""; - case ZigLLVM_ARMSubArch_v8_5a: - return "v8_5a"; - case ZigLLVM_ARMSubArch_v8_4a: - return "v8_4a"; - case ZigLLVM_ARMSubArch_v8_3a: - return "v8_3a"; - case ZigLLVM_ARMSubArch_v8_2a: - return "v8_2a"; - case ZigLLVM_ARMSubArch_v8_1a: - return "v8_1a"; - case ZigLLVM_ARMSubArch_v8: - return "v8a"; - case ZigLLVM_ARMSubArch_v8r: - return "v8r"; - case ZigLLVM_ARMSubArch_v8m_baseline: - return "v8m_baseline"; - case ZigLLVM_ARMSubArch_v8m_mainline: - return "v8m_mainline"; - case ZigLLVM_ARMSubArch_v8_1m_mainline: - return "v8_1m_mainline"; - case ZigLLVM_ARMSubArch_v7: - return "v7a"; - case ZigLLVM_ARMSubArch_v7em: - return "v7em"; - case ZigLLVM_ARMSubArch_v7m: - return "v7m"; - case ZigLLVM_ARMSubArch_v7s: - return "v7s"; - case ZigLLVM_ARMSubArch_v7k: - return "v7k"; - case ZigLLVM_ARMSubArch_v7ve: - return "v7ve"; - case ZigLLVM_ARMSubArch_v6: - return "v6"; - case ZigLLVM_ARMSubArch_v6m: - return "v6m"; - case ZigLLVM_ARMSubArch_v6k: - return "v6k"; - case ZigLLVM_ARMSubArch_v6t2: - return "v6t2"; - case ZigLLVM_ARMSubArch_v5: - return "v5"; - case ZigLLVM_ARMSubArch_v5te: - return "v5te"; - case ZigLLVM_ARMSubArch_v4t: - return "v4t"; - case ZigLLVM_KalimbaSubArch_v3: - return "v3"; - case ZigLLVM_KalimbaSubArch_v4: - return "v4"; - case ZigLLVM_KalimbaSubArch_v5: - return "v5"; - case ZigLLVM_MipsSubArch_r6: - return "r6"; - case ZigLLVM_PPCSubArch_spe: - return "spe"; - } - zig_unreachable(); -} - -size_t target_subarch_list_count(void) { - return array_length(subarch_list_list); -} - -SubArchList target_subarch_list_enum(size_t index) { - assert(index < array_length(subarch_list_list)); - return subarch_list_list[index]; -} - -const char *target_subarch_list_name(SubArchList sub_arch_list) { - switch (sub_arch_list) { - case SubArchListNone: - return "None"; - case SubArchListArm32: - return "Arm32"; - case SubArchListArm64: - return "Arm64"; - case SubArchListKalimba: - return "Kalimba"; - case SubArchListMips: - return "Mips"; - case SubArchListPPC: - return "PPC"; - } - zig_unreachable(); -} - Error target_parse_os(Os *out_os, const char *os_ptr, size_t os_len) { for (size_t i = 0; i < array_length(os_list); i += 1) { Os os = os_list[i]; @@ -790,42 +509,8 @@ Error target_parse_abi(ZigLLVM_EnvironmentType *out_abi, const char *abi_ptr, si return ErrorUnknownABI; } -Error target_parse_triple(ZigTarget *target, const char *triple) { - Error err; - - // first initialize all to zero - *target = {}; - - SplitIterator it = memSplit(str(triple), str("-")); - - Optional<Slice<uint8_t>> opt_archsub = SplitIterator_next(&it); - Optional<Slice<uint8_t>> opt_os = SplitIterator_next(&it); - Optional<Slice<uint8_t>> opt_abi = SplitIterator_next(&it); - - if (!opt_archsub.is_some) - return ErrorMissingArchitecture; - - if ((err = target_parse_archsub(&target->arch, &target->sub_arch, - (char*)opt_archsub.value.ptr, opt_archsub.value.len))) - { - return err; - } - - if (!opt_os.is_some) - return ErrorMissingOperatingSystem; - - if ((err = target_parse_os(&target->os, (char*)opt_os.value.ptr, opt_os.value.len))) { - return err; - } - - if (opt_abi.is_some) { - if ((err = target_parse_abi(&target->abi, (char*)opt_abi.value.ptr, opt_abi.value.len))) { - return err; - } - } else { - target->abi = target_default_abi(target->arch, target->os); - } - return ErrorNone; +Error target_parse_triple(ZigTarget *target, const char *triple, const char *mcpu) { + return stage2_target_parse(target, triple, mcpu); } const char *target_arch_name(ZigLLVM_ArchType arch) { @@ -842,18 +527,16 @@ void init_all_targets(void) { void target_triple_zig(Buf *triple, const ZigTarget *target) { buf_resize(triple, 0); - buf_appendf(triple, "%s%s-%s-%s", + buf_appendf(triple, "%s-%s-%s", target_arch_name(target->arch), - target_subarch_name(target->sub_arch), target_os_name(target->os), target_abi_name(target->abi)); } void target_triple_llvm(Buf *triple, const ZigTarget *target) { buf_resize(triple, 0); - buf_appendf(triple, "%s%s-%s-%s-%s", + buf_appendf(triple, "%s-%s-%s-%s", ZigLLVMGetArchTypeName(target->arch), - ZigLLVMGetSubArchTypeName(target->sub_arch), ZigLLVMGetVendorTypeName(target->vendor), ZigLLVMGetOSTypeName(get_llvm_os_type(target->os)), ZigLLVMGetEnvironmentTypeName(target->abi)); @@ -1220,214 +903,10 @@ const char *target_lib_file_ext(const ZigTarget *target, bool is_static, } } -enum FloatAbi { - FloatAbiHard, - FloatAbiSoft, - FloatAbiSoftFp, -}; - -static FloatAbi get_float_abi(const ZigTarget *target) { - const ZigLLVM_EnvironmentType env = target->abi; - if (env == ZigLLVM_GNUEABIHF || - env == ZigLLVM_EABIHF || - env == ZigLLVM_MuslEABIHF) - { - return FloatAbiHard; - } else { - return FloatAbiSoft; - } -} - -static bool is_64_bit(ZigLLVM_ArchType arch) { - return target_arch_pointer_bit_width(arch) == 64; -} - bool target_is_android(const ZigTarget *target) { return target->abi == ZigLLVM_Android; } -const char *target_dynamic_linker(const ZigTarget *target) { - if (target_is_android(target)) { - return is_64_bit(target->arch) ? "/system/bin/linker64" : "/system/bin/linker"; - } - - if (target_is_musl(target)) { - Buf buf = BUF_INIT; - buf_init_from_str(&buf, "/lib/ld-musl-"); - bool is_arm = false; - switch (target->arch) { - case ZigLLVM_arm: - case ZigLLVM_thumb: - buf_append_str(&buf, "arm"); - is_arm = true; - break; - case ZigLLVM_armeb: - case ZigLLVM_thumbeb: - buf_append_str(&buf, "armeb"); - is_arm = true; - break; - default: - buf_append_str(&buf, target_arch_name(target->arch)); - } - if (is_arm && get_float_abi(target) == FloatAbiHard) { - buf_append_str(&buf, "hf"); - } - buf_append_str(&buf, ".so.1"); - return buf_ptr(&buf); - } - - switch (target->os) { - case OsFreeBSD: - return "/libexec/ld-elf.so.1"; - case OsNetBSD: - return "/libexec/ld.elf_so"; - case OsDragonFly: - return "/libexec/ld-elf.so.2"; - case OsLinux: { - const ZigLLVM_EnvironmentType abi = target->abi; - switch (target->arch) { - case ZigLLVM_UnknownArch: - zig_unreachable(); - case ZigLLVM_x86: - case ZigLLVM_sparc: - case ZigLLVM_sparcel: - return "/lib/ld-linux.so.2"; - - case ZigLLVM_aarch64: - return "/lib/ld-linux-aarch64.so.1"; - - case ZigLLVM_aarch64_be: - return "/lib/ld-linux-aarch64_be.so.1"; - - case ZigLLVM_aarch64_32: - return "/lib/ld-linux-aarch64_32.so.1"; - - case ZigLLVM_arm: - case ZigLLVM_thumb: - if (get_float_abi(target) == FloatAbiHard) { - return "/lib/ld-linux-armhf.so.3"; - } else { - return "/lib/ld-linux.so.3"; - } - - case ZigLLVM_armeb: - case ZigLLVM_thumbeb: - if (get_float_abi(target) == FloatAbiHard) { - return "/lib/ld-linux-armhf.so.3"; - } else { - return "/lib/ld-linux.so.3"; - } - - case ZigLLVM_mips: - case ZigLLVM_mipsel: - case ZigLLVM_mips64: - case ZigLLVM_mips64el: - zig_panic("TODO implement target_dynamic_linker for mips"); - - case ZigLLVM_ppc: - return "/lib/ld.so.1"; - - case ZigLLVM_ppc64: - return "/lib64/ld64.so.2"; - - case ZigLLVM_ppc64le: - return "/lib64/ld64.so.2"; - - case ZigLLVM_systemz: - return "/lib64/ld64.so.1"; - - case ZigLLVM_sparcv9: - return "/lib64/ld-linux.so.2"; - - case ZigLLVM_x86_64: - if (abi == ZigLLVM_GNUX32) { - return "/libx32/ld-linux-x32.so.2"; - } - if (abi == ZigLLVM_Musl || abi == ZigLLVM_MuslEABI || abi == ZigLLVM_MuslEABIHF) { - return "/lib/ld-musl-x86_64.so.1"; - } - return "/lib64/ld-linux-x86-64.so.2"; - - case ZigLLVM_wasm32: - case ZigLLVM_wasm64: - return nullptr; - - case ZigLLVM_riscv32: - return "/lib/ld-linux-riscv32-ilp32.so.1"; - case ZigLLVM_riscv64: - return "/lib/ld-linux-riscv64-lp64.so.1"; - - case ZigLLVM_arc: - case ZigLLVM_avr: - case ZigLLVM_bpfel: - case ZigLLVM_bpfeb: - case ZigLLVM_hexagon: - case ZigLLVM_msp430: - case ZigLLVM_r600: - case ZigLLVM_amdgcn: - case ZigLLVM_tce: - case ZigLLVM_tcele: - case ZigLLVM_xcore: - case ZigLLVM_nvptx: - case ZigLLVM_nvptx64: - case ZigLLVM_le32: - case ZigLLVM_le64: - case ZigLLVM_amdil: - case ZigLLVM_amdil64: - case ZigLLVM_hsail: - case ZigLLVM_hsail64: - case ZigLLVM_spir: - case ZigLLVM_spir64: - case ZigLLVM_kalimba: - case ZigLLVM_shave: - case ZigLLVM_lanai: - case ZigLLVM_renderscript32: - case ZigLLVM_renderscript64: - case ZigLLVM_ve: - zig_panic("TODO implement target_dynamic_linker for this arch"); - } - zig_unreachable(); - } - case OsFreestanding: - case OsIOS: - case OsTvOS: - case OsWatchOS: - case OsMacOSX: - case OsUefi: - case OsWindows: - case OsEmscripten: - case OsOther: - return nullptr; - - case OsAnanas: - case OsCloudABI: - case OsFuchsia: - case OsKFreeBSD: - case OsLv2: - case OsOpenBSD: - case OsSolaris: - case OsHaiku: - case OsMinix: - case OsRTEMS: - case OsNaCl: - case OsCNK: - case OsAIX: - case OsCUDA: - case OsNVCL: - case OsAMDHSA: - case OsPS4: - case OsELFIAMCU: - case OsMesa3D: - case OsContiki: - case OsAMDPAL: - case OsHermitCore: - case OsHurd: - case OsWASI: - zig_panic("TODO implement target_dynamic_linker for this OS"); - } - zig_unreachable(); -} - bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target) { assert(host_target != nullptr); @@ -1436,10 +915,8 @@ bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target return true; } - if (guest_target->os == host_target->os && guest_target->arch == host_target->arch && - guest_target->sub_arch == host_target->sub_arch) - { - // OS, arch, and sub-arch match + if (guest_target->os == host_target->os && guest_target->arch == host_target->arch) { + // OS and arch match return true; } @@ -1861,7 +1338,6 @@ void target_libc_enum(size_t index, ZigTarget *out_target) { out_target->arch = libcs_available[index].arch; out_target->os = libcs_available[index].os; out_target->abi = libcs_available[index].abi; - out_target->sub_arch = ZigLLVM_NoSubArch; out_target->vendor = ZigLLVM_UnknownVendor; out_target->is_native = false; } diff --git a/src/target.hpp b/src/target.hpp @@ -8,61 +8,10 @@ #ifndef ZIG_TARGET_HPP #define ZIG_TARGET_HPP -#include <zig_llvm.h> +#include "stage2.h" struct Buf; -// Synchronize with target.cpp::os_list -enum Os { - OsFreestanding, - OsAnanas, - OsCloudABI, - OsDragonFly, - OsFreeBSD, - OsFuchsia, - OsIOS, - OsKFreeBSD, - OsLinux, - OsLv2, // PS3 - OsMacOSX, - OsNetBSD, - OsOpenBSD, - OsSolaris, - OsWindows, - OsHaiku, - OsMinix, - OsRTEMS, - OsNaCl, // Native Client - OsCNK, // BG/P Compute-Node Kernel - OsAIX, - OsCUDA, // NVIDIA CUDA - OsNVCL, // NVIDIA OpenCL - OsAMDHSA, // AMD HSA Runtime - OsPS4, - OsELFIAMCU, - OsTvOS, // Apple tvOS - OsWatchOS, // Apple watchOS - OsMesa3D, - OsContiki, - OsAMDPAL, - OsHermitCore, - OsHurd, - OsWASI, - OsEmscripten, - OsUefi, - OsOther, -}; - -// Synchronize with target.cpp::subarch_list_list -enum SubArchList { - SubArchListNone, - SubArchListArm32, - SubArchListArm64, - SubArchListKalimba, - SubArchListMips, - SubArchListPPC, -}; - enum TargetSubsystem { TargetSubsystemConsole, TargetSubsystemWindows, @@ -79,23 +28,6 @@ enum TargetSubsystem { TargetSubsystemAuto }; -struct ZigGLibCVersion { - uint32_t major; // always 2 - uint32_t minor; - uint32_t patch; -}; - -struct ZigTarget { - ZigLLVM_ArchType arch; - ZigLLVM_SubArchType sub_arch; - ZigLLVM_VendorType vendor; - Os os; - ZigLLVM_EnvironmentType abi; - ZigGLibCVersion *glibc_version; // null means default - Stage2CpuFeatures *cpu_features; - bool is_native; -}; - enum CIntType { CIntTypeShort, CIntTypeUShort, @@ -109,9 +41,8 @@ enum CIntType { CIntTypeCount, }; -Error target_parse_triple(ZigTarget *target, const char *triple); -Error target_parse_archsub(ZigLLVM_ArchType *arch, ZigLLVM_SubArchType *sub, - const char *archsub_ptr, size_t archsub_len); +Error target_parse_triple(ZigTarget *target, const char *triple, const char *mcpu); +Error target_parse_arch(ZigLLVM_ArchType *arch, const char *arch_ptr, size_t arch_len); Error target_parse_os(Os *os, const char *os_ptr, size_t os_len); Error target_parse_abi(ZigLLVM_EnvironmentType *abi, const char *abi_ptr, size_t abi_len); @@ -122,15 +53,6 @@ size_t target_arch_count(void); ZigLLVM_ArchType target_arch_enum(size_t index); const char *target_arch_name(ZigLLVM_ArchType arch); -SubArchList target_subarch_list(ZigLLVM_ArchType arch); -size_t target_subarch_count(SubArchList sub_arch_list); -ZigLLVM_SubArchType target_subarch_enum(SubArchList subarch_list, size_t index); -const char *target_subarch_name(ZigLLVM_SubArchType subarch); - -size_t target_subarch_list_count(void); -SubArchList target_subarch_list_enum(size_t index); -const char *target_subarch_list_name(SubArchList sub_arch_list); - const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch); size_t target_vendor_count(void); @@ -169,8 +91,6 @@ const char *target_lib_file_prefix(const ZigTarget *target); const char *target_lib_file_ext(const ZigTarget *target, bool is_static, size_t version_major, size_t version_minor, size_t version_patch); -const char *target_dynamic_linker(const ZigTarget *target); - bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target); ZigLLVM_OSType get_llvm_os_type(Os os_type); diff --git a/src/userland.cpp b/src/userland.cpp @@ -1,146 +0,0 @@ -// This file is a shim for zig1. The real implementations of these are in -// src-self-hosted/stage1.zig - -#include "userland.h" -#include "util.hpp" -#include "zig_llvm.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -Error stage2_translate_c(struct Stage2Ast **out_ast, - struct Stage2ErrorMsg **out_errors_ptr, size_t *out_errors_len, - const char **args_begin, const char **args_end, const char *resources_path) -{ - const char *msg = "stage0 called stage2_translate_c"; - stage2_panic(msg, strlen(msg)); -} - -void stage2_free_clang_errors(struct Stage2ErrorMsg *ptr, size_t len) { - const char *msg = "stage0 called stage2_free_clang_errors"; - stage2_panic(msg, strlen(msg)); -} - -void stage2_zen(const char **ptr, size_t *len) { - const char *msg = "stage0 called stage2_zen"; - stage2_panic(msg, strlen(msg)); -} - -void stage2_attach_segfault_handler(void) { } - -void stage2_panic(const char *ptr, size_t len) { - fwrite(ptr, 1, len, stderr); - fprintf(stderr, "\n"); - fflush(stderr); - abort(); -} - -void stage2_render_ast(struct Stage2Ast *ast, FILE *output_file) { - const char *msg = "stage0 called stage2_render_ast"; - stage2_panic(msg, strlen(msg)); -} - -int stage2_fmt(int argc, char **argv) { - const char *msg = "stage0 called stage2_fmt"; - stage2_panic(msg, strlen(msg)); -} - -stage2_DepTokenizer stage2_DepTokenizer_init(const char *input, size_t len) { - const char *msg = "stage0 called stage2_DepTokenizer_init"; - stage2_panic(msg, strlen(msg)); -} - -void stage2_DepTokenizer_deinit(stage2_DepTokenizer *self) { - const char *msg = "stage0 called stage2_DepTokenizer_deinit"; - stage2_panic(msg, strlen(msg)); -} - -stage2_DepNextResult stage2_DepTokenizer_next(stage2_DepTokenizer *self) { - const char *msg = "stage0 called stage2_DepTokenizer_next"; - stage2_panic(msg, strlen(msg)); -} - - -struct Stage2Progress { - int trash; -}; - -struct Stage2ProgressNode { - int trash; -}; - -Stage2Progress *stage2_progress_create(void) { - return nullptr; -} - -void stage2_progress_destroy(Stage2Progress *progress) {} - -Stage2ProgressNode *stage2_progress_start_root(Stage2Progress *progress, - const char *name_ptr, size_t name_len, size_t estimated_total_items) -{ - return nullptr; -} -Stage2ProgressNode *stage2_progress_start(Stage2ProgressNode *node, - const char *name_ptr, size_t name_len, size_t estimated_total_items) -{ - return nullptr; -} -void stage2_progress_end(Stage2ProgressNode *node) {} -void stage2_progress_complete_one(Stage2ProgressNode *node) {} -void stage2_progress_disable_tty(Stage2Progress *progress) {} -void stage2_progress_update_node(Stage2ProgressNode *node, size_t completed_count, size_t estimated_total_items){} - -struct Stage2CpuFeatures { - const char *llvm_cpu_name; - const char *llvm_cpu_features; - const char *builtin_str; - const char *cache_hash; -}; - -Error stage2_cpu_features_parse(struct Stage2CpuFeatures **out, const char *zig_triple, - const char *cpu_name, const char *cpu_features) -{ - if (zig_triple == nullptr) { - Stage2CpuFeatures *result = heap::c_allocator.create<Stage2CpuFeatures>(); - result->llvm_cpu_name = ZigLLVMGetHostCPUName(); - result->llvm_cpu_features = ZigLLVMGetNativeFeatures(); - result->builtin_str = "arch.getBaselineCpuFeatures();\n"; - result->cache_hash = "native\n\n"; - *out = result; - return ErrorNone; - } - if (cpu_name == nullptr && cpu_features == nullptr) { - Stage2CpuFeatures *result = heap::c_allocator.create<Stage2CpuFeatures>(); - result->builtin_str = "arch.getBaselineCpuFeatures();\n"; - result->cache_hash = "\n\n"; - *out = result; - return ErrorNone; - } - - const char *msg = "stage0 called stage2_cpu_features_parse with non-null cpu name or features"; - stage2_panic(msg, strlen(msg)); -} - -void stage2_cpu_features_get_cache_hash(const Stage2CpuFeatures *cpu_features, - const char **ptr, size_t *len) -{ - *ptr = cpu_features->cache_hash; - *len = strlen(cpu_features->cache_hash); -} -const char *stage2_cpu_features_get_llvm_cpu(const Stage2CpuFeatures *cpu_features) { - return cpu_features->llvm_cpu_name; -} -const char *stage2_cpu_features_get_llvm_features(const Stage2CpuFeatures *cpu_features) { - return cpu_features->llvm_cpu_features; -} -void stage2_cpu_features_get_builtin_str(const Stage2CpuFeatures *cpu_features, - const char **ptr, size_t *len) -{ - *ptr = cpu_features->builtin_str; - *len = strlen(cpu_features->builtin_str); -} - -int stage2_cmd_targets(const char *zig_triple) { - const char *msg = "stage0 called stage2_cmd_targets"; - stage2_panic(msg, strlen(msg)); -} diff --git a/src/userland.h b/src/userland.h @@ -1,208 +0,0 @@ -/* - * Copyright (c) 2019 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_USERLAND_H -#define ZIG_USERLAND_H - -#include <stddef.h> -#include <stdint.h> -#include <stdio.h> - -#ifdef __cplusplus -#define ZIG_EXTERN_C extern "C" -#else -#define ZIG_EXTERN_C -#endif - -#if defined(_MSC_VER) -#define ZIG_ATTRIBUTE_NORETURN __declspec(noreturn) -#else -#define ZIG_ATTRIBUTE_NORETURN __attribute__((noreturn)) -#endif - -// ABI warning: the types and declarations in this file must match both those in -// userland.cpp and src-self-hosted/stage1.zig. - -// ABI warning -enum Error { - ErrorNone, - ErrorNoMem, - ErrorInvalidFormat, - ErrorSemanticAnalyzeFail, - ErrorAccess, - ErrorInterrupted, - ErrorSystemResources, - ErrorFileNotFound, - ErrorFileSystem, - ErrorFileTooBig, - ErrorDivByZero, - ErrorOverflow, - ErrorPathAlreadyExists, - ErrorUnexpected, - ErrorExactDivRemainder, - ErrorNegativeDenominator, - ErrorShiftedOutOneBits, - ErrorCCompileErrors, - ErrorEndOfFile, - ErrorIsDir, - ErrorNotDir, - ErrorUnsupportedOperatingSystem, - ErrorSharingViolation, - ErrorPipeBusy, - ErrorPrimitiveTypeNotFound, - ErrorCacheUnavailable, - ErrorPathTooLong, - ErrorCCompilerCannotFindFile, - ErrorNoCCompilerInstalled, - ErrorReadingDepFile, - ErrorInvalidDepFile, - ErrorMissingArchitecture, - ErrorMissingOperatingSystem, - ErrorUnknownArchitecture, - ErrorUnknownOperatingSystem, - ErrorUnknownABI, - ErrorInvalidFilename, - ErrorDiskQuota, - ErrorDiskSpace, - ErrorUnexpectedWriteFailure, - ErrorUnexpectedSeekFailure, - ErrorUnexpectedFileTruncationFailure, - ErrorUnimplemented, - ErrorOperationAborted, - ErrorBrokenPipe, - ErrorNoSpaceLeft, - ErrorNotLazy, - ErrorIsAsync, - ErrorImportOutsidePkgPath, - ErrorUnknownCpu, - ErrorUnknownSubArchitecture, - ErrorUnknownCpuFeature, - ErrorInvalidCpuFeatures, - ErrorInvalidLlvmCpuFeaturesFormat, - ErrorUnknownApplicationBinaryInterface, -}; - -// ABI warning -struct Stage2ErrorMsg { - const char *filename_ptr; // can be null - size_t filename_len; - const char *msg_ptr; - size_t msg_len; - const char *source; // valid until the ASTUnit is freed. can be null - unsigned line; // 0 based - unsigned column; // 0 based - unsigned offset; // byte offset into source -}; - -// ABI warning -struct Stage2Ast; - -// ABI warning -ZIG_EXTERN_C enum Error stage2_translate_c(struct Stage2Ast **out_ast, - struct Stage2ErrorMsg **out_errors_ptr, size_t *out_errors_len, - const char **args_begin, const char **args_end, const char *resources_path); - -// ABI warning -ZIG_EXTERN_C void stage2_free_clang_errors(struct Stage2ErrorMsg *ptr, size_t len); - -// ABI warning -ZIG_EXTERN_C void stage2_render_ast(struct Stage2Ast *ast, FILE *output_file); - -// ABI warning -ZIG_EXTERN_C void stage2_zen(const char **ptr, size_t *len); - -// ABI warning -ZIG_EXTERN_C void stage2_attach_segfault_handler(void); - -// ABI warning -ZIG_EXTERN_C ZIG_ATTRIBUTE_NORETURN void stage2_panic(const char *ptr, size_t len); - -// ABI warning -ZIG_EXTERN_C int stage2_fmt(int argc, char **argv); - -// ABI warning -struct stage2_DepTokenizer { - void *handle; -}; - -// ABI warning -struct stage2_DepNextResult { - enum TypeId { - error, - null, - target, - prereq, - }; - - TypeId type_id; - - // when ent == error --> error text - // when ent == null --> undefined - // when ent == target --> target pathname - // when ent == prereq --> prereq pathname - const char *textz; -}; - -// ABI warning -ZIG_EXTERN_C stage2_DepTokenizer stage2_DepTokenizer_init(const char *input, size_t len); - -// ABI warning -ZIG_EXTERN_C void stage2_DepTokenizer_deinit(stage2_DepTokenizer *self); - -// ABI warning -ZIG_EXTERN_C stage2_DepNextResult stage2_DepTokenizer_next(stage2_DepTokenizer *self); - -// ABI warning -struct Stage2Progress; -// ABI warning -struct Stage2ProgressNode; -// ABI warning -ZIG_EXTERN_C Stage2Progress *stage2_progress_create(void); -// ABI warning -ZIG_EXTERN_C void stage2_progress_disable_tty(Stage2Progress *progress); -// ABI warning -ZIG_EXTERN_C void stage2_progress_destroy(Stage2Progress *progress); -// ABI warning -ZIG_EXTERN_C Stage2ProgressNode *stage2_progress_start_root(Stage2Progress *progress, - const char *name_ptr, size_t name_len, size_t estimated_total_items); -// ABI warning -ZIG_EXTERN_C Stage2ProgressNode *stage2_progress_start(Stage2ProgressNode *node, - const char *name_ptr, size_t name_len, size_t estimated_total_items); -// ABI warning -ZIG_EXTERN_C void stage2_progress_end(Stage2ProgressNode *node); -// ABI warning -ZIG_EXTERN_C void stage2_progress_complete_one(Stage2ProgressNode *node); -// ABI warning -ZIG_EXTERN_C void stage2_progress_update_node(Stage2ProgressNode *node, - size_t completed_count, size_t estimated_total_items); - -// ABI warning -struct Stage2CpuFeatures; - -// ABI warning -ZIG_EXTERN_C Error stage2_cpu_features_parse(struct Stage2CpuFeatures **result, - const char *zig_triple, const char *cpu_name, const char *cpu_features); - -// ABI warning -ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_cpu(const struct Stage2CpuFeatures *cpu_features); - -// ABI warning -ZIG_EXTERN_C const char *stage2_cpu_features_get_llvm_features(const struct Stage2CpuFeatures *cpu_features); - -// ABI warning -ZIG_EXTERN_C void stage2_cpu_features_get_builtin_str(const struct Stage2CpuFeatures *cpu_features, - const char **ptr, size_t *len); - -// ABI warning -ZIG_EXTERN_C void stage2_cpu_features_get_cache_hash(const struct Stage2CpuFeatures *cpu_features, - const char **ptr, size_t *len); - -// ABI warning -ZIG_EXTERN_C int stage2_cmd_targets(const char *zig_triple); - - -#endif diff --git a/src/util.cpp b/src/util.cpp @@ -6,7 +6,7 @@ */ #include "util.hpp" -#include "userland.h" +#include "stage2.h" #include <stdio.h> #include <stdarg.h> diff --git a/src/windows_sdk.h b/src/windows_sdk.h @@ -16,6 +16,7 @@ #include <stddef.h> +// ABI warning - src-self-hosted/windows_sdk.zig struct ZigWindowsSDK { const char *path10_ptr; size_t path10_len; @@ -33,6 +34,7 @@ struct ZigWindowsSDK { size_t msvc_lib_dir_len; }; +// ABI warning - src-self-hosted/windows_sdk.zig enum ZigFindWindowsSdkError { ZigFindWindowsSdkErrorNone, ZigFindWindowsSdkErrorOutOfMemory, @@ -40,8 +42,10 @@ enum ZigFindWindowsSdkError { ZigFindWindowsSdkErrorPathTooLong, }; +// ABI warning - src-self-hosted/windows_sdk.zig ZIG_EXTERN_C enum ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk); +// ABI warning - src-self-hosted/windows_sdk.zig ZIG_EXTERN_C void zig_free_windows_sdk(struct ZigWindowsSDK *sdk); #endif diff --git a/src/zig_clang.h b/src/zig_clang.h @@ -8,7 +8,7 @@ #ifndef ZIG_ZIG_CLANG_H #define ZIG_ZIG_CLANG_H -#include "userland.h" +#include "stage2.h" #include <inttypes.h> #include <stdbool.h> diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp @@ -162,17 +162,32 @@ unsigned ZigLLVMDataLayoutGetProgramAddressSpace(LLVMTargetDataRef TD) { } bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, - const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug, - bool is_small, bool time_report) + char **error_message, bool is_debug, + bool is_small, bool time_report, + const char *asm_filename, const char *bin_filename, const char *llvm_ir_filename) { TimePassesIsEnabled = time_report; - std::error_code EC; - raw_fd_ostream dest(filename, EC, sys::fs::F_None); - if (EC) { - *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin()); - return true; + raw_fd_ostream *dest_asm = nullptr; + raw_fd_ostream *dest_bin = nullptr; + + if (asm_filename) { + std::error_code EC; + dest_asm = new(std::nothrow) raw_fd_ostream(asm_filename, EC, sys::fs::F_None); + if (EC) { + *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin()); + return true; + } } + if (bin_filename) { + std::error_code EC; + dest_bin = new(std::nothrow) raw_fd_ostream(bin_filename, EC, sys::fs::F_None); + if (EC) { + *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin()); + return true; + } + } + TargetMachine* target_machine = reinterpret_cast<TargetMachine*>(targ_machine_ref); target_machine->setO0WantsFastISel(true); @@ -223,49 +238,51 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM } PMBuilder->populateFunctionPassManager(FPM); - // Set up the per-module pass manager. - legacy::PassManager MPM; - MPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); - PMBuilder->populateModulePassManager(MPM); - - // Set output pass. - CodeGenFileType ft; - if (output_type != ZigLLVM_EmitLLVMIr) { - switch (output_type) { - case ZigLLVM_EmitAssembly: - ft = CGFT_AssemblyFile; - break; - case ZigLLVM_EmitBinary: - ft = CGFT_ObjectFile; - break; - default: - abort(); + { + // Set up the per-module pass manager. + legacy::PassManager MPM; + MPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); + PMBuilder->populateModulePassManager(MPM); + + // Set output passes. + if (dest_bin) { + if (target_machine->addPassesToEmitFile(MPM, *dest_bin, nullptr, CGFT_ObjectFile)) { + *error_message = strdup("TargetMachine can't emit an object file"); + return true; + } } - - if (target_machine->addPassesToEmitFile(MPM, dest, nullptr, ft)) { - *error_message = strdup("TargetMachine can't emit a file of this type"); - return true; + if (dest_asm) { + if (target_machine->addPassesToEmitFile(MPM, *dest_asm, nullptr, CGFT_AssemblyFile)) { + *error_message = strdup("TargetMachine can't emit an assembly file"); + return true; + } } - } - // run per function optimization passes - FPM.doInitialization(); - for (Function &F : *module) - if (!F.isDeclaration()) - FPM.run(F); - FPM.doFinalization(); + // run per function optimization passes + FPM.doInitialization(); + for (Function &F : *module) + if (!F.isDeclaration()) + FPM.run(F); + FPM.doFinalization(); - MPM.run(*module); + MPM.run(*module); - if (output_type == ZigLLVM_EmitLLVMIr) { - if (LLVMPrintModuleToFile(module_ref, filename, error_message)) { - return true; + if (llvm_ir_filename) { + if (LLVMPrintModuleToFile(module_ref, llvm_ir_filename, error_message)) { + return true; + } + } + + if (time_report) { + TimerGroup::printAll(errs()); } - } - if (time_report) { - TimerGroup::printAll(errs()); + // MPM goes out of scope and writes to the out streams } + + delete dest_asm; + delete dest_bin; + return false; } @@ -792,7 +809,7 @@ const char *ZigLLVMGetEnvironmentTypeName(ZigLLVM_EnvironmentType env_type) { return (const char*)Triple::getEnvironmentTypeName((Triple::EnvironmentType)env_type).bytes_begin(); } -void ZigLLVMGetNativeTarget(ZigLLVM_ArchType *arch_type, ZigLLVM_SubArchType *sub_arch_type, +void ZigLLVMGetNativeTarget(ZigLLVM_ArchType *arch_type, ZigLLVM_VendorType *vendor_type, ZigLLVM_OSType *os_type, ZigLLVM_EnvironmentType *environ_type, ZigLLVM_ObjectFormatType *oformat) { @@ -800,7 +817,6 @@ void ZigLLVMGetNativeTarget(ZigLLVM_ArchType *arch_type, ZigLLVM_SubArchType *su Triple triple(Triple::normalize(native_triple)); *arch_type = (ZigLLVM_ArchType)triple.getArch(); - *sub_arch_type = (ZigLLVM_SubArchType)triple.getSubArch(); *vendor_type = (ZigLLVM_VendorType)triple.getVendor(); *os_type = (ZigLLVM_OSType)triple.getOS(); *environ_type = (ZigLLVM_EnvironmentType)triple.getEnvironment(); @@ -809,70 +825,6 @@ void ZigLLVMGetNativeTarget(ZigLLVM_ArchType *arch_type, ZigLLVM_SubArchType *su free(native_triple); } -const char *ZigLLVMGetSubArchTypeName(ZigLLVM_SubArchType sub_arch) { - switch (sub_arch) { - case ZigLLVM_NoSubArch: - return ""; - case ZigLLVM_ARMSubArch_v8_5a: - return "v8.5a"; - case ZigLLVM_ARMSubArch_v8_4a: - return "v8.4a"; - case ZigLLVM_ARMSubArch_v8_3a: - return "v8.3a"; - case ZigLLVM_ARMSubArch_v8_2a: - return "v8.2a"; - case ZigLLVM_ARMSubArch_v8_1a: - return "v8.1a"; - case ZigLLVM_ARMSubArch_v8: - return "v8a"; - case ZigLLVM_ARMSubArch_v8r: - return "v8r"; - case ZigLLVM_ARMSubArch_v8m_baseline: - return "v8m.base"; - case ZigLLVM_ARMSubArch_v8m_mainline: - return "v8m.main"; - case ZigLLVM_ARMSubArch_v8_1m_mainline: - return "v8.1m.main"; - case ZigLLVM_ARMSubArch_v7: - return "v7a"; - case ZigLLVM_ARMSubArch_v7em: - return "v7em"; - case ZigLLVM_ARMSubArch_v7m: - return "v7m"; - case ZigLLVM_ARMSubArch_v7s: - return "v7s"; - case ZigLLVM_ARMSubArch_v7k: - return "v7k"; - case ZigLLVM_ARMSubArch_v7ve: - return "v7ve"; - case ZigLLVM_ARMSubArch_v6: - return "v6"; - case ZigLLVM_ARMSubArch_v6m: - return "v6m"; - case ZigLLVM_ARMSubArch_v6k: - return "v6k"; - case ZigLLVM_ARMSubArch_v6t2: - return "v6t2"; - case ZigLLVM_ARMSubArch_v5: - return "v5"; - case ZigLLVM_ARMSubArch_v5te: - return "v5te"; - case ZigLLVM_ARMSubArch_v4t: - return "v4t"; - case ZigLLVM_KalimbaSubArch_v3: - return "v3"; - case ZigLLVM_KalimbaSubArch_v4: - return "v4"; - case ZigLLVM_KalimbaSubArch_v5: - return "v5"; - case ZigLLVM_MipsSubArch_r6: - return "r6"; - case ZigLLVM_PPCSubArch_spe: - return "spe"; - } - abort(); -} - void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module) { unwrap(module)->addModuleFlag(Module::Warning, "Debug Info Version", DEBUG_METADATA_VERSION); unwrap(module)->addModuleFlag(Module::Warning, "Dwarf Version", 4); @@ -1210,36 +1162,6 @@ static_assert((Triple::ArchType)ZigLLVM_renderscript64 == Triple::renderscript64 static_assert((Triple::ArchType)ZigLLVM_ve == Triple::ve, ""); static_assert((Triple::ArchType)ZigLLVM_LastArchType == Triple::LastArchType, ""); -static_assert((Triple::SubArchType)ZigLLVM_NoSubArch == Triple::NoSubArch, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_4a == Triple::ARMSubArch_v8_4a, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_3a == Triple::ARMSubArch_v8_3a, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_2a == Triple::ARMSubArch_v8_2a, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_1a == Triple::ARMSubArch_v8_1a, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8 == Triple::ARMSubArch_v8, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8r == Triple::ARMSubArch_v8r, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8m_baseline == Triple::ARMSubArch_v8m_baseline, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8m_mainline == Triple::ARMSubArch_v8m_mainline, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_1m_mainline == Triple::ARMSubArch_v8_1m_mainline, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7 == Triple::ARMSubArch_v7, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7em == Triple::ARMSubArch_v7em, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7m == Triple::ARMSubArch_v7m, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7s == Triple::ARMSubArch_v7s, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7k == Triple::ARMSubArch_v7k, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7ve == Triple::ARMSubArch_v7ve, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6 == Triple::ARMSubArch_v6, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6m == Triple::ARMSubArch_v6m, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6k == Triple::ARMSubArch_v6k, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6t2 == Triple::ARMSubArch_v6t2, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v5 == Triple::ARMSubArch_v5, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v5te == Triple::ARMSubArch_v5te, ""); -static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v4t == Triple::ARMSubArch_v4t, ""); -static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v3 == Triple::KalimbaSubArch_v3, ""); -static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v4 == Triple::KalimbaSubArch_v4, ""); -static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v5 == Triple::KalimbaSubArch_v5, ""); -static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v5 == Triple::KalimbaSubArch_v5, ""); -static_assert((Triple::SubArchType)ZigLLVM_MipsSubArch_r6 == Triple::MipsSubArch_r6, ""); -static_assert((Triple::SubArchType)ZigLLVM_PPCSubArch_spe == Triple::PPCSubArch_spe, ""); - static_assert((Triple::VendorType)ZigLLVM_UnknownVendor == Triple::UnknownVendor, ""); static_assert((Triple::VendorType)ZigLLVM_Apple == Triple::Apple, ""); static_assert((Triple::VendorType)ZigLLVM_PC == Triple::PC, ""); diff --git a/src/zig_llvm.h b/src/zig_llvm.h @@ -46,17 +46,10 @@ ZIG_EXTERN_C void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R); ZIG_EXTERN_C char *ZigLLVMGetHostCPUName(void); ZIG_EXTERN_C char *ZigLLVMGetNativeFeatures(void); -// We use a custom enum here since LLVM does not expose LLVMIr as an emit -// output through the same mechanism as assembly/binary. -enum ZigLLVM_EmitOutputType { - ZigLLVM_EmitAssembly, - ZigLLVM_EmitBinary, - ZigLLVM_EmitLLVMIr, -}; - ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, - const char *filename, enum ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug, - bool is_small, bool time_report); + char **error_message, bool is_debug, + bool is_small, bool time_report, + const char *asm_filename, const char *bin_filename, const char *llvm_ir_filename); ZIG_EXTERN_C LLVMTargetMachineRef ZigLLVMCreateTargetMachine(LLVMTargetRef T, const char *Triple, const char *CPU, const char *Features, LLVMCodeGenOptLevel Level, LLVMRelocMode Reloc, @@ -332,43 +325,6 @@ enum ZigLLVM_ArchType { ZigLLVM_LastArchType = ZigLLVM_ve }; -// synchronize with lists in target.cpp -enum ZigLLVM_SubArchType { - ZigLLVM_NoSubArch, - - ZigLLVM_ARMSubArch_v8_5a, - ZigLLVM_ARMSubArch_v8_4a, - ZigLLVM_ARMSubArch_v8_3a, - ZigLLVM_ARMSubArch_v8_2a, - ZigLLVM_ARMSubArch_v8_1a, - ZigLLVM_ARMSubArch_v8, - ZigLLVM_ARMSubArch_v8r, - ZigLLVM_ARMSubArch_v8m_baseline, - ZigLLVM_ARMSubArch_v8m_mainline, - ZigLLVM_ARMSubArch_v8_1m_mainline, - ZigLLVM_ARMSubArch_v7, - ZigLLVM_ARMSubArch_v7em, - ZigLLVM_ARMSubArch_v7m, - ZigLLVM_ARMSubArch_v7s, - ZigLLVM_ARMSubArch_v7k, - ZigLLVM_ARMSubArch_v7ve, - ZigLLVM_ARMSubArch_v6, - ZigLLVM_ARMSubArch_v6m, - ZigLLVM_ARMSubArch_v6k, - ZigLLVM_ARMSubArch_v6t2, - ZigLLVM_ARMSubArch_v5, - ZigLLVM_ARMSubArch_v5te, - ZigLLVM_ARMSubArch_v4t, - - ZigLLVM_KalimbaSubArch_v3, - ZigLLVM_KalimbaSubArch_v4, - ZigLLVM_KalimbaSubArch_v5, - - ZigLLVM_MipsSubArch_r6, - - ZigLLVM_PPCSubArch_spe, -}; - enum ZigLLVM_VendorType { ZigLLVM_UnknownVendor, @@ -526,7 +482,6 @@ LLVMValueRef ZigLLVMBuildAtomicRMW(LLVMBuilderRef B, enum ZigLLVM_AtomicRMWBinOp #define ZigLLVM_DIFlags_AllCallsDescribed (1U << 29) ZIG_EXTERN_C const char *ZigLLVMGetArchTypeName(enum ZigLLVM_ArchType arch); -ZIG_EXTERN_C const char *ZigLLVMGetSubArchTypeName(enum ZigLLVM_SubArchType sub_arch); ZIG_EXTERN_C const char *ZigLLVMGetVendorTypeName(enum ZigLLVM_VendorType vendor); ZIG_EXTERN_C const char *ZigLLVMGetOSTypeName(enum ZigLLVM_OSType os); ZIG_EXTERN_C const char *ZigLLVMGetEnvironmentTypeName(enum ZigLLVM_EnvironmentType abi); @@ -541,7 +496,7 @@ ZIG_EXTERN_C bool ZigLLVMWriteArchive(const char *archive_name, const char **fil bool ZigLLVMWriteImportLibrary(const char *def_path, const enum ZigLLVM_ArchType arch, const char *output_lib_path, const bool kill_at); -ZIG_EXTERN_C void ZigLLVMGetNativeTarget(enum ZigLLVM_ArchType *arch_type, enum ZigLLVM_SubArchType *sub_arch_type, +ZIG_EXTERN_C void ZigLLVMGetNativeTarget(enum ZigLLVM_ArchType *arch_type, enum ZigLLVM_VendorType *vendor_type, enum ZigLLVM_OSType *os_type, enum ZigLLVM_EnvironmentType *environ_type, enum ZigLLVM_ObjectFormatType *oformat); diff --git a/test/compile_errors.zig b/test/compile_errors.zig @@ -3,6 +3,35 @@ const builtin = @import("builtin"); const Target = @import("std").Target; pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest("slice to pointer conversion mismatch", + \\pub fn bytesAsSlice(bytes: var) [*]align(1) const u16 { + \\ return @ptrCast([*]align(1) const u16, bytes.ptr)[0..1]; + \\} + \\test "bytesAsSlice" { + \\ const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF }; + \\ const slice = bytesAsSlice(bytes[0..]); + \\} + , &[_][]const u8{ + "tmp.zig:2:54: error: expected type '[*]align(1) const u16', found '[]align(1) const u16'", + }); + + cases.addTest("access invalid @typeInfo decl", + \\const A = B; + \\test "Crash" { + \\ _ = @typeInfo(@This()).Struct.decls[0]; + \\} + , &[_][]const u8{ + "tmp.zig:1:11: error: use of undeclared identifier 'B'", + }); + + cases.addTest("reject extern function definitions with body", + \\extern "c" fn definitelyNotInLibC(a: i32, b: i32) i32 { + \\ return a + b; + \\} + , &[_][]const u8{ + "tmp.zig:1:1: error: extern functions have no body", + }); + cases.addTest("duplicate field in anonymous struct literal", \\export fn entry() void { \\ const anon = .{ @@ -30,10 +59,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:5:22: error: expected type 'fn([*c]u8, ...) callconv(.C) void', found 'fn([*:0]u8, ...) callconv(.C) void'", }); - cases.addTest("dependency loop in top-level decl with @TypeInfo", - \\export const foo = @typeInfo(@This()); + cases.addTest("dependency loop in top-level decl with @TypeInfo when accessing the decls", + \\export const foo = @typeInfo(@This()).Struct.decls; , &[_][]const u8{ "tmp.zig:1:20: error: dependency loop detected", + "tmp.zig:1:45: note: referenced here", }); cases.add("function call assigned to incorrect type", @@ -332,8 +362,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { }); tc.target = Target{ .Cross = .{ - .arch = .wasm32, - .cpu_features = Target.Arch.wasm32.getBaselineCpuFeatures(), + .cpu = Target.Cpu.baseline(.wasm32), .os = .wasi, .abi = .none, }, @@ -734,8 +763,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { }); tc.target = Target{ .Cross = .{ - .arch = .x86_64, - .cpu_features = Target.Arch.x86_64.getBaselineCpuFeatures(), + .cpu = Target.Cpu.baseline(.x86_64), .os = .linux, .abi = .gnu, }, @@ -1346,24 +1374,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:8:28: note: referenced here", }); - cases.add("@typeInfo causing depend on itself compile error", - \\const start = struct { - \\ fn crash() bug() { - \\ return bug; - \\ } - \\}; - \\fn bug() void { - \\ _ = @typeInfo(start).Struct; - \\} - \\export fn entry() void { - \\ var boom = start.crash(); - \\} - , &[_][]const u8{ - "tmp.zig:7:9: error: dependency loop detected", - "tmp.zig:2:19: note: referenced here", - "tmp.zig:10:21: note: referenced here", - }); - cases.add("enum field value references enum", \\pub const Foo = extern enum { \\ A = Foo.B, @@ -1647,7 +1657,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var ptr: [*c]u8 = (1 << 64) + 1; \\} \\export fn b() void { - \\ var x: @IntType(false, 65) = 0x1234; + \\ var x: u65 = 0x1234; \\ var ptr: [*c]u8 = x; \\} , &[_][]const u8{ @@ -1886,13 +1896,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add("exceeded maximum bit width of integer", \\export fn entry1() void { - \\ const T = @IntType(false, 65536); + \\ const T = u65536; \\} \\export fn entry2() void { \\ var x: i65536 = 1; \\} , &[_][]const u8{ - "tmp.zig:2:31: error: integer value 65536 cannot be coerced to type 'u16'", "tmp.zig:5:12: error: primitive integer type 'i65536' exceeds maximum bit width of 65535", }); @@ -2932,14 +2941,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:11:13: error: error.B not a member of error set 'Set2'", }); - cases.add("@memberCount of error", - \\comptime { - \\ _ = @memberCount(anyerror); - \\} - , &[_][]const u8{ - "tmp.zig:2:9: error: global error set member count not available at comptime", - }); - cases.add("duplicate error value in error set", \\const Foo = error { \\ Bar, @@ -4735,16 +4736,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:1:15: error: comptime parameter not allowed in function with calling convention 'C'", }); - cases.add("convert fixed size array to slice with invalid size", - \\export fn f() void { - \\ var array: [5]u8 = undefined; - \\ var foo = @bytesToSlice(u32, &array)[0]; - \\} - , &[_][]const u8{ - "tmp.zig:3:15: error: unable to convert [5]u8 to []align(1) u32: size mismatch", - "tmp.zig:3:29: note: u32 has size 4; remaining bytes: 1", - }); - cases.add("non-pure function returns type", \\var a: u32 = 0; \\pub fn List(comptime T: type) type { @@ -5606,7 +5597,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { }); cases.add("globally shadowing a primitive type", - \\const u16 = @intType(false, 8); + \\const u16 = u8; \\export fn entry() void { \\ const a: u16 = 300; \\} @@ -5947,93 +5938,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:2:1: error: invalid character: '\\t'", }); - cases.add("@ArgType given non function parameter", - \\comptime { - \\ _ = @ArgType(i32, 3); - \\} - , &[_][]const u8{ - "tmp.zig:2:18: error: expected function, found 'i32'", - }); - - cases.add("@ArgType arg index out of bounds", - \\comptime { - \\ _ = @ArgType(@TypeOf(add), 2); - \\} - \\fn add(a: i32, b: i32) i32 { return a + b; } - , &[_][]const u8{ - "tmp.zig:2:32: error: arg index 2 out of bounds; 'fn(i32, i32) i32' has 2 arguments", - }); - - cases.add("@memberType on unsupported type", - \\comptime { - \\ _ = @memberType(i32, 0); - \\} - , &[_][]const u8{ - "tmp.zig:2:21: error: type 'i32' does not support @memberType", - }); - - cases.add("@memberType on enum", - \\comptime { - \\ _ = @memberType(Foo, 0); - \\} - \\const Foo = enum {A,}; - , &[_][]const u8{ - "tmp.zig:2:21: error: type 'Foo' does not support @memberType", - }); - - cases.add("@memberType struct out of bounds", - \\comptime { - \\ _ = @memberType(Foo, 0); - \\} - \\const Foo = struct {}; - , &[_][]const u8{ - "tmp.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members", - }); - - cases.add("@memberType union out of bounds", - \\comptime { - \\ _ = @memberType(Foo, 1); - \\} - \\const Foo = union {A: void,}; - , &[_][]const u8{ - "tmp.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members", - }); - - cases.add("@memberName on unsupported type", - \\comptime { - \\ _ = @memberName(i32, 0); - \\} - , &[_][]const u8{ - "tmp.zig:2:21: error: type 'i32' does not support @memberName", - }); - - cases.add("@memberName struct out of bounds", - \\comptime { - \\ _ = @memberName(Foo, 0); - \\} - \\const Foo = struct {}; - , &[_][]const u8{ - "tmp.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members", - }); - - cases.add("@memberName enum out of bounds", - \\comptime { - \\ _ = @memberName(Foo, 1); - \\} - \\const Foo = enum {A,}; - , &[_][]const u8{ - "tmp.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members", - }); - - cases.add("@memberName union out of bounds", - \\comptime { - \\ _ = @memberName(Foo, 1); - \\} - \\const Foo = union {A:i32,}; - , &[_][]const u8{ - "tmp.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members", - }); - cases.add("calling var args extern function, passing array instead of pointer", \\export fn entry() void { \\ foo("hello".*,); @@ -6457,15 +6361,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:3:25: error: ReturnType has not been resolved because 'fn(var) var' is generic", }); - cases.add("getting @ArgType of generic function", - \\fn generic(a: var) void {} - \\comptime { - \\ _ = @ArgType(@TypeOf(generic), 0); - \\} - , &[_][]const u8{ - "tmp.zig:3:36: error: @ArgType could not resolve the type of arg 0 because 'fn(var) var' is generic", - }); - cases.add("unsupported modifier at start of asm output constraint", \\export fn foo() void { \\ var bar: u32 = 3; diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig @@ -553,15 +553,16 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { ); cases.addRuntimeSafety("cast []u8 to bigger slice of wrong size", - \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { - \\ @import("std").os.exit(126); + \\const std = @import("std"); + \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { + \\ std.os.exit(126); \\} \\pub fn main() !void { \\ const x = widenSlice(&[_]u8{1, 2, 3, 4, 5}); \\ if (x.len == 0) return error.Whatever; \\} \\fn widenSlice(slice: []align(1) const u8) []align(1) const i32 { - \\ return @bytesToSlice(i32, slice); + \\ return std.mem.bytesAsSlice(i32, slice); \\} ); @@ -656,17 +657,18 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { ); cases.addRuntimeSafety("@alignCast misaligned", - \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { - \\ @import("std").os.exit(126); + \\const std = @import("std"); + \\pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { + \\ std.os.exit(126); \\} \\pub fn main() !void { \\ var array align(4) = [_]u32{0x11111111, 0x11111111}; - \\ const bytes = @sliceToBytes(array[0..]); + \\ const bytes = std.mem.sliceAsBytes(array[0..]); \\ if (foo(bytes) != 0x11111111) return error.Wrong; \\} \\fn foo(bytes: []u8) u32 { \\ const slice4 = bytes[1..5]; - \\ const int_slice = @bytesToSlice(u32, @alignCast(4, slice4)); + \\ const int_slice = std.mem.bytesAsSlice(u32, @alignCast(4, slice4)); \\ return int_slice[0]; \\} ); diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig @@ -38,6 +38,7 @@ comptime { _ = @import("behavior/bugs/3112.zig"); _ = @import("behavior/bugs/3367.zig"); _ = @import("behavior/bugs/3384.zig"); + _ = @import("behavior/bugs/3586.zig"); _ = @import("behavior/bugs/3742.zig"); _ = @import("behavior/bugs/394.zig"); _ = @import("behavior/bugs/421.zig"); @@ -91,7 +92,6 @@ comptime { _ = @import("behavior/shuffle.zig"); _ = @import("behavior/sizeof_and_typeof.zig"); _ = @import("behavior/slice.zig"); - _ = @import("behavior/slicetobytes.zig"); _ = @import("behavior/struct.zig"); _ = @import("behavior/struct_contains_null_ptr_itself.zig"); _ = @import("behavior/struct_contains_slice_of_itself.zig"); diff --git a/test/stage1/behavior/align.zig b/test/stage1/behavior/align.zig @@ -81,20 +81,6 @@ fn testBytesAlign(b: u8) void { expect(ptr.* == 0x33333333); } -test "specifying alignment allows slice cast" { - testBytesAlignSlice(0x33); -} -fn testBytesAlignSlice(b: u8) void { - var bytes align(4) = [_]u8{ - b, - b, - b, - b, - }; - const slice: []u32 = @bytesToSlice(u32, bytes[0..]); - expect(slice[0] == 0x33333333); -} - test "@alignCast pointers" { var x: u32 align(4) = 1; expectsOnly1(&x); diff --git a/test/stage1/behavior/async_fn.zig b/test/stage1/behavior/async_fn.zig @@ -334,7 +334,7 @@ test "async fn with inferred error set" { var frame: [1]@Frame(middle) = undefined; var fn_ptr = middle; var result: @TypeOf(fn_ptr).ReturnType.ErrorSet!void = undefined; - _ = @asyncCall(@sliceToBytes(frame[0..]), &result, fn_ptr); + _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, fn_ptr); resume global_frame; std.testing.expectError(error.Fail, result); } @@ -954,7 +954,7 @@ test "@asyncCall with comptime-known function, but not awaited directly" { fn doTheTest() void { var frame: [1]@Frame(middle) = undefined; var result: @TypeOf(middle).ReturnType.ErrorSet!void = undefined; - _ = @asyncCall(@sliceToBytes(frame[0..]), &result, middle); + _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, middle); resume global_frame; std.testing.expectError(error.Fail, result); } @@ -1481,3 +1481,53 @@ test "handle defer interfering with return value spill" { }; S.doTheTest(); } + +test "take address of temporary async frame" { + const S = struct { + var global_frame: anyframe = undefined; + var finished = false; + + fn doTheTest() void { + _ = async asyncDoTheTest(); + resume global_frame; + expect(finished); + } + + fn asyncDoTheTest() void { + expect(finishIt(&async foo(10)) == 1245); + finished = true; + } + + fn foo(arg: i32) i32 { + global_frame = @frame(); + suspend; + return arg + 1234; + } + + fn finishIt(frame: anyframe->i32) i32 { + return (await frame) + 1; + } + }; + S.doTheTest(); +} + +test "noasync await" { + const S = struct { + var finished = false; + + fn doTheTest() void { + var frame = async foo(false); + expect(noasync await frame == 42); + finished = true; + } + + fn foo(want_suspend: bool) i32 { + if (want_suspend) { + suspend; + } + return 42; + } + }; + S.doTheTest(); + expect(S.finished); +} diff --git a/test/stage1/behavior/bit_shifting.zig b/test/stage1/behavior/bit_shifting.zig @@ -2,9 +2,9 @@ const std = @import("std"); const expect = std.testing.expect; fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime V: type) type { - expect(Key == @IntType(false, Key.bit_count)); + expect(Key == std.meta.IntType(false, Key.bit_count)); expect(Key.bit_count >= mask_bit_count); - const ShardKey = @IntType(false, mask_bit_count); + const ShardKey = std.meta.IntType(false, mask_bit_count); const shift_amount = Key.bit_count - ShardKey.bit_count; return struct { const Self = @This(); diff --git a/test/stage1/behavior/bugs/1851.zig b/test/stage1/behavior/bugs/1851.zig @@ -13,7 +13,7 @@ test "allocation and looping over 3-byte integer" { x[0] = 0xFFFFFF; x[1] = 0xFFFFFF; - const bytes = @sliceToBytes(x); + const bytes = std.mem.sliceAsBytes(x); expect(@TypeOf(bytes) == []align(4) u8); expect(bytes.len == 8); diff --git a/test/stage1/behavior/bugs/3586.zig b/test/stage1/behavior/bugs/3586.zig @@ -0,0 +1,11 @@ +const NoteParams = struct {}; + +const Container = struct { + params: ?NoteParams, +}; + +test "fixed" { + var ctr = Container{ + .params = NoteParams{}, + }; +} diff --git a/test/stage1/behavior/bugs/3742.zig b/test/stage1/behavior/bugs/3742.zig @@ -17,7 +17,7 @@ pub const GET = struct { }; pub fn isCommand(comptime T: type) bool { - const tid = @typeId(T); + const tid = @typeInfo(T); return (tid == .Struct or tid == .Enum or tid == .Union) and @hasDecl(T, "Redis") and @hasDecl(T.Redis, "Command"); } diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig @@ -300,20 +300,6 @@ fn cast128Float(x: u128) f128 { return @bitCast(f128, x); } -test "const slice widen cast" { - const bytes align(4) = [_]u8{ - 0x12, - 0x12, - 0x12, - 0x12, - }; - - const u32_value = @bytesToSlice(u32, bytes[0..])[0]; - expect(u32_value == 0x12121212); - - expect(@bitCast(u32, bytes) == 0x12121212); -} - test "single-item pointer of array to slice and to unknown length pointer" { testCastPtrOfArrayToSliceAndPtr(); comptime testCastPtrOfArrayToSliceAndPtr(); @@ -388,12 +374,6 @@ test "comptime_int @intToFloat" { } } -test "@bytesToSlice keeps pointer alignment" { - var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 }; - const numbers = @bytesToSlice(u32, bytes[0..]); - comptime expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32); -} - test "@intCast i32 to u7" { var x: u128 = maxInt(u128); var y: i32 = 120; diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig @@ -96,8 +96,8 @@ test "enum type" { const bar = Bar.B; expect(bar == Bar.B); - expect(@memberCount(Foo) == 3); - expect(@memberCount(Bar) == 4); + expect(@typeInfo(Foo).Union.fields.len == 3); + expect(@typeInfo(Bar).Enum.fields.len == 4); expect(@sizeOf(Foo) == @sizeOf(FooNoVoid)); expect(@sizeOf(Bar) == 1); } diff --git a/test/stage1/behavior/error.zig b/test/stage1/behavior/error.zig @@ -3,7 +3,6 @@ const expect = std.testing.expect; const expectError = std.testing.expectError; const expectEqual = std.testing.expectEqual; const mem = std.mem; -const builtin = @import("builtin"); pub fn foo() anyerror!i32 { const x = try bar(); @@ -84,8 +83,8 @@ test "error union type " { fn testErrorUnionType() void { const x: anyerror!i32 = 1234; if (x) |value| expect(value == 1234) else |_| unreachable; - expect(@typeId(@TypeOf(x)) == builtin.TypeId.ErrorUnion); - expect(@typeId(@TypeOf(x).ErrorSet) == builtin.TypeId.ErrorSet); + expect(@typeInfo(@TypeOf(x)) == .ErrorUnion); + expect(@typeInfo(@TypeOf(x).ErrorSet) == .ErrorSet); expect(@TypeOf(x).ErrorSet == anyerror); } @@ -100,7 +99,7 @@ const MyErrSet = error{ }; fn testErrorSetType() void { - expect(@memberCount(MyErrSet) == 2); + expect(@typeInfo(MyErrSet).ErrorSet.?.len == 2); const a: MyErrSet!i32 = 5678; const b: MyErrSet!i32 = MyErrSet.OutOfMemory; diff --git a/test/stage1/behavior/eval.zig b/test/stage1/behavior/eval.zig @@ -654,8 +654,8 @@ test "call method with comptime pass-by-non-copying-value self parameter" { expect(b == 2); } -test "@tagName of @typeId" { - const str = @tagName(@typeId(u8)); +test "@tagName of @typeInfo" { + const str = @tagName(@typeInfo(u8)); expect(std.mem.eql(u8, str, "Int")); } @@ -711,16 +711,6 @@ test "bit shift a u1" { expect(y == 1); } -test "@bytesToslice on a packed struct" { - const F = packed struct { - a: u8, - }; - - var b = [1]u8{9}; - var f = @bytesToSlice(F, &b); - expect(f[0].a == 9); -} - test "comptime pointer cast array and then slice" { const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 }; diff --git a/test/stage1/behavior/for.zig b/test/stage1/behavior/for.zig @@ -1,5 +1,6 @@ const std = @import("std"); const expect = std.testing.expect; +const expectEqual = std.testing.expectEqual; const mem = std.mem; test "continue in for loop" { @@ -142,3 +143,30 @@ test "for with null and T peer types and inferred result location type" { S.doTheTest(&[_]u8{ 1, 2 }); comptime S.doTheTest(&[_]u8{ 1, 2 }); } + +test "for copies its payload" { + const S = struct { + fn doTheTest() void { + var x = [_]usize{ 1, 2, 3 }; + for (x) |value, i| { + // Modify the original array + x[i] += 99; + expectEqual(value, i + 1); + } + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} + +test "for on slice with allowzero ptr" { + const S = struct { + fn doTheTest(slice: []u8) void { + var ptr = @ptrCast([*]allowzero u8, slice.ptr)[0..slice.len]; + for (ptr) |x, i| expect(x == i + 1); + for (ptr) |*x, i| expect(x.* == i + 1); + } + }; + S.doTheTest(&[_]u8{ 1, 2, 3, 4 }); + comptime S.doTheTest(&[_]u8{ 1, 2, 3, 4 }); +} diff --git a/test/stage1/behavior/if.zig b/test/stage1/behavior/if.zig @@ -1,4 +1,6 @@ -const expect = @import("std").testing.expect; +const std = @import("std"); +const expect = std.testing.expect; +const expectEqual = std.testing.expectEqual; test "if statements" { shouldBeEqual(1, 1); @@ -90,3 +92,18 @@ test "if prongs cast to expected type instead of peer type resolution" { S.doTheTest(false); comptime S.doTheTest(false); } + +test "while copies its payload" { + const S = struct { + fn doTheTest() void { + var tmp: ?i32 = 10; + if (tmp) |value| { + // Modify the original variable + tmp = null; + expectEqual(@as(i32, 10), value); + } else unreachable; + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} diff --git a/test/stage1/behavior/math.zig b/test/stage1/behavior/math.zig @@ -266,7 +266,7 @@ fn testBinaryNot(x: u16) void { } test "small int addition" { - var x: @IntType(false, 2) = 0; + var x: u2 = 0; expect(x == 0); x += 1; diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig @@ -3,7 +3,6 @@ const expect = std.testing.expect; const expectEqualSlices = std.testing.expectEqualSlices; const mem = std.mem; const builtin = @import("builtin"); -const maxInt = std.math.maxInt; // normal comment @@ -25,35 +24,6 @@ test "call disabled extern fn" { disabledExternFn(); } -test "@IntType builtin" { - expect(@IntType(true, 8) == i8); - expect(@IntType(true, 16) == i16); - expect(@IntType(true, 32) == i32); - expect(@IntType(true, 64) == i64); - - expect(@IntType(false, 8) == u8); - expect(@IntType(false, 16) == u16); - expect(@IntType(false, 32) == u32); - expect(@IntType(false, 64) == u64); - - expect(i8.bit_count == 8); - expect(i16.bit_count == 16); - expect(i32.bit_count == 32); - expect(i64.bit_count == 64); - - expect(i8.is_signed); - expect(i16.is_signed); - expect(i32.is_signed); - expect(i64.is_signed); - expect(isize.is_signed); - - expect(!u8.is_signed); - expect(!u16.is_signed); - expect(!u32.is_signed); - expect(!u64.is_signed); - expect(!usize.is_signed); -} - test "floating point primitive bit counts" { expect(f16.bit_count == 16); expect(f32.bit_count == 32); @@ -377,26 +347,6 @@ test "string concatenation" { expect(b[len] == 0); } -test "cast slice to u8 slice" { - expect(@sizeOf(i32) == 4); - var big_thing_array = [_]i32{ 1, 2, 3, 4 }; - const big_thing_slice: []i32 = big_thing_array[0..]; - const bytes = @sliceToBytes(big_thing_slice); - expect(bytes.len == 4 * 4); - bytes[4] = 0; - bytes[5] = 0; - bytes[6] = 0; - bytes[7] = 0; - expect(big_thing_slice[1] == 0); - const big_thing_again = @bytesToSlice(i32, bytes); - expect(big_thing_again[2] == 3); - big_thing_again[2] = -1; - expect(bytes[8] == maxInt(u8)); - expect(bytes[9] == maxInt(u8)); - expect(bytes[10] == maxInt(u8)); - expect(bytes[11] == maxInt(u8)); -} - test "pointer to void return type" { testPointerToVoidReturnType() catch unreachable; } @@ -428,7 +378,6 @@ fn testArray2DConstDoublePtr(ptr: *const f32) void { expect(ptr2[1] == 2.0); } -const Tid = builtin.TypeId; const AStruct = struct { x: i32, }; @@ -445,40 +394,6 @@ const AUnion = union { Two: void, }; -test "@typeId" { - comptime { - expect(@typeId(type) == Tid.Type); - expect(@typeId(void) == Tid.Void); - expect(@typeId(bool) == Tid.Bool); - expect(@typeId(noreturn) == Tid.NoReturn); - expect(@typeId(i8) == Tid.Int); - expect(@typeId(u8) == Tid.Int); - expect(@typeId(i64) == Tid.Int); - expect(@typeId(u64) == Tid.Int); - expect(@typeId(f32) == Tid.Float); - expect(@typeId(f64) == Tid.Float); - expect(@typeId(*f32) == Tid.Pointer); - expect(@typeId([2]u8) == Tid.Array); - expect(@typeId(AStruct) == Tid.Struct); - expect(@typeId(@TypeOf(1)) == Tid.ComptimeInt); - expect(@typeId(@TypeOf(1.0)) == Tid.ComptimeFloat); - expect(@typeId(@TypeOf(undefined)) == Tid.Undefined); - expect(@typeId(@TypeOf(null)) == Tid.Null); - expect(@typeId(?i32) == Tid.Optional); - expect(@typeId(anyerror!i32) == Tid.ErrorUnion); - expect(@typeId(anyerror) == Tid.ErrorSet); - expect(@typeId(AnEnum) == Tid.Enum); - expect(@typeId(@TypeOf(AUnionEnum.One)) == Tid.Enum); - expect(@typeId(AUnionEnum) == Tid.Union); - expect(@typeId(AUnion) == Tid.Union); - expect(@typeId(fn () void) == Tid.Fn); - expect(@typeId(@TypeOf(builtin)) == Tid.Type); - // TODO bound fn - // TODO arg tuple - // TODO opaque - } -} - test "@typeName" { const Struct = struct {}; const Union = union { diff --git a/test/stage1/behavior/reflection.zig b/test/stage1/behavior/reflection.zig @@ -16,9 +16,9 @@ test "reflection: function return type, var args, and param types" { expect(@TypeOf(dummy).ReturnType == i32); expect(!@TypeOf(dummy).is_var_args); expect(@TypeOf(dummy).arg_count == 3); - expect(@ArgType(@TypeOf(dummy), 0) == bool); - expect(@ArgType(@TypeOf(dummy), 1) == i32); - expect(@ArgType(@TypeOf(dummy), 2) == f32); + expect(@typeInfo(@TypeOf(dummy)).Fn.args[0].arg_type.? == bool); + expect(@typeInfo(@TypeOf(dummy)).Fn.args[1].arg_type.? == i32); + expect(@typeInfo(@TypeOf(dummy)).Fn.args[2].arg_type.? == f32); } } @@ -26,36 +26,6 @@ fn dummy(a: bool, b: i32, c: f32) i32 { return 1234; } -test "reflection: struct member types and names" { - comptime { - expect(@memberCount(Foo) == 3); - - expect(@memberType(Foo, 0) == i32); - expect(@memberType(Foo, 1) == bool); - expect(@memberType(Foo, 2) == void); - - expect(mem.eql(u8, @memberName(Foo, 0), "one")); - expect(mem.eql(u8, @memberName(Foo, 1), "two")); - expect(mem.eql(u8, @memberName(Foo, 2), "three")); - } -} - -test "reflection: enum member types and names" { - comptime { - expect(@memberCount(Bar) == 4); - - expect(@memberType(Bar, 0) == void); - expect(@memberType(Bar, 1) == i32); - expect(@memberType(Bar, 2) == bool); - expect(@memberType(Bar, 3) == f64); - - expect(mem.eql(u8, @memberName(Bar, 0), "One")); - expect(mem.eql(u8, @memberName(Bar, 1), "Two")); - expect(mem.eql(u8, @memberName(Bar, 2), "Three")); - expect(mem.eql(u8, @memberName(Bar, 3), "Four")); - } -} - test "reflection: @field" { var f = Foo{ .one = 42, diff --git a/test/stage1/behavior/slicetobytes.zig b/test/stage1/behavior/slicetobytes.zig @@ -1,29 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const expect = std.testing.expect; - -test "@sliceToBytes packed struct at runtime and comptime" { - const Foo = packed struct { - a: u4, - b: u4, - }; - const S = struct { - fn doTheTest() void { - var foo: Foo = undefined; - var slice = @sliceToBytes(@as(*[1]Foo, &foo)[0..1]); - slice[0] = 0x13; - switch (builtin.endian) { - builtin.Endian.Big => { - expect(foo.a == 0x1); - expect(foo.b == 0x3); - }, - builtin.Endian.Little => { - expect(foo.a == 0x3); - expect(foo.b == 0x1); - }, - } - } - }; - S.doTheTest(); - comptime S.doTheTest(); -} diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig @@ -315,7 +315,7 @@ test "packed array 24bits" { var bytes = [_]u8{0} ** (@sizeOf(FooArray24Bits) + 1); bytes[bytes.len - 1] = 0xaa; - const ptr = &@bytesToSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0]; + const ptr = &std.mem.bytesAsSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0]; expect(ptr.a == 0); expect(ptr.b[0].field == 0); expect(ptr.b[1].field == 0); @@ -364,7 +364,7 @@ test "aligned array of packed struct" { } var bytes = [_]u8{0xbb} ** @sizeOf(FooArrayOfAligned); - const ptr = &@bytesToSlice(FooArrayOfAligned, bytes[0..bytes.len])[0]; + const ptr = &std.mem.bytesAsSlice(FooArrayOfAligned, bytes[0..])[0]; expect(ptr.a[0].a == 0xbb); expect(ptr.a[0].b == 0xbb); diff --git a/test/stage1/behavior/switch.zig b/test/stage1/behavior/switch.zig @@ -1,6 +1,7 @@ const std = @import("std"); const expect = std.testing.expect; const expectError = std.testing.expectError; +const expectEqual = std.testing.expectEqual; test "switch with numbers" { testSwitchWithNumbers(13); @@ -493,3 +494,24 @@ test "switch on error set with single else" { S.doTheTest(); comptime S.doTheTest(); } + +test "while copies its payload" { + const S = struct { + fn doTheTest() void { + var tmp: union(enum) { + A: u8, + B: u32, + } = .{ .A = 42 }; + switch (tmp) { + .A => |value| { + // Modify the original union + tmp = .{ .B = 0x10101010 }; + expectEqual(@as(u8, 42), value); + }, + else => unreachable, + } + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig @@ -375,3 +375,14 @@ test "sentinel of opaque pointer type" { const c_void_info = @typeInfo(*c_void); expect(c_void_info.Pointer.sentinel == null); } + +test "@typeInfo does not force declarations into existence" { + const S = struct { + x: i32, + + fn doNotReferenceMe() void { + @compileError("test failed"); + } + }; + comptime expect(@typeInfo(S).Struct.fields.len == 1); +} diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig @@ -531,7 +531,7 @@ var glbl: Foo1 = undefined; test "global union with single field is correctly initialized" { glbl = Foo1{ - .f = @memberType(Foo1, 0){ .x = 123 }, + .f = @typeInfo(Foo1).Union.fields[0].field_type{ .x = 123 }, }; expect(glbl.f.x == 123); } diff --git a/test/stage1/behavior/while.zig b/test/stage1/behavior/while.zig @@ -1,4 +1,5 @@ -const expect = @import("std").testing.expect; +const std = @import("std"); +const expect = std.testing.expect; test "while loop" { var i: i32 = 0; @@ -271,3 +272,18 @@ test "while error 2 break statements and an else" { S.entry(true, false); comptime S.entry(true, false); } + +test "while copies its payload" { + const S = struct { + fn doTheTest() void { + var tmp: ?i32 = 10; + while (tmp) |value| { + // Modify the original variable + tmp = null; + expect(value == 10); + } + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} diff --git a/test/standalone/guess_number/main.zig b/test/standalone/guess_number/main.zig @@ -5,6 +5,7 @@ const fmt = std.fmt; pub fn main() !void { const stdout = &io.getStdOut().outStream().stream; + const stdin = io.getStdIn(); try stdout.print("Welcome to the Guess Number Game in Zig.\n", .{}); @@ -22,13 +23,12 @@ pub fn main() !void { try stdout.print("\nGuess a number between 1 and 100: ", .{}); var line_buf: [20]u8 = undefined; - const line = io.readLineSlice(line_buf[0..]) catch |err| switch (err) { - error.OutOfMemory => { - try stdout.print("Input too long.\n", .{}); - continue; - }, - else => return err, - }; + const amt = try stdin.read(&line_buf); + if (amt == line_buf.len) { + try stdout.print("Input too long.\n", .{}); + continue; + } + const line = std.mem.trimRight(u8, line_buf[0..amt], "\r\n"); const guess = fmt.parseUnsigned(u8, line, 10) catch { try stdout.print("Invalid number.\n", .{}); diff --git a/test/tests.zig b/test/tests.zig @@ -55,20 +55,18 @@ const test_targets = blk: { TestTarget{ .target = Target{ .Cross = CrossTarget{ + .cpu = Target.Cpu.baseline(.x86_64), .os = .linux, - .arch = .x86_64, .abi = .none, - .cpu_features = Target.Arch.x86_64.getBaselineCpuFeatures(), }, }, }, TestTarget{ .target = Target{ .Cross = CrossTarget{ + .cpu = Target.Cpu.baseline(.x86_64), .os = .linux, - .arch = .x86_64, .abi = .gnu, - .cpu_features = Target.Arch.x86_64.getBaselineCpuFeatures(), }, }, .link_libc = true, @@ -76,9 +74,8 @@ const test_targets = blk: { TestTarget{ .target = Target{ .Cross = CrossTarget{ + .cpu = Target.Cpu.baseline(.x86_64), .os = .linux, - .arch = .x86_64, - .cpu_features = Target.Arch.x86_64.getBaselineCpuFeatures(), .abi = .musl, }, }, @@ -88,9 +85,8 @@ const test_targets = blk: { TestTarget{ .target = Target{ .Cross = CrossTarget{ + .cpu = Target.Cpu.baseline(.i386), .os = .linux, - .arch = .i386, - .cpu_features = Target.Arch.i386.getBaselineCpuFeatures(), .abi = .none, }, }, @@ -98,9 +94,8 @@ const test_targets = blk: { TestTarget{ .target = Target{ .Cross = CrossTarget{ + .cpu = Target.Cpu.baseline(.i386), .os = .linux, - .arch = .i386, - .cpu_features = Target.Arch.i386.getBaselineCpuFeatures(), .abi = .musl, }, }, @@ -110,9 +105,8 @@ const test_targets = blk: { TestTarget{ .target = Target{ .Cross = CrossTarget{ + .cpu = Target.Cpu.baseline(.aarch64), .os = .linux, - .arch = Target.Arch{ .aarch64 = .v8a }, - .cpu_features = (Target.Arch{ .aarch64 = .v8a }).getBaselineCpuFeatures(), .abi = .none, }, }, @@ -120,9 +114,8 @@ const test_targets = blk: { TestTarget{ .target = Target{ .Cross = CrossTarget{ + .cpu = Target.Cpu.baseline(.aarch64), .os = .linux, - .arch = Target.Arch{ .aarch64 = .v8a }, - .cpu_features = (Target.Arch{ .aarch64 = .v8a }).getBaselineCpuFeatures(), .abi = .musl, }, }, @@ -131,9 +124,8 @@ const test_targets = blk: { TestTarget{ .target = Target{ .Cross = CrossTarget{ + .cpu = Target.Cpu.baseline(.aarch64), .os = .linux, - .arch = Target.Arch{ .aarch64 = .v8a }, - .cpu_features = (Target.Arch{ .aarch64 = .v8a }).getBaselineCpuFeatures(), .abi = .gnu, }, }, @@ -141,45 +133,32 @@ const test_targets = blk: { }, TestTarget{ - .target = Target{ - .Cross = CrossTarget{ - .os = .linux, - .arch = Target.Arch{ .arm = .v8a }, - .cpu_features = (Target.Arch{ .arm = .v8a }).getBaselineCpuFeatures(), - .abi = .none, - }, - }, + .target = Target.parse(.{ + .arch_os_abi = "arm-linux-none", + .cpu_features = "generic+v8a", + }) catch unreachable, }, TestTarget{ - .target = Target{ - .Cross = CrossTarget{ - .os = .linux, - .arch = Target.Arch{ .arm = .v8a }, - .cpu_features = (Target.Arch{ .arm = .v8a }).getBaselineCpuFeatures(), - .abi = .musleabihf, - }, - }, + .target = Target.parse(.{ + .arch_os_abi = "arm-linux-musleabihf", + .cpu_features = "generic+v8a", + }) catch unreachable, .link_libc = true, }, // TODO https://github.com/ziglang/zig/issues/3287 //TestTarget{ - // .target = Target{ - // .Cross = CrossTarget{ - // .os = .linux, - // .arch = Target.Arch{ .arm = .v8a }, - // .cpu_features = (Target.Arch{ .arm = .v8a }).getBaselineCpuFeatures(), - // .abi = .gnueabihf, - // }, - // }, + // .target = Target.parse(.{ + // .arch_os_abi = "arm-linux-gnueabihf", + // .cpu_features = "generic+v8a", + // }) catch unreachable, // .link_libc = true, //}, TestTarget{ .target = Target{ .Cross = CrossTarget{ + .cpu = Target.Cpu.baseline(.mipsel), .os = .linux, - .arch = .mipsel, - .cpu_features = Target.Arch.mipsel.getBaselineCpuFeatures(), .abi = .none, }, }, @@ -187,9 +166,8 @@ const test_targets = blk: { TestTarget{ .target = Target{ .Cross = CrossTarget{ + .cpu = Target.Cpu.baseline(.mipsel), .os = .linux, - .arch = .mipsel, - .cpu_features = Target.Arch.mipsel.getBaselineCpuFeatures(), .abi = .musl, }, }, @@ -236,9 +214,8 @@ const test_targets = blk: { TestTarget{ .target = Target{ .Cross = CrossTarget{ + .cpu = Target.Cpu.baseline(.x86_64), .os = .macosx, - .arch = .x86_64, - .cpu_features = Target.Arch.x86_64.getBaselineCpuFeatures(), .abi = .gnu, }, }, @@ -249,9 +226,8 @@ const test_targets = blk: { TestTarget{ .target = Target{ .Cross = CrossTarget{ + .cpu = Target.Cpu.baseline(.i386), .os = .windows, - .arch = .i386, - .cpu_features = Target.Arch.i386.getBaselineCpuFeatures(), .abi = .msvc, }, }, @@ -260,9 +236,8 @@ const test_targets = blk: { TestTarget{ .target = Target{ .Cross = CrossTarget{ + .cpu = Target.Cpu.baseline(.x86_64), .os = .windows, - .arch = .x86_64, - .cpu_features = Target.Arch.x86_64.getBaselineCpuFeatures(), .abi = .msvc, }, }, @@ -271,9 +246,8 @@ const test_targets = blk: { TestTarget{ .target = Target{ .Cross = CrossTarget{ + .cpu = Target.Cpu.baseline(.i386), .os = .windows, - .arch = .i386, - .cpu_features = Target.Arch.i386.getBaselineCpuFeatures(), .abi = .gnu, }, }, @@ -283,9 +257,8 @@ const test_targets = blk: { TestTarget{ .target = Target{ .Cross = CrossTarget{ + .cpu = Target.Cpu.baseline(.x86_64), .os = .windows, - .arch = .x86_64, - .cpu_features = Target.Arch.x86_64.getBaselineCpuFeatures(), .abi = .gnu, }, }, @@ -513,7 +486,7 @@ pub fn addPkgTests( const ArchTag = @TagType(builtin.Arch); if (test_target.disable_native and test_target.target.getOs() == builtin.os and - @as(ArchTag, test_target.target.getArch()) == @as(ArchTag, builtin.arch)) + test_target.target.getArch() == builtin.arch) { continue; } @@ -714,8 +687,10 @@ pub const StackTracesContext = struct { const got: []const u8 = got_result: { var buf = try Buffer.initSize(b.allocator, 0); defer buf.deinit(); - var bytes = stderr.toSliceConst(); - if (bytes.len != 0 and bytes[bytes.len - 1] == '\n') bytes = bytes[0 .. bytes.len - 1]; + const bytes = if (stderr.endsWith("\n")) + stderr.toSliceConst()[0 .. stderr.len() - 1] + else + stderr.toSliceConst()[0..stderr.len()]; var it = mem.separate(bytes, "\n"); process_lines: while (it.next()) |line| { if (line.len == 0) continue; diff --git a/test/translate_c.zig b/test/translate_c.zig @@ -3,6 +3,13 @@ const builtin = @import("builtin"); const Target = @import("std").Target; pub fn addCases(cases: *tests.TranslateCContext) void { + cases.add("macro line continuation", + \\#define FOO -\ + \\BAR + , &[_][]const u8{ + \\pub const FOO = -BAR; + }); + cases.add("function prototype translated as optional", \\typedef void (*fnptr_ty)(void); \\typedef __attribute__((cdecl)) void (*fnptr_attr_ty)(void); @@ -1088,10 +1095,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { cases.addWithTarget("Calling convention", tests.Target{ .Cross = .{ + .cpu = Target.Cpu.baseline(.i386), .os = .linux, - .arch = .i386, .abi = .none, - .cpu_features = Target.Arch.i386.getBaselineCpuFeatures(), }, }, \\void __attribute__((fastcall)) foo1(float *a); @@ -1107,14 +1113,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub fn foo5(a: [*c]f32) callconv(.Thiscall) void; }); - cases.addWithTarget("Calling convention", tests.Target{ - .Cross = .{ - .os = .linux, - .arch = .{ .arm = .v8_5a }, - .abi = .none, - .cpu_features = (Target.Arch{ .arm = .v8_5a }).getBaselineCpuFeatures(), - }, - }, + cases.addWithTarget("Calling convention", Target.parse(.{ + .arch_os_abi = "arm-linux-none", + .cpu_features = "generic+v8_5a", + }) catch unreachable, \\void __attribute__((pcs("aapcs"))) foo1(float *a); \\void __attribute__((pcs("aapcs-vfp"))) foo2(float *a); , &[_][]const u8{ @@ -1122,14 +1124,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub fn foo2(a: [*c]f32) callconv(.AAPCSVFP) void; }); - cases.addWithTarget("Calling convention", tests.Target{ - .Cross = .{ - .os = .linux, - .arch = .{ .aarch64 = .v8_5a }, - .abi = .none, - .cpu_features = (Target.Arch{ .aarch64 = .v8_5a }).getBaselineCpuFeatures(), - }, - }, + cases.addWithTarget("Calling convention", Target.parse(.{ + .arch_os_abi = "aarch64-linux-none", + .cpu_features = "generic+v8_5a", + }) catch unreachable, \\void __attribute__((aarch64_vector_pcs)) foo1(float *a); , &[_][]const u8{ \\pub fn foo1(a: [*c]f32) callconv(.Vectorcall) void; @@ -1356,7 +1354,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { cases.add("macro pointer cast", \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) , &[_][]const u8{ - \\pub const NRF_GPIO = if (@typeId(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@TypeOf(NRF_GPIO_BASE)) == .Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE); + \\pub const NRF_GPIO = if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeInfo(@TypeOf(NRF_GPIO_BASE)) == .Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else @as([*c]NRF_GPIO_Type, NRF_GPIO_BASE); }); cases.add("basic macro function", @@ -2540,11 +2538,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\#define FOO(bar) baz((void *)(baz)) \\#define BAR (void*) a , &[_][]const u8{ - \\pub inline fn FOO(bar: var) @TypeOf(baz(if (@typeId(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeId(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz))) { - \\ return baz(if (@typeId(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeId(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz)); + \\pub inline fn FOO(bar: var) @TypeOf(baz(if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeInfo(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz))) { + \\ return baz(if (@typeInfo(@TypeOf(baz)) == .Pointer) @ptrCast(*c_void, baz) else if (@typeInfo(@TypeOf(baz)) == .Int) @intToPtr(*c_void, baz) else @as(*c_void, baz)); \\} , - \\pub const BAR = if (@typeId(@TypeOf(a)) == .Pointer) @ptrCast(*c_void, a) else if (@typeId(@TypeOf(a)) == .Int) @intToPtr(*c_void, a) else @as(*c_void, a); + \\pub const BAR = if (@typeInfo(@TypeOf(a)) == .Pointer) @ptrCast(*c_void, a) else if (@typeInfo(@TypeOf(a)) == .Int) @intToPtr(*c_void, a) else @as(*c_void, a); }); cases.add("macro conditional operator",