authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-10-07 00:46:05-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-10-07 00:46:05-07:00
logb5a36f676b1fd69f195d9f1eb6e35f3eb2f15946
tree92ce1ffa64bc2d32d5ef73dce66daf3c8e893ee6
parentd6d05fc84d33c71434a1f8bae51ca5956e08cdf0
parentf2d374e8465042fa5cb6bf2be7b9b086948f3a94

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

Conflicts: cmake/Findllvm.cmake The llvm11 branch changed 10's to 11's and master branch added the "using LLVM_CONFIG_EXE" help message, so the resolution was to merge these changes together. I also added a check to make sure LLVM is built with AVR enabled, which is no longer an experimental target.

78 files changed, 5719 insertions(+), 3111 deletions(-)

CMakeLists.txt+24-18
......@@ -27,23 +27,26 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
2727set(ZIG_VERSION_MAJOR 0)
2828set(ZIG_VERSION_MINOR 6)
2929set(ZIG_VERSION_PATCH 0)
30set(ZIG_VERSION "${ZIG_VERSION_MAJOR}.${ZIG_VERSION_MINOR}.${ZIG_VERSION_PATCH}")
31
32find_program(GIT_EXE NAMES git)
33if(GIT_EXE)
34 execute_process(
35 COMMAND ${GIT_EXE} -C ${CMAKE_SOURCE_DIR} name-rev HEAD --tags --name-only --no-undefined --always
36 RESULT_VARIABLE EXIT_STATUS
37 OUTPUT_VARIABLE ZIG_GIT_REV
38 OUTPUT_STRIP_TRAILING_WHITESPACE
39 ERROR_QUIET)
40 if(EXIT_STATUS EQUAL "0")
41 if(ZIG_GIT_REV MATCHES "\\^0$")
42 if(NOT("${ZIG_GIT_REV}" STREQUAL "${ZIG_VERSION}^0"))
43 message("WARNING: Tag does not match configured Zig version")
30set(ZIG_VERSION "" CACHE STRING "Override Zig version string. Default is to find out with git.")
31
32if("${ZIG_VERSION}" STREQUAL "")
33 set(ZIG_VERSION "${ZIG_VERSION_MAJOR}.${ZIG_VERSION_MINOR}.${ZIG_VERSION_PATCH}")
34 find_program(GIT_EXE NAMES git)
35 if(GIT_EXE)
36 execute_process(
37 COMMAND ${GIT_EXE} -C ${CMAKE_SOURCE_DIR} name-rev HEAD --tags --name-only --no-undefined --always
38 RESULT_VARIABLE EXIT_STATUS
39 OUTPUT_VARIABLE ZIG_GIT_REV
40 OUTPUT_STRIP_TRAILING_WHITESPACE
41 ERROR_QUIET)
42 if(EXIT_STATUS EQUAL "0")
43 if(ZIG_GIT_REV MATCHES "\\^0$")
44 if(NOT("${ZIG_GIT_REV}" STREQUAL "${ZIG_VERSION}^0"))
45 message("WARNING: Tag does not match configured Zig version")
46 endif()
47 else()
48 set(ZIG_VERSION "${ZIG_VERSION}+${ZIG_GIT_REV}")
4449 endif()
45 else()
46 set(ZIG_VERSION "${ZIG_VERSION}+${ZIG_GIT_REV}")
4750 endif()
4851 endif()
4952endif()
......@@ -63,6 +66,9 @@ endif()
6366
6467if(ZIG_STATIC)
6568 set(ZIG_STATIC_LLVM "on")
69 set(ZIG_LINK_MODE "Static")
70else()
71 set(ZIG_LINK_MODE "Dynamic")
6672endif()
6773
6874string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_LIB_DIR_ESCAPED "${ZIG_LIBC_LIB_DIR}")
......@@ -74,6 +80,7 @@ option(ZIG_TEST_COVERAGE "Build Zig with test coverage instrumentation" OFF)
7480set(ZIG_TARGET_TRIPLE "native" CACHE STRING "arch-os-abi to output binaries for")
7581set(ZIG_TARGET_MCPU "baseline" CACHE STRING "-mcpu parameter to output binaries for")
7682set(ZIG_EXECUTABLE "" CACHE STRING "(when cross compiling) path to already-built zig binary")
83set(ZIG_PREFER_LLVM_CONFIG off CACHE BOOL "(when cross compiling) use llvm-config to find target llvm dependencies if needed")
7784
7885find_package(llvm)
7986find_package(clang)
......@@ -257,7 +264,6 @@ target_include_directories(embedded_softfloat PUBLIC
257264)
258265include_directories("${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/include")
259266set(SOFTFLOAT_LIBRARIES embedded_softfloat)
260include_directories("${CMAKE_SOURCE_DIR}/deps/dbg-macro")
261267
262268find_package(Threads)
263269
......@@ -487,7 +493,7 @@ if("${ZIG_TARGET_TRIPLE}" STREQUAL "native")
487493 endif()
488494else()
489495 add_custom_target(zig_build_zig1 ALL
490 COMMAND "${ZIG_EXECUTABLE}" ${BUILD_ZIG1_ARGS}
496 COMMAND "${ZIG_EXECUTABLE}" "build-obj" ${BUILD_ZIG1_ARGS}
491497 BYPRODUCTS "${ZIG1_OBJECT}"
492498 COMMENT STATUS "Building self-hosted component ${ZIG1_OBJECT}"
493499 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
README.md-1
......@@ -37,7 +37,6 @@ This step must be repeated when you make changes to any of the C++ source code.
3737
3838 * cmake >= 3.15.3
3939 * Microsoft Visual Studio. Supported versions:
40 - 2015 (version 14)
4140 - 2017 (version 15.8)
4241 - 2019 (version 16)
4342 * LLVM, Clang, LLD development libraries == 11.x
ci/azure/pipelines.yml+2-12
......@@ -28,20 +28,10 @@ jobs:
2828- job: BuildWindows
2929 pool:
3030 vmImage: 'windows-2019'
31 strategy:
32 matrix:
33 mingw64:
34 CHERE_INVOKING: yes
35 MSYSTEM: MINGW64
36 SCRIPT: '%CD:~0,2%\msys64\usr\bin\bash -lc "bash ci/azure/windows_mingw_script"'
37 msvc:
38 SCRIPT: ci/azure/windows_msvc_script.bat
39
4031 timeoutInMinutes: 360
41
4232 steps:
4333 - powershell: |
44 (New-Object Net.WebClient).DownloadFile("https://github.com/msys2/msys2-installer/releases/download/2020-07-20/msys2-base-x86_64-20200720.sfx.exe", "sfx.exe")
34 (New-Object Net.WebClient).DownloadFile("https://github.com/msys2/msys2-installer/releases/download/2020-09-03/msys2-base-x86_64-20200903.sfx.exe", "sfx.exe")
4535 .\sfx.exe -y -o\
4636 del sfx.exe
4737 displayName: Download/Extract/Install MSYS2
......@@ -57,7 +47,7 @@ jobs:
5747 - task: DownloadSecureFile@1
5848 inputs:
5949 secureFile: s3cfg
60 - script: $(SCRIPT)
50 - script: ci/azure/windows_msvc_script.bat
6151 name: main
6252 displayName: 'Build and test'
6353- job: OnMasterSuccess
ci/azure/windows_mingw_script deleted-28
......@@ -1,28 +0,0 @@
1#!/bin/sh
2
3set -x
4set -e
5
6pacman --noconfirm --needed -S git base-devel mingw-w64-x86_64-toolchain mingw-w64-x86_64-cmake mingw-w64-x86_64-clang mingw-w64-x86_64-lld mingw-w64-x86_64-llvm
7
8git config core.abbrev 9
9
10# Git is wrong for autocrlf being enabled by default on Windows.
11# git is mangling files on Windows by default.
12# This is the second bug I've tracked down to being caused by autocrlf.
13git config core.autocrlf false
14# Too late; the files are already mangled.
15git checkout .
16
17ZIGBUILDDIR="$(pwd)/build"
18PREFIX="$ZIGBUILDDIR/dist"
19CMAKEFLAGS="-DCMAKE_COLOR_MAKEFILE=OFF -DCMAKE_INSTALL_PREFIX=$PREFIX -DZIG_STATIC=ON"
20
21mkdir $ZIGBUILDDIR
22cd $ZIGBUILDDIR
23
24cmake .. -G 'MSYS Makefiles' -DCMAKE_BUILD_TYPE=RelWithDebInfo $CMAKEFLAGS -DCMAKE_EXE_LINKER_FLAGS='-fuse-ld=lld -Wl,/debug,/pdb:zig.pdb'
25
26make -j$(nproc) install
27
28./zig build test-behavior -Dskip-non-native -Dskip-release
ci/azure/windows_msvc_install+1-6
......@@ -4,12 +4,7 @@ set -x
44set -e
55
66pacman -Su --needed --noconfirm
7
8# Uncomment when https://github.com/msys2/MSYS2-packages/issues/2050 is fixed
9#pacman -S --needed --noconfirm wget p7zip python3-pip tar xz
10pacman -S --needed --noconfirm wget p7zip tar xz
11pacman -U --noconfirm http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-python-3.8.4-1-any.pkg.tar.zst
12pacman -U --noconfirm http://repo.msys2.org/mingw/x86_64/mingw-w64-x86_64-python-pip-20.0.2-1-any.pkg.tar.xz
7pacman -S --needed --noconfirm wget p7zip python3-pip tar xz
138
149pip install s3cmd
1510wget -nv "https://ziglang.org/deps/llvm%2bclang%2blld-10.0.0-x86_64-windows-msvc-release-mt.tar.xz"
cmake/Findllvm.cmake+7-7
......@@ -32,7 +32,7 @@ if(ZIG_PREFER_CLANG_CPP_DYLIB)
3232 /usr/local/llvm11/lib
3333 /usr/local/llvm110/lib
3434 )
35elseif("${ZIG_TARGET_TRIPLE}" STREQUAL "native")
35elseif(("${ZIG_TARGET_TRIPLE}" STREQUAL "native") OR ZIG_PREFER_LLVM_CONFIG)
3636 find_program(LLVM_CONFIG_EXE
3737 NAMES llvm-config-11 llvm-config-11.0 llvm-config110 llvm-config11 llvm-config
3838 PATHS
......@@ -55,13 +55,13 @@ elseif("${ZIG_TARGET_TRIPLE}" STREQUAL "native")
5555 OUTPUT_STRIP_TRAILING_WHITESPACE)
5656
5757 if("${LLVM_CONFIG_VERSION}" VERSION_LESS 11)
58 message(FATAL_ERROR "expected LLVM 11.x but found ${LLVM_CONFIG_VERSION}")
58 message(FATAL_ERROR "expected LLVM 11.x but found ${LLVM_CONFIG_VERSION} using ${LLVM_CONFIG_EXE}")
5959 endif()
6060 if("${LLVM_CONFIG_VERSION}" VERSION_EQUAL 12)
61 message(FATAL_ERROR "expected LLVM 11.x but found ${LLVM_CONFIG_VERSION}")
61 message(FATAL_ERROR "expected LLVM 11.x but found ${LLVM_CONFIG_VERSION} using ${LLVM_CONFIG_EXE}")
6262 endif()
6363 if("${LLVM_CONFIG_VERSION}" VERSION_GREATER 11)
64 message(FATAL_ERROR "expected LLVM 11.x but found ${LLVM_CONFIG_VERSION}")
64 message(FATAL_ERROR "expected LLVM 11.x but found ${LLVM_CONFIG_VERSION} using ${LLVM_CONFIG_EXE}")
6565 endif()
6666
6767 execute_process(
......@@ -72,12 +72,13 @@ elseif("${ZIG_TARGET_TRIPLE}" STREQUAL "native")
7272 function(NEED_TARGET TARGET_NAME)
7373 list (FIND LLVM_TARGETS_BUILT "${TARGET_NAME}" _index)
7474 if (${_index} EQUAL -1)
75 message(FATAL_ERROR "LLVM is missing target ${TARGET_NAME}. Zig requires LLVM to be built with all default targets enabled.")
75 message(FATAL_ERROR "LLVM (according to ${LLVM_CONFIG_EXE}) is missing target ${TARGET_NAME}. Zig requires LLVM to be built with all default targets enabled.")
7676 endif()
7777 endfunction(NEED_TARGET)
7878 NEED_TARGET("AArch64")
7979 NEED_TARGET("AMDGPU")
8080 NEED_TARGET("ARM")
81 NEED_TARGET("AVR")
8182 NEED_TARGET("BPF")
8283 NEED_TARGET("Hexagon")
8384 NEED_TARGET("Lanai")
......@@ -141,8 +142,7 @@ elseif("${ZIG_TARGET_TRIPLE}" STREQUAL "native")
141142 link_directories("${LLVM_LIBDIRS}")
142143else()
143144 # Here we assume that we're cross compiling with Zig, of course. No reason
144 # to support more complicated setups. We also assume the experimental target
145 # AVR is enabled.
145 # to support more complicated setups.
146146
147147 macro(FIND_AND_ADD_LLVM_LIB _libname_)
148148 string(TOUPPER ${_libname_} _prettylibname_)
deps/dbg-macro/LICENSE deleted-21
......@@ -1,21 +0,0 @@
1MIT License
2
3Copyright (c) 2019 David Peter <mail@david-peter.de>
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in all
13copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21SOFTWARE.
deps/dbg-macro/README.md deleted-172
......@@ -1,172 +0,0 @@
1# `dbg(…)`
2
3[![Build Status](https://travis-ci.org/sharkdp/dbg-macro.svg?branch=master)](https://travis-ci.org/sharkdp/dbg-macro) [![Build status](https://ci.appveyor.com/api/projects/status/vmo9rw4te2wifkul/branch/master?svg=true)](https://ci.appveyor.com/project/sharkdp/dbg-macro) [![Try it online](https://img.shields.io/badge/try-online-f34b7d.svg)](https://repl.it/@sharkdp/dbg-macro-demo) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](dbg.h)
4
5*A macro for `printf`-style debugging fans.*
6
7Debuggers are great. But sometimes you just don't have the time or patience to set
8up everything correctly and just want a quick way to inspect some values at runtime.
9
10This projects provides a [single header file](dbg.h) with a `dbg(…)`
11macro that can be used in all circumstances where you would typically write
12`printf("…", …)` or `std::cout << …`. But it comes with a few extras.
13
14## Examples
15
16``` c++
17#include <vector>
18#include <dbg.h>
19
20// You can use "dbg(..)" in expressions:
21int factorial(int n) {
22 if (dbg(n <= 1)) {
23 return dbg(1);
24 } else {
25 return dbg(n * factorial(n - 1));
26 }
27}
28
29int main() {
30 std::string message = "hello";
31 dbg(message); // [example.cpp:15 (main)] message = "hello" (std::string)
32
33 const int a = 2;
34 const int b = dbg(3 * a) + 1; // [example.cpp:18 (main)] 3 * a = 6 (int)
35
36 std::vector<int> numbers{b, 13, 42};
37 dbg(numbers); // [example.cpp:21 (main)] numbers = {7, 13, 42} (size: 3) (std::vector<int>)
38
39 dbg("this line is executed"); // [example.cpp:23 (main)] this line is executed
40
41 factorial(4);
42
43 return 0;
44}
45```
46
47The code above produces this output ([try it yourself](https://repl.it/@sharkdp/dbg-macro-demo)):
48
49![dbg(…) macro output](https://i.imgur.com/NHEYk9A.png)
50
51## Features
52
53 * Easy to read, colorized output (colors auto-disable when the output is not an interactive terminal)
54 * Prints file name, line number, function name and the original expression
55 * Adds type information for the printed-out value
56 * Specialized pretty-printers for containers, pointers, string literals, enums, `std::optional`, etc.
57 * Can be used inside expressions (passing through the original value)
58 * The `dbg.h` header issues a compiler warning when included (so you don't forget to remove it).
59 * Compatible and tested with C++11, C++14 and C++17.
60
61## Installation
62
63To make this practical, the `dbg.h` header should to be readily available from all kinds of different
64places and in all kinds of environments. The quick & dirty way is to actually copy the header file
65to `/usr/include` or to clone the repository and symlink `dbg.h` to `/usr/include/dbg.h`.
66``` bash
67git clone https://github.com/sharkdp/dbg-macro
68sudo ln -s $(readlink -f dbg-macro/dbg.h) /usr/include/dbg.h
69```
70If you don't want to make untracked changes to your filesystem, check below if there is a package for
71your operating system or package manager.
72
73### On Arch Linux
74
75You can install [`dbg-macro` from the AUR](https://aur.archlinux.org/packages/dbg-macro/):
76``` bash
77yay -S dbg-macro
78```
79
80### With vcpkg
81
82You can install the [`dbg-macro` port](https://github.com/microsoft/vcpkg/tree/master/ports/dbg-macro) via:
83``` bash
84vcpkg install dbg-macro
85```
86
87## Configuration
88
89* Set the `DBG_MACRO_DISABLE` flag to disable the `dbg(…)` macro (i.e. to make it a no-op).
90* Set the `DBG_MACRO_NO_WARNING` flag to disable the *"'dbg.h' header is included in your code base"* warnings.
91
92## Advanced features
93
94### Hexadecimal, octal and binary format
95
96If you want to format integers in hexadecimal, octal or binary representation, you can
97simply wrap them in `dbg::hex(…)`, `dbg::oct(…)` or `dbg::bin(…)`:
98```c++
99const uint32_t secret = 12648430;
100dbg(dbg::hex(secret));
101```
102
103### Printing type names
104
105`dbg(…)` already prints the type for each value in parenthesis (see screenshot above). But
106sometimes you just want to print a type (maybe because you don't have a value for that type).
107In this case, you can use the `dbg::type<T>()` helper to pretty-print a given type `T`.
108For example:
109```c++
110template <typename T>
111void my_function_template() {
112 using MyDependentType = typename std::remove_reference<T>::type&&;
113 dbg(dbg::type<MyDependentType>());
114}
115```
116
117### Print the current time
118
119To print a timestamp, you can use the `dbg::time()` helper:
120```c++
121dbg(dbg::time());
122```
123
124### Customization
125
126If you want `dbg(…)` to work for your custom datatype, you can simply overload `operator<<` for
127`std::ostream&`:
128```c++
129std::ostream& operator<<(std::ostream& out, const user_defined_type& v) {
130 out << "…";
131 return out;
132}
133```
134
135If you want to modify the type name that is printed by `dbg(…)`, you can add a custom
136`get_type_name` overload:
137```c++
138// Customization point for type information
139namespace dbg {
140 std::string get_type_name(type_tag<bool>) {
141 return "truth value";
142 }
143}
144```
145
146## Development
147
148If you want to contribute to `dbg-macro`, here is how you can build the tests and demos:
149
150Make sure that the submodule(s) are up to date:
151```bash
152git submodule update --init
153```
154
155Then, use the typical `cmake` workflow. Usage of `-DCMAKE_CXX_STANDARD=17` is optional,
156but recommended in order to have the largest set of features enabled:
157```bash
158mkdir build
159cd build
160cmake .. -DCMAKE_CXX_STANDARD=17
161make
162```
163
164To run the tests, simply call:
165```bash
166make test
167```
168You can find the unit tests in `tests/basic.cpp`.
169
170## Acknowledgement
171
172This project is inspired by Rusts [`dbg!(…)` macro](https://doc.rust-lang.org/std/macro.dbg.html).
deps/dbg-macro/dbg.h deleted-711
......@@ -1,711 +0,0 @@
1/*****************************************************************************
2
3 dbg(...) macro
4
5License (MIT):
6
7 Copyright (c) 2019 David Peter <mail@david-peter.de>
8
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to
11 deal in the Software without restriction, including without limitation the
12 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
13 sell copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 SOFTWARE.
26
27*****************************************************************************/
28
29#ifndef DBG_MACRO_DBG_H
30#define DBG_MACRO_DBG_H
31
32#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
33#define DBG_MACRO_UNIX
34#elif defined(_MSC_VER)
35#define DBG_MACRO_WINDOWS
36#endif
37
38#ifndef DBG_MACRO_NO_WARNING
39#pragma message("WARNING: the 'dbg.h' header is included in your code base")
40#endif // DBG_MACRO_NO_WARNING
41
42#include <algorithm>
43#include <chrono>
44#include <ctime>
45#include <iomanip>
46#include <ios>
47#include <iostream>
48#include <memory>
49#include <sstream>
50#include <string>
51#include <tuple>
52#include <type_traits>
53#include <vector>
54
55#ifdef DBG_MACRO_UNIX
56#include <unistd.h>
57#endif
58
59#if __cplusplus >= 201703L || defined(_MSC_VER)
60#define DBG_MACRO_CXX_STANDARD 17
61#elif __cplusplus >= 201402L
62#define DBG_MACRO_CXX_STANDARD 14
63#else
64#define DBG_MACRO_CXX_STANDARD 11
65#endif
66
67#if DBG_MACRO_CXX_STANDARD >= 17
68#include <optional>
69#include <variant>
70#endif
71
72namespace dbg {
73
74#ifdef DBG_MACRO_UNIX
75inline bool isColorizedOutputEnabled() {
76 return isatty(fileno(stderr));
77}
78#else
79inline bool isColorizedOutputEnabled() {
80 return true;
81}
82#endif
83
84struct time {};
85
86namespace pretty_function {
87
88// Compiler-agnostic version of __PRETTY_FUNCTION__ and constants to
89// extract the template argument in `type_name_impl`
90
91#if defined(__clang__)
92#define DBG_MACRO_PRETTY_FUNCTION __PRETTY_FUNCTION__
93static constexpr size_t PREFIX_LENGTH =
94 sizeof("const char *dbg::type_name_impl() [T = ") - 1;
95static constexpr size_t SUFFIX_LENGTH = sizeof("]") - 1;
96#elif defined(__GNUC__) && !defined(__clang__)
97#define DBG_MACRO_PRETTY_FUNCTION __PRETTY_FUNCTION__
98static constexpr size_t PREFIX_LENGTH =
99 sizeof("const char* dbg::type_name_impl() [with T = ") - 1;
100static constexpr size_t SUFFIX_LENGTH = sizeof("]") - 1;
101#elif defined(_MSC_VER)
102#define DBG_MACRO_PRETTY_FUNCTION __FUNCSIG__
103static constexpr size_t PREFIX_LENGTH =
104 sizeof("const char *__cdecl dbg::type_name_impl<") - 1;
105static constexpr size_t SUFFIX_LENGTH = sizeof(">(void)") - 1;
106#else
107#error "This compiler is currently not supported by dbg_macro."
108#endif
109
110} // namespace pretty_function
111
112// Formatting helpers
113
114template <typename T>
115struct print_formatted {
116 static_assert(std::is_integral<T>::value,
117 "Only integral types are supported.");
118
119 print_formatted(T value, int numeric_base)
120 : inner(value), base(numeric_base) {}
121
122 operator T() const { return inner; }
123
124 const char* prefix() const {
125 switch (base) {
126 case 8:
127 return "0o";
128 case 16:
129 return "0x";
130 case 2:
131 return "0b";
132 default:
133 return "";
134 }
135 }
136
137 T inner;
138 int base;
139};
140
141template <typename T>
142print_formatted<T> hex(T value) {
143 return print_formatted<T>{value, 16};
144}
145
146template <typename T>
147print_formatted<T> oct(T value) {
148 return print_formatted<T>{value, 8};
149}
150
151template <typename T>
152print_formatted<T> bin(T value) {
153 return print_formatted<T>{value, 2};
154}
155
156// Implementation of 'type_name<T>()'
157
158template <typename T>
159const char* type_name_impl() {
160 return DBG_MACRO_PRETTY_FUNCTION;
161}
162
163template <typename T>
164struct type_tag {};
165
166template <int&... ExplicitArgumentBarrier, typename T>
167std::string get_type_name(type_tag<T>) {
168 namespace pf = pretty_function;
169
170 std::string type = type_name_impl<T>();
171 return type.substr(pf::PREFIX_LENGTH,
172 type.size() - pf::PREFIX_LENGTH - pf::SUFFIX_LENGTH);
173}
174
175template <typename T>
176std::string type_name() {
177 if (std::is_volatile<T>::value) {
178 if (std::is_pointer<T>::value) {
179 return type_name<typename std::remove_volatile<T>::type>() + " volatile";
180 } else {
181 return "volatile " + type_name<typename std::remove_volatile<T>::type>();
182 }
183 }
184 if (std::is_const<T>::value) {
185 if (std::is_pointer<T>::value) {
186 return type_name<typename std::remove_const<T>::type>() + " const";
187 } else {
188 return "const " + type_name<typename std::remove_const<T>::type>();
189 }
190 }
191 if (std::is_pointer<T>::value) {
192 return type_name<typename std::remove_pointer<T>::type>() + "*";
193 }
194 if (std::is_lvalue_reference<T>::value) {
195 return type_name<typename std::remove_reference<T>::type>() + "&";
196 }
197 if (std::is_rvalue_reference<T>::value) {
198 return type_name<typename std::remove_reference<T>::type>() + "&&";
199 }
200 return get_type_name(type_tag<T>{});
201}
202
203inline std::string get_type_name(type_tag<short>) {
204 return "short";
205}
206
207inline std::string get_type_name(type_tag<unsigned short>) {
208 return "unsigned short";
209}
210
211inline std::string get_type_name(type_tag<long>) {
212 return "long";
213}
214
215inline std::string get_type_name(type_tag<unsigned long>) {
216 return "unsigned long";
217}
218
219inline std::string get_type_name(type_tag<std::string>) {
220 return "std::string";
221}
222
223template <typename T>
224std::string get_type_name(type_tag<std::vector<T, std::allocator<T>>>) {
225 return "std::vector<" + type_name<T>() + ">";
226}
227
228template <typename T1, typename T2>
229std::string get_type_name(type_tag<std::pair<T1, T2>>) {
230 return "std::pair<" + type_name<T1>() + ", " + type_name<T2>() + ">";
231}
232
233template <typename... T>
234std::string type_list_to_string() {
235 std::string result;
236 auto unused = {(result += type_name<T>() + ", ", 0)..., 0};
237 static_cast<void>(unused);
238
239 if (sizeof...(T) > 0) {
240 result.pop_back();
241 result.pop_back();
242 }
243 return result;
244}
245
246template <typename... T>
247std::string get_type_name(type_tag<std::tuple<T...>>) {
248 return "std::tuple<" + type_list_to_string<T...>() + ">";
249}
250
251template <typename T>
252inline std::string get_type_name(type_tag<print_formatted<T>>) {
253 return type_name<T>();
254}
255
256// Implementation of 'is_detected' to specialize for container-like types
257
258namespace detail_detector {
259
260struct nonesuch {
261 nonesuch() = delete;
262 ~nonesuch() = delete;
263 nonesuch(nonesuch const&) = delete;
264 void operator=(nonesuch const&) = delete;
265};
266
267template <typename...>
268using void_t = void;
269
270template <class Default,
271 class AlwaysVoid,
272 template <class...>
273 class Op,
274 class... Args>
275struct detector {
276 using value_t = std::false_type;
277 using type = Default;
278};
279
280template <class Default, template <class...> class Op, class... Args>
281struct detector<Default, void_t<Op<Args...>>, Op, Args...> {
282 using value_t = std::true_type;
283 using type = Op<Args...>;
284};
285
286} // namespace detail_detector
287
288template <template <class...> class Op, class... Args>
289using is_detected = typename detail_detector::
290 detector<detail_detector::nonesuch, void, Op, Args...>::value_t;
291
292namespace detail {
293
294namespace {
295using std::begin;
296using std::end;
297#if DBG_MACRO_CXX_STANDARD < 17
298template <typename T>
299constexpr auto size(const T& c) -> decltype(c.size()) {
300 return c.size();
301}
302template <typename T, std::size_t N>
303constexpr std::size_t size(const T (&)[N]) {
304 return N;
305}
306#else
307using std::size;
308#endif
309} // namespace
310
311template <typename T>
312using detect_begin_t = decltype(detail::begin(std::declval<T>()));
313
314template <typename T>
315using detect_end_t = decltype(detail::end(std::declval<T>()));
316
317template <typename T>
318using detect_size_t = decltype(detail::size(std::declval<T>()));
319
320template <typename T>
321struct is_container {
322 static constexpr bool value =
323 is_detected<detect_begin_t, T>::value &&
324 is_detected<detect_end_t, T>::value &&
325 is_detected<detect_size_t, T>::value &&
326 !std::is_same<std::string,
327 typename std::remove_cv<
328 typename std::remove_reference<T>::type>::type>::value;
329};
330
331template <typename T>
332using ostream_operator_t =
333 decltype(std::declval<std::ostream&>() << std::declval<T>());
334
335template <typename T>
336struct has_ostream_operator : is_detected<ostream_operator_t, T> {};
337
338} // namespace detail
339
340// Helper to dbg(…)-print types
341template <typename T>
342struct print_type {};
343
344template <typename T>
345print_type<T> type() {
346 return print_type<T>{};
347}
348
349// Specializations of "pretty_print"
350
351template <typename T>
352inline void pretty_print(std::ostream& stream, const T& value, std::true_type) {
353 stream << value;
354}
355
356template <typename T>
357inline void pretty_print(std::ostream&, const T&, std::false_type) {
358 static_assert(detail::has_ostream_operator<const T&>::value,
359 "Type does not support the << ostream operator");
360}
361
362template <typename T>
363inline typename std::enable_if<!detail::is_container<const T&>::value &&
364 !std::is_enum<T>::value,
365 bool>::type
366pretty_print(std::ostream& stream, const T& value) {
367 pretty_print(stream, value,
368 typename detail::has_ostream_operator<const T&>::type{});
369 return true;
370}
371
372inline bool pretty_print(std::ostream& stream, const bool& value) {
373 stream << std::boolalpha << value;
374 return true;
375}
376
377inline bool pretty_print(std::ostream& stream, const char& value) {
378 const bool printable = value >= 0x20 && value <= 0x7E;
379
380 if (printable) {
381 stream << "'" << value << "'";
382 } else {
383 stream << "'\\x" << std::setw(2) << std::setfill('0') << std::hex
384 << std::uppercase << (0xFF & value) << "'";
385 }
386 return true;
387}
388
389template <typename P>
390inline bool pretty_print(std::ostream& stream, P* const& value) {
391 if (value == nullptr) {
392 stream << "nullptr";
393 } else {
394 stream << value;
395 }
396 return true;
397}
398
399template <typename T, typename Deleter>
400inline bool pretty_print(std::ostream& stream,
401 std::unique_ptr<T, Deleter>& value) {
402 pretty_print(stream, value.get());
403 return true;
404}
405
406template <typename T>
407inline bool pretty_print(std::ostream& stream, std::shared_ptr<T>& value) {
408 pretty_print(stream, value.get());
409 stream << " (use_count = " << value.use_count() << ")";
410
411 return true;
412}
413
414template <size_t N>
415inline bool pretty_print(std::ostream& stream, const char (&value)[N]) {
416 stream << value;
417 return false;
418}
419
420template <>
421inline bool pretty_print(std::ostream& stream, const char* const& value) {
422 stream << '"' << value << '"';
423 return true;
424}
425
426template <size_t Idx>
427struct pretty_print_tuple {
428 template <typename... Ts>
429 static void print(std::ostream& stream, const std::tuple<Ts...>& tuple) {
430 pretty_print_tuple<Idx - 1>::print(stream, tuple);
431 stream << ", ";
432 pretty_print(stream, std::get<Idx>(tuple));
433 }
434};
435
436template <>
437struct pretty_print_tuple<0> {
438 template <typename... Ts>
439 static void print(std::ostream& stream, const std::tuple<Ts...>& tuple) {
440 pretty_print(stream, std::get<0>(tuple));
441 }
442};
443
444template <typename... Ts>
445inline bool pretty_print(std::ostream& stream, const std::tuple<Ts...>& value) {
446 stream << "{";
447 pretty_print_tuple<sizeof...(Ts) - 1>::print(stream, value);
448 stream << "}";
449
450 return true;
451}
452
453template <>
454inline bool pretty_print(std::ostream& stream, const std::tuple<>&) {
455 stream << "{}";
456
457 return true;
458}
459
460template <>
461inline bool pretty_print(std::ostream& stream, const time&) {
462 using namespace std::chrono;
463
464 const auto now = system_clock::now();
465 const auto us =
466 duration_cast<microseconds>(now.time_since_epoch()).count() % 1000000;
467 const auto hms = system_clock::to_time_t(now);
468 const std::tm* tm = std::localtime(&hms);
469 stream << "current time = " << std::put_time(tm, "%H:%M:%S") << '.'
470 << std::setw(6) << std::setfill('0') << us;
471
472 return false;
473}
474
475// Converts decimal integer to binary string
476template <typename T>
477std::string decimalToBinary(T n) {
478 const size_t length = 8 * sizeof(T);
479 std::string toRet;
480 toRet.resize(length);
481
482 for (size_t i = 0; i < length; ++i) {
483 const auto bit_at_index_i = (n >> i) & 1;
484 toRet[length - 1 - i] = bit_at_index_i + '0';
485 }
486
487 return toRet;
488}
489
490template <typename T>
491inline bool pretty_print(std::ostream& stream,
492 const print_formatted<T>& value) {
493 if (value.inner < 0) {
494 stream << "-";
495 }
496 stream << value.prefix();
497
498 // Print using setbase
499 if (value.base != 2) {
500 stream << std::setw(sizeof(T)) << std::setfill('0')
501 << std::setbase(value.base) << std::uppercase;
502
503 if (value.inner >= 0) {
504 // The '+' sign makes sure that a uint_8 is printed as a number
505 stream << +value.inner;
506 } else {
507 using unsigned_type = typename std::make_unsigned<T>::type;
508 stream << +(static_cast<unsigned_type>(-(value.inner + 1)) + 1);
509 }
510 } else {
511 // Print for binary
512 if (value.inner >= 0) {
513 stream << decimalToBinary(value.inner);
514 } else {
515 using unsigned_type = typename std::make_unsigned<T>::type;
516 stream << decimalToBinary<unsigned_type>(
517 static_cast<unsigned_type>(-(value.inner + 1)) + 1);
518 }
519 }
520
521 return true;
522}
523
524template <typename T>
525inline bool pretty_print(std::ostream& stream, const print_type<T>&) {
526 stream << type_name<T>();
527
528 stream << " [sizeof: " << sizeof(T) << " byte, ";
529
530 stream << "trivial: ";
531 if (std::is_trivial<T>::value) {
532 stream << "yes";
533 } else {
534 stream << "no";
535 }
536
537 stream << ", standard layout: ";
538 if (std::is_standard_layout<T>::value) {
539 stream << "yes";
540 } else {
541 stream << "no";
542 }
543 stream << "]";
544
545 return false;
546}
547
548template <typename Container>
549inline typename std::enable_if<detail::is_container<const Container&>::value,
550 bool>::type
551pretty_print(std::ostream& stream, const Container& value) {
552 stream << "{";
553 const size_t size = detail::size(value);
554 const size_t n = std::min(size_t{10}, size);
555 size_t i = 0;
556 using std::begin;
557 using std::end;
558 for (auto it = begin(value); it != end(value) && i < n; ++it, ++i) {
559 pretty_print(stream, *it);
560 if (i != n - 1) {
561 stream << ", ";
562 }
563 }
564
565 if (size > n) {
566 stream << ", ...";
567 stream << " size:" << size;
568 }
569
570 stream << "}";
571 return true;
572}
573
574template <typename Enum>
575inline typename std::enable_if<std::is_enum<Enum>::value, bool>::type
576pretty_print(std::ostream& stream, Enum const& value) {
577 using UnderlyingType = typename std::underlying_type<Enum>::type;
578 stream << static_cast<UnderlyingType>(value);
579
580 return true;
581}
582
583inline bool pretty_print(std::ostream& stream, const std::string& value) {
584 stream << '"' << value << '"';
585 return true;
586}
587
588template <typename T1, typename T2>
589inline bool pretty_print(std::ostream& stream, const std::pair<T1, T2>& value) {
590 stream << "{";
591 pretty_print(stream, value.first);
592 stream << ", ";
593 pretty_print(stream, value.second);
594 stream << "}";
595 return true;
596}
597
598#if DBG_MACRO_CXX_STANDARD >= 17
599
600template <typename T>
601inline bool pretty_print(std::ostream& stream, const std::optional<T>& value) {
602 if (value) {
603 stream << '{';
604 pretty_print(stream, *value);
605 stream << '}';
606 } else {
607 stream << "nullopt";
608 }
609
610 return true;
611}
612
613template <typename... Ts>
614inline bool pretty_print(std::ostream& stream,
615 const std::variant<Ts...>& value) {
616 stream << "{";
617 std::visit([&stream](auto&& arg) { pretty_print(stream, arg); }, value);
618 stream << "}";
619
620 return true;
621}
622
623#endif
624
625class DebugOutput {
626 public:
627 DebugOutput(const char* filepath,
628 int line,
629 const char* function_name,
630 const char* expression)
631 : m_use_colorized_output(isColorizedOutputEnabled()),
632 m_filepath(filepath),
633 m_line(line),
634 m_function_name(function_name),
635 m_expression(expression) {
636 const std::size_t path_length = m_filepath.length();
637 if (path_length > MAX_PATH_LENGTH) {
638 m_filepath = ".." + m_filepath.substr(path_length - MAX_PATH_LENGTH,
639 MAX_PATH_LENGTH);
640 }
641 }
642
643 template <typename T>
644 T&& print(const std::string& type, T&& value) const {
645 const T& ref = value;
646 std::stringstream stream_value;
647 const bool print_expr_and_type = pretty_print(stream_value, ref);
648
649 std::stringstream output;
650 output << ansi(ANSI_DEBUG) << "[" << m_filepath << ":" << m_line << " ("
651 << m_function_name << ")] " << ansi(ANSI_RESET);
652 if (print_expr_and_type) {
653 output << ansi(ANSI_EXPRESSION) << m_expression << ansi(ANSI_RESET)
654 << " = ";
655 }
656 output << ansi(ANSI_VALUE) << stream_value.str() << ansi(ANSI_RESET);
657 if (print_expr_and_type) {
658 output << " (" << ansi(ANSI_TYPE) << type << ansi(ANSI_RESET) << ")";
659 }
660 output << std::endl;
661 std::cerr << output.str();
662
663 return std::forward<T>(value);
664 }
665
666 private:
667 const char* ansi(const char* code) const {
668 if (m_use_colorized_output) {
669 return code;
670 } else {
671 return ANSI_EMPTY;
672 }
673 }
674
675 const bool m_use_colorized_output;
676
677 std::string m_filepath;
678 const int m_line;
679 const std::string m_function_name;
680 const std::string m_expression;
681
682 static constexpr std::size_t MAX_PATH_LENGTH = 20;
683
684 static constexpr const char* const ANSI_EMPTY = "";
685 static constexpr const char* const ANSI_DEBUG = "\x1b[02m";
686 static constexpr const char* const ANSI_EXPRESSION = "\x1b[36m";
687 static constexpr const char* const ANSI_VALUE = "\x1b[01m";
688 static constexpr const char* const ANSI_TYPE = "\x1b[32m";
689 static constexpr const char* const ANSI_RESET = "\x1b[0m";
690};
691
692// Identity function to suppress "-Wunused-value" warnings in DBG_MACRO_DISABLE
693// mode
694template <typename T>
695T&& identity(T&& t) {
696 return std::forward<T>(t);
697}
698
699} // namespace dbg
700
701#ifndef DBG_MACRO_DISABLE
702// We use a variadic macro to support commas inside expressions (e.g.
703// initializer lists):
704#define dbg(...) \
705 dbg::DebugOutput(__FILE__, __LINE__, __func__, #__VA_ARGS__) \
706 .print(dbg::type_name<decltype(__VA_ARGS__)>(), (__VA_ARGS__))
707#else
708#define dbg(...) dbg::identity(__VA_ARGS__)
709#endif // DBG_MACRO_DISABLE
710
711#endif // DBG_MACRO_DBG_H
lib/libc/mingw/lib32/user32.def created+998
......@@ -0,0 +1,998 @@
1LIBRARY USER32.dll
2EXPORTS
3;ord_1500@16 @1500
4;ord_1501@4 @1501
5;ord_1502@12 @1502
6ActivateKeyboardLayout@8
7AddClipboardFormatListener@4
8AdjustWindowRect@12
9AdjustWindowRectEx@16
10AlignRects@16
11AllowForegroundActivation@0
12AllowSetForegroundWindow@4
13AnimateWindow@12
14AnyPopup@0
15AppendMenuA@16
16AppendMenuW@16
17ArrangeIconicWindows@4
18AttachThreadInput@12
19BeginDeferWindowPos@4
20BeginPaint@8
21BlockInput@4
22BringWindowToTop@4
23BroadcastSystemMessage@20
24BroadcastSystemMessageA@20
25BroadcastSystemMessageExA@24
26BroadcastSystemMessageExW@24
27BroadcastSystemMessageW@20
28BuildReasonArray@12
29CalcChildScroll@8
30CalcMenuBar@20
31CalculatePopupWindowPosition@20
32CallMsgFilter@8
33CallMsgFilterA@8
34CallMsgFilterW@8
35CallNextHookEx@16
36CallWindowProcA@20
37CallWindowProcW@20
38CancelShutdown@0
39CascadeChildWindows@8
40CascadeWindows@20
41ChangeClipboardChain@8
42ChangeDisplaySettingsA@8
43ChangeDisplaySettingsExA@20
44ChangeDisplaySettingsExW@20
45ChangeDisplaySettingsW@8
46ChangeMenuA@20
47ChangeMenuW@20
48ChangeWindowMessageFilter@8
49ChangeWindowMessageFilterEx@16
50CharLowerA@4
51CharLowerBuffA@8
52CharLowerBuffW@8
53CharLowerW@4
54CharNextA@4
55;ord_1550@12 @1550
56;ord_1551@8 @1551
57;ord_1552@8 @1552
58;ord_1553@12 @1553
59;ord_1554@8 @1554
60;ord_1555@16 @1555
61;ord_1556@4 @1556
62CharNextExA@12
63CharNextW@4
64CharPrevA@8
65CharPrevExA@16
66CharPrevW@8
67CharToOemA@8
68CharToOemBuffA@12
69CharToOemBuffW@12
70CharToOemW@8
71CharUpperA@4
72CharUpperBuffA@8
73CharUpperBuffW@8
74CharUpperW@4
75CheckDesktopByThreadId@4
76CheckDBCSEnabledExt@0
77CheckDlgButton@12
78CheckMenuItem@12
79CheckMenuRadioItem@20
80CheckProcessForClipboardAccess@8
81CheckProcessSession@4
82CheckRadioButton@16
83CheckWindowThreadDesktop@8
84ChildWindowFromPoint@12
85ChildWindowFromPointEx@16
86CliImmSetHotKey@16
87ClientThreadSetup@0
88ClientToScreen@8
89ClipCursor@4
90CloseClipboard@0
91CloseDesktop@4
92CloseGestureInfoHandle@4
93CloseTouchInputHandle@4
94CloseWindow@4
95CloseWindowStation@4
96ConsoleControl@12
97ControlMagnification@8
98CopyAcceleratorTableA@12
99CopyAcceleratorTableW@12
100CopyIcon@4
101CopyImage@20
102CopyRect@8
103CountClipboardFormats@0
104CreateAcceleratorTableA@8
105CreateAcceleratorTableW@8
106CreateCaret@16
107CreateCursor@28
108CreateDCompositionHwndTarget@12
109CreateDesktopA@24
110CreateDesktopExA@32
111CreateDesktopExW@32
112CreateDesktopW@24
113CreateDialogIndirectParamA@20
114CreateDialogIndirectParamAorW@24
115CreateDialogIndirectParamW@20
116CreateDialogParamA@20
117CreateDialogParamW@20
118CreateIcon@28
119CreateIconFromResource@16
120CreateIconFromResourceEx@28
121CreateIconIndirect@4
122CreateMDIWindowA@40
123CreateMDIWindowW@40
124CreateMenu@0
125CreatePopupMenu@0
126CreateSystemThreads@16 ; ReactOS has the @8 variant
127CreateWindowExA@48
128CreateWindowExW@48
129CreateWindowInBand@52
130CreateWindowIndirect@4
131CreateWindowStationA@16
132CreateWindowStationW@16
133CsrBroadcastSystemMessageExW@24
134CtxInitUser32@0
135DdeAbandonTransaction@12
136DdeAccessData@8
137DdeAddData@16
138DdeClientTransaction@32
139DdeCmpStringHandles@8
140DdeConnect@16
141DdeConnectList@20
142DdeCreateDataHandle@28
143DdeCreateStringHandleA@12
144DdeCreateStringHandleW@12
145DdeDisconnect@4
146DdeDisconnectList@4
147DdeEnableCallback@12
148DdeFreeDataHandle@4
149DdeFreeStringHandle@8
150DdeGetData@16
151DdeGetLastError@4
152DdeGetQualityOfService@12
153DdeImpersonateClient@4
154DdeInitializeA@16
155DdeInitializeW@16
156DdeKeepStringHandle@8
157DdeNameService@16
158DdePostAdvise@12
159DdeQueryConvInfo@12
160DdeQueryNextServer@8
161DdeQueryStringA@20
162DdeQueryStringW@20
163DdeReconnect@4
164DdeSetQualityOfService@12
165DdeSetUserHandle@12
166DdeUnaccessData@4
167DdeUninitialize@4
168DefDlgProcA@16
169DefDlgProcW@16
170DefFrameProcA@20
171DefFrameProcW@20
172DefMDIChildProcA@16
173DefMDIChildProcW@16
174DefRawInputProc@12
175DefWindowProcA@16
176DefWindowProcW@16
177DeferWindowPos@32
178DeferWindowPosAndBand@36
179DeleteMenu@12
180DeregisterShellHookWindow@4
181DestroyAcceleratorTable@4
182DestroyCaret@0
183DestroyCursor@4
184DestroyDCompositionHwndTarget@8
185DestroyIcon@4
186DestroyMenu@4
187DestroyReasons@4
188DestroyWindow@4
189DeviceEventWorker@24 ; No documentation whatsoever, ReactOS has a stub with @20 - https://www.reactos.org/archives/public/ros-diffs/2011-February/040308.html
190DialogBoxIndirectParamA@20
191DialogBoxIndirectParamAorW@24
192DialogBoxIndirectParamW@20
193DialogBoxParamA@20
194DialogBoxParamW@20
195DisableProcessWindowsGhosting@0
196DispatchMessageA@4
197DispatchMessageW@4
198DisplayConfigGetDeviceInfo@4
199DisplayConfigSetDeviceInfo@4
200DisplayExitWindowsWarnings@4
201DlgDirListA@20
202DlgDirListComboBoxA@20
203DlgDirListComboBoxW@20
204DlgDirListW@20
205DlgDirSelectComboBoxExA@16
206DlgDirSelectComboBoxExW@16
207DlgDirSelectExA@16
208DlgDirSelectExW@16
209DoSoundConnect@0
210DoSoundDisconnect@0
211DragDetect@12
212DragObject@20
213DrawAnimatedRects@16
214DrawCaption@16
215DrawCaptionTempA@28
216DrawCaptionTempW@28
217DrawEdge@16
218DrawFocusRect@8
219DrawFrame@16
220DrawFrameControl@16
221DrawIcon@16
222DrawIconEx@36
223DrawMenuBar@4
224DrawMenuBarTemp@20
225DrawStateA@40
226DrawStateW@40
227DrawTextA@20
228DrawTextExA@24
229DrawTextExW@24
230DrawTextW@20
231DwmGetDxSharedSurface@24
232DwmGetRemoteSessionOcclusionEvent@0
233DwmGetRemoteSessionOcclusionState@0
234DwmLockScreenUpdates@4
235DwmStartRedirection@8 ; Mentioned on http://habrahabr.ru/post/145174/ , enables GDI virtualization (for security purposes)
236DwmStopRedirection@0
237DwmValidateWindow@8
238EditWndProc@16
239EmptyClipboard@0
240EnableMenuItem@12
241EnableMouseInPointer@4
242EnableScrollBar@12
243EnableSessionForMMCSS@4
244EnableWindow@8
245EndDeferWindowPos@4
246EndDeferWindowPosEx@8
247EndDialog@8
248EndMenu@0
249EndPaint@8
250EndTask@12
251EnterReaderModeHelper@4
252EnumChildWindows@12
253EnumClipboardFormats@4
254EnumDesktopWindows@12
255EnumDesktopsA@12
256EnumDesktopsW@12
257EnumDisplayDevicesA@16
258EnumDisplayDevicesW@16
259EnumDisplayMonitors@16
260EnumDisplaySettingsA@12
261EnumDisplaySettingsExA@16
262EnumDisplaySettingsExW@16
263EnumDisplaySettingsW@12
264EnumPropsA@8
265EnumPropsExA@12
266EnumPropsExW@12
267EnumPropsW@8
268EnumThreadWindows@12
269EnumWindowStationsA@8
270EnumWindowStationsW@8
271EnumWindows@8
272EqualRect@8
273EvaluateProximityToPolygon@16
274EvaluateProximityToRect@12
275ExcludeUpdateRgn@8
276ExitWindowsEx@8
277FillRect@12
278FindWindowA@8
279FindWindowExA@16
280FindWindowExW@16
281FindWindowW@8
282FlashWindow@8
283FlashWindowEx@4
284FrameRect@12
285FreeDDElParam@8
286FrostCrashedWindow@8
287GetActiveWindow@0
288GetAltTabInfo@20
289GetAltTabInfoA@20
290GetAltTabInfoW@20
291GetAncestor@8
292GetAppCompatFlags2@4
293GetAppCompatFlags@8 ; ReactOS has @4 version http://doxygen.reactos.org/d9/d71/undocuser_8h_a9b76cdc68c523a061c86a40367049ed2.html
294GetAsyncKeyState@4
295GetAutoRotationState@4
296GetCIMSSM@4
297GetCapture@0
298GetCaretBlinkTime@0
299GetCaretPos@4
300GetClassInfoA@12
301GetClassInfoExA@12
302GetClassInfoExW@12
303GetClassInfoW@12
304GetClassLongA@8
305GetClassLongW@8
306GetClassNameA@12
307GetClassNameW@12
308GetClassWord@8
309GetClientRect@8
310GetClipCursor@4
311GetClipboardAccessToken@8
312GetClipboardData@4
313GetClipboardFormatNameA@12
314GetClipboardFormatNameW@12
315GetClipboardOwner@0
316GetClipboardSequenceNumber@0
317GetClipboardViewer@0
318GetComboBoxInfo@8
319GetCurrentInputMessageSource@4
320GetCursor@0
321GetCursorFrameInfo@20
322GetCursorInfo@4
323GetCursorPos@4
324GetDC@4
325GetDCEx@12
326GetDesktopID@8
327GetDesktopWindow@0
328GetDialogBaseUnits@0
329GetDisplayAutoRotationPreferences@4
330GetDisplayConfigBufferSizes@12
331GetDlgCtrlID@4
332GetDlgItem@8
333GetDlgItemInt@16
334GetDlgItemTextA@16
335GetDlgItemTextW@16
336GetDoubleClickTime@0
337GetDpiForMonitorInternal@16
338GetFocus@0
339GetForegroundWindow@0
340GetGUIThreadInfo@8
341GetGestureConfig@24
342GetGestureExtraArgs@12
343GetGestureInfo@8
344GetGuiResources@8
345GetIconInfo@8
346GetIconInfoExA@8
347GetIconInfoExW@8
348GetInputDesktop@0
349GetInputLocaleInfo@8
350GetInputState@0
351GetInternalWindowPos@12
352GetKBCodePage@0
353GetKeyNameTextA@12
354GetKeyNameTextW@12
355GetKeyState@4
356GetKeyboardLayout@4
357GetKeyboardLayoutList@8
358GetKeyboardLayoutNameA@4
359GetKeyboardLayoutNameW@4
360GetKeyboardState@4
361GetKeyboardType@4
362GetLastActivePopup@4
363GetLastInputInfo@4
364GetLayeredWindowAttributes@16
365GetListBoxInfo@4
366GetMagnificationDesktopColorEffect@4
367GetMagnificationDesktopMagnification@12
368GetMagnificationLensCtxInformation@16
369GetMenu@4
370GetMenuBarInfo@16
371GetMenuCheckMarkDimensions@0
372GetMenuContextHelpId@4
373GetMenuDefaultItem@12
374GetMenuInfo@8
375GetMenuItemCount@4
376GetMenuItemID@8
377GetMenuItemInfoA@16
378GetMenuItemInfoW@16
379GetMenuItemRect@16
380GetMenuState@12
381GetMenuStringA@20
382GetMenuStringW@20
383GetMessageA@16
384GetMessageExtraInfo@0
385GetMessagePos@0
386GetMessageTime@0
387GetMessageW@16
388GetMonitorInfoA@8
389GetMonitorInfoW@8
390GetMouseMovePointsEx@20
391GetNextDlgGroupItem@12
392GetNextDlgTabItem@12
393GetOpenClipboardWindow@0
394GetParent@4
395GetPhysicalCursorPos@4
396GetPointerCursorId@8
397GetPointerDevice@8
398GetPointerDeviceCursors@12
399GetPointerDeviceProperties@12
400GetPointerDeviceRects@12
401GetPointerDevices@8
402GetPointerFrameInfo@12
403GetPointerFrameInfoHistory@16
404GetPointerFramePenInfo@12
405GetPointerFramePenInfoHistory@16
406GetPointerFrameTouchInfo@12
407GetPointerFrameTouchInfoHistory@16
408GetPointerInfo@8
409GetPointerInfoHistory@12
410GetPointerInputTransform@12
411GetPointerPenInfo@8
412GetPointerPenInfoHistory@12
413GetPointerTouchInfo@8
414GetPointerTouchInfoHistory@12
415GetPointerType@8
416GetPriorityClipboardFormat@8
417GetProcessDefaultLayout@4
418GetProcessDpiAwarenessInternal@8
419GetProcessWindowStation@0
420GetProgmanWindow@0
421GetPropA@8
422GetPropW@8
423GetQueueStatus@4
424GetRawInputBuffer@12
425GetRawInputData@20
426GetRawInputDeviceInfoA@16
427GetRawInputDeviceInfoW@16
428GetRawInputDeviceList@12
429GetRawPointerDeviceData@20
430GetReasonTitleFromReasonCode@12
431GetRegisteredRawInputDevices@12
432GetQueueStatus@4
433GetScrollBarInfo@12
434GetScrollInfo@12
435GetScrollPos@8
436GetScrollRange@16
437GetSendMessageReceiver@4
438GetShellWindow@0
439GetSubMenu@8
440GetSysColor@4
441GetSysColorBrush@4
442GetSystemMenu@8
443GetSystemMetrics@4
444GetTabbedTextExtentA@20
445GetTabbedTextExtentW@20
446GetTaskmanWindow@0
447GetThreadDesktop@4
448GetTitleBarInfo@8
449GetTopLevelWindow@4
450GetTopWindow@4
451GetTouchInputInfo@16
452GetUnpredictedMessagePos@0
453GetUpdateRect@12
454GetUpdateRgn@12
455GetUpdatedClipboardFormats@12
456GetUserObjectInformationA@20
457GetUserObjectInformationW@20
458GetUserObjectSecurity@20
459GetWinStationInfo@4
460GetWindow@8
461GetWindowBand@8
462GetWindowCompositionAttribute@8
463GetWindowCompositionInfo@8
464GetWindowContextHelpId@4
465GetWindowDC@4
466GetWindowDisplayAffinity@8
467GetWindowFeedbackSetting@20
468GetWindowInfo@8
469GetWindowLongA@8
470GetWindowLongW@8
471GetWindowMinimizeRect@8
472GetWindowModuleFileName@12
473GetWindowModuleFileNameA@12
474GetWindowModuleFileNameW@12
475GetWindowPlacement@8
476GetWindowRect@8
477GetWindowRgn@8
478GetWindowRgnBox@8
479GetWindowRgnEx@12
480GetWindowTextA@12
481GetWindowTextLengthA@4
482GetWindowTextLengthW@4
483GetWindowTextW@12
484GetWindowThreadProcessId@8
485GetWindowWord@8
486GhostWindowFromHungWindow@4
487GrayStringA@36
488GrayStringW@36
489HideCaret@4
490HiliteMenuItem@16
491HungWindowFromGhostWindow@4
492IMPGetIMEA@8
493IMPGetIMEW@8
494IMPQueryIMEA@4
495IMPQueryIMEW@4
496IMPSetIMEA@8
497IMPSetIMEW@8
498ImpersonateDdeClientWindow@8
499InSendMessage@0
500InSendMessageEx@4
501InflateRect@12
502InitializeLpkHooks@4
503InitializeWin32EntryTable@4
504InitializeTouchInjection@8
505InjectTouchInput@8
506InsertMenuA@20
507InsertMenuItemA@16
508InsertMenuItemW@16
509InsertMenuW@20
510InternalGetWindowIcon@8
511;ord_2001@4 @2001
512;ord_2002@4 @2002
513InternalGetWindowText@12
514IntersectRect@12
515;ord_2005@4 @2005
516InvalidateRect@12
517InvalidateRgn@12
518InvertRect@8
519IsCharAlphaA@4
520;ord_2010@16 @2010
521IsCharAlphaNumericA@4
522IsCharAlphaNumericW@4
523IsCharAlphaW@4
524IsCharLowerA@4
525IsCharLowerW@4
526IsCharUpperA@4
527IsCharUpperW@4
528IsChild@8
529IsClipboardFormatAvailable@4
530IsDialogMessage@8
531IsDialogMessageA@8
532IsDialogMessageW@8
533IsDlgButtonChecked@8
534IsGUIThread@4
535IsHungAppWindow@4
536IsIconic@4
537IsImmersiveProcess@4
538IsInDesktopWindowBand@4
539IsMenu@4
540IsProcess16Bit@0
541IsMouseInPointerEnabled@0
542IsProcessDPIAware@0
543IsQueueAttached@0
544IsRectEmpty@4
545IsSETEnabled@0
546IsServerSideWindow@4
547IsThreadDesktopComposited@0
548IsTopLevelWindow@4
549IsTouchWindow@8
550IsWinEventHookInstalled@4
551IsWindow@4
552IsWindowEnabled@4
553IsWindowInDestroy@4
554IsWindowRedirectedForPrint@4
555IsWindowUnicode@4
556IsWindowVisible@4
557IsWow64Message@0
558IsZoomed@4
559KillSystemTimer@8
560KillTimer@8
561LoadAcceleratorsA@8
562LoadAcceleratorsW@8
563LoadBitmapA@8
564LoadBitmapW@8
565LoadCursorA@8
566LoadCursorFromFileA@4
567LoadCursorFromFileW@4
568;ord_2000@0 @2000
569;ord_2001@4 @2001
570;ord_2002@4 @2002
571LoadCursorW@8
572LoadIconA@8
573;ord_2005@4 @2005
574LoadIconW@8
575LoadImageA@24
576LoadImageW@24
577LoadKeyboardLayoutA@8
578LoadKeyboardLayoutEx@12
579LoadKeyboardLayoutW@8
580LoadLocalFonts@0
581LoadMenuA@8
582LoadMenuIndirectA@4
583LoadMenuIndirectW@4
584LoadMenuW@8
585LoadRemoteFonts@0
586LoadStringA@16
587LoadStringW@16
588LockSetForegroundWindow@4
589LockWindowStation@4
590LockWindowUpdate@4
591LockWorkStation@0
592LogicalToPhysicalPoint@8
593LogicalToPhysicalPointForPerMonitorDPI@8
594LookupIconIdFromDirectory@8
595LookupIconIdFromDirectoryEx@20
596MBToWCSEx@24
597MBToWCSExt@20
598MB_GetString@4
599MapDialogRect@8
600MapVirtualKeyA@8
601MapVirtualKeyExA@12
602MapVirtualKeyExW@12
603MapVirtualKeyW@8
604MapWindowPoints@16
605MenuItemFromPoint@16
606MenuWindowProcA@20
607MenuWindowProcW@20
608MessageBeep@4
609MessageBoxA@16
610MessageBoxExA@20
611MessageBoxExW@20
612MessageBoxIndirectA@4
613MessageBoxIndirectW@4
614MessageBoxTimeoutA@24
615MessageBoxTimeoutW@24
616MessageBoxW@16
617ModifyMenuA@20
618ModifyMenuW@20
619MonitorFromPoint@12
620MonitorFromRect@8
621MonitorFromWindow@8
622MoveWindow@24
623MsgWaitForMultipleObjects@20
624MsgWaitForMultipleObjectsEx@20
625NotifyOverlayWindow@8
626NotifyWinEvent@16
627OemKeyScan@4
628OemToCharA@8
629OemToCharBuffA@12
630OemToCharBuffW@12
631OemToCharW@8
632OffsetRect@12
633OpenClipboard@4
634OpenDesktopA@16
635OpenDesktopW@16
636OpenIcon@4
637OpenInputDesktop@12
638OpenThreadDesktop@16
639OpenWindowStationA@12
640OpenWindowStationW@12
641PackDDElParam@12
642PackTouchHitTestingProximityEvaluation@8
643PaintDesktop@4
644PaintMenuBar@24
645PaintMonitor@12
646PeekMessageA@20
647PeekMessageW@20
648PhysicalToLogicalPoint@8
649PhysicalToLogicalPointForPerMonitorDPI@8
650PostMessageA@16
651PostMessageW@16
652PostQuitMessage@4
653PostThreadMessageA@16
654PostThreadMessageW@16
655PrintWindow@12
656PrivateExtractIconExA@20
657PrivateExtractIconExW@20
658PrivateExtractIconsA@32
659PrivateExtractIconsW@32
660PrivateSetDbgTag@8
661PrivateSetRipFlags@8
662PrivateRegisterICSProc@4
663PtInRect@12
664QueryBSDRWindow@0
665QueryDisplayConfig@24
666QuerySendMessage@4
667QueryUserCounters@20
668RealChildWindowFromPoint@12
669RealGetWindowClass@12
670RealGetWindowClassA@12
671RealGetWindowClassW@12
672ReasonCodeNeedsBugID@4
673ReasonCodeNeedsComment@4
674RecordShutdownReason@4
675RedrawWindow@16
676RegisterBSDRWindow@8
677RegisterClassA@4
678RegisterClassExA@4
679RegisterClassExW@4
680RegisterClassW@4
681RegisterClipboardFormatA@4
682RegisterClipboardFormatW@4
683RegisterDeviceNotificationA@12
684RegisterDeviceNotificationW@12
685RegisterErrorReportingDialog@8
686RegisterFrostWindow@8
687RegisterGhostWindow@8
688RegisterHotKey@16
689RegisterPowerSettingNotification@12
690RegisterLogonProcess@8
691RegisterMessagePumpHook@4
692RegisterPointerDeviceNotifications@8
693RegisterPointerInputTarget@8
694RegisterPowerSettingNotification@12
695RegisterRawInputDevices@12
696RegisterServicesProcess@4
697RegisterSessionPort@4 ; Undocumented, rumored to be related to ALPC - http://blogs.msdn.com/b/ntdebugging/archive/2007/07/26/lpc-local-procedure-calls-part-1-architecture.aspx
698RegisterShellHookWindow@4
699RegisterSuspendResumeNotification@8
700RegisterSystemThread@8
701RegisterTasklist@4
702RegisterTouchHitTestingWindow@8
703RegisterTouchWindow@8
704RegisterUserApiHook@4 ; Prototype changed in 2003 - https://www.reactos.org/wiki/Techwiki:RegisterUserApiHook
705RegisterWindowMessageA@4
706RegisterWindowMessageW@4
707ReleaseCapture@0
708ReleaseDC@8
709RemoveClipboardFormatListener@4
710RemoveMenu@12
711RemovePropA@8
712RemovePropW@8
713ReplyMessage@4
714ResolveDesktopForWOW@4
715ReuseDDElParam@20
716ScreenToClient@8
717ScrollChildren@12
718ScrollDC@28
719ScrollWindow@20
720ScrollWindowEx@32
721SendDlgItemMessageA@20
722SendDlgItemMessageW@20
723SendIMEMessageExA@8
724SendIMEMessageExW@8
725SendInput@12
726SendMessageA@16
727SendMessageCallbackA@24
728SendMessageCallbackW@24
729SendMessageTimeoutA@28
730SendMessageTimeoutW@28
731SendMessageW@16
732SendNotifyMessageA@16
733SendNotifyMessageW@16
734SetActiveWindow@4
735SetCapture@4
736SetCaretBlinkTime@4
737SetCaretPos@8
738SetClassLongA@12
739SetClassLongW@12
740SetClassWord@12
741SetClipboardData@8
742SetClipboardViewer@4
743SetConsoleReserveKeys@8
744SetCoalescableTimer@20
745SetCursor@4
746SetCursorContents@8
747SetCursorPos@8
748SetDebugErrorLevel@4
749SetDeskWallpaper@4
750SetDisplayAutoRotationPreferences@4
751SetDisplayConfig@20
752SetDlgItemInt@16
753SetDlgItemTextA@12
754SetDlgItemTextW@12
755SetDoubleClickTime@4
756SetFocus@4
757SetForegroundWindow@4
758SetGestureConfig@20
759SetImmersiveBackgroundWindow@4
760SetInternalWindowPos@16
761SetKeyboardState@4
762SetLastErrorEx@8
763SetLayeredWindowAttributes@16
764SetLogonNotifyWindow@4
765SetMagnificationDesktopColorEffect@4
766SetMagnificationDesktopMagnification@16
767SetMagnificationLensCtxInformation@16
768SetMenu@8
769SetMenuContextHelpId@8
770SetMenuDefaultItem@12
771SetMenuInfo@8
772SetMenuItemBitmaps@20
773SetMenuItemInfoA@16
774SetMenuItemInfoW@16
775SetMessageExtraInfo@4
776SetMessageQueue@4
777SetMirrorRendering@8
778SetParent@8
779SetPhysicalCursorPos@8
780SetProcessDPIAware@0
781SetProcessDefaultLayout@4
782SetProcessDpiAwarenessInternal@4
783SetProcessRestrictionExemption@4
784SetProcessWindowStation@4
785SetProgmanWindow@4
786SetPropA@12
787SetPropW@12
788SetRect@20
789SetRectEmpty@4
790SetScrollInfo@16
791SetScrollPos@16
792SetScrollRange@20
793SetShellWindow@4
794SetShellWindowEx@8
795SetSysColors@12
796SetSysColorsTemp@12
797SetSystemCursor@8
798SetSystemMenu@8
799SetSystemTimer@16
800SetTaskmanWindow@4
801SetThreadDesktop@4
802SetThreadInputBlocked@8
803SetTimer@16
804SetUserObjectInformationA@16
805SetUserObjectInformationW@16
806SetUserObjectSecurity@12
807SetWinEventHook@28
808SetWindowBand@12
809SetWindowCompositionAttribute@8
810SetWindowCompositionTransition@28
811SetWindowContextHelpId@8
812SetWindowDisplayAffinity@8
813SetWindowFeedbackSetting@20
814SetWindowLongA@12
815SetWindowLongW@12
816SetWindowPlacement@8
817SetWindowPos@28
818SetWindowRgn@12
819SetWindowRgnEx@12
820SetWindowStationUser@16
821SetWindowTextA@8
822SetWindowTextW@8
823SetWindowWord@12
824SetWindowsHookA@8
825SetWindowsHookExA@16
826SetWindowsHookExW@16
827SetWindowsHookW@8
828SfmDxBindSwapChain@12
829SfmDxGetSwapChainStats@8
830SfmDxOpenSwapChain@16
831SfmDxQuerySwapChainBindingStatus@12
832SfmDxReleaseSwapChain@8
833SfmDxReportPendingBindingsToDwm@0
834SfmDxSetSwapChainBindingStatus@8
835SfmDxSetSwapChainStats@8
836ShowCaret@4
837ShowCursor@4
838ShowOwnedPopups@8
839ShowScrollBar@12
840ShowStartGlass@4
841ShowSystemCursor@4
842ShowWindow@8
843ShowWindowAsync@8
844ShutdownBlockReasonCreate@8
845ShutdownBlockReasonDestroy@4
846ShutdownBlockReasonQuery@12
847SignalRedirectionStartComplete@0
848SkipPointerFrameMessages@4
849SoftModalMessageBox@4
850SoundSentry@0
851SubtractRect@12
852SwapMouseButton@4
853SwitchDesktop@4
854SwitchDesktopWithFade@12 ; Same as SwithDesktop(), only with fade (done at log-in), only usable by winlogon - http://blog.airesoft.co.uk/2010/08/things-microsoft-can-do-that-you-cant/
855SwitchToThisWindow@8
856SystemParametersInfoA@16
857SystemParametersInfoW@16
858TabbedTextOutA@32
859TabbedTextOutW@32
860TileChildWindows@8
861TileWindows@20
862ToAscii@20
863ToAsciiEx@24
864ToUnicode@24
865ToUnicodeEx@28
866TrackMouseEvent@4
867TrackPopupMenu@28
868TrackPopupMenuEx@24
869TranslateAccelerator@12
870TranslateAcceleratorA@12
871TranslateAcceleratorW@12
872TranslateMDISysAccel@8
873TranslateMessage@4
874TranslateMessageEx@8
875UnhookWinEvent@4
876UnhookWindowsHook@8
877UnhookWindowsHookEx@4
878UnionRect@12
879UnloadKeyboardLayout@4
880UnlockWindowStation@4
881UnpackDDElParam@16
882UnregisterClassA@8
883UnregisterClassW@8
884UnregisterDeviceNotification@4
885UnregisterHotKey@8
886UnregisterMessagePumpHook@0
887UnregisterPointerInputTarget@8
888UnregisterPowerSettingNotification@4
889UnregisterSessionPort@0
890UnregisterSuspendResumeNotification@4
891UnregisterTouchWindow@4
892UnregisterUserApiHook@0
893UpdateDefaultDesktopThumbnail@20
894UpdateLayeredWindow@36
895UpdateLayeredWindowIndirect@8
896UpdatePerUserSystemParameters@4 ; Undocumented, seems to apply certain registry settings to desktop, etc. ReactOS has @8 version - http://doxygen.reactos.org/d0/d92/win32ss_2user_2user32_2misc_2misc_8c_a1ff565f0af6bac6dce604f9f4473fe79.html ; @4 is rumored to be without the first DWORD
897UpdateWindow@4
898UpdateWindowInputSinkHints@8
899UpdateWindowTransform@12
900User32InitializeImmEntryTable@4
901UserClientDllInitialize@12
902UserHandleGrantAccess@12
903UserLpkPSMTextOut@24
904UserLpkTabbedTextOut@48
905UserRealizePalette@4
906UserRegisterWowHandlers@8
907VRipOutput@0
908VTagOutput@0
909ValidateRect@8
910ValidateRgn@8
911VkKeyScanA@4
912VkKeyScanExA@8
913VkKeyScanExW@8
914VkKeyScanW@4
915WCSToMBEx@24
916WINNLSEnableIME@8
917WINNLSGetEnableStatus@4
918WINNLSGetIMEHotkey@4
919WaitForInputIdle@8
920WaitForRedirectionStartComplete@0
921WaitMessage@0
922Win32PoolAllocationStats@24
923WinHelpA@16
924WinHelpW@16
925WindowFromDC@4
926WindowFromPhysicalPoint@8
927WindowFromPoint@8
928_UserTestTokenForInteractive@8
929gSharedInfo DATA
930gapfnScSendMessage DATA
931keybd_event@16
932mouse_event@20
933wsprintfA
934wsprintfW
935wvsprintfA@12
936wvsprintfW@12
937;ord_2500@16 @2500
938;ord_2501@12 @2501
939;ord_2502@8 @2502
940;ord_2503@24 @2503
941;ord_2504@8 @2504
942;ord_2505@8 @2505
943;ord_2506@12 @2506
944;ord_2507@4 @2507
945;ord_2508@8 @2508
946;ord_2509@4 @2509
947;ord_2510@12 @2510
948;ord_2511@8 @2511
949;ord_2512@12 @2512
950;ord_2513@4 @2513
951;ord_2514@8 @2514
952;ord_2515@8 @2515
953;ord_2516@12 @2516
954;ord_2517@4 @2517
955;ord_2518@0 @2518
956;ord_2519@4 @2519
957;ord_2520@0 @2520
958;ord_2521@8 @2521
959;ord_2522@4 @2522
960;ord_2523@8 @2523
961;ord_2524@8 @2524
962;ord_2525@12 @2525
963;ord_2526@12 @2526
964;ord_2527@12 @2527
965IsThreadMessageQueueAttached@4
966;ord_2529@4 @2529
967;ord_2530@8 @2530
968;ord_2531@16 @2531
969;ord_2532@8 @2532
970;ord_2533@4 @2533
971;ord_2534@8 @2534
972;ord_2535@0 @2535
973;ord_2536@8 @2536
974;ord_2537@16 @2537
975;ord_2538@4 @2538
976;ord_2539@4 @2539
977;ord_2540@4 @2540
978;ord_2541@0 @2541
979;ord_2544@4 @2544
980;ord_2545@8 @2545
981;ord_2546@4 @2546
982;ord_2547@4 @2547
983;ord_2548@4 @2548
984;ord_2549@4 @2549
985;ord_2550@8 @2550
986;ord_2551@20 @2551
987;ord_2552@8 @2552
988;ord_2553@32 @2553
989;ord_2554@12 @2554
990;ord_2555@16 @2555
991;ord_2556@8 @2556
992;ord_2557@12 @2557
993;ord_2558@12 @2558
994;ord_2559@16 @2559
995;ord_2560@20 @2560
996;ord_2561@0 @2561
997;ord_2562@0 @2562
998;ord_2563@0 @2563
lib/std/array_list.zig+407-167
......@@ -371,7 +371,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
371371 pub fn initCapacity(allocator: *Allocator, num: usize) !Self {
372372 var self = Self{};
373373
374 const new_memory = try self.allocator.allocAdvanced(T, alignment, num, .at_least);
374 const new_memory = try allocator.allocAdvanced(T, alignment, num, .at_least);
375375 self.items.ptr = new_memory.ptr;
376376 self.capacity = new_memory.len;
377377
......@@ -419,7 +419,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
419419 /// Replace range of elements `list[start..start+len]` with `new_items`
420420 /// grows list if `len < new_items.len`. may allocate
421421 /// shrinks list if `len > new_items.len`
422 pub fn replaceRange(self: *Self, start: usize, len: usize, new_items: SliceConst) !void {
422 pub fn replaceRange(self: *Self, allocator: *Allocator, start: usize, len: usize, new_items: SliceConst) !void {
423423 var managed = self.toManaged(allocator);
424424 try managed.replaceRange(start, len, new_items);
425425 self.* = managed.toUnmanaged();
......@@ -617,201 +617,414 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
617617 };
618618}
619619
620test "std.ArrayList.init" {
621 var list = ArrayList(i32).init(testing.allocator);
622 defer list.deinit();
620test "std.ArrayList/ArrayListUnmanaged.init" {
621 {
622 var list = ArrayList(i32).init(testing.allocator);
623 defer list.deinit();
623624
624 testing.expect(list.items.len == 0);
625 testing.expect(list.capacity == 0);
626}
625 testing.expect(list.items.len == 0);
626 testing.expect(list.capacity == 0);
627 }
627628
628test "std.ArrayList.initCapacity" {
629 var list = try ArrayList(i8).initCapacity(testing.allocator, 200);
630 defer list.deinit();
631 testing.expect(list.items.len == 0);
632 testing.expect(list.capacity >= 200);
633}
629 {
630 var list = ArrayListUnmanaged(i32){};
634631
635test "std.ArrayList.basic" {
636 var list = ArrayList(i32).init(testing.allocator);
637 defer list.deinit();
632 testing.expect(list.items.len == 0);
633 testing.expect(list.capacity == 0);
634 }
635}
638636
637test "std.ArrayList/ArrayListUnmanaged.initCapacity" {
638 const a = testing.allocator;
639639 {
640 var i: usize = 0;
641 while (i < 10) : (i += 1) {
642 list.append(@intCast(i32, i + 1)) catch unreachable;
643 }
640 var list = try ArrayList(i8).initCapacity(a, 200);
641 defer list.deinit();
642 testing.expect(list.items.len == 0);
643 testing.expect(list.capacity >= 200);
644 }
645 {
646 var list = try ArrayListUnmanaged(i8).initCapacity(a, 200);
647 defer list.deinit(a);
648 testing.expect(list.items.len == 0);
649 testing.expect(list.capacity >= 200);
644650 }
651}
645652
653test "std.ArrayList/ArrayListUnmanaged.basic" {
654 const a = testing.allocator;
646655 {
647 var i: usize = 0;
648 while (i < 10) : (i += 1) {
649 testing.expect(list.items[i] == @intCast(i32, i + 1));
656 var list = ArrayList(i32).init(a);
657 defer list.deinit();
658
659 {
660 var i: usize = 0;
661 while (i < 10) : (i += 1) {
662 list.append(@intCast(i32, i + 1)) catch unreachable;
663 }
664 }
665
666 {
667 var i: usize = 0;
668 while (i < 10) : (i += 1) {
669 testing.expect(list.items[i] == @intCast(i32, i + 1));
670 }
671 }
672
673 for (list.items) |v, i| {
674 testing.expect(v == @intCast(i32, i + 1));
650675 }
651 }
652676
653 for (list.items) |v, i| {
654 testing.expect(v == @intCast(i32, i + 1));
677 testing.expect(list.pop() == 10);
678 testing.expect(list.items.len == 9);
679
680 list.appendSlice(&[_]i32{ 1, 2, 3 }) catch unreachable;
681 testing.expect(list.items.len == 12);
682 testing.expect(list.pop() == 3);
683 testing.expect(list.pop() == 2);
684 testing.expect(list.pop() == 1);
685 testing.expect(list.items.len == 9);
686
687 list.appendSlice(&[_]i32{}) catch unreachable;
688 testing.expect(list.items.len == 9);
689
690 // can only set on indices < self.items.len
691 list.items[7] = 33;
692 list.items[8] = 42;
693
694 testing.expect(list.pop() == 42);
695 testing.expect(list.pop() == 33);
655696 }
697 {
698 var list = ArrayListUnmanaged(i32){};
699 defer list.deinit(a);
700
701 {
702 var i: usize = 0;
703 while (i < 10) : (i += 1) {
704 list.append(a, @intCast(i32, i + 1)) catch unreachable;
705 }
706 }
707
708 {
709 var i: usize = 0;
710 while (i < 10) : (i += 1) {
711 testing.expect(list.items[i] == @intCast(i32, i + 1));
712 }
713 }
714
715 for (list.items) |v, i| {
716 testing.expect(v == @intCast(i32, i + 1));
717 }
656718
657 testing.expect(list.pop() == 10);
658 testing.expect(list.items.len == 9);
719 testing.expect(list.pop() == 10);
720 testing.expect(list.items.len == 9);
659721
660 list.appendSlice(&[_]i32{ 1, 2, 3 }) catch unreachable;
661 testing.expect(list.items.len == 12);
662 testing.expect(list.pop() == 3);
663 testing.expect(list.pop() == 2);
664 testing.expect(list.pop() == 1);
665 testing.expect(list.items.len == 9);
722 list.appendSlice(a, &[_]i32{ 1, 2, 3 }) catch unreachable;
723 testing.expect(list.items.len == 12);
724 testing.expect(list.pop() == 3);
725 testing.expect(list.pop() == 2);
726 testing.expect(list.pop() == 1);
727 testing.expect(list.items.len == 9);
666728
667 list.appendSlice(&[_]i32{}) catch unreachable;
668 testing.expect(list.items.len == 9);
729 list.appendSlice(a, &[_]i32{}) catch unreachable;
730 testing.expect(list.items.len == 9);
669731
670 // can only set on indices < self.items.len
671 list.items[7] = 33;
672 list.items[8] = 42;
732 // can only set on indices < self.items.len
733 list.items[7] = 33;
734 list.items[8] = 42;
673735
674 testing.expect(list.pop() == 42);
675 testing.expect(list.pop() == 33);
736 testing.expect(list.pop() == 42);
737 testing.expect(list.pop() == 33);
738 }
676739}
677740
678test "std.ArrayList.appendNTimes" {
679 var list = ArrayList(i32).init(testing.allocator);
680 defer list.deinit();
741test "std.ArrayList/ArrayListUnmanaged.appendNTimes" {
742 const a = testing.allocator;
743 {
744 var list = ArrayList(i32).init(a);
745 defer list.deinit();
746
747 try list.appendNTimes(2, 10);
748 testing.expectEqual(@as(usize, 10), list.items.len);
749 for (list.items) |element| {
750 testing.expectEqual(@as(i32, 2), element);
751 }
752 }
753 {
754 var list = ArrayListUnmanaged(i32){};
755 defer list.deinit(a);
681756
682 try list.appendNTimes(2, 10);
683 testing.expectEqual(@as(usize, 10), list.items.len);
684 for (list.items) |element| {
685 testing.expectEqual(@as(i32, 2), element);
757 try list.appendNTimes(a, 2, 10);
758 testing.expectEqual(@as(usize, 10), list.items.len);
759 for (list.items) |element| {
760 testing.expectEqual(@as(i32, 2), element);
761 }
686762 }
687763}
688764
689test "std.ArrayList.appendNTimes with failing allocator" {
690 var list = ArrayList(i32).init(testing.failing_allocator);
691 defer list.deinit();
692 testing.expectError(error.OutOfMemory, list.appendNTimes(2, 10));
765test "std.ArrayList/ArrayListUnmanaged.appendNTimes with failing allocator" {
766 const a = testing.failing_allocator;
767 {
768 var list = ArrayList(i32).init(a);
769 defer list.deinit();
770 testing.expectError(error.OutOfMemory, list.appendNTimes(2, 10));
771 }
772 {
773 var list = ArrayListUnmanaged(i32){};
774 defer list.deinit(a);
775 testing.expectError(error.OutOfMemory, list.appendNTimes(a, 2, 10));
776 }
693777}
694778
695test "std.ArrayList.orderedRemove" {
696 var list = ArrayList(i32).init(testing.allocator);
697 defer list.deinit();
779test "std.ArrayList/ArrayListUnmanaged.orderedRemove" {
780 const a = testing.allocator;
781 {
782 var list = ArrayList(i32).init(a);
783 defer list.deinit();
784
785 try list.append(1);
786 try list.append(2);
787 try list.append(3);
788 try list.append(4);
789 try list.append(5);
790 try list.append(6);
791 try list.append(7);
792
793 //remove from middle
794 testing.expectEqual(@as(i32, 4), list.orderedRemove(3));
795 testing.expectEqual(@as(i32, 5), list.items[3]);
796 testing.expectEqual(@as(usize, 6), list.items.len);
797
798 //remove from end
799 testing.expectEqual(@as(i32, 7), list.orderedRemove(5));
800 testing.expectEqual(@as(usize, 5), list.items.len);
801
802 //remove from front
803 testing.expectEqual(@as(i32, 1), list.orderedRemove(0));
804 testing.expectEqual(@as(i32, 2), list.items[0]);
805 testing.expectEqual(@as(usize, 4), list.items.len);
806 }
807 {
808 var list = ArrayListUnmanaged(i32){};
809 defer list.deinit(a);
698810
699 try list.append(1);
700 try list.append(2);
701 try list.append(3);
702 try list.append(4);
703 try list.append(5);
704 try list.append(6);
705 try list.append(7);
706
707 //remove from middle
708 testing.expectEqual(@as(i32, 4), list.orderedRemove(3));
709 testing.expectEqual(@as(i32, 5), list.items[3]);
710 testing.expectEqual(@as(usize, 6), list.items.len);
711
712 //remove from end
713 testing.expectEqual(@as(i32, 7), list.orderedRemove(5));
714 testing.expectEqual(@as(usize, 5), list.items.len);
715
716 //remove from front
717 testing.expectEqual(@as(i32, 1), list.orderedRemove(0));
718 testing.expectEqual(@as(i32, 2), list.items[0]);
719 testing.expectEqual(@as(usize, 4), list.items.len);
811 try list.append(a, 1);
812 try list.append(a, 2);
813 try list.append(a, 3);
814 try list.append(a, 4);
815 try list.append(a, 5);
816 try list.append(a, 6);
817 try list.append(a, 7);
818
819 //remove from middle
820 testing.expectEqual(@as(i32, 4), list.orderedRemove(3));
821 testing.expectEqual(@as(i32, 5), list.items[3]);
822 testing.expectEqual(@as(usize, 6), list.items.len);
823
824 //remove from end
825 testing.expectEqual(@as(i32, 7), list.orderedRemove(5));
826 testing.expectEqual(@as(usize, 5), list.items.len);
827
828 //remove from front
829 testing.expectEqual(@as(i32, 1), list.orderedRemove(0));
830 testing.expectEqual(@as(i32, 2), list.items[0]);
831 testing.expectEqual(@as(usize, 4), list.items.len);
832 }
720833}
721834
722test "std.ArrayList.swapRemove" {
723 var list = ArrayList(i32).init(testing.allocator);
724 defer list.deinit();
835test "std.ArrayList/ArrayListUnmanaged.swapRemove" {
836 const a = testing.allocator;
837 {
838 var list = ArrayList(i32).init(a);
839 defer list.deinit();
725840
726 try list.append(1);
727 try list.append(2);
728 try list.append(3);
729 try list.append(4);
730 try list.append(5);
731 try list.append(6);
732 try list.append(7);
733
734 //remove from middle
735 testing.expect(list.swapRemove(3) == 4);
736 testing.expect(list.items[3] == 7);
737 testing.expect(list.items.len == 6);
738
739 //remove from end
740 testing.expect(list.swapRemove(5) == 6);
741 testing.expect(list.items.len == 5);
742
743 //remove from front
744 testing.expect(list.swapRemove(0) == 1);
745 testing.expect(list.items[0] == 5);
746 testing.expect(list.items.len == 4);
841 try list.append(1);
842 try list.append(2);
843 try list.append(3);
844 try list.append(4);
845 try list.append(5);
846 try list.append(6);
847 try list.append(7);
848
849 //remove from middle
850 testing.expect(list.swapRemove(3) == 4);
851 testing.expect(list.items[3] == 7);
852 testing.expect(list.items.len == 6);
853
854 //remove from end
855 testing.expect(list.swapRemove(5) == 6);
856 testing.expect(list.items.len == 5);
857
858 //remove from front
859 testing.expect(list.swapRemove(0) == 1);
860 testing.expect(list.items[0] == 5);
861 testing.expect(list.items.len == 4);
862 }
863 {
864 var list = ArrayListUnmanaged(i32){};
865 defer list.deinit(a);
866
867 try list.append(a, 1);
868 try list.append(a, 2);
869 try list.append(a, 3);
870 try list.append(a, 4);
871 try list.append(a, 5);
872 try list.append(a, 6);
873 try list.append(a, 7);
874
875 //remove from middle
876 testing.expect(list.swapRemove(3) == 4);
877 testing.expect(list.items[3] == 7);
878 testing.expect(list.items.len == 6);
879
880 //remove from end
881 testing.expect(list.swapRemove(5) == 6);
882 testing.expect(list.items.len == 5);
883
884 //remove from front
885 testing.expect(list.swapRemove(0) == 1);
886 testing.expect(list.items[0] == 5);
887 testing.expect(list.items.len == 4);
888 }
747889}
748890
749test "std.ArrayList.insert" {
750 var list = ArrayList(i32).init(testing.allocator);
751 defer list.deinit();
891test "std.ArrayList/ArrayListUnmanaged.insert" {
892 const a = testing.allocator;
893 {
894 var list = ArrayList(i32).init(a);
895 defer list.deinit();
752896
753 try list.append(1);
754 try list.append(2);
755 try list.append(3);
756 try list.insert(0, 5);
757 testing.expect(list.items[0] == 5);
758 testing.expect(list.items[1] == 1);
759 testing.expect(list.items[2] == 2);
760 testing.expect(list.items[3] == 3);
897 try list.append(1);
898 try list.append(2);
899 try list.append(3);
900 try list.insert(0, 5);
901 testing.expect(list.items[0] == 5);
902 testing.expect(list.items[1] == 1);
903 testing.expect(list.items[2] == 2);
904 testing.expect(list.items[3] == 3);
905 }
906 {
907 var list = ArrayListUnmanaged(i32){};
908 defer list.deinit(a);
909
910 try list.append(a, 1);
911 try list.append(a, 2);
912 try list.append(a, 3);
913 try list.insert(a, 0, 5);
914 testing.expect(list.items[0] == 5);
915 testing.expect(list.items[1] == 1);
916 testing.expect(list.items[2] == 2);
917 testing.expect(list.items[3] == 3);
918 }
761919}
762920
763test "std.ArrayList.insertSlice" {
764 var list = ArrayList(i32).init(testing.allocator);
765 defer list.deinit();
921test "std.ArrayList/ArrayListUnmanaged.insertSlice" {
922 const a = testing.allocator;
923 {
924 var list = ArrayList(i32).init(a);
925 defer list.deinit();
766926
767 try list.append(1);
768 try list.append(2);
769 try list.append(3);
770 try list.append(4);
771 try list.insertSlice(1, &[_]i32{ 9, 8 });
772 testing.expect(list.items[0] == 1);
773 testing.expect(list.items[1] == 9);
774 testing.expect(list.items[2] == 8);
775 testing.expect(list.items[3] == 2);
776 testing.expect(list.items[4] == 3);
777 testing.expect(list.items[5] == 4);
778
779 const items = [_]i32{1};
780 try list.insertSlice(0, items[0..0]);
781 testing.expect(list.items.len == 6);
782 testing.expect(list.items[0] == 1);
927 try list.append(1);
928 try list.append(2);
929 try list.append(3);
930 try list.append(4);
931 try list.insertSlice(1, &[_]i32{ 9, 8 });
932 testing.expect(list.items[0] == 1);
933 testing.expect(list.items[1] == 9);
934 testing.expect(list.items[2] == 8);
935 testing.expect(list.items[3] == 2);
936 testing.expect(list.items[4] == 3);
937 testing.expect(list.items[5] == 4);
938
939 const items = [_]i32{1};
940 try list.insertSlice(0, items[0..0]);
941 testing.expect(list.items.len == 6);
942 testing.expect(list.items[0] == 1);
943 }
944 {
945 var list = ArrayListUnmanaged(i32){};
946 defer list.deinit(a);
947
948 try list.append(a, 1);
949 try list.append(a, 2);
950 try list.append(a, 3);
951 try list.append(a, 4);
952 try list.insertSlice(a, 1, &[_]i32{ 9, 8 });
953 testing.expect(list.items[0] == 1);
954 testing.expect(list.items[1] == 9);
955 testing.expect(list.items[2] == 8);
956 testing.expect(list.items[3] == 2);
957 testing.expect(list.items[4] == 3);
958 testing.expect(list.items[5] == 4);
959
960 const items = [_]i32{1};
961 try list.insertSlice(a, 0, items[0..0]);
962 testing.expect(list.items.len == 6);
963 testing.expect(list.items[0] == 1);
964 }
783965}
784966
785test "std.ArrayList.replaceRange" {
967test "std.ArrayList/ArrayListUnmanaged.replaceRange" {
786968 var arena = std.heap.ArenaAllocator.init(testing.allocator);
787969 defer arena.deinit();
970 const a = &arena.allocator;
788971
789 const alloc = &arena.allocator;
790972 const init = [_]i32{ 1, 2, 3, 4, 5 };
791973 const new = [_]i32{ 0, 0, 0 };
792974
793 var list_zero = ArrayList(i32).init(alloc);
794 var list_eq = ArrayList(i32).init(alloc);
795 var list_lt = ArrayList(i32).init(alloc);
796 var list_gt = ArrayList(i32).init(alloc);
975 const result_zero = [_]i32{ 1, 0, 0, 0, 2, 3, 4, 5 };
976 const result_eq = [_]i32{ 1, 0, 0, 0, 5 };
977 const result_le = [_]i32{ 1, 0, 0, 0, 4, 5 };
978 const result_gt = [_]i32{ 1, 0, 0, 0 };
797979
798 try list_zero.appendSlice(&init);
799 try list_eq.appendSlice(&init);
800 try list_lt.appendSlice(&init);
801 try list_gt.appendSlice(&init);
802
803 try list_zero.replaceRange(1, 0, &new);
804 try list_eq.replaceRange(1, 3, &new);
805 try list_lt.replaceRange(1, 2, &new);
806
807 // after_range > new_items.len in function body
808 testing.expect(1 + 4 > new.len);
809 try list_gt.replaceRange(1, 4, &new);
810
811 testing.expectEqualSlices(i32, list_zero.items, &[_]i32{ 1, 0, 0, 0, 2, 3, 4, 5 });
812 testing.expectEqualSlices(i32, list_eq.items, &[_]i32{ 1, 0, 0, 0, 5 });
813 testing.expectEqualSlices(i32, list_lt.items, &[_]i32{ 1, 0, 0, 0, 4, 5 });
814 testing.expectEqualSlices(i32, list_gt.items, &[_]i32{ 1, 0, 0, 0 });
980 {
981 var list_zero = ArrayList(i32).init(a);
982 var list_eq = ArrayList(i32).init(a);
983 var list_lt = ArrayList(i32).init(a);
984 var list_gt = ArrayList(i32).init(a);
985
986 try list_zero.appendSlice(&init);
987 try list_eq.appendSlice(&init);
988 try list_lt.appendSlice(&init);
989 try list_gt.appendSlice(&init);
990
991 try list_zero.replaceRange(1, 0, &new);
992 try list_eq.replaceRange(1, 3, &new);
993 try list_lt.replaceRange(1, 2, &new);
994
995 // after_range > new_items.len in function body
996 testing.expect(1 + 4 > new.len);
997 try list_gt.replaceRange(1, 4, &new);
998
999 testing.expectEqualSlices(i32, list_zero.items, &result_zero);
1000 testing.expectEqualSlices(i32, list_eq.items, &result_eq);
1001 testing.expectEqualSlices(i32, list_lt.items, &result_le);
1002 testing.expectEqualSlices(i32, list_gt.items, &result_gt);
1003 }
1004 {
1005 var list_zero = ArrayListUnmanaged(i32){};
1006 var list_eq = ArrayListUnmanaged(i32){};
1007 var list_lt = ArrayListUnmanaged(i32){};
1008 var list_gt = ArrayListUnmanaged(i32){};
1009
1010 try list_zero.appendSlice(a, &init);
1011 try list_eq.appendSlice(a, &init);
1012 try list_lt.appendSlice(a, &init);
1013 try list_gt.appendSlice(a, &init);
1014
1015 try list_zero.replaceRange(a, 1, 0, &new);
1016 try list_eq.replaceRange(a, 1, 3, &new);
1017 try list_lt.replaceRange(a, 1, 2, &new);
1018
1019 // after_range > new_items.len in function body
1020 testing.expect(1 + 4 > new.len);
1021 try list_gt.replaceRange(a, 1, 4, &new);
1022
1023 testing.expectEqualSlices(i32, list_zero.items, &result_zero);
1024 testing.expectEqualSlices(i32, list_eq.items, &result_eq);
1025 testing.expectEqualSlices(i32, list_lt.items, &result_le);
1026 testing.expectEqualSlices(i32, list_gt.items, &result_gt);
1027 }
8151028}
8161029
8171030const Item = struct {
......@@ -819,11 +1032,25 @@ const Item = struct {
8191032 sub_items: ArrayList(Item),
8201033};
8211034
822test "std.ArrayList: ArrayList(T) of struct T" {
823 var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(testing.allocator) };
824 defer root.sub_items.deinit();
825 try root.sub_items.append(Item{ .integer = 42, .sub_items = ArrayList(Item).init(testing.allocator) });
826 testing.expect(root.sub_items.items[0].integer == 42);
1035const ItemUnmanaged = struct {
1036 integer: i32,
1037 sub_items: ArrayListUnmanaged(ItemUnmanaged),
1038};
1039
1040test "std.ArrayList/ArrayListUnmanaged: ArrayList(T) of struct T" {
1041 const a = std.testing.allocator;
1042 {
1043 var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(a) };
1044 defer root.sub_items.deinit();
1045 try root.sub_items.append(Item{ .integer = 42, .sub_items = ArrayList(Item).init(a) });
1046 testing.expect(root.sub_items.items[0].integer == 42);
1047 }
1048 {
1049 var root = ItemUnmanaged{ .integer = 1, .sub_items = ArrayListUnmanaged(ItemUnmanaged){} };
1050 defer root.sub_items.deinit(a);
1051 try root.sub_items.append(a, ItemUnmanaged{ .integer = 42, .sub_items = ArrayListUnmanaged(ItemUnmanaged){} });
1052 testing.expect(root.sub_items.items[0].integer == 42);
1053 }
8271054}
8281055
8291056test "std.ArrayList(u8) implements outStream" {
......@@ -837,19 +1064,32 @@ test "std.ArrayList(u8) implements outStream" {
8371064 testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", buffer.span());
8381065}
8391066
840test "std.ArrayList.shrink still sets length on error.OutOfMemory" {
1067test "std.ArrayList/ArrayListUnmanaged.shrink still sets length on error.OutOfMemory" {
8411068 // use an arena allocator to make sure realloc returns error.OutOfMemory
8421069 var arena = std.heap.ArenaAllocator.init(testing.allocator);
8431070 defer arena.deinit();
1071 const a = &arena.allocator;
8441072
845 var list = ArrayList(i32).init(&arena.allocator);
1073 {
1074 var list = ArrayList(i32).init(a);
8461075
847 try list.append(1);
848 try list.append(2);
849 try list.append(3);
1076 try list.append(1);
1077 try list.append(2);
1078 try list.append(3);
8501079
851 list.shrink(1);
852 testing.expect(list.items.len == 1);
1080 list.shrink(1);
1081 testing.expect(list.items.len == 1);
1082 }
1083 {
1084 var list = ArrayListUnmanaged(i32){};
1085
1086 try list.append(a, 1);
1087 try list.append(a, 2);
1088 try list.append(a, 3);
1089
1090 list.shrink(a, 1);
1091 testing.expect(list.items.len == 1);
1092 }
8531093}
8541094
8551095test "std.ArrayList.writer" {
......@@ -864,7 +1104,7 @@ test "std.ArrayList.writer" {
8641104 testing.expectEqualSlices(u8, list.items, "abcdefg");
8651105}
8661106
867test "addManyAsArray" {
1107test "std.ArrayList/ArrayListUnmanaged.addManyAsArray" {
8681108 const a = std.testing.allocator;
8691109 {
8701110 var list = ArrayList(u8).init(a);
lib/std/build.zig+60-56
......@@ -1232,6 +1232,9 @@ pub const LibExeObjStep = struct {
12321232 installed_path: ?[]const u8,
12331233 install_step: ?*InstallArtifactStep,
12341234
1235 /// Base address for an executable image.
1236 image_base: ?u64 = null,
1237
12351238 libc_file: ?[]const u8 = null,
12361239
12371240 valgrind_support: ?bool = null,
......@@ -1239,6 +1242,7 @@ pub const LibExeObjStep = struct {
12391242 /// Create a .eh_frame_hdr section and a PT_GNU_EH_FRAME segment in the ELF
12401243 /// file.
12411244 link_eh_frame_hdr: bool = false,
1245 link_emit_relocs: bool = false,
12421246
12431247 /// Place every function in its own section so that unused ones may be
12441248 /// safely garbage-collected during the linking phase.
......@@ -1384,66 +1388,50 @@ pub const LibExeObjStep = struct {
13841388 }
13851389
13861390 fn computeOutFileNames(self: *LibExeObjStep) void {
1387 // TODO make this call std.zig.binNameAlloc
1388 switch (self.kind) {
1389 .Obj => {
1390 self.out_filename = self.builder.fmt("{}{}", .{ self.name, self.target.oFileExt() });
1391 },
1392 .Exe => {
1393 self.out_filename = self.builder.fmt("{}{}", .{ self.name, self.target.exeFileExt() });
1394 },
1395 .Test => {
1396 self.out_filename = self.builder.fmt("test{}", .{self.target.exeFileExt()});
1391 const target_info = std.zig.system.NativeTargetInfo.detect(
1392 self.builder.allocator,
1393 self.target,
1394 ) catch unreachable;
1395 const target = target_info.target;
1396 self.out_filename = std.zig.binNameAlloc(self.builder.allocator, .{
1397 .root_name = self.name,
1398 .target = target,
1399 .output_mode = switch (self.kind) {
1400 .Lib => .Lib,
1401 .Obj => .Obj,
1402 .Exe, .Test => .Exe,
13971403 },
1398 .Lib => {
1399 if (!self.is_dynamic) {
1400 self.out_filename = self.builder.fmt("{}{}{}", .{
1401 self.target.libPrefix(),
1404 .link_mode = if (self.is_dynamic) .Dynamic else .Static,
1405 .version = self.version,
1406 }) catch unreachable;
1407
1408 if (self.kind == .Lib) {
1409 if (!self.is_dynamic) {
1410 self.out_lib_filename = self.out_filename;
1411 } else if (self.version) |version| {
1412 if (target.isDarwin()) {
1413 self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", .{
14021414 self.name,
1403 self.target.staticLibSuffix(),
1415 version.major,
14041416 });
1417 self.name_only_filename = self.builder.fmt("lib{}.dylib", .{self.name});
14051418 self.out_lib_filename = self.out_filename;
1406 } else if (self.version) |version| {
1407 if (self.target.isDarwin()) {
1408 self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib", .{
1409 self.name,
1410 version.major,
1411 version.minor,
1412 version.patch,
1413 });
1414 self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", .{
1415 self.name,
1416 version.major,
1417 });
1418 self.name_only_filename = self.builder.fmt("lib{}.dylib", .{self.name});
1419 self.out_lib_filename = self.out_filename;
1420 } else if (self.target.isWindows()) {
1421 self.out_filename = self.builder.fmt("{}.dll", .{self.name});
1422 self.out_lib_filename = self.builder.fmt("{}.lib", .{self.name});
1423 } else {
1424 self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}", .{
1425 self.name,
1426 version.major,
1427 version.minor,
1428 version.patch,
1429 });
1430 self.major_only_filename = self.builder.fmt("lib{}.so.{d}", .{ self.name, version.major });
1431 self.name_only_filename = self.builder.fmt("lib{}.so", .{self.name});
1432 self.out_lib_filename = self.out_filename;
1433 }
1419 } else if (target.os.tag == .windows) {
1420 self.out_lib_filename = self.builder.fmt("{}.lib", .{self.name});
14341421 } else {
1435 if (self.target.isDarwin()) {
1436 self.out_filename = self.builder.fmt("lib{}.dylib", .{self.name});
1437 self.out_lib_filename = self.out_filename;
1438 } else if (self.target.isWindows()) {
1439 self.out_filename = self.builder.fmt("{}.dll", .{self.name});
1440 self.out_lib_filename = self.builder.fmt("{}.lib", .{self.name});
1441 } else {
1442 self.out_filename = self.builder.fmt("lib{}.so", .{self.name});
1443 self.out_lib_filename = self.out_filename;
1444 }
1422 self.major_only_filename = self.builder.fmt("lib{}.so.{d}", .{ self.name, version.major });
1423 self.name_only_filename = self.builder.fmt("lib{}.so", .{self.name});
1424 self.out_lib_filename = self.out_filename;
14451425 }
1446 },
1426 } else {
1427 if (target.isDarwin()) {
1428 self.out_lib_filename = self.out_filename;
1429 } else if (target.os.tag == .windows) {
1430 self.out_lib_filename = self.builder.fmt("{}.lib", .{self.name});
1431 } else {
1432 self.out_lib_filename = self.out_filename;
1433 }
1434 }
14471435 }
14481436 }
14491437
......@@ -2040,6 +2028,11 @@ pub const LibExeObjStep = struct {
20402028 try zig_args.append("--pkg-end");
20412029 }
20422030
2031 if (self.image_base) |image_base| {
2032 try zig_args.append("--image-base");
2033 try zig_args.append(builder.fmt("0x{x}", .{image_base}));
2034 }
2035
20432036 if (self.filter) |filter| {
20442037 try zig_args.append("--test-filter");
20452038 try zig_args.append(filter);
......@@ -2075,6 +2068,9 @@ pub const LibExeObjStep = struct {
20752068 if (self.link_eh_frame_hdr) {
20762069 try zig_args.append("--eh-frame-hdr");
20772070 }
2071 if (self.link_emit_relocs) {
2072 try zig_args.append("--emit-relocs");
2073 }
20782074 if (self.link_function_sections) {
20792075 try zig_args.append("-ffunction-sections");
20802076 }
......@@ -2168,8 +2164,8 @@ pub const LibExeObjStep = struct {
21682164 }
21692165
21702166 if (self.linker_script) |linker_script| {
2171 zig_args.append("--linker-script") catch unreachable;
2172 zig_args.append(builder.pathFromRoot(linker_script)) catch unreachable;
2167 try zig_args.append("--script");
2168 try zig_args.append(builder.pathFromRoot(linker_script));
21732169 }
21742170
21752171 if (self.version_script) |version_script| {
......@@ -2335,6 +2331,14 @@ pub const LibExeObjStep = struct {
23352331
23362332 var it = src_dir.iterate();
23372333 while (try it.next()) |entry| {
2334 // The compiler can put these files into the same directory, but we don't
2335 // want to copy them over.
2336 if (mem.eql(u8, entry.name, "stage1.id") or
2337 mem.eql(u8, entry.name, "llvm-ar.id") or
2338 mem.eql(u8, entry.name, "libs.txt") or
2339 mem.eql(u8, entry.name, "builtin.zig") or
2340 mem.eql(u8, entry.name, "lld.id")) continue;
2341
23382342 _ = try src_dir.updateFile(entry.name, dest_dir, entry.name, .{});
23392343 }
23402344 } else {
lib/std/builtin.zig+13
......@@ -98,6 +98,16 @@ pub const AtomicOrder = enum {
9898 SeqCst,
9999};
100100
101/// This data structure is used by the Zig language code generation and
102/// therefore must be kept in sync with the compiler implementation.
103pub const ReduceOp = enum {
104 And,
105 Or,
106 Xor,
107 Min,
108 Max,
109};
110
101111/// This data structure is used by the Zig language code generation and
102112/// therefore must be kept in sync with the compiler implementation.
103113pub const AtomicRmwOp = enum {
......@@ -262,6 +272,7 @@ pub const TypeInfo = union(enum) {
262272 field_type: type,
263273 default_value: anytype,
264274 is_comptime: bool,
275 alignment: comptime_int,
265276 };
266277
267278 /// This data structure is used by the Zig language code generation and
......@@ -318,6 +329,7 @@ pub const TypeInfo = union(enum) {
318329 pub const UnionField = struct {
319330 name: []const u8,
320331 field_type: type,
332 alignment: comptime_int,
321333 };
322334
323335 /// This data structure is used by the Zig language code generation and
......@@ -341,6 +353,7 @@ pub const TypeInfo = union(enum) {
341353 /// therefore must be kept in sync with the compiler implementation.
342354 pub const Fn = struct {
343355 calling_convention: CallingConvention,
356 alignment: comptime_int,
344357 is_generic: bool,
345358 is_var_args: bool,
346359 return_type: ?type,
lib/std/c.zig+3
......@@ -342,3 +342,6 @@ pub extern "c" fn fsync(fd: c_int) c_int;
342342pub extern "c" fn fdatasync(fd: c_int) c_int;
343343
344344pub extern "c" fn prctl(option: c_int, ...) c_int;
345
346pub extern "c" fn getrlimit(resource: rlimit_resource, rlim: *rlimit) c_int;
347pub extern "c" fn setrlimit(resource: rlimit_resource, rlim: *const rlimit) c_int;
lib/std/c/darwin.zig+1-1
......@@ -12,7 +12,7 @@ usingnamespace @import("../os/bits.zig");
1212
1313extern "c" fn __error() *c_int;
1414pub extern "c" fn NSVersionOfRunTimeLibrary(library_name: [*:0]const u8) u32;
15pub extern "c" fn _NSGetExecutablePath(buf: [*]u8, bufsize: *u32) c_int;
15pub extern "c" fn _NSGetExecutablePath(buf: [*:0]u8, bufsize: *u32) c_int;
1616pub extern "c" fn _dyld_image_count() u32;
1717pub extern "c" fn _dyld_get_image_header(image_index: u32) ?*mach_header;
1818pub extern "c" fn _dyld_get_image_vmaddr_slide(image_index: u32) usize;
lib/std/c/linux.zig+2
......@@ -100,6 +100,8 @@ pub extern "c" fn copy_file_range(fd_in: fd_t, off_in: ?*i64, fd_out: fd_t, off_
100100
101101pub extern "c" fn signalfd(fd: fd_t, mask: *const sigset_t, flags: c_uint) c_int;
102102
103pub extern "c" fn prlimit(pid: pid_t, resource: rlimit_resource, new_limit: *const rlimit, old_limit: *rlimit) c_int;
104
103105pub const pthread_attr_t = extern struct {
104106 __size: [56]u8,
105107 __align: c_long,
lib/std/child_process.zig+2-2
......@@ -105,8 +105,8 @@ pub const ChildProcess = struct {
105105 .term = null,
106106 .env_map = null,
107107 .cwd = null,
108 .uid = if (builtin.os.tag == .windows) {} else null,
109 .gid = if (builtin.os.tag == .windows) {} else null,
108 .uid = if (builtin.os.tag == .windows or builtin.os.tag == .wasi) {} else null,
109 .gid = if (builtin.os.tag == .windows or builtin.os.tag == .wasi) {} else null,
110110 .stdin = null,
111111 .stdout = null,
112112 .stderr = null,
lib/std/crypto.zig+48-40
......@@ -4,6 +4,50 @@
44// The MIT license requires this copyright notice to be included in all copies
55// and substantial portions of the software.
66
7/// Authenticated Encryption with Associated Data
8pub const aead = struct {
9 const chacha20 = @import("crypto/chacha20.zig");
10
11 pub const Gimli = @import("crypto/gimli.zig").Aead;
12 pub const ChaCha20Poly1305 = chacha20.Chacha20Poly1305;
13 pub const XChaCha20Poly1305 = chacha20.XChacha20Poly1305;
14 pub const AEGIS128L = @import("crypto/aegis.zig").AEGIS128L;
15 pub const AEGIS256 = @import("crypto/aegis.zig").AEGIS256;
16 pub const AES128GCM = @import("crypto/aes_gcm.zig").AES128GCM;
17 pub const AES256GCM = @import("crypto/aes_gcm.zig").AES256GCM;
18};
19
20/// Authentication (MAC) functions.
21pub const auth = struct {
22 pub const hmac = @import("crypto/hmac.zig");
23 pub const siphash = @import("crypto/siphash.zig");
24};
25
26/// Core functions, that should rarely be used directly by applications.
27pub const core = struct {
28 pub const aes = @import("crypto/aes.zig");
29 pub const Gimli = @import("crypto/gimli.zig").State;
30
31 /// Modes are generic compositions to construct encryption/decryption functions from block ciphers and permutations.
32 ///
33 /// These modes are designed to be building blocks for higher-level constructions, and should generally not be used directly by applications, as they may not provide the expected properties and security guarantees.
34 ///
35 /// Most applications may want to use AEADs instead.
36 pub const modes = @import("crypto/modes.zig");
37};
38
39/// Diffie-Hellman key exchange functions.
40pub const dh = struct {
41 pub const X25519 = @import("crypto/25519/x25519.zig").X25519;
42};
43
44/// Elliptic-curve arithmetic.
45pub const ecc = struct {
46 pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519;
47 pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519;
48 pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255;
49};
50
751/// Hash functions.
852pub const hash = struct {
953 pub const Md5 = @import("crypto/md5.zig").Md5;
......@@ -15,26 +59,15 @@ pub const hash = struct {
1559 pub const Gimli = @import("crypto/gimli.zig").Hash;
1660};
1761
18/// Authentication (MAC) functions.
19pub const auth = struct {
20 pub const hmac = @import("crypto/hmac.zig");
21 pub const siphash = @import("crypto/siphash.zig");
22};
23
24/// Authenticated Encryption with Associated Data
25pub const aead = struct {
26 const chacha20 = @import("crypto/chacha20.zig");
27
28 pub const Gimli = @import("crypto/gimli.zig").Aead;
29 pub const ChaCha20Poly1305 = chacha20.Chacha20Poly1305;
30 pub const XChaCha20Poly1305 = chacha20.XChacha20Poly1305;
31 pub const AEGIS128L = @import("crypto/aegis.zig").AEGIS128L;
32 pub const AEGIS256 = @import("crypto/aegis.zig").AEGIS256;
62/// Key derivation functions.
63pub const kdf = struct {
64 pub const hkdf = @import("crypto/hkdf.zig");
3365};
3466
3567/// MAC functions requiring single-use secret keys.
3668pub const onetimeauth = struct {
3769 pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305;
70 pub const Ghash = @import("crypto/ghash.zig").Ghash;
3871};
3972
4073/// A password hashing function derives a uniform key from low-entropy input material such as passwords.
......@@ -57,31 +90,6 @@ pub const pwhash = struct {
5790 pub const pbkdf2 = @import("crypto/pbkdf2.zig").pbkdf2;
5891};
5992
60/// Core functions, that should rarely be used directly by applications.
61pub const core = struct {
62 pub const aes = @import("crypto/aes.zig");
63 pub const Gimli = @import("crypto/gimli.zig").State;
64
65 /// Modes are generic compositions to construct encryption/decryption functions from block ciphers and permutations.
66 ///
67 /// These modes are designed to be building blocks for higher-level constructions, and should generally not be used directly by applications, as they may not provide the expected properties and security guarantees.
68 ///
69 /// Most applications may want to use AEADs instead.
70 pub const modes = @import("crypto/modes.zig");
71};
72
73/// Elliptic-curve arithmetic.
74pub const ecc = struct {
75 pub const Curve25519 = @import("crypto/25519/curve25519.zig").Curve25519;
76 pub const Edwards25519 = @import("crypto/25519/edwards25519.zig").Edwards25519;
77 pub const Ristretto255 = @import("crypto/25519/ristretto255.zig").Ristretto255;
78};
79
80/// Diffie-Hellman key exchange functions.
81pub const dh = struct {
82 pub const X25519 = @import("crypto/25519/x25519.zig").X25519;
83};
84
8593/// Digital signature functions.
8694pub const sign = struct {
8795 pub const Ed25519 = @import("crypto/25519/ed25519.zig").Ed25519;
lib/std/crypto/25519/field.zig+8-6
......@@ -307,12 +307,14 @@ pub const Fe = struct {
307307 }
308308
309309 pub fn pow2523(a: Fe) Fe {
310 var c = a;
311 var i: usize = 0;
312 while (i < 249) : (i += 1) {
313 c = c.sq().mul(a);
314 }
315 return c.sq().sq().mul(a);
310 var t0 = a.mul(a.sq());
311 var t1 = t0.mul(t0.sqn(2)).sq().mul(a);
312 t0 = t1.sqn(5).mul(t1);
313 var t2 = t0.sqn(5).mul(t1);
314 t1 = t2.sqn(15).mul(t2);
315 t2 = t1.sqn(30).mul(t1);
316 t1 = t2.sqn(60).mul(t2);
317 return t1.sqn(120).mul(t1).sqn(10).mul(t0).sqn(2).mul(a);
316318 }
317319
318320 pub fn abs(a: Fe) Fe {
lib/std/crypto/aes_gcm.zig created+161
......@@ -0,0 +1,161 @@
1const std = @import("std");
2const assert = std.debug.assert;
3const builtin = std.builtin;
4const crypto = std.crypto;
5const debug = std.debug;
6const Ghash = std.crypto.onetimeauth.Ghash;
7const mem = std.mem;
8const modes = crypto.core.modes;
9
10pub const AES128GCM = AESGCM(crypto.core.aes.AES128);
11pub const AES256GCM = AESGCM(crypto.core.aes.AES256);
12
13fn AESGCM(comptime AES: anytype) type {
14 debug.assert(AES.block.block_size == 16);
15
16 return struct {
17 pub const tag_length = 16;
18 pub const nonce_length = 12;
19 pub const key_length = AES.key_bits / 8;
20
21 const zeros = [_]u8{0} ** 16;
22
23 pub fn encrypt(c: []u8, tag: *[tag_length]u8, m: []const u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) void {
24 debug.assert(c.len == m.len);
25 debug.assert(m.len <= 16 * ((1 << 32) - 2));
26
27 const aes = AES.initEnc(key);
28 var h: [16]u8 = undefined;
29 aes.encrypt(&h, &zeros);
30
31 var t: [16]u8 = undefined;
32 var j: [16]u8 = undefined;
33 mem.copy(u8, j[0..nonce_length], npub[0..]);
34 mem.writeIntBig(u32, j[nonce_length..][0..4], 1);
35 aes.encrypt(&t, &j);
36
37 var mac = Ghash.init(&h);
38 mac.update(ad);
39 mac.pad();
40
41 mem.writeIntBig(u32, j[nonce_length..][0..4], 2);
42 modes.ctr(@TypeOf(aes), aes, c, m, j, builtin.Endian.Big);
43 mac.update(c[0..m.len][0..]);
44 mac.pad();
45
46 var final_block = h;
47 mem.writeIntBig(u64, final_block[0..8], ad.len * 8);
48 mem.writeIntBig(u64, final_block[8..16], m.len * 8);
49 mac.update(&final_block);
50 mac.final(tag);
51 for (t) |x, i| {
52 tag[i] ^= x;
53 }
54 }
55
56 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) !void {
57 assert(c.len == m.len);
58
59 const aes = AES.initEnc(key);
60 var h: [16]u8 = undefined;
61 aes.encrypt(&h, &zeros);
62
63 var t: [16]u8 = undefined;
64 var j: [16]u8 = undefined;
65 mem.copy(u8, j[0..nonce_length], npub[0..]);
66 mem.writeIntBig(u32, j[nonce_length..][0..4], 1);
67 aes.encrypt(&t, &j);
68
69 var mac = Ghash.init(&h);
70 mac.update(ad);
71 mac.pad();
72
73 mac.update(c);
74 mac.pad();
75
76 var final_block = h;
77 mem.writeIntBig(u64, final_block[0..8], ad.len * 8);
78 mem.writeIntBig(u64, final_block[8..16], m.len * 8);
79 mac.update(&final_block);
80 var computed_tag: [Ghash.mac_length]u8 = undefined;
81 mac.final(&computed_tag);
82 for (t) |x, i| {
83 computed_tag[i] ^= x;
84 }
85
86 var acc: u8 = 0;
87 for (computed_tag) |_, p| {
88 acc |= (computed_tag[p] ^ tag[p]);
89 }
90 if (acc != 0) {
91 mem.set(u8, m, 0xaa);
92 return error.AuthenticationFailed;
93 }
94
95 mem.writeIntBig(u32, j[nonce_length..][0..4], 2);
96 modes.ctr(@TypeOf(aes), aes, m, c, j, builtin.Endian.Big);
97 }
98 };
99}
100
101const htest = @import("test.zig");
102const testing = std.testing;
103
104test "AES256GCM - Empty message and no associated data" {
105 const key: [AES256GCM.key_length]u8 = [_]u8{0x69} ** AES256GCM.key_length;
106 const nonce: [AES256GCM.nonce_length]u8 = [_]u8{0x42} ** AES256GCM.nonce_length;
107 const ad = "";
108 const m = "";
109 var c: [m.len]u8 = undefined;
110 var m2: [m.len]u8 = undefined;
111 var tag: [AES256GCM.tag_length]u8 = undefined;
112
113 AES256GCM.encrypt(&c, &tag, m, ad, nonce, key);
114 htest.assertEqual("6b6ff610a16fa4cd59f1fb7903154e92", &tag);
115}
116
117test "AES256GCM - Associated data only" {
118 const key: [AES256GCM.key_length]u8 = [_]u8{0x69} ** AES256GCM.key_length;
119 const nonce: [AES256GCM.nonce_length]u8 = [_]u8{0x42} ** AES256GCM.nonce_length;
120 const m = "";
121 const ad = "Test with associated data";
122 var c: [m.len]u8 = undefined;
123 var tag: [AES256GCM.tag_length]u8 = undefined;
124
125 AES256GCM.encrypt(&c, &tag, m, ad, nonce, key);
126 htest.assertEqual("262ed164c2dfb26e080a9d108dd9dd4c", &tag);
127}
128
129test "AES256GCM - Message only" {
130 const key: [AES256GCM.key_length]u8 = [_]u8{0x69} ** AES256GCM.key_length;
131 const nonce: [AES256GCM.nonce_length]u8 = [_]u8{0x42} ** AES256GCM.nonce_length;
132 const m = "Test with message only";
133 const ad = "";
134 var c: [m.len]u8 = undefined;
135 var m2: [m.len]u8 = undefined;
136 var tag: [AES256GCM.tag_length]u8 = undefined;
137
138 AES256GCM.encrypt(&c, &tag, m, ad, nonce, key);
139 try AES256GCM.decrypt(&m2, &c, tag, ad, nonce, key);
140 testing.expectEqualSlices(u8, m[0..], m2[0..]);
141
142 htest.assertEqual("5ca1642d90009fea33d01f78cf6eefaf01d539472f7c", &c);
143 htest.assertEqual("07cd7fc9103e2f9e9bf2dfaa319caff4", &tag);
144}
145
146test "AES256GCM - Message and associated data" {
147 const key: [AES256GCM.key_length]u8 = [_]u8{0x69} ** AES256GCM.key_length;
148 const nonce: [AES256GCM.nonce_length]u8 = [_]u8{0x42} ** AES256GCM.nonce_length;
149 const m = "Test with message";
150 const ad = "Test with associated data";
151 var c: [m.len]u8 = undefined;
152 var m2: [m.len]u8 = undefined;
153 var tag: [AES256GCM.tag_length]u8 = undefined;
154
155 AES256GCM.encrypt(&c, &tag, m, ad, nonce, key);
156 try AES256GCM.decrypt(&m2, &c, tag, ad, nonce, key);
157 testing.expectEqualSlices(u8, m[0..], m2[0..]);
158
159 htest.assertEqual("5ca1642d90009fea33d01f78cf6eefaf01", &c);
160 htest.assertEqual("64accec679d444e2373bd9f6796c0d2c", &tag);
161}
lib/std/crypto/benchmark.zig+3
......@@ -57,6 +57,7 @@ pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64
5757}
5858
5959const macs = [_]Crypto{
60 Crypto{ .ty = crypto.onetimeauth.Ghash, .name = "ghash" },
6061 Crypto{ .ty = crypto.onetimeauth.Poly1305, .name = "poly1305" },
6162 Crypto{ .ty = crypto.auth.hmac.HmacMd5, .name = "hmac-md5" },
6263 Crypto{ .ty = crypto.auth.hmac.HmacSha1, .name = "hmac-sha1" },
......@@ -151,6 +152,8 @@ const aeads = [_]Crypto{
151152 Crypto{ .ty = crypto.aead.Gimli, .name = "gimli-aead" },
152153 Crypto{ .ty = crypto.aead.AEGIS128L, .name = "aegis-128l" },
153154 Crypto{ .ty = crypto.aead.AEGIS256, .name = "aegis-256" },
155 Crypto{ .ty = crypto.aead.AES128GCM, .name = "aes128-gcm" },
156 Crypto{ .ty = crypto.aead.AES256GCM, .name = "aes256-gcm" },
154157};
155158
156159pub fn benchmarkAead(comptime Aead: anytype, comptime bytes: comptime_int) !u64 {
lib/std/crypto/ghash.zig created+317
......@@ -0,0 +1,317 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2020 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6//
7// Adapted from BearSSL's ctmul64 implementation originally written by Thomas Pornin <pornin@bolet.org>
8
9const std = @import("../std.zig");
10const assert = std.debug.assert;
11const math = std.math;
12const mem = std.mem;
13
14/// GHASH is a universal hash function that features multiplication
15/// by a fixed parameter within a Galois field.
16///
17/// It is not a general purpose hash function - The key must be secret, unpredictable and never reused.
18///
19/// GHASH is typically used to compute the authentication tag in the AES-GCM construction.
20pub const Ghash = struct {
21 pub const block_size: usize = 16;
22 pub const mac_length = 16;
23 pub const minimum_key_length = 16;
24
25 y0: u64 = 0,
26 y1: u64 = 0,
27 h0: u64,
28 h1: u64,
29 h2: u64,
30 h0r: u64,
31 h1r: u64,
32 h2r: u64,
33
34 hh0: u64 = undefined,
35 hh1: u64 = undefined,
36 hh2: u64 = undefined,
37 hh0r: u64 = undefined,
38 hh1r: u64 = undefined,
39 hh2r: u64 = undefined,
40
41 leftover: usize = 0,
42 buf: [block_size]u8 align(16) = undefined,
43
44 pub fn init(key: *const [minimum_key_length]u8) Ghash {
45 const h1 = mem.readIntBig(u64, key[0..8]);
46 const h0 = mem.readIntBig(u64, key[8..16]);
47 const h1r = @bitReverse(u64, h1);
48 const h0r = @bitReverse(u64, h0);
49 const h2 = h0 ^ h1;
50 const h2r = h0r ^ h1r;
51
52 if (std.builtin.mode == .ReleaseSmall) {
53 return Ghash{
54 .h0 = h0,
55 .h1 = h1,
56 .h2 = h2,
57 .h0r = h0r,
58 .h1r = h1r,
59 .h2r = h2r,
60 };
61 } else {
62 // Precompute H^2
63 var hh = Ghash{
64 .h0 = h0,
65 .h1 = h1,
66 .h2 = h2,
67 .h0r = h0r,
68 .h1r = h1r,
69 .h2r = h2r,
70 };
71 hh.update(key);
72 const hh1 = hh.y1;
73 const hh0 = hh.y0;
74 const hh1r = @bitReverse(u64, hh1);
75 const hh0r = @bitReverse(u64, hh0);
76 const hh2 = hh0 ^ hh1;
77 const hh2r = hh0r ^ hh1r;
78
79 return Ghash{
80 .h0 = h0,
81 .h1 = h1,
82 .h2 = h2,
83 .h0r = h0r,
84 .h1r = h1r,
85 .h2r = h2r,
86
87 .hh0 = hh0,
88 .hh1 = hh1,
89 .hh2 = hh2,
90 .hh0r = hh0r,
91 .hh1r = hh1r,
92 .hh2r = hh2r,
93 };
94 }
95 }
96
97 inline fn clmul_pclmul(x: u64, y: u64) u64 {
98 const Vector = std.meta.Vector;
99 const product = asm (
100 \\ vpclmulqdq $0x00, %[x], %[y], %[out]
101 : [out] "=x" (-> Vector(2, u64))
102 : [x] "x" (@bitCast(Vector(2, u64), @as(u128, x))),
103 [y] "x" (@bitCast(Vector(2, u64), @as(u128, y)))
104 );
105 return product[0];
106 }
107
108 fn clmul_soft(x: u64, y: u64) u64 {
109 const x0 = x & 0x1111111111111111;
110 const x1 = x & 0x2222222222222222;
111 const x2 = x & 0x4444444444444444;
112 const x3 = x & 0x8888888888888888;
113 const y0 = y & 0x1111111111111111;
114 const y1 = y & 0x2222222222222222;
115 const y2 = y & 0x4444444444444444;
116 const y3 = y & 0x8888888888888888;
117 var z0 = (x0 *% y0) ^ (x1 *% y3) ^ (x2 *% y2) ^ (x3 *% y1);
118 var z1 = (x0 *% y1) ^ (x1 *% y0) ^ (x2 *% y3) ^ (x3 *% y2);
119 var z2 = (x0 *% y2) ^ (x1 *% y1) ^ (x2 *% y0) ^ (x3 *% y3);
120 var z3 = (x0 *% y3) ^ (x1 *% y2) ^ (x2 *% y1) ^ (x3 *% y0);
121 z0 &= 0x1111111111111111;
122 z1 &= 0x2222222222222222;
123 z2 &= 0x4444444444444444;
124 z3 &= 0x8888888888888888;
125 return z0 | z1 | z2 | z3;
126 }
127
128 const has_pclmul = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .pclmul);
129 const has_avx = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .avx);
130 const clmul = if (std.Target.current.cpu.arch == .x86_64 and has_pclmul and has_avx) clmul_pclmul else clmul_soft;
131
132 fn blocks(st: *Ghash, msg: []const u8) void {
133 assert(msg.len % 16 == 0); // GHASH blocks() expects full blocks
134 var y1 = st.y1;
135 var y0 = st.y0;
136
137 var i: usize = 0;
138
139 // 2-blocks aggregated reduction
140 if (std.builtin.mode != .ReleaseSmall) {
141 while (i + 32 <= msg.len) : (i += 32) {
142 // B0 * H^2 unreduced
143 y1 ^= mem.readIntBig(u64, msg[i..][0..8]);
144 y0 ^= mem.readIntBig(u64, msg[i..][8..16]);
145
146 const y1r = @bitReverse(u64, y1);
147 const y0r = @bitReverse(u64, y0);
148 const y2 = y0 ^ y1;
149 const y2r = y0r ^ y1r;
150
151 var z0 = clmul(y0, st.hh0);
152 var z1 = clmul(y1, st.hh1);
153 var z2 = clmul(y2, st.hh2) ^ z0 ^ z1;
154 var z0h = clmul(y0r, st.hh0r);
155 var z1h = clmul(y1r, st.hh1r);
156 var z2h = clmul(y2r, st.hh2r) ^ z0h ^ z1h;
157
158 // B1 * H unreduced
159 const sy1 = mem.readIntBig(u64, msg[i..][16..24]);
160 const sy0 = mem.readIntBig(u64, msg[i..][24..32]);
161
162 const sy1r = @bitReverse(u64, sy1);
163 const sy0r = @bitReverse(u64, sy0);
164 const sy2 = sy0 ^ sy1;
165 const sy2r = sy0r ^ sy1r;
166
167 const sz0 = clmul(sy0, st.h0);
168 const sz1 = clmul(sy1, st.h1);
169 const sz2 = clmul(sy2, st.h2) ^ sz0 ^ sz1;
170 const sz0h = clmul(sy0r, st.h0r);
171 const sz1h = clmul(sy1r, st.h1r);
172 const sz2h = clmul(sy2r, st.h2r) ^ sz0h ^ sz1h;
173
174 // ((B0 * H^2) + B1 * H) (mod M)
175 z0 ^= sz0;
176 z1 ^= sz1;
177 z2 ^= sz2;
178 z0h ^= sz0h;
179 z1h ^= sz1h;
180 z2h ^= sz2h;
181 z0h = @bitReverse(u64, z0h) >> 1;
182 z1h = @bitReverse(u64, z1h) >> 1;
183 z2h = @bitReverse(u64, z2h) >> 1;
184
185 var v3 = z1h;
186 var v2 = z1 ^ z2h;
187 var v1 = z0h ^ z2;
188 var v0 = z0;
189
190 v3 = (v3 << 1) | (v2 >> 63);
191 v2 = (v2 << 1) | (v1 >> 63);
192 v1 = (v1 << 1) | (v0 >> 63);
193 v0 = (v0 << 1);
194
195 v2 ^= v0 ^ (v0 >> 1) ^ (v0 >> 2) ^ (v0 >> 7);
196 v1 ^= (v0 << 63) ^ (v0 << 62) ^ (v0 << 57);
197 y1 = v3 ^ v1 ^ (v1 >> 1) ^ (v1 >> 2) ^ (v1 >> 7);
198 y0 = v2 ^ (v1 << 63) ^ (v1 << 62) ^ (v1 << 57);
199 }
200 }
201
202 // single block
203 while (i + 16 <= msg.len) : (i += 16) {
204 y1 ^= mem.readIntBig(u64, msg[i..][0..8]);
205 y0 ^= mem.readIntBig(u64, msg[i..][8..16]);
206
207 const y1r = @bitReverse(u64, y1);
208 const y0r = @bitReverse(u64, y0);
209 const y2 = y0 ^ y1;
210 const y2r = y0r ^ y1r;
211
212 const z0 = clmul(y0, st.h0);
213 const z1 = clmul(y1, st.h1);
214 var z2 = clmul(y2, st.h2) ^ z0 ^ z1;
215 var z0h = clmul(y0r, st.h0r);
216 var z1h = clmul(y1r, st.h1r);
217 var z2h = clmul(y2r, st.h2r) ^ z0h ^ z1h;
218 z0h = @bitReverse(u64, z0h) >> 1;
219 z1h = @bitReverse(u64, z1h) >> 1;
220 z2h = @bitReverse(u64, z2h) >> 1;
221
222 // shift & reduce
223 var v3 = z1h;
224 var v2 = z1 ^ z2h;
225 var v1 = z0h ^ z2;
226 var v0 = z0;
227
228 v3 = (v3 << 1) | (v2 >> 63);
229 v2 = (v2 << 1) | (v1 >> 63);
230 v1 = (v1 << 1) | (v0 >> 63);
231 v0 = (v0 << 1);
232
233 v2 ^= v0 ^ (v0 >> 1) ^ (v0 >> 2) ^ (v0 >> 7);
234 v1 ^= (v0 << 63) ^ (v0 << 62) ^ (v0 << 57);
235 y1 = v3 ^ v1 ^ (v1 >> 1) ^ (v1 >> 2) ^ (v1 >> 7);
236 y0 = v2 ^ (v1 << 63) ^ (v1 << 62) ^ (v1 << 57);
237 }
238 st.y1 = y1;
239 st.y0 = y0;
240 }
241
242 pub fn update(st: *Ghash, m: []const u8) void {
243 var mb = m;
244
245 if (st.leftover > 0) {
246 const want = math.min(block_size - st.leftover, mb.len);
247 const mc = mb[0..want];
248 for (mc) |x, i| {
249 st.buf[st.leftover + i] = x;
250 }
251 mb = mb[want..];
252 st.leftover += want;
253 if (st.leftover < block_size) {
254 return;
255 }
256 st.blocks(&st.buf);
257 st.leftover = 0;
258 }
259 if (mb.len >= block_size) {
260 const want = mb.len & ~(block_size - 1);
261 st.blocks(mb[0..want]);
262 mb = mb[want..];
263 }
264 if (mb.len > 0) {
265 for (mb) |x, i| {
266 st.buf[st.leftover + i] = x;
267 }
268 st.leftover += mb.len;
269 }
270 }
271
272 /// Zero-pad to align the next input to the first byte of a block
273 pub fn pad(st: *Ghash) void {
274 if (st.leftover == 0) {
275 return;
276 }
277 var i = st.leftover;
278 while (i < block_size) : (i += 1) {
279 st.buf[i] = 0;
280 }
281 st.blocks(&st.buf);
282 st.leftover = 0;
283 }
284
285 pub fn final(st: *Ghash, out: *[mac_length]u8) void {
286 st.pad();
287 mem.writeIntBig(u64, out[0..8], st.y1);
288 mem.writeIntBig(u64, out[8..16], st.y0);
289
290 mem.secureZero(u8, @ptrCast([*]u8, st)[0..@sizeOf(Ghash)]);
291 }
292
293 pub fn create(out: *[mac_length]u8, msg: []const u8, key: *const [minimum_key_length]u8) void {
294 var st = Ghash.init(key);
295 st.update(msg);
296 st.final(out);
297 }
298};
299
300const htest = @import("test.zig");
301
302test "ghash" {
303 const key = [_]u8{0x42} ** 16;
304 const m = [_]u8{0x69} ** 256;
305
306 var st = Ghash.init(&key);
307 st.update(&m);
308 var out: [16]u8 = undefined;
309 st.final(&out);
310 htest.assertEqual("889295fa746e8b174bf4ec80a65dea41", &out);
311
312 st = Ghash.init(&key);
313 st.update(m[0..100]);
314 st.update(m[100..]);
315 st.final(&out);
316 htest.assertEqual("889295fa746e8b174bf4ec80a65dea41", &out);
317}
lib/std/crypto/hkdf.zig created+66
......@@ -0,0 +1,66 @@
1const std = @import("../std.zig");
2const assert = std.debug.assert;
3const hmac = std.crypto.auth.hmac;
4const mem = std.mem;
5
6/// HKDF-SHA256
7pub const HkdfSha256 = Hkdf(hmac.sha2.HmacSha256);
8
9/// HKDF-SHA512
10pub const HkdfSha512 = Hkdf(hmac.sha2.HmacSha512);
11
12/// The Hkdf construction takes some source of initial keying material and
13/// derives one or more uniform keys from it.
14pub fn Hkdf(comptime Hmac: type) type {
15 return struct {
16 /// Return a master key from a salt and initial keying material.
17 fn extract(salt: []const u8, ikm: []const u8) [Hmac.mac_length]u8 {
18 var prk: [Hmac.mac_length]u8 = undefined;
19 Hmac.create(&prk, ikm, salt);
20 return prk;
21 }
22
23 /// Derive a subkey from a master key `prk` and a subkey description `ctx`.
24 fn expand(out: []u8, ctx: []const u8, prk: [Hmac.mac_length]u8) void {
25 assert(out.len < Hmac.mac_length * 255); // output size is too large for the Hkdf construction
26 var i: usize = 0;
27 var counter = [1]u8{1};
28 while (i + Hmac.mac_length <= out.len) : (i += Hmac.mac_length) {
29 var st = Hmac.init(&prk);
30 if (i != 0) {
31 st.update(out[i - Hmac.mac_length ..][0..Hmac.mac_length]);
32 }
33 st.update(ctx);
34 st.update(&counter);
35 st.final(out[i..][0..Hmac.mac_length]);
36 counter[0] += 1;
37 }
38 const left = out.len % Hmac.mac_length;
39 if (left > 0) {
40 var st = Hmac.init(&prk);
41 if (i != 0) {
42 st.update(out[i - Hmac.mac_length ..][0..Hmac.mac_length]);
43 }
44 st.update(ctx);
45 st.update(&counter);
46 var tmp: [Hmac.mac_length]u8 = undefined;
47 st.final(tmp[0..Hmac.mac_length]);
48 mem.copy(u8, out[i..][0..left], tmp[0..left]);
49 }
50 }
51 };
52}
53
54const htest = @import("test.zig");
55
56test "Hkdf" {
57 const ikm = [_]u8{0x0b} ** 22;
58 const salt = [_]u8{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c };
59 const context = [_]u8{ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 };
60 const kdf = HkdfSha256;
61 const prk = kdf.extract(&salt, &ikm);
62 htest.assertEqual("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5", &prk);
63 var out: [42]u8 = undefined;
64 kdf.expand(&out, &context, prk);
65 htest.assertEqual("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865", &out);
66}
lib/std/crypto/poly1305.zig+17-9
......@@ -22,8 +22,7 @@ pub const Poly1305 = struct {
2222 // partial block buffer
2323 buf: [block_size]u8 align(16) = undefined,
2424
25 pub fn init(key: []const u8) Poly1305 {
26 std.debug.assert(key.len >= minimum_key_length);
25 pub fn init(key: *const [minimum_key_length]u8) Poly1305 {
2726 const t0 = mem.readIntLittle(u64, key[0..8]);
2827 const t1 = mem.readIntLittle(u64, key[8..16]);
2928 return Poly1305{
......@@ -92,7 +91,7 @@ pub const Poly1305 = struct {
9291 }
9392 mb = mb[want..];
9493 st.leftover += want;
95 if (st.leftover > block_size) {
94 if (st.leftover < block_size) {
9695 return;
9796 }
9897 st.blocks(&st.buf, false);
......@@ -115,8 +114,20 @@ pub const Poly1305 = struct {
115114 }
116115 }
117116
118 pub fn final(st: *Poly1305, out: []u8) void {
119 std.debug.assert(out.len >= mac_length);
117 /// Zero-pad to align the next input to the first byte of a block
118 pub fn pad(st: *Poly1305) void {
119 if (st.leftover == 0) {
120 return;
121 }
122 var i = st.leftover;
123 while (i < block_size) : (i += 1) {
124 st.buf[i] = 0;
125 }
126 st.blocks(&st.buf);
127 st.leftover = 0;
128 }
129
130 pub fn final(st: *Poly1305, out: *[mac_length]u8) void {
120131 if (st.leftover > 0) {
121132 var i = st.leftover;
122133 st.buf[i] = 1;
......@@ -187,10 +198,7 @@ pub const Poly1305 = struct {
187198 std.mem.secureZero(u8, @ptrCast([*]u8, st)[0..@sizeOf(Poly1305)]);
188199 }
189200
190 pub fn create(out: []u8, msg: []const u8, key: []const u8) void {
191 std.debug.assert(out.len >= mac_length);
192 std.debug.assert(key.len >= minimum_key_length);
193
201 pub fn create(out: *[mac_length]u8, msg: []const u8, key: *const [minimum_key_length]u8) void {
194202 var st = Poly1305.init(key);
195203 st.update(msg);
196204 st.final(out);
lib/std/event/loop.zig+55
......@@ -647,6 +647,31 @@ pub const Loop = struct {
647647 }
648648 }
649649
650 /// Runs the provided function asynchronously. The function's frame is allocated
651 /// with `allocator` and freed when the function returns.
652 /// `func` must return void and it can be an async function.
653 /// Yields to the event loop, running the function on the next tick.
654 pub fn runDetached(self: *Loop, alloc: *mem.Allocator, comptime func: anytype, args: anytype) error{OutOfMemory}!void {
655 if (!std.io.is_async) @compileError("Can't use runDetached in non-async mode!");
656 if (@TypeOf(@call(.{}, func, args)) != void) {
657 @compileError("`func` must not have a return value");
658 }
659
660 const Wrapper = struct {
661 const Args = @TypeOf(args);
662 fn run(func_args: Args, loop: *Loop, allocator: *mem.Allocator) void {
663 loop.yield();
664 const result = @call(.{}, func, func_args);
665 suspend {
666 allocator.destroy(@frame());
667 }
668 }
669 };
670
671 var run_frame = try alloc.create(@Frame(Wrapper.run));
672 run_frame.* = async Wrapper.run(args, self, alloc);
673 }
674
650675 /// Yielding lets the event loop run, starting any unstarted async operations.
651676 /// Note that async operations automatically start when a function yields for any other reason,
652677 /// for example, when async I/O is performed. This function is intended to be used only when
......@@ -1493,3 +1518,33 @@ fn testEventLoop2(h: anyframe->i32, did_it: *bool) void {
14931518 testing.expect(value == 1234);
14941519 did_it.* = true;
14951520}
1521
1522var testRunDetachedData: usize = 0;
1523test "std.event.Loop - runDetached" {
1524 // https://github.com/ziglang/zig/issues/1908
1525 if (builtin.single_threaded) return error.SkipZigTest;
1526 if (!std.io.is_async) return error.SkipZigTest;
1527 if (true) {
1528 // https://github.com/ziglang/zig/issues/4922
1529 return error.SkipZigTest;
1530 }
1531
1532 var loop: Loop = undefined;
1533 try loop.initMultiThreaded();
1534 defer loop.deinit();
1535
1536 // Schedule the execution, won't actually start until we start the
1537 // event loop.
1538 try loop.runDetached(std.testing.allocator, testRunDetached, .{});
1539
1540 // Now we can start the event loop. The function will return only
1541 // after all tasks have been completed, allowing us to synchonize
1542 // with the previous runDetached.
1543 loop.run();
1544
1545 testing.expect(testRunDetachedData == 1);
1546}
1547
1548fn testRunDetached() void {
1549 testRunDetachedData += 1;
1550}
lib/std/fmt.zig+10
......@@ -1181,6 +1181,16 @@ fn bufPrintIntToSlice(buf: []u8, value: anytype, base: u8, uppercase: bool, opti
11811181 return buf[0..formatIntBuf(buf, value, base, uppercase, options)];
11821182}
11831183
1184pub fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [count(fmt, args)]u8 {
1185 comptime var buf: [count(fmt, args)]u8 = undefined;
1186 _ = bufPrint(&buf, fmt, args) catch unreachable;
1187 return &buf;
1188}
1189
1190test "comptimePrint" {
1191 std.testing.expectEqualSlices(u8, "100", comptime comptimePrint("{}", .{100}));
1192}
1193
11841194test "parse u64 digit too big" {
11851195 _ = parseUnsigned(u64, "123a", 10) catch |err| {
11861196 if (err == error.InvalidCharacter) return;
lib/std/fs.zig+13-5
......@@ -1856,7 +1856,7 @@ pub const Dir = struct {
18561856 }
18571857};
18581858
1859/// Returns an handle to the current working directory. It is not opened with iteration capability.
1859/// Returns a handle to the current working directory. It is not opened with iteration capability.
18601860/// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior.
18611861/// On POSIX targets, this function is comptime-callable.
18621862pub fn cwd() Dir {
......@@ -2162,7 +2162,7 @@ pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File {
21622162 return openFileAbsoluteZ(buf[0..self_exe_path.len :0].ptr, flags);
21632163}
21642164
2165pub const SelfExePathError = os.ReadLinkError || os.SysCtlError;
2165pub const SelfExePathError = os.ReadLinkError || os.SysCtlError || os.RealPathError;
21662166
21672167/// `selfExePath` except allocates the result on the heap.
21682168/// Caller owns returned memory.
......@@ -2190,10 +2190,18 @@ pub fn selfExePathAlloc(allocator: *Allocator) ![]u8 {
21902190/// TODO make the return type of this a null terminated pointer
21912191pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 {
21922192 if (is_darwin) {
2193 var u32_len: u32 = @intCast(u32, math.min(out_buffer.len, math.maxInt(u32)));
2194 const rc = std.c._NSGetExecutablePath(out_buffer.ptr, &u32_len);
2193 // Note that _NSGetExecutablePath() will return "a path" to
2194 // the executable not a "real path" to the executable.
2195 var symlink_path_buf: [MAX_PATH_BYTES:0]u8 = undefined;
2196 var u32_len: u32 = MAX_PATH_BYTES + 1; // include the sentinel
2197 const rc = std.c._NSGetExecutablePath(&symlink_path_buf, &u32_len);
21952198 if (rc != 0) return error.NameTooLong;
2196 return mem.spanZ(@ptrCast([*:0]u8, out_buffer));
2199
2200 var real_path_buf: [MAX_PATH_BYTES]u8 = undefined;
2201 const real_path = try std.os.realpathZ(&symlink_path_buf, &real_path_buf);
2202 if (real_path.len > out_buffer.len) return error.NameTooLong;
2203 std.mem.copy(u8, out_buffer, real_path);
2204 return out_buffer[0..real_path.len];
21972205 }
21982206 switch (builtin.os.tag) {
21992207 .linux => return os.readlinkZ("/proc/self/exe", out_buffer),
lib/std/fs/file.zig+9-7
......@@ -615,7 +615,7 @@ pub const File = struct {
615615 }
616616 }
617617
618 pub fn pwritev(self: File, iovecs: []os.iovec_const, offset: usize) PWriteError!usize {
618 pub fn pwritev(self: File, iovecs: []os.iovec_const, offset: u64) PWriteError!usize {
619619 if (is_windows) {
620620 // TODO improve this to use WriteFileScatter
621621 if (iovecs.len == 0) return @as(usize, 0);
......@@ -632,11 +632,11 @@ pub const File = struct {
632632
633633 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in
634634 /// order to handle partial writes from the underlying OS layer.
635 pub fn pwritevAll(self: File, iovecs: []os.iovec_const, offset: usize) PWriteError!void {
635 pub fn pwritevAll(self: File, iovecs: []os.iovec_const, offset: u64) PWriteError!void {
636636 if (iovecs.len == 0) return;
637637
638638 var i: usize = 0;
639 var off: usize = 0;
639 var off: u64 = 0;
640640 while (true) {
641641 var amt = try self.pwritev(iovecs[i..], offset + off);
642642 off += amt;
......@@ -652,14 +652,16 @@ pub const File = struct {
652652
653653 pub const CopyRangeError = os.CopyFileRangeError;
654654
655 pub fn copyRange(in: File, in_offset: u64, out: File, out_offset: u64, len: usize) CopyRangeError!usize {
656 return os.copy_file_range(in.handle, in_offset, out.handle, out_offset, len, 0);
655 pub fn copyRange(in: File, in_offset: u64, out: File, out_offset: u64, len: u64) CopyRangeError!u64 {
656 const adjusted_len = math.cast(usize, len) catch math.maxInt(usize);
657 const result = try os.copy_file_range(in.handle, in_offset, out.handle, out_offset, adjusted_len, 0);
658 return result;
657659 }
658660
659661 /// Returns the number of bytes copied. If the number read is smaller than `buffer.len`, it
660662 /// means the in file reached the end. Reaching the end of a file is not an error condition.
661 pub fn copyRangeAll(in: File, in_offset: u64, out: File, out_offset: u64, len: usize) CopyRangeError!usize {
662 var total_bytes_copied: usize = 0;
663 pub fn copyRangeAll(in: File, in_offset: u64, out: File, out_offset: u64, len: u64) CopyRangeError!u64 {
664 var total_bytes_copied: u64 = 0;
663665 var in_off = in_offset;
664666 var out_off = out_offset;
665667 while (total_bytes_copied < len) {
lib/std/macho.zig+44
......@@ -1257,3 +1257,47 @@ pub const reloc_type_x86_64 = packed enum(u4) {
12571257 /// for thread local variables
12581258 X86_64_RELOC_TLV,
12591259};
1260
1261/// This symbol is a reference to an external non-lazy (data) symbol.
1262pub const REFERENCE_FLAG_UNDEFINED_NON_LAZY: u16 = 0x0;
1263
1264/// This symbol is a reference to an external lazy symbol—that is, to a function call.
1265pub const REFERENCE_FLAG_UNDEFINED_LAZY: u16 = 0x1;
1266
1267/// This symbol is defined in this module.
1268pub const REFERENCE_FLAG_DEFINED: u16 = 0x2;
1269
1270/// This symbol is defined in this module and is visible only to modules within this shared library.
1271pub const REFERENCE_FLAG_PRIVATE_DEFINED: u16 = 3;
1272
1273/// This symbol is defined in another module in this file, is a non-lazy (data) symbol, and is visible
1274/// only to modules within this shared library.
1275pub const REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY: u16 = 4;
1276
1277/// This symbol is defined in another module in this file, is a lazy (function) symbol, and is visible
1278/// only to modules within this shared library.
1279pub const REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY: u16 = 5;
1280
1281/// Must be set for any defined symbol that is referenced by dynamic-loader APIs (such as dlsym and
1282/// NSLookupSymbolInImage) and not ordinary undefined symbol references. The strip tool uses this bit
1283/// to avoid removing symbols that must exist: If the symbol has this bit set, strip does not strip it.
1284pub const REFERENCED_DYNAMICALLY: u16 = 0x10;
1285
1286/// Used by the dynamic linker at runtime. Do not set this bit.
1287pub const N_DESC_DISCARDED: u16 = 0x20;
1288
1289/// Indicates that this symbol is a weak reference. If the dynamic linker cannot find a definition
1290/// for this symbol, it sets the address of this symbol to 0. The static linker sets this symbol given
1291/// the appropriate weak-linking flags.
1292pub const N_WEAK_REF: u16 = 0x40;
1293
1294/// Indicates that this symbol is a weak definition. If the static linker or the dynamic linker finds
1295/// another (non-weak) definition for this symbol, the weak definition is ignored. Only symbols in a
1296/// coalesced section (page 23) can be marked as a weak definition.
1297pub const N_WEAK_DEF: u16 = 0x80;
1298
1299/// The N_SYMBOL_RESOLVER bit of the n_desc field indicates that the
1300/// that the function is actually a resolver function and should
1301/// be called to get the address of the real function to use.
1302/// This bit is only available in .o files (MH_OBJECT filetype)
1303pub const N_SYMBOL_RESOLVER: u16 = 0x100;
lib/std/math/big/int.zig+124
......@@ -58,6 +58,11 @@ pub fn calcSetStringLimbCount(base: u8, string_len: usize) usize {
5858 return (string_len + (limb_bits / base - 1)) / (limb_bits / base);
5959}
6060
61pub fn calcPowLimbsBufferLen(a_bit_count: usize, y: usize) usize {
62 // The 2 accounts for the minimum space requirement for llmulacc
63 return 2 + (a_bit_count * y + (limb_bits - 1)) / limb_bits;
64}
65
6166/// a + b * c + *carry, sets carry to the overflow bits
6267pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb {
6368 @setRuntimeSafety(debug_safety);
......@@ -597,6 +602,52 @@ pub const Mutable = struct {
597602 return gcdLehmer(rma, x_copy, y_copy, limbs_buffer);
598603 }
599604
605 /// q = a ^ b
606 ///
607 /// r may not alias a.
608 ///
609 /// Asserts that `r` has enough limbs to store the result. Upper bound is
610 /// `calcPowLimbsBufferLen(a.bitCountAbs(), b)`.
611 ///
612 /// `limbs_buffer` is used for temporary storage.
613 /// The amount required is given by `calcPowLimbsBufferLen`.
614 pub fn pow(r: *Mutable, a: Const, b: u32, limbs_buffer: []Limb) !void {
615 assert(r.limbs.ptr != a.limbs.ptr); // illegal aliasing
616
617 // Handle all the trivial cases first
618 switch (b) {
619 0 => {
620 // a^0 = 1
621 return r.set(1);
622 },
623 1 => {
624 // a^1 = a
625 return r.copy(a);
626 },
627 else => {},
628 }
629
630 if (a.eqZero()) {
631 // 0^b = 0
632 return r.set(0);
633 } else if (a.limbs.len == 1 and a.limbs[0] == 1) {
634 // 1^b = 1 and -1^b = ±1
635 r.set(1);
636 r.positive = a.positive or (b & 1) == 0;
637 return;
638 }
639
640 // Here a>1 and b>1
641 const needed_limbs = calcPowLimbsBufferLen(a.bitCountAbs(), b);
642 assert(r.limbs.len >= needed_limbs);
643 assert(limbs_buffer.len >= needed_limbs);
644
645 llpow(r.limbs, a.limbs, b, limbs_buffer);
646
647 r.normalize(needed_limbs);
648 r.positive = a.positive or (b & 1) == 0;
649 }
650
600651 /// rma may not alias x or y.
601652 /// x and y may alias each other.
602653 /// Asserts that `rma` has enough limbs to store the result. Upper bound is given by `calcGcdNoAliasLimbLen`.
......@@ -1775,6 +1826,29 @@ pub const Managed = struct {
17751826 try m.gcd(x.toConst(), y.toConst(), &limbs_buffer);
17761827 rma.setMetadata(m.positive, m.len);
17771828 }
1829
1830 pub fn pow(rma: *Managed, a: Managed, b: u32) !void {
1831 const needed_limbs = calcPowLimbsBufferLen(a.bitCountAbs(), b);
1832
1833 const limbs_buffer = try rma.allocator.alloc(Limb, needed_limbs);
1834 defer rma.allocator.free(limbs_buffer);
1835
1836 if (rma.limbs.ptr == a.limbs.ptr) {
1837 var m = try Managed.initCapacity(rma.allocator, needed_limbs);
1838 errdefer m.deinit();
1839 var m_mut = m.toMutable();
1840 try m_mut.pow(a.toConst(), b, limbs_buffer);
1841 m.setMetadata(m_mut.positive, m_mut.len);
1842
1843 rma.deinit();
1844 rma.swap(&m);
1845 } else {
1846 try rma.ensureCapacity(needed_limbs);
1847 var rma_mut = rma.toMutable();
1848 try rma_mut.pow(a.toConst(), b, limbs_buffer);
1849 rma.setMetadata(rma_mut.positive, rma_mut.len);
1850 }
1851 }
17781852};
17791853
17801854/// Knuth 4.3.1, Algorithm M.
......@@ -2129,6 +2203,56 @@ fn llxor(r: []Limb, a: []const Limb, b: []const Limb) void {
21292203 }
21302204}
21312205
2206/// Knuth 4.6.3
2207fn llpow(r: []Limb, a: []const Limb, b: u32, tmp_limbs: []Limb) void {
2208 var tmp1: []Limb = undefined;
2209 var tmp2: []Limb = undefined;
2210
2211 // Multiplication requires no aliasing between the operand and the result
2212 // variable, use the output limbs and another temporary set to overcome this
2213 // limitation.
2214 // The initial assignment makes the result end in `r` so an extra memory
2215 // copy is saved, each 1 flips the index twice so it's a no-op so count the
2216 // 0.
2217 const b_leading_zeros = @intCast(u5, @clz(u32, b));
2218 const exp_zeros = @popCount(u32, ~b) - b_leading_zeros;
2219 if (exp_zeros & 1 != 0) {
2220 tmp1 = tmp_limbs;
2221 tmp2 = r;
2222 } else {
2223 tmp1 = r;
2224 tmp2 = tmp_limbs;
2225 }
2226
2227 const a_norm = a[0..llnormalize(a)];
2228
2229 mem.copy(Limb, tmp1, a_norm);
2230 mem.set(Limb, tmp1[a_norm.len..], 0);
2231
2232 // Scan the exponent as a binary number, from left to right, dropping the
2233 // most significant bit set.
2234 const exp_bits = @intCast(u5, 31 - b_leading_zeros);
2235 var exp = @bitReverse(u32, b) >> 1 + b_leading_zeros;
2236
2237 var i: u5 = 0;
2238 while (i < exp_bits) : (i += 1) {
2239 // Square
2240 {
2241 mem.set(Limb, tmp2, 0);
2242 const op = tmp1[0..llnormalize(tmp1)];
2243 llmulacc(null, tmp2, op, op);
2244 mem.swap([]Limb, &tmp1, &tmp2);
2245 }
2246 // Multiply by a
2247 if (exp & 1 != 0) {
2248 mem.set(Limb, tmp2, 0);
2249 llmulacc(null, tmp2, tmp1[0..llnormalize(tmp1)], a_norm);
2250 mem.swap([]Limb, &tmp1, &tmp2);
2251 }
2252 exp >>= 1;
2253 }
2254}
2255
21322256// Storage must live for the lifetime of the returned value
21332257fn fixedIntFromSignedDoubleLimb(A: SignedDoubleLimb, storage: []Limb) Mutable {
21342258 assert(storage.len >= 2);
lib/std/math/big/int_test.zig+52
......@@ -1480,3 +1480,55 @@ test "big.int const to managed" {
14801480
14811481 testing.expect(a.toConst().eq(b.toConst()));
14821482}
1483
1484test "big.int pow" {
1485 {
1486 var a = try Managed.initSet(testing.allocator, 10);
1487 defer a.deinit();
1488
1489 try a.pow(a, 8);
1490 testing.expectEqual(@as(u32, 100000000), try a.to(u32));
1491 }
1492 {
1493 var a = try Managed.initSet(testing.allocator, 10);
1494 defer a.deinit();
1495
1496 var y = try Managed.init(testing.allocator);
1497 defer y.deinit();
1498
1499 // y and a are not aliased
1500 try y.pow(a, 123);
1501 // y and a are aliased
1502 try a.pow(a, 123);
1503
1504 testing.expect(a.eq(y));
1505
1506 const ys = try y.toString(testing.allocator, 16, false);
1507 defer testing.allocator.free(ys);
1508 testing.expectEqualSlices(
1509 u8,
1510 "183425a5f872f126e00a5ad62c839075cd6846c6fb0230887c7ad7a9dc530fcb" ++
1511 "4933f60e8000000000000000000000000000000",
1512 ys,
1513 );
1514 }
1515 // Special cases
1516 {
1517 var a = try Managed.initSet(testing.allocator, 0);
1518 defer a.deinit();
1519
1520 try a.pow(a, 100);
1521 testing.expectEqual(@as(i32, 0), try a.to(i32));
1522
1523 try a.set(1);
1524 try a.pow(a, 0);
1525 testing.expectEqual(@as(i32, 1), try a.to(i32));
1526 try a.pow(a, 100);
1527 testing.expectEqual(@as(i32, 1), try a.to(i32));
1528 try a.set(-1);
1529 try a.pow(a, 15);
1530 testing.expectEqual(@as(i32, -1), try a.to(i32));
1531 try a.pow(a, 16);
1532 testing.expectEqual(@as(i32, 1), try a.to(i32));
1533 }
1534}
lib/std/meta.zig+2
......@@ -854,6 +854,7 @@ pub fn ArgsTuple(comptime Function: type) type {
854854 .field_type = arg.arg_type.?,
855855 .default_value = @as(?(arg.arg_type.?), null),
856856 .is_comptime = false,
857 .alignment = @alignOf(arg.arg_type.?),
857858 };
858859 }
859860
......@@ -884,6 +885,7 @@ pub fn Tuple(comptime types: []const type) type {
884885 .field_type = T,
885886 .default_value = @as(?T, null),
886887 .is_comptime = false,
888 .alignment = @alignOf(T),
887889 };
888890 }
889891
lib/std/meta/trailer_flags.zig+1
......@@ -47,6 +47,7 @@ pub fn TrailerFlags(comptime Fields: type) type {
4747 @as(?struct_field.field_type, null),
4848 ),
4949 .is_comptime = false,
50 .alignment = @alignOf(?struct_field.field_type),
5051 };
5152 }
5253 break :blk @Type(.{
lib/std/os.zig+31-1
......@@ -3993,7 +3993,7 @@ pub const RealPathError = error{
39933993/// Expands all symbolic links and resolves references to `.`, `..`, and
39943994/// extra `/` characters in `pathname`.
39953995/// The return value is a slice of `out_buffer`, but not necessarily from the beginning.
3996/// See also `realpathC` and `realpathW`.
3996/// See also `realpathZ` and `realpathW`.
39973997pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
39983998 if (builtin.os.tag == .windows) {
39993999 const pathname_w = try windows.sliceToPrefixedFileW(pathname);
......@@ -5410,3 +5410,33 @@ pub fn prctl(option: i32, args: anytype) PrctlError!u31 {
54105410 else => |err| return std.os.unexpectedErrno(err),
54115411 }
54125412}
5413
5414pub const GetrlimitError = UnexpectedError;
5415
5416pub fn getrlimit(resource: rlimit_resource) GetrlimitError!rlimit {
5417 // TODO implement for systems other than linux and enable test
5418 var limits: rlimit = undefined;
5419 const rc = system.getrlimit(resource, &limits);
5420 switch (errno(rc)) {
5421 0 => return limits,
5422 EFAULT => unreachable, // bogus pointer
5423 EINVAL => unreachable,
5424 else => |err| return std.os.unexpectedErrno(err),
5425 }
5426}
5427
5428pub const SetrlimitError = error{
5429 PermissionDenied,
5430} || UnexpectedError;
5431
5432pub fn setrlimit(resource: rlimit_resource, limits: rlimit) SetrlimitError!void {
5433 // TODO implement for systems other than linux and enable test
5434 const rc = system.setrlimit(resource, &limits);
5435 switch (errno(rc)) {
5436 0 => return,
5437 EFAULT => unreachable, // bogus pointer
5438 EINVAL => unreachable,
5439 EPERM => return error.PermissionDenied,
5440 else => |err| return std.os.unexpectedErrno(err),
5441 }
5442}
lib/std/os/bits/linux.zig+76
......@@ -1890,3 +1890,79 @@ pub const ifreq = extern struct {
18901890 data: ?[*]u8,
18911891 },
18921892};
1893
1894// doc comments copied from musl
1895pub const rlimit_resource = extern enum(c_int) {
1896 /// Per-process CPU limit, in seconds.
1897 CPU,
1898
1899 /// Largest file that can be created, in bytes.
1900 FSIZE,
1901
1902 /// Maximum size of data segment, in bytes.
1903 DATA,
1904
1905 /// Maximum size of stack segment, in bytes.
1906 STACK,
1907
1908 /// Largest core file that can be created, in bytes.
1909 CORE,
1910
1911 /// Largest resident set size, in bytes.
1912 /// This affects swapping; processes that are exceeding their
1913 /// resident set size will be more likely to have physical memory
1914 /// taken from them.
1915 RSS,
1916
1917 /// Number of processes.
1918 NPROC,
1919
1920 /// Number of open files.
1921 NOFILE,
1922
1923 /// Locked-in-memory address space.
1924 MEMLOCK,
1925
1926 /// Address space limit.
1927 AS,
1928
1929 /// Maximum number of file locks.
1930 LOCKS,
1931
1932 /// Maximum number of pending signals.
1933 SIGPENDING,
1934
1935 /// Maximum bytes in POSIX message queues.
1936 MSGQUEUE,
1937
1938 /// Maximum nice priority allowed to raise to.
1939 /// Nice levels 19 .. -20 correspond to 0 .. 39
1940 /// values of this resource limit.
1941 NICE,
1942
1943 /// Maximum realtime priority allowed for non-priviledged
1944 /// processes.
1945 RTPRIO,
1946
1947 /// Maximum CPU time in µs that a process scheduled under a real-time
1948 /// scheduling policy may consume without making a blocking system
1949 /// call before being forcibly descheduled.
1950 RTTIME,
1951
1952 _,
1953};
1954
1955pub const rlim_t = u64;
1956
1957/// No limit
1958pub const RLIM_INFINITY = ~@as(rlim_t, 0);
1959
1960pub const RLIM_SAVED_MAX = RLIM_INFINITY;
1961pub const RLIM_SAVED_CUR = RLIM_INFINITY;
1962
1963pub const rlimit = extern struct {
1964 /// Soft limit
1965 cur: rlim_t,
1966 /// Hard limit
1967 max: rlim_t,
1968};
lib/std/os/linux.zig+20
......@@ -1263,6 +1263,26 @@ pub fn prctl(option: i32, arg2: usize, arg3: usize, arg4: usize, arg5: usize) us
12631263 return syscall5(.prctl, @bitCast(usize, @as(isize, option)), arg2, arg3, arg4, arg5);
12641264}
12651265
1266pub fn getrlimit(resource: rlimit_resource, rlim: *rlimit) usize {
1267 // use prlimit64 to have 64 bit limits on 32 bit platforms
1268 return prlimit(0, resource, null, rlim);
1269}
1270
1271pub fn setrlimit(resource: rlimit_resource, rlim: *const rlimit) usize {
1272 // use prlimit64 to have 64 bit limits on 32 bit platforms
1273 return prlimit(0, resource, rlim, null);
1274}
1275
1276pub fn prlimit(pid: pid_t, resource: rlimit_resource, new_limit: ?*const rlimit, old_limit: ?*rlimit) usize {
1277 return syscall4(
1278 .prlimit64,
1279 @bitCast(usize, @as(isize, pid)),
1280 @bitCast(usize, @as(isize, @enumToInt(resource))),
1281 @ptrToInt(new_limit),
1282 @ptrToInt(old_limit)
1283 );
1284}
1285
12661286test "" {
12671287 if (builtin.os.tag == .linux) {
12681288 _ = @import("linux/test.zig");
lib/std/os/test.zig+10
......@@ -591,3 +591,13 @@ test "fsync" {
591591 try os.fsync(file.handle);
592592 try os.fdatasync(file.handle);
593593}
594
595test "getrlimit and setrlimit" {
596 // TODO enable for other systems when implemented
597 if(builtin.os.tag != .linux){
598 return error.SkipZigTest;
599 }
600
601 const cpuLimit = try os.getrlimit(.CPU);
602 try os.setrlimit(.CPU, cpuLimit);
603}
lib/std/packed_int_array.zig+15
......@@ -318,9 +318,12 @@ pub fn PackedIntSliceEndian(comptime Int: type, comptime endian: builtin.Endian)
318318 };
319319}
320320
321const we_are_testing_this_with_stage1_which_leaks_comptime_memory = true;
322
321323test "PackedIntArray" {
322324 // TODO @setEvalBranchQuota generates panics in wasm32. Investigate.
323325 if (builtin.arch == .wasm32) return error.SkipZigTest;
326 if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
324327
325328 @setEvalBranchQuota(10000);
326329 const max_bits = 256;
......@@ -358,6 +361,7 @@ test "PackedIntArray" {
358361}
359362
360363test "PackedIntArray init" {
364 if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
361365 const PackedArray = PackedIntArray(u3, 8);
362366 var packed_array = PackedArray.init([_]u3{ 0, 1, 2, 3, 4, 5, 6, 7 });
363367 var i = @as(usize, 0);
......@@ -367,6 +371,7 @@ test "PackedIntArray init" {
367371test "PackedIntSlice" {
368372 // TODO @setEvalBranchQuota generates panics in wasm32. Investigate.
369373 if (builtin.arch == .wasm32) return error.SkipZigTest;
374 if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
370375
371376 @setEvalBranchQuota(10000);
372377 const max_bits = 256;
......@@ -405,6 +410,7 @@ test "PackedIntSlice" {
405410}
406411
407412test "PackedIntSlice of PackedInt(Array/Slice)" {
413 if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
408414 const max_bits = 16;
409415 const int_count = 19;
410416
......@@ -470,6 +476,7 @@ test "PackedIntSlice of PackedInt(Array/Slice)" {
470476}
471477
472478test "PackedIntSlice accumulating bit offsets" {
479 if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
473480 //bit_offset is u3, so standard debugging asserts should catch
474481 // anything
475482 {
......@@ -497,6 +504,8 @@ test "PackedIntSlice accumulating bit offsets" {
497504//@NOTE: As I do not have a big endian system to test this on,
498505// big endian values were not tested
499506test "PackedInt(Array/Slice) sliceCast" {
507 if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
508
500509 const PackedArray = PackedIntArray(u1, 16);
501510 var packed_array = PackedArray.init([_]u1{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 });
502511 const packed_slice_cast_2 = packed_array.sliceCast(u2);
......@@ -537,6 +546,8 @@ test "PackedInt(Array/Slice) sliceCast" {
537546}
538547
539548test "PackedInt(Array/Slice)Endian" {
549 if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
550
540551 {
541552 const PackedArrayBe = PackedIntArrayEndian(u4, .Big, 8);
542553 var packed_array_be = PackedArrayBe.init([_]u4{ 0, 1, 2, 3, 4, 5, 6, 7 });
......@@ -604,6 +615,8 @@ test "PackedInt(Array/Slice)Endian" {
604615// after this one is not mapped and will cause a segfault if we
605616// don't account for the bounds.
606617test "PackedIntArray at end of available memory" {
618 if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
619
607620 switch (builtin.os.tag) {
608621 .linux, .macosx, .ios, .freebsd, .netbsd, .windows => {},
609622 else => return,
......@@ -623,6 +636,8 @@ test "PackedIntArray at end of available memory" {
623636}
624637
625638test "PackedIntSlice at end of available memory" {
639 if (we_are_testing_this_with_stage1_which_leaks_comptime_memory) return error.SkipZigTest;
640
626641 switch (builtin.os.tag) {
627642 .linux, .macosx, .ios, .freebsd, .netbsd, .windows => {},
628643 else => return,
lib/std/zig/system.zig+2
......@@ -213,6 +213,8 @@ pub const NativeTargetInfo = struct {
213213 // kernel version
214214 const kernel_version = if (mem.indexOfScalar(u8, release, '-')) |pos|
215215 release[0..pos]
216 else if (mem.indexOfScalar(u8, release, '_')) |pos|
217 release[0..pos]
216218 else
217219 release;
218220
src/Compilation.zig+51-13
......@@ -8,6 +8,7 @@ const log = std.log.scoped(.compilation);
88const Target = std.Target;
99
1010const Value = @import("value.zig").Value;
11const Type = @import("type.zig").Type;
1112const target_util = @import("target.zig");
1213const Package = @import("Package.zig");
1314const link = @import("link.zig");
......@@ -352,6 +353,7 @@ pub const InitOptions = struct {
352353 time_report: bool = false,
353354 stack_report: bool = false,
354355 link_eh_frame_hdr: bool = false,
356 link_emit_relocs: bool = false,
355357 linker_script: ?[]const u8 = null,
356358 version_script: ?[]const u8 = null,
357359 override_soname: ?[]const u8 = null,
......@@ -376,6 +378,7 @@ pub const InitOptions = struct {
376378 is_compiler_rt_or_libc: bool = false,
377379 parent_compilation_link_libc: bool = false,
378380 stack_size_override: ?u64 = null,
381 image_base_override: ?u64 = null,
379382 self_exe_path: ?[]const u8 = null,
380383 version: ?std.builtin.Version = null,
381384 libc_installation: ?*const LibCInstallation = null,
......@@ -447,8 +450,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
447450 options.system_libs.len != 0 or
448451 options.link_libc or options.link_libcpp or
449452 options.link_eh_frame_hdr or
453 options.link_emit_relocs or
450454 options.output_mode == .Lib or
451455 options.lld_argv.len != 0 or
456 options.image_base_override != null or
452457 options.linker_script != null or options.version_script != null)
453458 {
454459 break :blk true;
......@@ -473,8 +478,12 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
473478 {
474479 break :dl true;
475480 }
476 if (options.system_libs.len != 0)
477 break :dl true;
481 if (options.system_libs.len != 0) {
482 // when creating a executable that links to system libraries,
483 // we require dynamic linking, but we must not link static libraries
484 // or object files dynamically!
485 break :dl (options.output_mode == .Exe);
486 }
478487
479488 break :dl false;
480489 };
......@@ -638,15 +647,19 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
638647
639648 const root_scope = rs: {
640649 if (mem.endsWith(u8, root_pkg.root_src_path, ".zig")) {
650 const struct_payload = try gpa.create(Type.Payload.EmptyStruct);
641651 const root_scope = try gpa.create(Module.Scope.File);
652 struct_payload.* = .{ .scope = &root_scope.root_container };
642653 root_scope.* = .{
643 .sub_file_path = root_pkg.root_src_path,
654 // TODO this is duped so it can be freed in Container.deinit
655 .sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path),
644656 .source = .{ .unloaded = {} },
645657 .contents = .{ .not_available = {} },
646658 .status = .never_loaded,
647659 .root_container = .{
648660 .file_scope = root_scope,
649661 .decls = .{},
662 .ty = Type.initPayload(&struct_payload.base),
650663 },
651664 };
652665 break :rs &root_scope.base;
......@@ -765,10 +778,12 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
765778 .z_nodelete = options.linker_z_nodelete,
766779 .z_defs = options.linker_z_defs,
767780 .stack_size_override = options.stack_size_override,
781 .image_base_override = options.image_base_override,
768782 .linker_script = options.linker_script,
769783 .version_script = options.version_script,
770784 .gc_sections = options.linker_gc_sections,
771785 .eh_frame_hdr = options.link_eh_frame_hdr,
786 .emit_relocs = options.link_emit_relocs,
772787 .rdynamic = options.rdynamic,
773788 .extra_lld_args = options.lld_argv,
774789 .override_soname = options.override_soname,
......@@ -785,7 +800,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
785800 .llvm_cpu_features = llvm_cpu_features,
786801 .is_compiler_rt_or_libc = options.is_compiler_rt_or_libc,
787802 .parent_compilation_link_libc = options.parent_compilation_link_libc,
788 .each_lib_rpath = options.each_lib_rpath orelse false,
803 .each_lib_rpath = options.each_lib_rpath orelse options.is_native_os,
789804 .disable_lld_caching = options.disable_lld_caching,
790805 .subsystem = options.subsystem,
791806 .is_test = options.is_test,
......@@ -1022,6 +1037,17 @@ pub fn update(self: *Compilation) !void {
10221037 else => |e| return e,
10231038 };
10241039 }
1040
1041 // TODO only analyze imports if they are still referenced
1042 for (module.import_table.items()) |entry| {
1043 entry.value.unload(module.gpa);
1044 module.analyzeContainer(&entry.value.root_container) catch |err| switch (err) {
1045 error.AnalysisFail => {
1046 assert(self.totalErrorCount() != 0);
1047 },
1048 else => |e| return e,
1049 };
1050 }
10251051 }
10261052 }
10271053
......@@ -1146,7 +1172,15 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
11461172 };
11471173}
11481174
1149pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void {
1175pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemory }!void {
1176 var progress: std.Progress = .{};
1177 var main_progress_node = try progress.start("", null);
1178 defer main_progress_node.end();
1179 if (self.color == .Off) progress.terminal = null;
1180
1181 var c_comp_progress_node = main_progress_node.start("Compile C Objects", self.c_source_files.len);
1182 defer c_comp_progress_node.end();
1183
11501184 while (self.work_queue.readItem()) |work_item| switch (work_item) {
11511185 .codegen_decl => |decl| switch (decl.analysis) {
11521186 .unreferenced => unreachable,
......@@ -1223,7 +1257,7 @@ pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void {
12231257 };
12241258 },
12251259 .c_object => |c_object| {
1226 self.updateCObject(c_object) catch |err| switch (err) {
1260 self.updateCObject(c_object, &c_comp_progress_node) catch |err| switch (err) {
12271261 error.AnalysisFail => continue,
12281262 else => {
12291263 try self.failed_c_objects.ensureCapacity(self.gpa, self.failed_c_objects.items().len + 1);
......@@ -1309,7 +1343,7 @@ pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void {
13091343 if (!build_options.is_stage1)
13101344 unreachable;
13111345
1312 self.updateStage1Module() catch |err| {
1346 self.updateStage1Module(main_progress_node) catch |err| {
13131347 fatal("unable to build stage1 zig object: {}", .{@errorName(err)});
13141348 };
13151349 },
......@@ -1470,7 +1504,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
14701504 };
14711505}
14721506
1473fn updateCObject(comp: *Compilation, c_object: *CObject) !void {
1507fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: *std.Progress.Node) !void {
14741508 if (!build_options.have_llvm) {
14751509 return comp.failCObj(c_object, "clang not available: compiler built without LLVM extensions", .{});
14761510 }
......@@ -1513,6 +1547,12 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void {
15131547 const arena = &arena_allocator.allocator;
15141548
15151549 const c_source_basename = std.fs.path.basename(c_object.src.src_path);
1550
1551 c_comp_progress_node.activate();
1552 var child_progress_node = c_comp_progress_node.start(c_source_basename, null);
1553 child_progress_node.activate();
1554 defer child_progress_node.end();
1555
15161556 // Special case when doing build-obj for just one C file. When there are more than one object
15171557 // file and building an object we need to link them together, but with just one it should go
15181558 // directly to the output file.
......@@ -2506,7 +2546,7 @@ fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CR
25062546 };
25072547}
25082548
2509fn updateStage1Module(comp: *Compilation) !void {
2549fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node) !void {
25102550 const tracy = trace(@src());
25112551 defer tracy.end();
25122552
......@@ -2550,6 +2590,8 @@ fn updateStage1Module(comp: *Compilation) !void {
25502590 man.hash.add(comp.emit_llvm_ir != null);
25512591 man.hash.add(comp.emit_analysis != null);
25522592 man.hash.add(comp.emit_docs != null);
2593 man.hash.addOptionalBytes(comp.test_filter);
2594 man.hash.addOptionalBytes(comp.test_name_prefix);
25532595
25542596 // Capture the state in case we come back from this branch where the hash doesn't match.
25552597 const prev_hash_state = man.hash.peekBin();
......@@ -2612,10 +2654,6 @@ fn updateStage1Module(comp: *Compilation) !void {
26122654 .llvm_cpu_name = if (target.cpu.model.llvm_name) |s| s.ptr else null,
26132655 .llvm_cpu_features = comp.bin_file.options.llvm_cpu_features.?,
26142656 };
2615 var progress: std.Progress = .{};
2616 var main_progress_node = try progress.start("", null);
2617 defer main_progress_node.end();
2618 if (comp.color == .Off) progress.terminal = null;
26192657
26202658 comp.stage1_cache_manifest = &man;
26212659
src/Module.zig+52-4
......@@ -70,6 +70,9 @@ deletion_set: ArrayListUnmanaged(*Decl) = .{},
7070/// Error tags and their values, tag names are duped with mod.gpa.
7171global_error_set: std.StringHashMapUnmanaged(u16) = .{},
7272
73/// Keys are fully qualified paths
74import_table: std.StringArrayHashMapUnmanaged(*Scope.File) = .{},
75
7376/// Incrementing integer used to compare against the corresponding Decl
7477/// field to determine whether a Decl's status applies to an ongoing update, or a
7578/// previous analysis.
......@@ -208,7 +211,7 @@ pub const Decl = struct {
208211 .container => {
209212 const container = @fieldParentPtr(Scope.Container, "base", self.scope);
210213 const tree = container.file_scope.contents.tree;
211 // TODO Container should have it's own decls()
214 // TODO Container should have its own decls()
212215 const decl_node = tree.root_node.decls()[self.src_index];
213216 return tree.token_locs[decl_node.firstToken()].start;
214217 },
......@@ -532,12 +535,13 @@ pub const Scope = struct {
532535
533536 /// Direct children of the file.
534537 decls: std.AutoArrayHashMapUnmanaged(*Decl, void),
535
536 // TODO implement container types and put this in a status union
537 // ty: Type
538 ty: Type,
538539
539540 pub fn deinit(self: *Container, gpa: *Allocator) void {
540541 self.decls.deinit(gpa);
542 // TODO either Container of File should have an arena for sub_file_path and ty
543 gpa.destroy(self.ty.cast(Type.Payload.EmptyStruct).?);
544 gpa.free(self.file_scope.sub_file_path);
541545 self.* = undefined;
542546 }
543547
......@@ -854,6 +858,11 @@ pub fn deinit(self: *Module) void {
854858 gpa.free(entry.key);
855859 }
856860 self.global_error_set.deinit(gpa);
861
862 for (self.import_table.items()) |entry| {
863 entry.value.base.destroy(gpa);
864 }
865 self.import_table.deinit(gpa);
857866}
858867
859868fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
......@@ -2381,6 +2390,45 @@ pub fn analyzeSlice(self: *Module, scope: *Scope, src: usize, array_ptr: *Inst,
23812390 return self.fail(scope, src, "TODO implement analysis of slice", .{});
23822391}
23832392
2393pub fn analyzeImport(self: *Module, scope: *Scope, src: usize, target_string: []const u8) !*Scope.File {
2394 // TODO if (package_table.get(target_string)) |pkg|
2395 if (self.import_table.get(target_string)) |some| {
2396 return some;
2397 }
2398
2399 // TODO check for imports outside of pkg path
2400 if (false) return error.ImportOutsidePkgPath;
2401
2402 // TODO Scope.Container arena for ty and sub_file_path
2403 const struct_payload = try self.gpa.create(Type.Payload.EmptyStruct);
2404 errdefer self.gpa.destroy(struct_payload);
2405 const file_scope = try self.gpa.create(Scope.File);
2406 errdefer self.gpa.destroy(file_scope);
2407 const file_path = try self.gpa.dupe(u8, target_string);
2408 errdefer self.gpa.free(file_path);
2409
2410 struct_payload.* = .{ .scope = &file_scope.root_container };
2411 file_scope.* = .{
2412 .sub_file_path = file_path,
2413 .source = .{ .unloaded = {} },
2414 .contents = .{ .not_available = {} },
2415 .status = .never_loaded,
2416 .root_container = .{
2417 .file_scope = file_scope,
2418 .decls = .{},
2419 .ty = Type.initPayload(&struct_payload.base),
2420 },
2421 };
2422 self.analyzeContainer(&file_scope.root_container) catch |err| switch (err) {
2423 error.AnalysisFail => {
2424 assert(self.comp.totalErrorCount() != 0);
2425 },
2426 else => |e| return e,
2427 };
2428 try self.import_table.put(self.gpa, file_scope.sub_file_path, file_scope);
2429 return file_scope;
2430}
2431
23842432/// Asserts that lhs and rhs types are both numeric.
23852433pub fn cmpNumeric(
23862434 self: *Module,
src/astgen.zig+11
......@@ -1973,6 +1973,15 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa
19731973 }
19741974}
19751975
1976fn import(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
1977 try ensureBuiltinParamCount(mod, scope, call, 1);
1978 const tree = scope.tree();
1979 const src = tree.token_locs[call.builtin_token].start;
1980 const params = call.params();
1981 const target = try expr(mod, scope, .none, params[0]);
1982 return addZIRUnOp(mod, scope, src, .import, target);
1983}
1984
19761985fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
19771986 const tree = scope.tree();
19781987 const builtin_name = tree.tokenSlice(call.builtin_token);
......@@ -1995,6 +2004,8 @@ fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.Built
19952004 } else if (mem.eql(u8, builtin_name, "@breakpoint")) {
19962005 const src = tree.token_locs[call.builtin_token].start;
19972006 return rlWrap(mod, scope, rl, try addZIRNoOp(mod, scope, src, .breakpoint));
2007 } else if (mem.eql(u8, builtin_name, "@import")) {
2008 return rlWrap(mod, scope, rl, try import(mod, scope, call));
19982009 } else {
19992010 return mod.failTok(scope, call.builtin_token, "invalid builtin function: '{}'", .{builtin_name});
20002011 }
src/codegen.zig+175-42
......@@ -17,9 +17,6 @@ const DW = std.dwarf;
1717const leb128 = std.debug.leb;
1818const log = std.log.scoped(.codegen);
1919
20// TODO Turn back on zig fmt when https://github.com/ziglang/zig/issues/5948 is implemented.
21// zig fmt: off
22
2320/// The codegen-related data that is stored in `ir.Inst.Block` instructions.
2421pub const BlockData = struct {
2522 relocs: std.ArrayListUnmanaged(Reloc) = undefined,
......@@ -35,7 +32,7 @@ pub const BlockData = struct {
3532/// comptime assert that makes sure we guessed correctly about the size. This only
3633/// exists so that we can bitcast an arch-independent field to and from the real MCValue.
3734pub const AnyMCValue = extern struct {
38 a: u64,
35 a: usize,
3936 b: u64,
4037};
4138
......@@ -170,7 +167,6 @@ pub fn generateSymbol(
170167 },
171168 .Pointer => {
172169 // TODO populate .debug_info for the pointer
173
174170 if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
175171 const decl = payload.decl;
176172 if (decl.analysis != .complete) return error.AnalysisFail;
......@@ -206,7 +202,6 @@ pub fn generateSymbol(
206202 },
207203 .Int => {
208204 // TODO populate .debug_info for the integer
209
210205 const info = typed_value.ty.intInfo(bin_file.options.target);
211206 if (info.bits == 8 and !info.signed) {
212207 const x = typed_value.val.toUnsignedInt();
......@@ -399,7 +394,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
399394 self.free_registers &= ~(@as(FreeRegInt, 1) << free_index);
400395 const reg = callee_preserved_regs[free_index];
401396 self.registers.putAssumeCapacityNoClobber(reg, inst);
402 log.debug("alloc {} => {*}", .{reg, inst});
397 log.debug("alloc {} => {*}", .{ reg, inst });
403398 return reg;
404399 }
405400
......@@ -439,7 +434,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
439434 }
440435 try branch_stack.append(.{});
441436
442 const src_data: struct {lbrace_src: usize, rbrace_src: usize, source: []const u8} = blk: {
437 const src_data: struct { lbrace_src: usize, rbrace_src: usize, source: []const u8 } = blk: {
443438 if (module_fn.owner_decl.scope.cast(Module.Scope.Container)) |container_scope| {
444439 const tree = container_scope.file_scope.contents.tree;
445440 const fn_proto = tree.root_node.decls()[module_fn.owner_decl.src_index].castTag(.FnProto).?;
......@@ -570,6 +565,39 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
570565 try self.dbgSetEpilogueBegin();
571566 }
572567 },
568 .arm => {
569 const cc = self.fn_type.fnCallingConvention();
570 if (cc != .Naked) {
571 // push {fp, lr}
572 // mov fp, sp
573 // sub sp, sp, #reloc
574 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.push(.al, .{ .fp, .lr }).toU32());
575 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .fp, Instruction.Operand.reg(.sp, Instruction.Operand.Shift.none)).toU32());
576 // TODO: prepare stack for local variables
577 // const backpatch_reloc = try self.code.addManyAsArray(4);
578
579 try self.dbgSetPrologueEnd();
580
581 try self.genBody(self.mod_fn.analysis.success);
582
583 // Backpatch stack offset
584 // const stack_end = self.max_end_stack;
585 // const aligned_stack_end = mem.alignForward(stack_end, self.stack_align);
586 // mem.writeIntLittle(u32, backpatch_reloc, Instruction.sub(.al, .sp, .sp, Instruction.Operand.imm()));
587
588 try self.dbgSetEpilogueBegin();
589
590 // mov sp, fp
591 // pop {fp, pc}
592 // TODO: return by jumping to this code, use relocations
593 // mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .sp, Instruction.Operand.reg(.fp, Instruction.Operand.Shift.none)).toU32());
594 // mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.pop(.al, .{ .fp, .pc }).toU32());
595 } else {
596 try self.dbgSetPrologueEnd();
597 try self.genBody(self.mod_fn.analysis.success);
598 try self.dbgSetEpilogueBegin();
599 }
600 },
573601 else => {
574602 try self.dbgSetPrologueEnd();
575603 try self.genBody(self.mod_fn.analysis.success);
......@@ -586,7 +614,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
586614
587615 const mcv = try self.genFuncInst(inst);
588616 if (!inst.isUnused()) {
589 log.debug("{*} => {}", .{inst, mcv});
617 log.debug("{*} => {}", .{ inst, mcv });
590618 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
591619 try branch.inst_table.putNoClobber(self.gpa, inst, mcv);
592620 }
......@@ -851,7 +879,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
851879 // No side effects, so if it's unreferenced, do nothing.
852880 if (inst.base.isUnused())
853881 return MCValue.dead;
854
882
855883 const operand = try self.resolveInst(inst.operand);
856884 const info_a = inst.operand.ty.intInfo(self.target.*);
857885 const info_b = inst.base.ty.intInfo(self.target.*);
......@@ -972,10 +1000,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
9721000 if (self.registers.getEntry(toCanonicalReg(reg))) |entry| {
9731001 entry.value = inst;
9741002 }
975 log.debug("reusing {} => {*}", .{reg, inst});
1003 log.debug("reusing {} => {*}", .{ reg, inst });
9761004 },
9771005 .stack_offset => |off| {
978 log.debug("reusing stack offset {} => {*}", .{off, inst});
1006 log.debug("reusing stack offset {} => {*}", .{ off, inst });
9791007 return true;
9801008 },
9811009 else => return false,
......@@ -1274,7 +1302,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
12741302 const result = self.args[self.arg_index];
12751303 self.arg_index += 1;
12761304
1277 const name_with_null = inst.name[0..mem.lenZ(inst.name) + 1];
1305 const name_with_null = inst.name[0 .. mem.lenZ(inst.name) + 1];
12781306 switch (result) {
12791307 .register => |reg| {
12801308 self.registers.putAssumeCapacityNoClobber(toCanonicalReg(reg), &inst.base);
......@@ -1461,7 +1489,35 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
14611489 }
14621490 },
14631491 .arm => {
1464 if (info.args.len > 0) return self.fail(inst.base.src, "TODO implement fn args for {}", .{self.target.cpu.arch});
1492 for (info.args) |mc_arg, arg_i| {
1493 const arg = inst.args[arg_i];
1494 const arg_mcv = try self.resolveInst(inst.args[arg_i]);
1495
1496 switch (mc_arg) {
1497 .none => continue,
1498 .undef => unreachable,
1499 .immediate => unreachable,
1500 .unreach => unreachable,
1501 .dead => unreachable,
1502 .embedded_in_code => unreachable,
1503 .memory => unreachable,
1504 .compare_flags_signed => unreachable,
1505 .compare_flags_unsigned => unreachable,
1506 .register => |reg| {
1507 try self.genSetReg(arg.src, reg, arg_mcv);
1508 // TODO interact with the register allocator to mark the instruction as moved.
1509 },
1510 .stack_offset => {
1511 return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});
1512 },
1513 .ptr_stack_offset => {
1514 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});
1515 },
1516 .ptr_embedded_in_code => {
1517 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
1518 },
1519 }
1520 }
14651521
14661522 if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
14671523 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
......@@ -1476,13 +1532,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
14761532 else
14771533 unreachable;
14781534
1479 // TODO only works with leaf functions
1480 // at the moment, which works fine for
1481 // Hello World, but not for real code
1482 // of course. Add pushing lr to stack
1483 // and popping after call
14841535 try self.genSetReg(inst.base.src, .lr, .{ .memory = got_addr });
1485 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.blx(.al, .lr).toU32());
1536
1537 // TODO: add Instruction.supportedOn
1538 // function for ARM
1539 if (Target.arm.featureSetHas(self.target.cpu.features, .has_v5t)) {
1540 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.blx(.al, .lr).toU32());
1541 } else {
1542 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .lr, Instruction.Operand.reg(.pc, Instruction.Operand.Shift.none)).toU32());
1543 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.bx(.al, .lr).toU32());
1544 }
14861545 } else {
14871546 return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
14881547 }
......@@ -1532,12 +1591,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
15321591 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
15331592 const func = func_val.func;
15341593 const got = &macho_file.sections.items[macho_file.got_section_index.?];
1535 const ptr_bytes = 8;
1536 const got_addr = @intCast(u32, got.addr + func.owner_decl.link.macho.offset_table_index.? * ptr_bytes);
1537 // ff 14 25 xx xx xx xx call [addr]
1538 try self.code.ensureCapacity(self.code.items.len + 7);
1539 self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 });
1540 mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), got_addr);
1594 const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64);
1595 // Here, we store the got address in %rax, and then call %rax
1596 // movabsq [addr], %rax
1597 try self.genSetReg(inst.base.src, .rax, .{ .memory = got_addr });
1598 // callq *%rax
1599 try self.code.ensureCapacity(self.code.items.len + 2);
1600 self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 });
15411601 } else {
15421602 return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
15431603 }
......@@ -1601,7 +1661,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
16011661 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.zero, 0, .ra).toU32());
16021662 },
16031663 .arm => {
1604 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.bx(.al, .lr).toU32());
1664 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .sp, Instruction.Operand.reg(.fp, Instruction.Operand.Shift.none)).toU32());
1665 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.pop(.al, .{ .fp, .pc }).toU32());
1666 // TODO: jump to the end with relocation
1667 // // Just add space for an instruction, patch this later
1668 // try self.code.resize(self.code.items.len + 4);
1669 // try self.exitlude_jump_relocs.append(self.gpa, self.code.items.len - 4);
16051670 },
16061671 else => return self.fail(src, "TODO implement return for {}", .{self.target.cpu.arch}),
16071672 }
......@@ -1709,7 +1774,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
17091774 self.code.items.len += 4;
17101775 break :reloc reloc;
17111776 },
1712 else => return self.fail(inst.base.src, "TODO implement condbr {}", .{ self.target.cpu.arch }),
1777 else => return self.fail(inst.base.src, "TODO implement condbr {}", .{self.target.cpu.arch}),
17131778 };
17141779
17151780 // Capture the state of register and stack allocation state so that we can revert to it.
......@@ -1789,7 +1854,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
17891854 }
17901855 }
17911856 };
1792 log.debug("consolidating else_entry {*} {}=>{}", .{else_entry.key, else_entry.value, canon_mcv});
1857 log.debug("consolidating else_entry {*} {}=>{}", .{ else_entry.key, else_entry.value, canon_mcv });
17931858 // TODO make sure the destination stack offset / register does not already have something
17941859 // going on there.
17951860 try self.setRegOrMem(inst.base.src, else_entry.key.ty, canon_mcv, else_entry.value);
......@@ -1813,7 +1878,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
18131878 }
18141879 }
18151880 };
1816 log.debug("consolidating then_entry {*} {}=>{}", .{then_entry.key, parent_mcv, then_entry.value});
1881 log.debug("consolidating then_entry {*} {}=>{}", .{ then_entry.key, parent_mcv, then_entry.value });
18171882 // TODO make sure the destination stack offset / register does not already have something
18181883 // going on there.
18191884 try self.setRegOrMem(inst.base.src, then_entry.key.ty, parent_mcv, then_entry.value);
......@@ -1880,7 +1945,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
18801945 // break instruction will choose a MCValue for the block result and overwrite
18811946 // this field. Following break instructions will use that MCValue to put their
18821947 // block results.
1883 .mcv = @bitCast(AnyMCValue, MCValue { .none = {} }),
1948 .mcv = @bitCast(AnyMCValue, MCValue{ .none = {} }),
18841949 };
18851950 defer inst.codegen.relocs.deinit(self.gpa);
18861951
......@@ -2162,7 +2227,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
21622227 mem.writeIntLittle(u64, &buf, x_big);
21632228
21642229 // mov DWORD PTR [rbp+offset+4], immediate
2165 self.code.appendSliceAssumeCapacity(&[_]u8{ 0xc7, 0x45, twos_comp + 4});
2230 self.code.appendSliceAssumeCapacity(&[_]u8{ 0xc7, 0x45, twos_comp + 4 });
21662231 self.code.appendSliceAssumeCapacity(buf[4..8]);
21672232
21682233 // mov DWORD PTR [rbp+offset], immediate
......@@ -2213,14 +2278,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
22132278 // least amount of necessary instructions (use
22142279 // more intelligent rotating)
22152280 if (x <= math.maxInt(u8)) {
2216 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, 0, reg, Instruction.Operand.imm(@truncate(u8, x), 0)).toU32());
2281 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, reg, Instruction.Operand.imm(@truncate(u8, x), 0)).toU32());
22172282 return;
22182283 } else if (x <= math.maxInt(u16)) {
22192284 // TODO Use movw Note: Not supported on
22202285 // all ARM targets!
2221
2222 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, 0, reg, Instruction.Operand.imm(@truncate(u8, x), 0)).toU32());
2223 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, 0, reg, reg, Instruction.Operand.imm(@truncate(u8, x >> 8), 12)).toU32());
2286 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, reg, Instruction.Operand.imm(@truncate(u8, x), 0)).toU32());
2287 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, reg, reg, Instruction.Operand.imm(@truncate(u8, x >> 8), 12)).toU32());
22242288 } else if (x <= math.maxInt(u32)) {
22252289 // TODO Use movw and movt Note: Not
22262290 // supported on all ARM targets! Also TODO
......@@ -2232,20 +2296,28 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
22322296 // orr reg, reg, #0xbb, 24
22332297 // orr reg, reg, #0xcc, 16
22342298 // orr reg, reg, #0xdd, 8
2235 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, 0, reg, Instruction.Operand.imm(@truncate(u8, x), 0)).toU32());
2236 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, 0, reg, reg, Instruction.Operand.imm(@truncate(u8, x >> 8), 12)).toU32());
2237 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, 0, reg, reg, Instruction.Operand.imm(@truncate(u8, x >> 16), 8)).toU32());
2238 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, 0, reg, reg, Instruction.Operand.imm(@truncate(u8, x >> 24), 4)).toU32());
2299 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, reg, Instruction.Operand.imm(@truncate(u8, x), 0)).toU32());
2300 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, reg, reg, Instruction.Operand.imm(@truncate(u8, x >> 8), 12)).toU32());
2301 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, reg, reg, Instruction.Operand.imm(@truncate(u8, x >> 16), 8)).toU32());
2302 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(.al, reg, reg, Instruction.Operand.imm(@truncate(u8, x >> 24), 4)).toU32());
22392303 return;
22402304 } else {
22412305 return self.fail(src, "ARM registers are 32-bit wide", .{});
22422306 }
22432307 },
2308 .register => |src_reg| {
2309 // If the registers are the same, nothing to do.
2310 if (src_reg.id() == reg.id())
2311 return;
2312
2313 // mov reg, src_reg
2314 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, reg, Instruction.Operand.reg(src_reg, Instruction.Operand.Shift.none)).toU32());
2315 },
22442316 .memory => |addr| {
22452317 // The value is in memory at a hard-coded address.
22462318 // If the type is a pointer, it means the pointer address is at this memory location.
22472319 try self.genSetReg(src, reg, .{ .immediate = addr });
2248 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(.al, reg, reg, Instruction.Offset.none).toU32());
2320 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(.al, reg, reg, .{ .offset = Instruction.Offset.none }).toU32());
22492321 },
22502322 else => return self.fail(src, "TODO implement getSetReg for arm {}", .{mcv}),
22512323 },
......@@ -2590,7 +2662,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
25902662 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
25912663 const decl = payload.decl;
25922664 const got = &macho_file.sections.items[macho_file.got_section_index.?];
2593 const got_addr = got.addr + decl.link.macho.offset_table_index.? * ptr_bytes;
2665 const got_addr = got.addr + decl.link.macho.offset_table_index * ptr_bytes;
25942666 return MCValue{ .memory = got_addr };
25952667 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
25962668 const decl = payload.decl;
......@@ -2701,6 +2773,55 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
27012773 else => return self.fail(src, "TODO implement function parameters for {} on x86_64", .{cc}),
27022774 }
27032775 },
2776 .arm => {
2777 switch (cc) {
2778 .Naked => {
2779 assert(result.args.len == 0);
2780 result.return_value = .{ .unreach = {} };
2781 result.stack_byte_count = 0;
2782 result.stack_align = 1;
2783 return result;
2784 },
2785 .Unspecified, .C => {
2786 // ARM Procedure Call Standard, Chapter 6.5
2787 var ncrn: usize = 0; // Next Core Register Number
2788 var nsaa: u32 = 0; // Next stacked argument address
2789
2790 for (param_types) |ty, i| {
2791 if (ty.abiAlignment(self.target.*) == 8) {
2792 // Round up NCRN to the next even number
2793 ncrn += ncrn % 2;
2794 }
2795
2796 const param_size = @intCast(u32, ty.abiSize(self.target.*));
2797 if (std.math.divCeil(u32, param_size, 4) catch unreachable <= 4 - ncrn) {
2798 if (param_size <= 4) {
2799 result.args[i] = .{ .register = c_abi_int_param_regs[ncrn] };
2800 ncrn += 1;
2801 } else {
2802 return self.fail(src, "TODO MCValues with multiple registers", .{});
2803 }
2804 } else if (ncrn < 4 and nsaa == 0) {
2805 return self.fail(src, "TODO MCValues split between registers and stack", .{});
2806 } else {
2807 ncrn = 4;
2808 if (ty.abiAlignment(self.target.*) == 8) {
2809 if (nsaa % 8 != 0) {
2810 nsaa += 8 - (nsaa % 8);
2811 }
2812 }
2813
2814 result.args[i] = .{ .stack_offset = nsaa };
2815 nsaa += param_size;
2816 }
2817 }
2818
2819 result.stack_byte_count = nsaa;
2820 result.stack_align = 4;
2821 },
2822 else => return self.fail(src, "TODO implement function parameters for {} on arm", .{cc}),
2823 }
2824 },
27042825 else => if (param_types.len != 0)
27052826 return self.fail(src, "TODO implement codegen parameters for {}", .{self.target.cpu.arch}),
27062827 }
......@@ -2719,6 +2840,18 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
27192840 },
27202841 else => return self.fail(src, "TODO implement function return values for {}", .{cc}),
27212842 },
2843 .arm => switch (cc) {
2844 .Naked => unreachable,
2845 .Unspecified, .C => {
2846 const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*));
2847 if (ret_ty_size <= 4) {
2848 result.return_value = .{ .register = c_abi_int_return_regs[0] };
2849 } else {
2850 return self.fail(src, "TODO support more return types for ARM backend", .{});
2851 }
2852 },
2853 else => return self.fail(src, "TODO implement function return values for {}", .{cc}),
2854 },
27222855 else => return self.fail(src, "TODO implement codegen return values for {}", .{self.target.cpu.arch}),
27232856 }
27242857 return result;
src/codegen/arm.zig+342-55
......@@ -113,6 +113,13 @@ test "Register.id" {
113113 testing.expectEqual(@as(u4, 15), Register.pc.id());
114114}
115115
116/// Program status registers containing flags, mode bits and other
117/// vital information
118pub const Psr = enum {
119 cpsr,
120 spsr,
121};
122
116123pub const callee_preserved_regs = [_]Register{ .r0, .r1, .r2, .r3, .r4, .r5, .r6, .r7, .r8, .r10 };
117124pub const c_abi_int_param_regs = [_]Register{ .r0, .r1, .r2, .r3 };
118125pub const c_abi_int_return_regs = [_]Register{ .r0, .r1 };
......@@ -135,15 +142,26 @@ pub const Instruction = union(enum) {
135142 offset: u12,
136143 rd: u4,
137144 rn: u4,
138 l: u1,
139 w: u1,
140 b: u1,
141 u: u1,
142 p: u1,
143 i: u1,
145 load_store: u1,
146 write_back: u1,
147 byte_word: u1,
148 up_down: u1,
149 pre_post: u1,
150 imm: u1,
144151 fixed: u2 = 0b01,
145152 cond: u4,
146153 },
154 BlockDataTransfer: packed struct {
155 register_list: u16,
156 rn: u4,
157 load_store: u1,
158 write_back: u1,
159 psr_or_user: u1,
160 up_down: u1,
161 pre_post: u1,
162 fixed: u3 = 0b100,
163 cond: u4,
164 },
147165 Branch: packed struct {
148166 offset: u24,
149167 link: u1,
......@@ -235,14 +253,14 @@ pub const Instruction = union(enum) {
235253 rs: u4,
236254 },
237255
238 const Type = enum(u2) {
239 LogicalLeft,
240 LogicalRight,
241 ArithmeticRight,
242 RotateRight,
256 pub const Type = enum(u2) {
257 logical_left,
258 logical_right,
259 arithmetic_right,
260 rotate_right,
243261 };
244262
245 const none = Shift{
263 pub const none = Shift{
246264 .Immediate = .{
247265 .amount = 0,
248266 .typ = 0,
......@@ -338,10 +356,32 @@ pub const Instruction = union(enum) {
338356 }
339357 };
340358
359 /// Represents the register list operand to a block data transfer
360 /// instruction
361 pub const RegisterList = packed struct {
362 r0: bool = false,
363 r1: bool = false,
364 r2: bool = false,
365 r3: bool = false,
366 r4: bool = false,
367 r5: bool = false,
368 r6: bool = false,
369 r7: bool = false,
370 r8: bool = false,
371 r9: bool = false,
372 r10: bool = false,
373 r11: bool = false,
374 r12: bool = false,
375 r13: bool = false,
376 r14: bool = false,
377 r15: bool = false,
378 };
379
341380 pub fn toU32(self: Instruction) u32 {
342381 return switch (self) {
343382 .DataProcessing => |v| @bitCast(u32, v),
344383 .SingleDataTransfer => |v| @bitCast(u32, v),
384 .BlockDataTransfer => |v| @bitCast(u32, v),
345385 .Branch => |v| @bitCast(u32, v),
346386 .BranchExchange => |v| @bitCast(u32, v),
347387 .SupervisorCall => |v| @bitCast(u32, v),
......@@ -362,7 +402,7 @@ pub const Instruction = union(enum) {
362402 return Instruction{
363403 .DataProcessing = .{
364404 .cond = @enumToInt(cond),
365 .i = if (op2 == .Immediate) 1 else 0,
405 .i = @boolToInt(op2 == .Immediate),
366406 .opcode = @enumToInt(opcode),
367407 .s = s,
368408 .rn = rn.id(),
......@@ -377,10 +417,10 @@ pub const Instruction = union(enum) {
377417 rd: Register,
378418 rn: Register,
379419 offset: Offset,
380 pre_post: u1,
381 up_down: u1,
420 pre_index: bool,
421 positive: bool,
382422 byte_word: u1,
383 writeback: u1,
423 write_back: bool,
384424 load_store: u1,
385425 ) Instruction {
386426 return Instruction{
......@@ -389,12 +429,36 @@ pub const Instruction = union(enum) {
389429 .rn = rn.id(),
390430 .rd = rd.id(),
391431 .offset = offset.toU12(),
392 .l = load_store,
393 .w = writeback,
394 .b = byte_word,
395 .u = up_down,
396 .p = pre_post,
397 .i = if (offset == .Immediate) 0 else 1,
432 .load_store = load_store,
433 .write_back = @boolToInt(write_back),
434 .byte_word = byte_word,
435 .up_down = @boolToInt(positive),
436 .pre_post = @boolToInt(pre_index),
437 .imm = @boolToInt(offset != .Immediate),
438 },
439 };
440 }
441
442 fn blockDataTransfer(
443 cond: Condition,
444 rn: Register,
445 reg_list: RegisterList,
446 pre_post: u1,
447 up_down: u1,
448 psr_or_user: u1,
449 write_back: bool,
450 load_store: u1,
451 ) Instruction {
452 return Instruction{
453 .BlockDataTransfer = .{
454 .register_list = @bitCast(u16, reg_list),
455 .rn = rn.id(),
456 .load_store = load_store,
457 .write_back = @boolToInt(write_back),
458 .psr_or_user = psr_or_user,
459 .up_down = up_down,
460 .pre_post = pre_post,
461 .cond = @enumToInt(cond),
398462 },
399463 };
400464 }
......@@ -442,36 +506,68 @@ pub const Instruction = union(enum) {
442506
443507 // Data processing
444508
445 pub fn @"and"(cond: Condition, s: u1, rd: Register, rn: Register, op2: Operand) Instruction {
446 return dataProcessing(cond, .@"and", s, rd, rn, op2);
509 pub fn @"and"(cond: Condition, rd: Register, rn: Register, op2: Operand) Instruction {
510 return dataProcessing(cond, .@"and", 0, rd, rn, op2);
511 }
512
513 pub fn ands(cond: Condition, rd: Register, rn: Register, op2: Operand) Instruction {
514 return dataProcessing(cond, .@"and", 1, rd, rn, op2);
515 }
516
517 pub fn eor(cond: Condition, rd: Register, rn: Register, op2: Operand) Instruction {
518 return dataProcessing(cond, .eor, 0, rd, rn, op2);
519 }
520
521 pub fn eors(cond: Condition, rd: Register, rn: Register, op2: Operand) Instruction {
522 return dataProcessing(cond, .eor, 1, rd, rn, op2);
523 }
524
525 pub fn sub(cond: Condition, rd: Register, rn: Register, op2: Operand) Instruction {
526 return dataProcessing(cond, .sub, 0, rd, rn, op2);
527 }
528
529 pub fn subs(cond: Condition, rd: Register, rn: Register, op2: Operand) Instruction {
530 return dataProcessing(cond, .sub, 1, rd, rn, op2);
531 }
532
533 pub fn rsb(cond: Condition, rd: Register, rn: Register, op2: Operand) Instruction {
534 return dataProcessing(cond, .rsb, 0, rd, rn, op2);
535 }
536
537 pub fn rsbs(cond: Condition, rd: Register, rn: Register, op2: Operand) Instruction {
538 return dataProcessing(cond, .rsb, 1, rd, rn, op2);
539 }
540
541 pub fn add(cond: Condition, rd: Register, rn: Register, op2: Operand) Instruction {
542 return dataProcessing(cond, .add, 0, rd, rn, op2);
447543 }
448544
449 pub fn eor(cond: Condition, s: u1, rd: Register, rn: Register, op2: Operand) Instruction {
450 return dataProcessing(cond, .eor, s, rd, rn, op2);
545 pub fn adds(cond: Condition, rd: Register, rn: Register, op2: Operand) Instruction {
546 return dataProcessing(cond, .add, 1, rd, rn, op2);
451547 }
452548
453 pub fn sub(cond: Condition, s: u1, rd: Register, rn: Register, op2: Operand) Instruction {
454 return dataProcessing(cond, .sub, s, rd, rn, op2);
549 pub fn adc(cond: Condition, rd: Register, rn: Register, op2: Operand) Instruction {
550 return dataProcessing(cond, .adc, 0, rd, rn, op2);
455551 }
456552
457 pub fn rsb(cond: Condition, s: u1, rd: Register, rn: Register, op2: Operand) Instruction {
458 return dataProcessing(cond, .rsb, s, rd, rn, op2);
553 pub fn adcs(cond: Condition, rd: Register, rn: Register, op2: Operand) Instruction {
554 return dataProcessing(cond, .adc, 1, rd, rn, op2);
459555 }
460556
461 pub fn add(cond: Condition, s: u1, rd: Register, rn: Register, op2: Operand) Instruction {
462 return dataProcessing(cond, .add, s, rd, rn, op2);
557 pub fn sbc(cond: Condition, rd: Register, rn: Register, op2: Operand) Instruction {
558 return dataProcessing(cond, .sbc, 0, rd, rn, op2);
463559 }
464560
465 pub fn adc(cond: Condition, s: u1, rd: Register, rn: Register, op2: Operand) Instruction {
466 return dataProcessing(cond, .adc, s, rd, rn, op2);
561 pub fn sbcs(cond: Condition, rd: Register, rn: Register, op2: Operand) Instruction {
562 return dataProcessing(cond, .sbc, 1, rd, rn, op2);
467563 }
468564
469 pub fn sbc(cond: Condition, s: u1, rd: Register, rn: Register, op2: Operand) Instruction {
470 return dataProcessing(cond, .sbc, s, rd, rn, op2);
565 pub fn rsc(cond: Condition, rd: Register, rn: Register, op2: Operand) Instruction {
566 return dataProcessing(cond, .rsc, 0, rd, rn, op2);
471567 }
472568
473 pub fn rsc(cond: Condition, s: u1, rd: Register, rn: Register, op2: Operand) Instruction {
474 return dataProcessing(cond, .rsc, s, rd, rn, op2);
569 pub fn rscs(cond: Condition, rd: Register, rn: Register, op2: Operand) Instruction {
570 return dataProcessing(cond, .rsc, 1, rd, rn, op2);
475571 }
476572
477573 pub fn tst(cond: Condition, rn: Register, op2: Operand) Instruction {
......@@ -490,32 +586,115 @@ pub const Instruction = union(enum) {
490586 return dataProcessing(cond, .cmn, 1, .r0, rn, op2);
491587 }
492588
493 pub fn orr(cond: Condition, s: u1, rd: Register, rn: Register, op2: Operand) Instruction {
494 return dataProcessing(cond, .orr, s, rd, rn, op2);
589 pub fn orr(cond: Condition, rd: Register, rn: Register, op2: Operand) Instruction {
590 return dataProcessing(cond, .orr, 0, rd, rn, op2);
591 }
592
593 pub fn orrs(cond: Condition, rd: Register, rn: Register, op2: Operand) Instruction {
594 return dataProcessing(cond, .orr, 1, rd, rn, op2);
595 }
596
597 pub fn mov(cond: Condition, rd: Register, op2: Operand) Instruction {
598 return dataProcessing(cond, .mov, 0, rd, .r0, op2);
495599 }
496600
497 pub fn mov(cond: Condition, s: u1, rd: Register, op2: Operand) Instruction {
498 return dataProcessing(cond, .mov, s, rd, .r0, op2);
601 pub fn movs(cond: Condition, rd: Register, op2: Operand) Instruction {
602 return dataProcessing(cond, .mov, 1, rd, .r0, op2);
499603 }
500604
501 pub fn bic(cond: Condition, s: u1, rd: Register, op2: Operand) Instruction {
502 return dataProcessing(cond, .bic, s, rd, rn, op2);
605 pub fn bic(cond: Condition, rd: Register, op2: Operand) Instruction {
606 return dataProcessing(cond, .bic, 0, rd, rn, op2);
503607 }
504608
505 pub fn mvn(cond: Condition, s: u1, rd: Register, op2: Operand) Instruction {
506 return dataProcessing(cond, .mvn, s, rd, .r0, op2);
609 pub fn bics(cond: Condition, rd: Register, op2: Operand) Instruction {
610 return dataProcessing(cond, .bic, 1, rd, rn, op2);
611 }
612
613 pub fn mvn(cond: Condition, rd: Register, op2: Operand) Instruction {
614 return dataProcessing(cond, .mvn, 0, rd, .r0, op2);
615 }
616
617 pub fn mvns(cond: Condition, rd: Register, op2: Operand) Instruction {
618 return dataProcessing(cond, .mvn, 1, rd, .r0, op2);
619 }
620
621 // PSR transfer
622
623 pub fn mrs(cond: Condition, rd: Register, psr: Psr) Instruction {
624 return dataProcessing(cond, if (psr == .cpsr) .tst else .cmp, 0, rd, .r15, Operand.reg(.r0, Operand.Shift.none));
507625 }
508626
509627 // Single data transfer
510628
511 pub fn ldr(cond: Condition, rd: Register, rn: Register, offset: Offset) Instruction {
512 return singleDataTransfer(cond, rd, rn, offset, 1, 1, 0, 0, 1);
629 pub const OffsetArgs = struct {
630 pre_index: bool = true,
631 positive: bool = true,
632 offset: Offset,
633 write_back: bool = false,
634 };
635
636 pub fn ldr(cond: Condition, rd: Register, rn: Register, args: OffsetArgs) Instruction {
637 return singleDataTransfer(cond, rd, rn, args.offset, args.pre_index, args.positive, 0, args.write_back, 1);
638 }
639
640 pub fn ldrb(cond: Condition, rd: Register, rn: Register, args: OffsetArgs) Instruction {
641 return singleDataTransfer(cond, rd, rn, args.offset, args.pre_index, args.positive, 1, args.write_back, 1);
642 }
643
644 pub fn str(cond: Condition, rd: Register, rn: Register, args: OffsetArgs) Instruction {
645 return singleDataTransfer(cond, rd, rn, args.offset, args.pre_index, args.positive, 0, args.write_back, 0);
646 }
647
648 pub fn strb(cond: Condition, rd: Register, rn: Register, args: OffsetArgs) Instruction {
649 return singleDataTransfer(cond, rd, rn, args.offset, args.pre_index, args.positive, 1, args.write_back, 0);
650 }
651
652 // Block data transfer
653
654 pub fn ldmda(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction {
655 return blockDataTransfer(cond, rn, reg_list, 0, 0, 0, write_back, 1);
656 }
657
658 pub fn ldmdb(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction {
659 return blockDataTransfer(cond, rn, reg_list, 1, 0, 0, write_back, 1);
513660 }
514661
515 pub fn str(cond: Condition, rd: Register, rn: Register, offset: Offset) Instruction {
516 return singleDataTransfer(cond, rd, rn, offset, 1, 1, 0, 0, 0);
662 pub fn ldmib(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction {
663 return blockDataTransfer(cond, rn, reg_list, 1, 1, 0, write_back, 1);
517664 }
518665
666 pub fn ldmia(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction {
667 return blockDataTransfer(cond, rn, reg_list, 0, 1, 0, write_back, 1);
668 }
669
670 pub const ldmfa = ldmda;
671 pub const ldmea = ldmdb;
672 pub const ldmed = ldmib;
673 pub const ldmfd = ldmia;
674 pub const ldm = ldmia;
675
676 pub fn stmda(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction {
677 return blockDataTransfer(cond, rn, reg_list, 0, 0, 0, write_back, 0);
678 }
679
680 pub fn stmdb(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction {
681 return blockDataTransfer(cond, rn, reg_list, 1, 0, 0, write_back, 0);
682 }
683
684 pub fn stmib(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction {
685 return blockDataTransfer(cond, rn, reg_list, 1, 1, 0, write_back, 0);
686 }
687
688 pub fn stmia(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction {
689 return blockDataTransfer(cond, rn, reg_list, 0, 1, 0, write_back, 0);
690 }
691
692 pub const stmed = stmda;
693 pub const stmfd = stmdb;
694 pub const stmfa = stmib;
695 pub const stmea = stmia;
696 pub const stm = stmia;
697
519698 // Branch
520699
521700 pub fn b(cond: Condition, offset: i24) Instruction {
......@@ -549,6 +728,58 @@ pub const Instruction = union(enum) {
549728 pub fn bkpt(imm: u16) Instruction {
550729 return breakpoint(imm);
551730 }
731
732 // Aliases
733
734 pub fn pop(cond: Condition, args: anytype) Instruction {
735 if (@typeInfo(@TypeOf(args)) != .Struct) {
736 @compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(args)));
737 }
738
739 if (args.len < 1) {
740 @compileError("Expected at least one register");
741 } else if (args.len == 1) {
742 const reg = args[0];
743 return ldr(cond, reg, .sp, .{
744 .pre_index = false,
745 .positive = true,
746 .offset = Offset.imm(4),
747 .write_back = false,
748 });
749 } else {
750 var register_list: u16 = 0;
751 inline for (args) |arg| {
752 const reg = @as(Register, arg);
753 register_list |= @as(u16, 1) << reg.id();
754 }
755 return ldm(cond, .sp, true, @bitCast(RegisterList, register_list));
756 }
757 }
758
759 pub fn push(cond: Condition, args: anytype) Instruction {
760 if (@typeInfo(@TypeOf(args)) != .Struct) {
761 @compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(args)));
762 }
763
764 if (args.len < 1) {
765 @compileError("Expected at least one register");
766 } else if (args.len == 1) {
767 const reg = args[0];
768 return str(cond, reg, .sp, .{
769 .pre_index = true,
770 .positive = false,
771 .offset = Offset.imm(4),
772 .write_back = true,
773 });
774 } else {
775 var register_list: u16 = 0;
776 inline for (args) |arg| {
777 const reg = @as(Register, arg);
778 register_list |= @as(u16, 1) << reg.id();
779 }
780 return stmdb(cond, .sp, true, @bitCast(RegisterList, register_list));
781 }
782 }
552783};
553784
554785test "serialize instructions" {
......@@ -559,23 +790,31 @@ test "serialize instructions" {
559790
560791 const testcases = [_]Testcase{
561792 .{ // add r0, r0, r0
562 .inst = Instruction.add(.al, 0, .r0, .r0, Instruction.Operand.reg(.r0, Instruction.Operand.Shift.none)),
793 .inst = Instruction.add(.al, .r0, .r0, Instruction.Operand.reg(.r0, Instruction.Operand.Shift.none)),
563794 .expected = 0b1110_00_0_0100_0_0000_0000_00000000_0000,
564795 },
565796 .{ // mov r4, r2
566 .inst = Instruction.mov(.al, 0, .r4, Instruction.Operand.reg(.r2, Instruction.Operand.Shift.none)),
797 .inst = Instruction.mov(.al, .r4, Instruction.Operand.reg(.r2, Instruction.Operand.Shift.none)),
567798 .expected = 0b1110_00_0_1101_0_0000_0100_00000000_0010,
568799 },
569800 .{ // mov r0, #42
570 .inst = Instruction.mov(.al, 0, .r0, Instruction.Operand.imm(42, 0)),
801 .inst = Instruction.mov(.al, .r0, Instruction.Operand.imm(42, 0)),
571802 .expected = 0b1110_00_1_1101_0_0000_0000_0000_00101010,
572803 },
804 .{ // mrs r5, cpsr
805 .inst = Instruction.mrs(.al, .r5, .cpsr),
806 .expected = 0b1110_00010_0_001111_0101_000000000000,
807 },
573808 .{ // ldr r0, [r2, #42]
574 .inst = Instruction.ldr(.al, .r0, .r2, Instruction.Offset.imm(42)),
809 .inst = Instruction.ldr(.al, .r0, .r2, .{
810 .offset = Instruction.Offset.imm(42),
811 }),
575812 .expected = 0b1110_01_0_1_1_0_0_1_0010_0000_000000101010,
576813 },
577814 .{ // str r0, [r3]
578 .inst = Instruction.str(.al, .r0, .r3, Instruction.Offset.none),
815 .inst = Instruction.str(.al, .r0, .r3, .{
816 .offset = Instruction.Offset.none,
817 }),
579818 .expected = 0b1110_01_0_1_1_0_0_0_0011_0000_000000000000,
580819 },
581820 .{ // b #12
......@@ -598,6 +837,14 @@ test "serialize instructions" {
598837 .inst = Instruction.bkpt(42),
599838 .expected = 0b1110_0001_0010_000000000010_0111_1010,
600839 },
840 .{ // stmdb r9, {r0}
841 .inst = Instruction.stmdb(.al, .r9, false, .{ .r0 = true }),
842 .expected = 0b1110_100_1_0_0_0_0_1001_0000000000000001,
843 },
844 .{ // ldmea r4!, {r2, r5}
845 .inst = Instruction.ldmea(.al, .r4, true, .{ .r2 = true, .r5 = true }),
846 .expected = 0b1110_100_1_0_0_1_1_0100_0000000000100100,
847 },
601848 };
602849
603850 for (testcases) |case| {
......@@ -605,3 +852,43 @@ test "serialize instructions" {
605852 testing.expectEqual(case.expected, actual);
606853 }
607854}
855
856test "aliases" {
857 const Testcase = struct {
858 expected: Instruction,
859 actual: Instruction,
860 };
861
862 const testcases = [_]Testcase{
863 .{ // pop { r6 }
864 .actual = Instruction.pop(.al, .{.r6}),
865 .expected = Instruction.ldr(.al, .r6, .sp, .{
866 .pre_index = false,
867 .positive = true,
868 .offset = Instruction.Offset.imm(4),
869 .write_back = false,
870 }),
871 },
872 .{ // pop { r1, r5 }
873 .actual = Instruction.pop(.al, .{ .r1, .r5 }),
874 .expected = Instruction.ldm(.al, .sp, true, .{ .r1 = true, .r5 = true }),
875 },
876 .{ // push { r3 }
877 .actual = Instruction.push(.al, .{.r3}),
878 .expected = Instruction.str(.al, .r3, .sp, .{
879 .pre_index = true,
880 .positive = false,
881 .offset = Instruction.Offset.imm(4),
882 .write_back = true,
883 }),
884 },
885 .{ // push { r0, r2 }
886 .actual = Instruction.push(.al, .{ .r0, .r2 }),
887 .expected = Instruction.stmdb(.al, .sp, true, .{ .r0 = true, .r2 = true }),
888 },
889 };
890
891 for (testcases) |case| {
892 testing.expectEqual(case.expected.toU32(), case.actual.toU32());
893 }
894}
src/glibc.zig+18-9
......@@ -689,9 +689,6 @@ pub const BuiltSharedObjects = struct {
689689
690690const all_map_basename = "all.map";
691691
692// TODO Turn back on zig fmt when https://github.com/ziglang/zig/issues/5948 is implemented.
693// zig fmt: off
694
695692pub fn buildSharedObjects(comp: *Compilation) !void {
696693 const tracy = trace(@src());
697694 defer tracy.end();
......@@ -827,8 +824,9 @@ pub fn buildSharedObjects(comp: *Compilation) !void {
827824
828825 if (ver.patch == 0) {
829826 const sym_plus_ver = try std.fmt.allocPrint(
830 arena, "{s}_{d}_{d}",
831 .{sym_name, ver.major, ver.minor},
827 arena,
828 "{s}_{d}_{d}",
829 .{ sym_name, ver.major, ver.minor },
832830 );
833831 try zig_body.writer().print(
834832 \\.globl {s}
......@@ -840,13 +838,19 @@ pub fn buildSharedObjects(comp: *Compilation) !void {
840838 , .{
841839 sym_plus_ver,
842840 sym_plus_ver,
843 sym_plus_ver, sym_name, at_sign_str, ver.major, ver.minor,
841 sym_plus_ver,
842 sym_name,
843 at_sign_str,
844 ver.major,
845 ver.minor,
844846 sym_plus_ver,
845847 sym_plus_ver,
846848 });
847849 } else {
848 const sym_plus_ver = try std.fmt.allocPrint(arena, "{s}_{d}_{d}_{d}",
849 .{sym_name, ver.major, ver.minor, ver.patch},
850 const sym_plus_ver = try std.fmt.allocPrint(
851 arena,
852 "{s}_{d}_{d}_{d}",
853 .{ sym_name, ver.major, ver.minor, ver.patch },
850854 );
851855 try zig_body.writer().print(
852856 \\.globl {s}
......@@ -858,7 +862,12 @@ pub fn buildSharedObjects(comp: *Compilation) !void {
858862 , .{
859863 sym_plus_ver,
860864 sym_plus_ver,
861 sym_plus_ver, sym_name, at_sign_str, ver.major, ver.minor, ver.patch,
865 sym_plus_ver,
866 sym_name,
867 at_sign_str,
868 ver.major,
869 ver.minor,
870 ver.patch,
862871 sym_plus_ver,
863872 sym_plus_ver,
864873 });
src/link.zig+2
......@@ -45,6 +45,7 @@ pub const Options = struct {
4545 program_code_size_hint: u64 = 256 * 1024,
4646 entry_addr: ?u64 = null,
4747 stack_size_override: ?u64,
48 image_base_override: ?u64,
4849 /// Set to `true` to omit debug info.
4950 strip: bool,
5051 /// If this is true then this link code is responsible for outputting an object
......@@ -60,6 +61,7 @@ pub const Options = struct {
6061 link_libcpp: bool,
6162 function_sections: bool,
6263 eh_frame_hdr: bool,
64 emit_relocs: bool,
6365 rdynamic: bool,
6466 z_nodelete: bool,
6567 z_defs: bool,
src/link/Coff.zig+17-13
......@@ -22,10 +22,10 @@ const minimum_text_block_size = 64 * allocation_padding;
2222
2323const section_alignment = 4096;
2424const file_alignment = 512;
25const image_base = 0x400_000;
25const default_image_base = 0x400_000;
2626const section_table_size = 2 * 40;
2727comptime {
28 assert(mem.isAligned(image_base, section_alignment));
28 assert(mem.isAligned(default_image_base, section_alignment));
2929}
3030
3131pub const base_tag: link.File.Tag = .coff;
......@@ -55,7 +55,7 @@ offset_table: std.ArrayListUnmanaged(u64) = .{},
5555/// Free list of offset table indices
5656offset_table_free_list: std.ArrayListUnmanaged(u32) = .{},
5757
58/// Virtual address of the entry point procedure relative to `image_base`
58/// Virtual address of the entry point procedure relative to image base.
5959entry_addr: ?u32 = null,
6060
6161/// Absolute virtual address of the text section when the executable is loaded in memory.
......@@ -183,14 +183,14 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
183183
184184 self.section_data_offset = mem.alignForwardGeneric(u32, self.section_table_offset + section_table_size, file_alignment);
185185 const section_data_relative_virtual_address = mem.alignForwardGeneric(u32, self.section_table_offset + section_table_size, section_alignment);
186 self.offset_table_virtual_address = image_base + section_data_relative_virtual_address;
186 self.offset_table_virtual_address = default_image_base + section_data_relative_virtual_address;
187187 self.offset_table_size = default_offset_table_size;
188188 self.section_table_offset = section_table_offset;
189 self.text_section_virtual_address = image_base + section_data_relative_virtual_address + section_alignment;
189 self.text_section_virtual_address = default_image_base + section_data_relative_virtual_address + section_alignment;
190190 self.text_section_size = default_size_of_code;
191191
192192 // Size of file when loaded in memory
193 const size_of_image = mem.alignForwardGeneric(u32, self.text_section_virtual_address - image_base + default_size_of_code, section_alignment);
193 const size_of_image = mem.alignForwardGeneric(u32, self.text_section_virtual_address - default_image_base + default_size_of_code, section_alignment);
194194
195195 mem.writeIntLittle(u16, hdr_data[index..][0..2], optional_header_size);
196196 index += 2;
......@@ -234,11 +234,11 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
234234 index += 4;
235235
236236 // Image base address
237 mem.writeIntLittle(u32, hdr_data[index..][0..4], image_base);
237 mem.writeIntLittle(u32, hdr_data[index..][0..4], default_image_base);
238238 index += 4;
239239 } else {
240240 // Image base address
241 mem.writeIntLittle(u64, hdr_data[index..][0..8], image_base);
241 mem.writeIntLittle(u64, hdr_data[index..][0..8], default_image_base);
242242 index += 8;
243243 }
244244
......@@ -328,7 +328,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
328328 mem.writeIntLittle(u32, hdr_data[index..][0..4], default_offset_table_size);
329329 index += 4;
330330 // Virtual address (u32)
331 mem.writeIntLittle(u32, hdr_data[index..][0..4], self.offset_table_virtual_address - image_base);
331 mem.writeIntLittle(u32, hdr_data[index..][0..4], self.offset_table_virtual_address - default_image_base);
332332 index += 4;
333333 } else {
334334 mem.set(u8, hdr_data[index..][0..8], 0);
......@@ -354,7 +354,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
354354 mem.writeIntLittle(u32, hdr_data[index..][0..4], default_size_of_code);
355355 index += 4;
356356 // Virtual address (u32)
357 mem.writeIntLittle(u32, hdr_data[index..][0..4], self.text_section_virtual_address - image_base);
357 mem.writeIntLittle(u32, hdr_data[index..][0..4], self.text_section_virtual_address - default_image_base);
358358 index += 4;
359359 } else {
360360 mem.set(u8, hdr_data[index..][0..8], 0);
......@@ -601,7 +601,7 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {
601601
602602 // Write .text new virtual address
603603 self.text_section_virtual_address = self.text_section_virtual_address + va_offset;
604 mem.writeIntLittle(u32, buf[0..4], self.text_section_virtual_address - image_base);
604 mem.writeIntLittle(u32, buf[0..4], self.text_section_virtual_address - default_image_base);
605605 try self.base.file.?.pwriteAll(buf[0..4], self.section_table_offset + 40 + 12);
606606
607607 // Fix the VAs in the offset table
......@@ -716,7 +716,7 @@ pub fn updateDeclExports(self: *Coff, module: *Module, decl: *const Module.Decl,
716716 }
717717 }
718718 if (mem.eql(u8, exp.options.name, "_start")) {
719 self.entry_addr = decl.link.coff.getVAddr(self.*) - image_base;
719 self.entry_addr = decl.link.coff.getVAddr(self.*) - default_image_base;
720720 } else {
721721 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
722722 module.failed_exports.putAssumeCapacityNoClobber(
......@@ -754,7 +754,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation) !void {
754754 }
755755
756756 if (self.base.options.output_mode == .Exe and self.size_of_image_dirty) {
757 const new_size_of_image = mem.alignForwardGeneric(u32, self.text_section_virtual_address - image_base + self.text_section_size, section_alignment);
757 const new_size_of_image = mem.alignForwardGeneric(u32, self.text_section_virtual_address - default_image_base + self.text_section_size, section_alignment);
758758 var buf: [4]u8 = undefined;
759759 mem.writeIntLittle(u32, &buf, new_size_of_image);
760760 try self.base.file.?.pwriteAll(&buf, self.optional_header_offset + 56);
......@@ -832,6 +832,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
832832 }
833833 try man.addOptionalFile(module_obj_path);
834834 man.hash.addOptional(self.base.options.stack_size_override);
835 man.hash.addOptional(self.base.options.image_base_override);
835836 man.hash.addListOfBytes(self.base.options.extra_lld_args);
836837 man.hash.addListOfBytes(self.base.options.lib_dirs);
837838 man.hash.add(self.base.options.is_compiler_rt_or_libc);
......@@ -914,6 +915,9 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
914915 const stack_size = self.base.options.stack_size_override orelse 16777216;
915916 try argv.append(try allocPrint(arena, "-STACK:{d}", .{stack_size}));
916917 }
918 if (self.base.options.image_base_override) |image_base| {
919 try argv.append(try std.fmt.allocPrint(arena, "-BASE:{d}", .{image_base}));
920 }
917921
918922 if (target.cpu.arch == .i386) {
919923 try argv.append("-MACHINE:X86");
src/link/Elf.zig+70-47
......@@ -27,9 +27,6 @@ const Cache = @import("../Cache.zig");
2727
2828const default_entry_addr = 0x8000000;
2929
30// TODO Turn back on zig fmt when https://github.com/ziglang/zig/issues/5948 is implemented.
31// zig fmt: off
32
3330pub const base_tag: File.Tag = .elf;
3431
3532base: File,
......@@ -273,8 +270,8 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
273270
274271pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Elf {
275272 const ptr_width: PtrWidth = switch (options.target.cpu.arch.ptrBitWidth()) {
276 0 ... 32 => .p32,
277 33 ... 64 => .p64,
273 0...32 => .p32,
274 33...64 => .p64,
278275 else => return error.UnsupportedELFArchitecture,
279276 };
280277 const self = try gpa.create(Elf);
......@@ -752,40 +749,52 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
752749 // These are LEB encoded but since the values are all less than 127
753750 // we can simply append these bytes.
754751 const abbrev_buf = [_]u8{
755 abbrev_compile_unit, DW.TAG_compile_unit, DW.CHILDREN_yes, // header
756 DW.AT_stmt_list, DW.FORM_sec_offset, DW.AT_low_pc,
757 DW.FORM_addr, DW.AT_high_pc, DW.FORM_addr,
758 DW.AT_name, DW.FORM_strp, DW.AT_comp_dir,
759 DW.FORM_strp, DW.AT_producer, DW.FORM_strp,
760 DW.AT_language, DW.FORM_data2, 0,
752 abbrev_compile_unit, DW.TAG_compile_unit, DW.CHILDREN_yes, // header
753 DW.AT_stmt_list, DW.FORM_sec_offset, DW.AT_low_pc,
754 DW.FORM_addr, DW.AT_high_pc, DW.FORM_addr,
755 DW.AT_name, DW.FORM_strp, DW.AT_comp_dir,
756 DW.FORM_strp, DW.AT_producer, DW.FORM_strp,
757 DW.AT_language, DW.FORM_data2, 0,
761758 0, // table sentinel
762 abbrev_subprogram, DW.TAG_subprogram,
759 abbrev_subprogram,
760 DW.TAG_subprogram,
763761 DW.CHILDREN_yes, // header
764 DW.AT_low_pc, DW.FORM_addr,
765 DW.AT_high_pc, DW.FORM_data4, DW.AT_type,
766 DW.FORM_ref4, DW.AT_name, DW.FORM_string,
767 0, 0, // table sentinel
768 abbrev_subprogram_retvoid,
769 DW.TAG_subprogram, DW.CHILDREN_yes, // header
770 DW.AT_low_pc,
771 DW.FORM_addr, DW.AT_high_pc, DW.FORM_data4,
772 DW.AT_name, DW.FORM_string, 0,
762 DW.AT_low_pc,
763 DW.FORM_addr,
764 DW.AT_high_pc,
765 DW.FORM_data4,
766 DW.AT_type,
767 DW.FORM_ref4,
768 DW.AT_name,
769 DW.FORM_string,
770 0, 0, // table sentinel
771 abbrev_subprogram_retvoid,
772 DW.TAG_subprogram, DW.CHILDREN_yes, // header
773 DW.AT_low_pc, DW.FORM_addr,
774 DW.AT_high_pc, DW.FORM_data4,
775 DW.AT_name, DW.FORM_string,
776 0,
773777 0, // table sentinel
774 abbrev_base_type, DW.TAG_base_type,
778 abbrev_base_type,
779 DW.TAG_base_type,
775780 DW.CHILDREN_no, // header
776 DW.AT_encoding, DW.FORM_data1,
777 DW.AT_byte_size, DW.FORM_data1, DW.AT_name,
778 DW.FORM_string, 0, 0, // table sentinel
779
780 abbrev_pad1, DW.TAG_unspecified_type, DW.CHILDREN_no, // header
781 0, 0, // table sentinel
782 abbrev_parameter,
781 DW.AT_encoding,
782 DW.FORM_data1,
783 DW.AT_byte_size,
784 DW.FORM_data1,
785 DW.AT_name,
786 DW.FORM_string, 0, 0, // table sentinel
787 abbrev_pad1, DW.TAG_unspecified_type, DW.CHILDREN_no, // header
788 0, 0, // table sentinel
789 abbrev_parameter,
783790 DW.TAG_formal_parameter, DW.CHILDREN_no, // header
784 DW.AT_location,
785 DW.FORM_exprloc, DW.AT_type, DW.FORM_ref4,
786 DW.AT_name, DW.FORM_string, 0,
791 DW.AT_location, DW.FORM_exprloc,
792 DW.AT_type, DW.FORM_ref4,
793 DW.AT_name, DW.FORM_string,
794 0,
787795 0, // table sentinel
788 0, 0,
796 0,
797 0,
789798 0, // section sentinel
790799 };
791800
......@@ -1021,7 +1030,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
10211030 0, // `DW.LNS_set_prologue_end`
10221031 0, // `DW.LNS_set_epilogue_begin`
10231032 1, // `DW.LNS_set_isa`
1024
10251033 0, // include_directories (none except the compilation unit cwd)
10261034 });
10271035 // file_names[0]
......@@ -1284,8 +1292,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
12841292 // We can skip hashing libc and libc++ components that we are in charge of building from Zig
12851293 // installation sources because they are always a product of the compiler version + target information.
12861294 man.hash.add(stack_size);
1295 man.hash.addOptional(self.base.options.image_base_override);
12871296 man.hash.add(gc_sections);
12881297 man.hash.add(self.base.options.eh_frame_hdr);
1298 man.hash.add(self.base.options.emit_relocs);
12891299 man.hash.add(self.base.options.rdynamic);
12901300 man.hash.addListOfBytes(self.base.options.extra_lld_args);
12911301 man.hash.addListOfBytes(self.base.options.lib_dirs);
......@@ -1317,7 +1327,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
13171327
13181328 var prev_digest_buf: [digest.len]u8 = undefined;
13191329 const prev_digest: []u8 = directory.handle.readLink(id_symlink_basename, &prev_digest_buf) catch |err| blk: {
1320 log.debug("ELF LLD new_digest={} readlink error: {}", .{digest, @errorName(err)});
1330 log.debug("ELF LLD new_digest={} readlink error: {}", .{ digest, @errorName(err) });
13211331 // Handle this as a cache miss.
13221332 break :blk prev_digest_buf[0..0];
13231333 };
......@@ -1327,7 +1337,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
13271337 self.base.lock = man.toOwnedLock();
13281338 return;
13291339 }
1330 log.debug("ELF LLD prev_digest={} new_digest={}", .{prev_digest, digest});
1340 log.debug("ELF LLD prev_digest={} new_digest={}", .{ prev_digest, digest });
13311341
13321342 // We are about to change the output file to be different, so we invalidate the build hash now.
13331343 directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
......@@ -1352,6 +1362,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
13521362 try argv.append(try std.fmt.allocPrint(arena, "stack-size={}", .{stack_size}));
13531363 }
13541364
1365 if (self.base.options.image_base_override) |image_base| {
1366 try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{image_base}));
1367 }
1368
13551369 if (self.base.options.linker_script) |linker_script| {
13561370 try argv.append("-T");
13571371 try argv.append(linker_script);
......@@ -1365,6 +1379,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
13651379 try argv.append("--eh-frame-hdr");
13661380 }
13671381
1382 if (self.base.options.emit_relocs) {
1383 try argv.append("--emit-relocs");
1384 }
1385
13681386 if (self.base.options.rdynamic) {
13691387 try argv.append("--export-dynamic");
13701388 }
......@@ -1443,10 +1461,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
14431461 var test_path = std.ArrayList(u8).init(self.base.allocator);
14441462 defer test_path.deinit();
14451463 for (self.base.options.lib_dirs) |lib_dir_path| {
1446 for (self.base.options.system_libs.items()) |link_lib| {
1464 for (self.base.options.system_libs.items()) |entry| {
1465 const link_lib = entry.key;
14471466 test_path.shrinkRetainingCapacity(0);
14481467 const sep = fs.path.sep_str;
1449 try test_path.writer().print("{}" ++ sep ++ "lib{}.so", .{ lib_dir_path, link_lib });
1468 try test_path.writer().print("{s}" ++ sep ++ "lib{s}.so", .{ lib_dir_path, link_lib });
14501469 fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
14511470 error.FileNotFound => continue,
14521471 else => |e| return e,
......@@ -1480,9 +1499,9 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
14801499
14811500 if (is_dyn_lib) {
14821501 const soname = self.base.options.override_soname orelse if (self.base.options.version) |ver|
1483 try std.fmt.allocPrint(arena, "lib{}.so.{}", .{self.base.options.root_name, ver.major})
1484 else
1485 try std.fmt.allocPrint(arena, "lib{}.so", .{self.base.options.root_name});
1502 try std.fmt.allocPrint(arena, "lib{}.so.{}", .{ self.base.options.root_name, ver.major })
1503 else
1504 try std.fmt.allocPrint(arena, "lib{}.so", .{self.base.options.root_name});
14861505 try argv.append("-soname");
14871506 try argv.append(soname);
14881507
......@@ -1605,7 +1624,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
16051624 };
16061625 defer stdout_context.data.deinit();
16071626 const llvm = @import("../llvm.zig");
1608 const ok = llvm.Link(.ELF, new_argv.ptr, new_argv.len, append_diagnostic,
1627 const ok = llvm.Link(
1628 .ELF,
1629 new_argv.ptr,
1630 new_argv.len,
1631 append_diagnostic,
16091632 @ptrToInt(&stdout_context),
16101633 @ptrToInt(&stderr_context),
16111634 );
......@@ -1631,7 +1654,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
16311654 };
16321655 // Again failure here only means an unnecessary cache miss.
16331656 man.writeManifest() catch |err| {
1634 std.log.warn("failed to write cache manifest when linking: {}", .{ @errorName(err) });
1657 std.log.warn("failed to write cache manifest when linking: {}", .{@errorName(err)});
16351658 };
16361659 // We hang on to this lock so that the output file path can be used without
16371660 // other processes clobbering it.
......@@ -2866,8 +2889,8 @@ fn dbgLineNeededHeaderBytes(self: Elf) u32 {
28662889 const root_src_dir_path_len = if (self.base.options.module.?.root_pkg.root_src_directory.path) |p| p.len else 1; // "."
28672890 return @intCast(u32, 53 + directory_entry_format_count * 2 + file_name_entry_format_count * 2 +
28682891 directory_count * 8 + file_name_count * 8 +
2869 // These are encoded as DW.FORM_string rather than DW.FORM_strp as we would like
2870 // because of a workaround for readelf and gdb failing to understand DWARFv5 correctly.
2892 // These are encoded as DW.FORM_string rather than DW.FORM_strp as we would like
2893 // because of a workaround for readelf and gdb failing to understand DWARFv5 correctly.
28712894 root_src_dir_path_len +
28722895 self.base.options.module.?.root_pkg.root_src_path.len);
28732896}
......@@ -2888,7 +2911,7 @@ fn pwriteDbgLineNops(
28882911 prev_padding_size: usize,
28892912 buf: []const u8,
28902913 next_padding_size: usize,
2891 offset: usize,
2914 offset: u64,
28922915) !void {
28932916 const tracy = trace(@src());
28942917 defer tracy.end();
......@@ -2967,7 +2990,7 @@ fn pwriteDbgInfoNops(
29672990 buf: []const u8,
29682991 next_padding_size: usize,
29692992 trailing_zero: bool,
2970 offset: usize,
2993 offset: u64,
29712994) !void {
29722995 const tracy = trace(@src());
29732996 defer tracy.end();
src/link/MachO.zig+613-165
......@@ -27,6 +27,10 @@ const LoadCommand = union(enum) {
2727 LinkeditData: macho.linkedit_data_command,
2828 Symtab: macho.symtab_command,
2929 Dysymtab: macho.dysymtab_command,
30 DyldInfo: macho.dyld_info_command,
31 Dylinker: macho.dylinker_command,
32 Dylib: macho.dylib_command,
33 EntryPoint: macho.entry_point_command,
3034
3135 pub fn cmdsize(self: LoadCommand) u32 {
3236 return switch (self) {
......@@ -34,6 +38,10 @@ const LoadCommand = union(enum) {
3438 .LinkeditData => |x| x.cmdsize,
3539 .Symtab => |x| x.cmdsize,
3640 .Dysymtab => |x| x.cmdsize,
41 .DyldInfo => |x| x.cmdsize,
42 .Dylinker => |x| x.cmdsize,
43 .Dylib => |x| x.cmdsize,
44 .EntryPoint => |x| x.cmdsize,
3745 };
3846 }
3947
......@@ -43,6 +51,10 @@ const LoadCommand = union(enum) {
4351 .LinkeditData => |cmd| writeGeneric(cmd, file, offset),
4452 .Symtab => |cmd| writeGeneric(cmd, file, offset),
4553 .Dysymtab => |cmd| writeGeneric(cmd, file, offset),
54 .DyldInfo => |cmd| writeGeneric(cmd, file, offset),
55 .Dylinker => |cmd| writeGeneric(cmd, file, offset),
56 .Dylib => |cmd| writeGeneric(cmd, file, offset),
57 .EntryPoint => |cmd| writeGeneric(cmd, file, offset),
4658 };
4759 }
4860
......@@ -56,30 +68,52 @@ base: File,
5668
5769/// Table of all load commands
5870load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
59segment_cmd_index: ?u16 = null,
71/// __PAGEZERO segment
72pagezero_segment_cmd_index: ?u16 = null,
73/// __TEXT segment
74text_segment_cmd_index: ?u16 = null,
75/// __DATA segment
76data_segment_cmd_index: ?u16 = null,
77/// __LINKEDIT segment
78linkedit_segment_cmd_index: ?u16 = null,
79/// Dyld info
80dyld_info_cmd_index: ?u16 = null,
81/// Symbol table
6082symtab_cmd_index: ?u16 = null,
83/// Dynamic symbol table
6184dysymtab_cmd_index: ?u16 = null,
85/// Path to dyld linker
86dylinker_cmd_index: ?u16 = null,
87/// Path to libSystem
88libsystem_cmd_index: ?u16 = null,
89/// Data-in-code section of __LINKEDIT segment
6290data_in_code_cmd_index: ?u16 = null,
91/// Address to entry point function
92function_starts_cmd_index: ?u16 = null,
93/// Main/entry point
94/// Specifies offset wrt __TEXT segment start address to the main entry point
95/// of the binary.
96main_cmd_index: ?u16 = null,
6397
6498/// Table of all sections
6599sections: std.ArrayListUnmanaged(macho.section_64) = .{},
66100
67/// __TEXT segment sections
101/// __TEXT,__text section
68102text_section_index: ?u16 = null,
69cstring_section_index: ?u16 = null,
70const_text_section_index: ?u16 = null,
71stubs_section_index: ?u16 = null,
72stub_helper_section_index: ?u16 = null,
73103
74/// __DATA segment sections
104/// __DATA,__got section
75105got_section_index: ?u16 = null,
76const_data_section_index: ?u16 = null,
77106
78107entry_addr: ?u64 = null,
79108
80/// Table of all symbols used.
109/// Table of all local symbols
81110/// Internally references string table for names (which are optional).
82symbol_table: std.ArrayListUnmanaged(macho.nlist_64) = .{},
111local_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{},
112/// Table of all defined global symbols
113global_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{},
114/// Table of all undefined symbols
115undef_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{},
116dyld_stub_binder_index: ?u16 = null,
83117
84118/// Table of symbol names aka the string table.
85119string_table: std.ArrayListUnmanaged(u8) = .{},
......@@ -115,19 +149,27 @@ const LIB_SYSTEM_NAME: [*:0]const u8 = "System";
115149const LIB_SYSTEM_PATH: [*:0]const u8 = DEFAULT_LIB_SEARCH_PATH ++ "/libSystem.B.dylib";
116150
117151pub const TextBlock = struct {
118 /// Index into the symbol table
119 symbol_table_index: ?u32,
152 /// Each decl always gets a local symbol with the fully qualified name.
153 /// The vaddr and size are found here directly.
154 /// The file offset is found by computing the vaddr offset from the section vaddr
155 /// the symbol references, and adding that to the file offset of the section.
156 /// If this field is 0, it means the codegen size = 0 and there is no symbol or
157 /// offset table entry.
158 local_sym_index: u32,
120159 /// Index into offset table
121 offset_table_index: ?u32,
160 /// This field is undefined for symbols with size = 0.
161 offset_table_index: u32,
122162 /// Size of this text block
163 /// Unlike in Elf, we need to store the size of this symbol as part of
164 /// the TextBlock since macho.nlist_64 lacks this information.
123165 size: u64,
124166 /// Points to the previous and next neighbours
125167 prev: ?*TextBlock,
126168 next: ?*TextBlock,
127169
128170 pub const empty = TextBlock{
129 .symbol_table_index = null,
130 .offset_table_index = null,
171 .local_sym_index = 0,
172 .offset_table_index = undefined,
131173 .size = 0,
132174 .prev = null,
133175 .next = null,
......@@ -156,6 +198,15 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
156198
157199 self.base.file = file;
158200
201 // Index 0 is always a null symbol.
202 try self.local_symbols.append(allocator, .{
203 .n_strx = 0,
204 .n_type = 0,
205 .n_sect = 0,
206 .n_desc = 0,
207 .n_value = 0,
208 });
209
159210 switch (options.output_mode) {
160211 .Exe => {},
161212 .Obj => {},
......@@ -196,88 +247,83 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
196247 const tracy = trace(@src());
197248 defer tracy.end();
198249
250 // Unfortunately these have to be buffered and done at the end because MachO does not allow
251 // mixing local, global and undefined symbols within a symbol table.
252 try self.writeAllGlobalSymbols();
253 try self.writeAllUndefSymbols();
254
255 try self.writeStringTable();
256
199257 switch (self.base.options.output_mode) {
200258 .Exe => {
201 var last_cmd_offset: usize = @sizeOf(macho.mach_header_64);
202 {
203 // Specify path to dynamic linker dyld
204 const cmdsize = commandSize(@sizeOf(macho.dylinker_command) + mem.lenZ(DEFAULT_DYLD_PATH));
205 const load_dylinker = [1]macho.dylinker_command{
206 .{
207 .cmd = macho.LC_LOAD_DYLINKER,
208 .cmdsize = cmdsize,
209 .name = @sizeOf(macho.dylinker_command),
210 },
211 };
212
213 try self.base.file.?.pwriteAll(mem.sliceAsBytes(load_dylinker[0..1]), last_cmd_offset);
214
215 const file_offset = last_cmd_offset + @sizeOf(macho.dylinker_command);
216 try self.addPadding(cmdsize - @sizeOf(macho.dylinker_command), file_offset);
217
218 try self.base.file.?.pwriteAll(mem.spanZ(DEFAULT_DYLD_PATH), file_offset);
219 last_cmd_offset += cmdsize;
259 if (self.entry_addr) |addr| {
260 // Write export trie.
261 try self.writeExportTrie();
262
263 // Update LC_MAIN with entry offset
264 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
265 const main_cmd = &self.load_commands.items[self.main_cmd_index.?].EntryPoint;
266 main_cmd.entryoff = addr - text_segment.vmaddr;
220267 }
221268
222269 {
223 // Link against libSystem
224 const cmdsize = commandSize(@sizeOf(macho.dylib_command) + mem.lenZ(LIB_SYSTEM_PATH));
225 // TODO Find a way to work out runtime version from the OS version triple stored in std.Target.
226 // In the meantime, we're gonna hardcode to the minimum compatibility version of 1.0.0.
227 const min_version = 0x10000;
228 const dylib = .{
229 .name = @sizeOf(macho.dylib_command),
230 .timestamp = 2, // not sure why not simply 0; this is reverse engineered from Mach-O files
231 .current_version = min_version,
232 .compatibility_version = min_version,
233 };
234 const load_dylib = [1]macho.dylib_command{
235 .{
236 .cmd = macho.LC_LOAD_DYLIB,
237 .cmdsize = cmdsize,
238 .dylib = dylib,
239 },
240 };
241
242 try self.base.file.?.pwriteAll(mem.sliceAsBytes(load_dylib[0..1]), last_cmd_offset);
243
244 const file_offset = last_cmd_offset + @sizeOf(macho.dylib_command);
245 try self.addPadding(cmdsize - @sizeOf(macho.dylib_command), file_offset);
246
247 try self.base.file.?.pwriteAll(mem.spanZ(LIB_SYSTEM_PATH), file_offset);
248 last_cmd_offset += cmdsize;
270 // Update dynamic symbol table.
271 const nlocals = @intCast(u32, self.local_symbols.items.len);
272 const nglobals = @intCast(u32, self.global_symbols.items.len);
273 const nundefs = @intCast(u32, self.undef_symbols.items.len);
274 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
275 dysymtab.nlocalsym = nlocals;
276 dysymtab.iextdefsym = nlocals;
277 dysymtab.nextdefsym = nglobals;
278 dysymtab.iundefsym = nlocals + nglobals;
279 dysymtab.nundefsym = nundefs;
249280 }
250 },
251 .Obj => {
252281 {
253 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
254 symtab.nsyms = @intCast(u32, self.symbol_table.items.len);
255 const allocated_size = self.allocatedSize(symtab.stroff);
256 const needed_size = self.string_table.items.len;
257 log.debug("allocated_size = 0x{x}, needed_size = 0x{x}\n", .{ allocated_size, needed_size });
258
259 if (needed_size > allocated_size) {
260 symtab.strsize = 0;
261 symtab.stroff = @intCast(u32, self.findFreeSpace(needed_size, 1));
282 // Write path to dyld loader.
283 var off: usize = @sizeOf(macho.mach_header_64);
284 for (self.load_commands.items) |cmd| {
285 if (cmd == .Dylinker) break;
286 off += cmd.cmdsize();
262287 }
263 symtab.strsize = @intCast(u32, needed_size);
264
265 log.debug("writing string table from 0x{x} to 0x{x}\n", .{ symtab.stroff, symtab.stroff + symtab.strsize });
266
267 try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff);
288 const cmd = &self.load_commands.items[self.dylinker_cmd_index.?].Dylinker;
289 off += cmd.name;
290 const padding = cmd.cmdsize - @sizeOf(macho.dylinker_command);
291 log.debug("writing LC_LOAD_DYLINKER padding of size {} at 0x{x}\n", .{ padding, off });
292 try self.addPadding(padding, off);
293 log.debug("writing LC_LOAD_DYLINKER path to dyld at 0x{x}\n", .{off});
294 try self.base.file.?.pwriteAll(mem.spanZ(DEFAULT_DYLD_PATH), off);
268295 }
269
270 var last_cmd_offset: usize = @sizeOf(macho.mach_header_64);
271 for (self.load_commands.items) |cmd| {
272 try cmd.write(&self.base.file.?, last_cmd_offset);
273 last_cmd_offset += cmd.cmdsize();
296 {
297 // Write path to libSystem.
298 var off: usize = @sizeOf(macho.mach_header_64);
299 for (self.load_commands.items) |cmd| {
300 if (cmd == .Dylib) break;
301 off += cmd.cmdsize();
302 }
303 const cmd = &self.load_commands.items[self.libsystem_cmd_index.?].Dylib;
304 off += cmd.dylib.name;
305 const padding = cmd.cmdsize - @sizeOf(macho.dylib_command);
306 log.debug("writing LC_LOAD_DYLIB padding of size {} at 0x{x}\n", .{ padding, off });
307 try self.addPadding(padding, off);
308 log.debug("writing LC_LOAD_DYLIB path to libSystem at 0x{x}\n", .{off});
309 try self.base.file.?.pwriteAll(mem.spanZ(LIB_SYSTEM_PATH), off);
274310 }
275 const off = @sizeOf(macho.mach_header_64) + @sizeOf(macho.segment_command_64);
276 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items), off);
277311 },
312 .Obj => {},
278313 .Lib => return error.TODOImplementWritingLibFiles,
279314 }
280315
316 if (self.cmd_table_dirty) try self.writeCmdHeaders();
317
318 {
319 // Update symbol table.
320 const nlocals = @intCast(u32, self.local_symbols.items.len);
321 const nglobals = @intCast(u32, self.global_symbols.items.len);
322 const nundefs = @intCast(u32, self.undef_symbols.items.len);
323 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
324 symtab.nsyms = nlocals + nglobals + nundefs;
325 }
326
281327 if (self.entry_addr == null and self.base.options.output_mode == .Exe) {
282328 log.debug("flushing. no_entry_point_found = true\n", .{});
283329 self.error_flags.no_entry_point_found = true;
......@@ -669,32 +715,34 @@ fn darwinArchString(arch: std.Target.Cpu.Arch) []const u8 {
669715pub fn deinit(self: *MachO) void {
670716 self.offset_table.deinit(self.base.allocator);
671717 self.string_table.deinit(self.base.allocator);
672 self.symbol_table.deinit(self.base.allocator);
718 self.undef_symbols.deinit(self.base.allocator);
719 self.global_symbols.deinit(self.base.allocator);
720 self.local_symbols.deinit(self.base.allocator);
673721 self.sections.deinit(self.base.allocator);
674722 self.load_commands.deinit(self.base.allocator);
675723}
676724
677725pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
678 if (decl.link.macho.symbol_table_index) |_| return;
726 if (decl.link.macho.local_sym_index != 0) return;
679727
680 try self.symbol_table.ensureCapacity(self.base.allocator, self.symbol_table.items.len + 1);
728 try self.local_symbols.ensureCapacity(self.base.allocator, self.local_symbols.items.len + 1);
681729 try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1);
682730
683 log.debug("allocating symbol index {} for {}\n", .{ self.symbol_table.items.len, decl.name });
684 decl.link.macho.symbol_table_index = @intCast(u32, self.symbol_table.items.len);
685 _ = self.symbol_table.addOneAssumeCapacity();
731 log.debug("allocating symbol index {} for {}\n", .{ self.local_symbols.items.len, decl.name });
732 decl.link.macho.local_sym_index = @intCast(u32, self.local_symbols.items.len);
733 _ = self.local_symbols.addOneAssumeCapacity();
686734
687735 decl.link.macho.offset_table_index = @intCast(u32, self.offset_table.items.len);
688736 _ = self.offset_table.addOneAssumeCapacity();
689737
690 self.symbol_table.items[decl.link.macho.symbol_table_index.?] = .{
738 self.local_symbols.items[decl.link.macho.local_sym_index] = .{
691739 .n_strx = 0,
692740 .n_type = 0,
693741 .n_sect = 0,
694742 .n_desc = 0,
695743 .n_value = 0,
696744 };
697 self.offset_table.items[decl.link.macho.offset_table_index.?] = 0;
745 self.offset_table.items[decl.link.macho.offset_table_index] = 0;
698746}
699747
700748pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
......@@ -716,16 +764,14 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
716764 return;
717765 },
718766 };
719 log.debug("generated code {}\n", .{code});
720767
721768 const required_alignment = typed_value.ty.abiAlignment(self.base.options.target);
722 const symbol = &self.symbol_table.items[decl.link.macho.symbol_table_index.?];
769 const symbol = &self.local_symbols.items[decl.link.macho.local_sym_index];
723770
724771 const decl_name = mem.spanZ(decl.name);
725772 const name_str_index = try self.makeString(decl_name);
726773 const addr = try self.allocateTextBlock(&decl.link.macho, code.len, required_alignment);
727774 log.debug("allocated text block for {} at 0x{x}\n", .{ decl_name, addr });
728 log.debug("updated text section {}\n", .{self.sections.items[self.text_section_index.?]});
729775
730776 symbol.* = .{
731777 .n_strx = name_str_index,
......@@ -734,18 +780,20 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
734780 .n_desc = 0,
735781 .n_value = addr,
736782 };
783 self.offset_table.items[decl.link.macho.offset_table_index] = addr;
737784
738 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
739 const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{};
740 try self.updateDeclExports(module, decl, decl_exports);
741 try self.writeSymbol(decl.link.macho.symbol_table_index.?);
785 try self.writeSymbol(decl.link.macho.local_sym_index);
786 try self.writeOffsetTableEntry(decl.link.macho.offset_table_index);
742787
743788 const text_section = self.sections.items[self.text_section_index.?];
744789 const section_offset = symbol.n_value - text_section.addr;
745790 const file_offset = text_section.offset + section_offset;
746 log.debug("file_offset 0x{x}\n", .{file_offset});
747791
748792 try self.base.file.?.pwriteAll(code, file_offset);
793
794 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
795 const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{};
796 try self.updateDeclExports(module, decl, decl_exports);
749797}
750798
751799pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl: *const Module.Decl) !void {}
......@@ -759,34 +807,89 @@ pub fn updateDeclExports(
759807 const tracy = trace(@src());
760808 defer tracy.end();
761809
762 if (decl.link.macho.symbol_table_index == null) return;
763
764 const decl_sym = &self.symbol_table.items[decl.link.macho.symbol_table_index.?];
765 // TODO implement
766 if (exports.len == 0) return;
767
768 const exp = exports[0];
769 self.entry_addr = decl_sym.n_value;
770 decl_sym.n_type |= macho.N_EXT;
771 exp.link.sym_index = 0;
810 try self.global_symbols.ensureCapacity(self.base.allocator, self.global_symbols.items.len + exports.len);
811 if (decl.link.macho.local_sym_index == 0) return;
812 const decl_sym = &self.local_symbols.items[decl.link.macho.local_sym_index];
813
814 for (exports) |exp| {
815 if (exp.options.section) |section_name| {
816 if (!mem.eql(u8, section_name, "__text")) {
817 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
818 module.failed_exports.putAssumeCapacityNoClobber(
819 exp,
820 try Compilation.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: ExportOptions.section", .{}),
821 );
822 continue;
823 }
824 }
825 const n_desc = switch (exp.options.linkage) {
826 .Internal => macho.REFERENCE_FLAG_PRIVATE_DEFINED,
827 .Strong => blk: {
828 if (mem.eql(u8, exp.options.name, "_start")) {
829 self.entry_addr = decl_sym.n_value;
830 }
831 break :blk macho.REFERENCE_FLAG_DEFINED;
832 },
833 .Weak => macho.N_WEAK_REF,
834 .LinkOnce => {
835 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
836 module.failed_exports.putAssumeCapacityNoClobber(
837 exp,
838 try Compilation.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: GlobalLinkage.LinkOnce", .{}),
839 );
840 continue;
841 },
842 };
843 const n_type = decl_sym.n_type | macho.N_EXT;
844 if (exp.link.sym_index) |i| {
845 const sym = &self.global_symbols.items[i];
846 sym.* = .{
847 .n_strx = try self.updateString(sym.n_strx, exp.options.name),
848 .n_type = n_type,
849 .n_sect = @intCast(u8, self.text_section_index.?) + 1,
850 .n_desc = n_desc,
851 .n_value = decl_sym.n_value,
852 };
853 } else {
854 const name_str_index = try self.makeString(exp.options.name);
855 _ = self.global_symbols.addOneAssumeCapacity();
856 const i = self.global_symbols.items.len - 1;
857 self.global_symbols.items[i] = .{
858 .n_strx = name_str_index,
859 .n_type = n_type,
860 .n_sect = @intCast(u8, self.text_section_index.?) + 1,
861 .n_desc = n_desc,
862 .n_value = decl_sym.n_value,
863 };
864
865 exp.link.sym_index = @intCast(u32, i);
866 }
867 }
772868}
773869
774870pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {}
775871
776872pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 {
777 return self.symbol_table.items[decl.link.macho.symbol_table_index.?].n_value;
873 assert(decl.link.macho.local_sym_index != 0);
874 return self.local_symbols.items[decl.link.macho.local_sym_index].n_value;
778875}
779876
780877pub fn populateMissingMetadata(self: *MachO) !void {
781 if (self.segment_cmd_index == null) {
782 self.segment_cmd_index = @intCast(u16, self.load_commands.items.len);
878 switch (self.base.options.output_mode) {
879 .Exe => {},
880 .Obj => return error.TODOImplementWritingObjFiles,
881 .Lib => return error.TODOImplementWritingLibFiles,
882 }
883
884 if (self.pagezero_segment_cmd_index == null) {
885 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
783886 try self.load_commands.append(self.base.allocator, .{
784887 .Segment = .{
785888 .cmd = macho.LC_SEGMENT_64,
786889 .cmdsize = @sizeOf(macho.segment_command_64),
787 .segname = makeStaticString(""),
890 .segname = makeStaticString("__PAGEZERO"),
788891 .vmaddr = 0,
789 .vmsize = 0,
892 .vmsize = 0x100000000, // size always set to 4GB
790893 .fileoff = 0,
791894 .filesize = 0,
792895 .maxprot = 0,
......@@ -797,28 +900,34 @@ pub fn populateMissingMetadata(self: *MachO) !void {
797900 });
798901 self.cmd_table_dirty = true;
799902 }
800 if (self.symtab_cmd_index == null) {
801 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);
903 if (self.text_segment_cmd_index == null) {
904 self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
905 const prot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE;
802906 try self.load_commands.append(self.base.allocator, .{
803 .Symtab = .{
804 .cmd = macho.LC_SYMTAB,
805 .cmdsize = @sizeOf(macho.symtab_command),
806 .symoff = 0,
807 .nsyms = 0,
808 .stroff = 0,
809 .strsize = 0,
907 .Segment = .{
908 .cmd = macho.LC_SEGMENT_64,
909 .cmdsize = @sizeOf(macho.segment_command_64),
910 .segname = makeStaticString("__TEXT"),
911 .vmaddr = 0x100000000, // always starts at 4GB
912 .vmsize = 0,
913 .fileoff = 0,
914 .filesize = 0,
915 .maxprot = prot,
916 .initprot = prot,
917 .nsects = 0,
918 .flags = 0,
810919 },
811920 });
812921 self.cmd_table_dirty = true;
813922 }
814923 if (self.text_section_index == null) {
815924 self.text_section_index = @intCast(u16, self.sections.items.len);
816 const segment = &self.load_commands.items[self.segment_cmd_index.?].Segment;
817 segment.cmdsize += @sizeOf(macho.section_64);
818 segment.nsects += 1;
925 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
926 text_segment.cmdsize += @sizeOf(macho.section_64);
927 text_segment.nsects += 1;
819928
820 const file_size = self.base.options.program_code_size_hint;
821 const off = @intCast(u32, self.findFreeSpace(file_size, 1));
929 const file_size = mem.alignForwardGeneric(u64, self.base.options.program_code_size_hint, 0x1000);
930 const off = @intCast(u32, self.findFreeSpace(file_size, 0x1000)); // TODO maybe findFreeSpace should return u32 directly?
822931 const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS;
823932
824933 log.debug("found __text section free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
......@@ -826,10 +935,10 @@ pub fn populateMissingMetadata(self: *MachO) !void {
826935 try self.sections.append(self.base.allocator, .{
827936 .sectname = makeStaticString("__text"),
828937 .segname = makeStaticString("__TEXT"),
829 .addr = 0,
938 .addr = text_segment.vmaddr + off,
830939 .size = file_size,
831940 .offset = off,
832 .@"align" = 0x1000,
941 .@"align" = 12, // 2^12 = 4096
833942 .reloff = 0,
834943 .nreloc = 0,
835944 .flags = flags,
......@@ -838,43 +947,256 @@ pub fn populateMissingMetadata(self: *MachO) !void {
838947 .reserved3 = 0,
839948 });
840949
841 segment.vmsize += file_size;
842 segment.filesize += file_size;
843 segment.fileoff = off;
950 text_segment.vmsize = file_size + off; // We add off here since __TEXT segment includes everything prior to __text section.
951 text_segment.filesize = file_size + off;
952 }
953 if (self.data_segment_cmd_index == null) {
954 self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
955 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
956 const prot = macho.VM_PROT_READ | macho.VM_PROT_WRITE;
957 try self.load_commands.append(self.base.allocator, .{
958 .Segment = .{
959 .cmd = macho.LC_SEGMENT_64,
960 .cmdsize = @sizeOf(macho.segment_command_64),
961 .segname = makeStaticString("__DATA"),
962 .vmaddr = text_segment.vmaddr + text_segment.vmsize,
963 .vmsize = 0,
964 .fileoff = 0,
965 .filesize = 0,
966 .maxprot = prot,
967 .initprot = prot,
968 .nsects = 0,
969 .flags = 0,
970 },
971 });
972 self.cmd_table_dirty = true;
973 }
974 if (self.got_section_index == null) {
975 self.got_section_index = @intCast(u16, self.sections.items.len);
976 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
977 data_segment.cmdsize += @sizeOf(macho.section_64);
978 data_segment.nsects += 1;
979
980 const file_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
981 const off = @intCast(u32, self.findFreeSpace(file_size, 0x1000));
982
983 log.debug("found __got section free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
984
985 try self.sections.append(self.base.allocator, .{
986 .sectname = makeStaticString("__got"),
987 .segname = makeStaticString("__DATA"),
988 .addr = data_segment.vmaddr,
989 .size = file_size,
990 .offset = off,
991 .@"align" = 3, // 2^3 = 8
992 .reloff = 0,
993 .nreloc = 0,
994 .flags = macho.S_REGULAR,
995 .reserved1 = 0,
996 .reserved2 = 0,
997 .reserved3 = 0,
998 });
844999
845 log.debug("initial text section {}\n", .{self.sections.items[self.text_section_index.?]});
1000 const segment_size = mem.alignForwardGeneric(u64, file_size, 0x1000);
1001 data_segment.vmsize = segment_size;
1002 data_segment.filesize = segment_size;
1003 data_segment.fileoff = off;
1004 }
1005 if (self.linkedit_segment_cmd_index == null) {
1006 self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
1007 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1008 const prot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE;
1009 try self.load_commands.append(self.base.allocator, .{
1010 .Segment = .{
1011 .cmd = macho.LC_SEGMENT_64,
1012 .cmdsize = @sizeOf(macho.segment_command_64),
1013 .segname = makeStaticString("__LINKEDIT"),
1014 .vmaddr = data_segment.vmaddr + data_segment.vmsize,
1015 .vmsize = 0,
1016 .fileoff = 0,
1017 .filesize = 0,
1018 .maxprot = prot,
1019 .initprot = prot,
1020 .nsects = 0,
1021 .flags = 0,
1022 },
1023 });
1024 self.cmd_table_dirty = true;
1025 }
1026 if (self.dyld_info_cmd_index == null) {
1027 self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len);
1028 try self.load_commands.append(self.base.allocator, .{
1029 .DyldInfo = .{
1030 .cmd = macho.LC_DYLD_INFO_ONLY,
1031 .cmdsize = @sizeOf(macho.dyld_info_command),
1032 .rebase_off = 0,
1033 .rebase_size = 0,
1034 .bind_off = 0,
1035 .bind_size = 0,
1036 .weak_bind_off = 0,
1037 .weak_bind_size = 0,
1038 .lazy_bind_off = 0,
1039 .lazy_bind_size = 0,
1040 .export_off = 0,
1041 .export_size = 0,
1042 },
1043 });
1044 self.cmd_table_dirty = true;
1045 }
1046 if (self.symtab_cmd_index == null) {
1047 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);
1048 try self.load_commands.append(self.base.allocator, .{
1049 .Symtab = .{
1050 .cmd = macho.LC_SYMTAB,
1051 .cmdsize = @sizeOf(macho.symtab_command),
1052 .symoff = 0,
1053 .nsyms = 0,
1054 .stroff = 0,
1055 .strsize = 0,
1056 },
1057 });
1058 self.cmd_table_dirty = true;
1059 }
1060 if (self.dysymtab_cmd_index == null) {
1061 self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len);
1062 try self.load_commands.append(self.base.allocator, .{
1063 .Dysymtab = .{
1064 .cmd = macho.LC_DYSYMTAB,
1065 .cmdsize = @sizeOf(macho.dysymtab_command),
1066 .ilocalsym = 0,
1067 .nlocalsym = 0,
1068 .iextdefsym = 0,
1069 .nextdefsym = 0,
1070 .iundefsym = 0,
1071 .nundefsym = 0,
1072 .tocoff = 0,
1073 .ntoc = 0,
1074 .modtaboff = 0,
1075 .nmodtab = 0,
1076 .extrefsymoff = 0,
1077 .nextrefsyms = 0,
1078 .indirectsymoff = 0,
1079 .nindirectsyms = 0,
1080 .extreloff = 0,
1081 .nextrel = 0,
1082 .locreloff = 0,
1083 .nlocrel = 0,
1084 },
1085 });
1086 self.cmd_table_dirty = true;
1087 }
1088 if (self.dylinker_cmd_index == null) {
1089 self.dylinker_cmd_index = @intCast(u16, self.load_commands.items.len);
1090 const cmdsize = mem.alignForwardGeneric(u64, @sizeOf(macho.dylinker_command) + mem.lenZ(DEFAULT_DYLD_PATH), @sizeOf(u64));
1091 try self.load_commands.append(self.base.allocator, .{
1092 .Dylinker = .{
1093 .cmd = macho.LC_LOAD_DYLINKER,
1094 .cmdsize = @intCast(u32, cmdsize),
1095 .name = @sizeOf(macho.dylinker_command),
1096 },
1097 });
1098 self.cmd_table_dirty = true;
1099 }
1100 if (self.libsystem_cmd_index == null) {
1101 self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len);
1102 const cmdsize = mem.alignForwardGeneric(u64, @sizeOf(macho.dylib_command) + mem.lenZ(LIB_SYSTEM_PATH), @sizeOf(u64));
1103 // TODO Find a way to work out runtime version from the OS version triple stored in std.Target.
1104 // In the meantime, we're gonna hardcode to the minimum compatibility version of 1.0.0.
1105 const min_version = 0x10000;
1106 const dylib = .{
1107 .name = @sizeOf(macho.dylib_command),
1108 .timestamp = 2, // not sure why not simply 0; this is reverse engineered from Mach-O files
1109 .current_version = min_version,
1110 .compatibility_version = min_version,
1111 };
1112 try self.load_commands.append(self.base.allocator, .{
1113 .Dylib = .{
1114 .cmd = macho.LC_LOAD_DYLIB,
1115 .cmdsize = @intCast(u32, cmdsize),
1116 .dylib = dylib,
1117 },
1118 });
1119 self.cmd_table_dirty = true;
1120 }
1121 if (self.main_cmd_index == null) {
1122 self.main_cmd_index = @intCast(u16, self.load_commands.items.len);
1123 try self.load_commands.append(self.base.allocator, .{
1124 .EntryPoint = .{
1125 .cmd = macho.LC_MAIN,
1126 .cmdsize = @sizeOf(macho.entry_point_command),
1127 .entryoff = 0x0,
1128 .stacksize = 0,
1129 },
1130 });
1131 self.cmd_table_dirty = true;
1132 }
1133 {
1134 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
1135 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo;
1136 if (dyld_info.export_off == 0) {
1137 const nsyms = self.base.options.symbol_count_hint;
1138 const file_size = @sizeOf(u64) * nsyms;
1139 const off = @intCast(u32, self.findFreeSpace(file_size, 0x1000));
1140 log.debug("found export trie free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
1141 dyld_info.export_off = off;
1142 dyld_info.export_size = @intCast(u32, file_size);
1143
1144 const segment_size = mem.alignForwardGeneric(u64, file_size, 0x1000);
1145 linkedit.vmsize += segment_size;
1146 linkedit.fileoff = off;
1147 }
8461148 }
8471149 {
1150 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
8481151 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
8491152 if (symtab.symoff == 0) {
850 const p_align = @sizeOf(macho.nlist_64);
8511153 const nsyms = self.base.options.symbol_count_hint;
852 const file_size = p_align * nsyms;
853 const off = @intCast(u32, self.findFreeSpace(file_size, p_align));
1154 const file_size = @sizeOf(macho.nlist_64) * nsyms;
1155 const off = @intCast(u32, self.findFreeSpace(file_size, 0x1000));
8541156 log.debug("found symbol table free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
8551157 symtab.symoff = off;
8561158 symtab.nsyms = @intCast(u32, nsyms);
1159
1160 const segment_size = mem.alignForwardGeneric(u64, file_size, 0x1000);
1161 linkedit.vmsize += segment_size;
8571162 }
8581163 if (symtab.stroff == 0) {
8591164 try self.string_table.append(self.base.allocator, 0);
8601165 const file_size = @intCast(u32, self.string_table.items.len);
861 const off = @intCast(u32, self.findFreeSpace(file_size, 1));
1166 const off = @intCast(u32, self.findFreeSpace(file_size, 0x1000));
8621167 log.debug("found string table free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
8631168 symtab.stroff = off;
8641169 symtab.strsize = file_size;
1170
1171 const segment_size = mem.alignForwardGeneric(u64, file_size, 0x1000);
1172 linkedit.vmsize += segment_size;
8651173 }
8661174 }
1175 if (self.dyld_stub_binder_index == null) {
1176 self.dyld_stub_binder_index = @intCast(u16, self.undef_symbols.items.len);
1177 const name = try self.makeString("dyld_stub_binder");
1178 try self.undef_symbols.append(self.base.allocator, .{
1179 .n_strx = name,
1180 .n_type = macho.N_UNDF | macho.N_EXT,
1181 .n_sect = 0,
1182 .n_desc = macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | macho.N_SYMBOL_RESOLVER,
1183 .n_value = 0,
1184 });
1185 }
8671186}
8681187
8691188fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 {
870 const segment = &self.load_commands.items[self.segment_cmd_index.?].Segment;
8711189 const text_section = &self.sections.items[self.text_section_index.?];
8721190 const new_block_ideal_capacity = new_block_size * alloc_num / alloc_den;
8731191
8741192 var block_placement: ?*TextBlock = null;
8751193 const addr = blk: {
8761194 if (self.last_text_block) |last| {
877 const last_symbol = self.symbol_table.items[last.symbol_table_index.?];
1195 const last_symbol = self.local_symbols.items[last.local_sym_index];
1196 // TODO pad out with NOPs and reenable
1197 // const ideal_capacity = last.size * alloc_num / alloc_den;
1198 // const ideal_capacity_end_addr = last_symbol.n_value + ideal_capacity;
1199 // const new_start_addr = mem.alignForwardGeneric(u64, ideal_capacity_end_addr, alignment);
8781200 const end_addr = last_symbol.n_value + last.size;
8791201 const new_start_addr = mem.alignForwardGeneric(u64, end_addr, alignment);
8801202 block_placement = last;
......@@ -883,22 +1205,15 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
8831205 break :blk text_section.addr;
8841206 }
8851207 };
886 log.debug("computed symbol address 0x{x}\n", .{addr});
8871208
8881209 const expand_text_section = block_placement == null or block_placement.?.next == null;
8891210 if (expand_text_section) {
8901211 const text_capacity = self.allocatedSize(text_section.offset);
8911212 const needed_size = (addr + new_block_size) - text_section.addr;
892 log.debug("text capacity 0x{x}, needed size 0x{x}\n", .{ text_capacity, needed_size });
8931213 assert(needed_size <= text_capacity); // TODO handle growth
8941214
8951215 self.last_text_block = text_block;
896 text_section.size = needed_size;
897 segment.vmsize = needed_size;
898 segment.filesize = needed_size;
899 if (alignment < text_section.@"align") {
900 text_section.@"align" = @intCast(u32, alignment);
901 }
1216 text_section.size = needed_size; // TODO temp until we pad out with NOPs
9021217 }
9031218 text_block.size = new_block_size;
9041219
......@@ -936,22 +1251,27 @@ fn makeString(self: *MachO, bytes: []const u8) !u32 {
9361251 return @intCast(u32, result);
9371252}
9381253
939fn alignSize(comptime Int: type, min_size: anytype, alignment: Int) Int {
940 const size = @intCast(Int, min_size);
941 if (size % alignment == 0) return size;
942
943 const div = size / alignment;
944 return (div + 1) * alignment;
1254fn getString(self: *MachO, str_off: u32) []const u8 {
1255 assert(str_off < self.string_table.items.len);
1256 return mem.spanZ(@ptrCast([*:0]const u8, self.string_table.items.ptr + str_off));
9451257}
9461258
947fn commandSize(min_size: anytype) u32 {
948 return alignSize(u32, min_size, @sizeOf(u64));
1259fn updateString(self: *MachO, old_str_off: u32, new_name: []const u8) !u32 {
1260 const existing_name = self.getString(old_str_off);
1261 if (mem.eql(u8, existing_name, new_name)) {
1262 return old_str_off;
1263 }
1264 return self.makeString(new_name);
9491265}
9501266
1267/// TODO This should not heap allocate, instead it should utilize a fixed size, statically allocated
1268/// global const array. You could even use pwritev to write the same buffer multiple times with only
1269/// 1 syscall if you needed to, for example, write 8192 bytes using a buffer of only 4096 bytes.
1270/// This size parameter should probably be a usize not u64.
9511271fn addPadding(self: *MachO, size: u64, file_offset: u64) !void {
9521272 if (size == 0) return;
9531273
954 const buf = try self.base.allocator.alloc(u8, size);
1274 const buf = try self.base.allocator.alloc(u8, @intCast(usize, size));
9551275 defer self.base.allocator.free(buf);
9561276
9571277 mem.set(u8, buf[0..], 0);
......@@ -961,11 +1281,8 @@ fn addPadding(self: *MachO, size: u64, file_offset: u64) !void {
9611281
9621282fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {
9631283 const hdr_size: u64 = @sizeOf(macho.mach_header_64);
964 if (start < hdr_size)
965 return hdr_size;
966
1284 if (start < hdr_size) return hdr_size;
9671285 const end = start + satMul(size, alloc_num) / alloc_den;
968
9691286 {
9701287 const off = @sizeOf(macho.mach_header_64);
9711288 var tight_size: u64 = 0;
......@@ -978,7 +1295,6 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {
9781295 return test_end;
9791296 }
9801297 }
981
9821298 for (self.sections.items) |section| {
9831299 const increased_size = satMul(section.size, alloc_num) / alloc_den;
9841300 const test_end = section.offset + increased_size;
......@@ -986,7 +1302,15 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {
9861302 return test_end;
9871303 }
9881304 }
989
1305 if (self.dyld_info_cmd_index) |dyld_info_index| {
1306 const dyld_info = self.load_commands.items[dyld_info_index].DyldInfo;
1307 const tight_size = dyld_info.export_size;
1308 const increased_size = satMul(tight_size, alloc_num) / alloc_den;
1309 const test_end = dyld_info.export_off + increased_size;
1310 if (end > dyld_info.export_off and start < test_end) {
1311 return test_end;
1312 }
1313 }
9901314 if (self.symtab_cmd_index) |symtab_index| {
9911315 const symtab = self.load_commands.items[symtab_index].Symtab;
9921316 {
......@@ -1005,7 +1329,6 @@ fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {
10051329 }
10061330 }
10071331 }
1008
10091332 return null;
10101333}
10111334
......@@ -1021,6 +1344,10 @@ fn allocatedSize(self: *MachO, start: u64) u64 {
10211344 if (section.offset <= start) continue;
10221345 if (section.offset < min_pos) min_pos = section.offset;
10231346 }
1347 if (self.dyld_info_cmd_index) |dyld_info_index| {
1348 const dyld_info = self.load_commands.items[dyld_info_index].DyldInfo;
1349 if (dyld_info.export_off > start and dyld_info.export_off < min_pos) min_pos = dyld_info.export_off;
1350 }
10241351 if (self.symtab_cmd_index) |symtab_index| {
10251352 const symtab = self.load_commands.items[symtab_index].Symtab;
10261353 if (symtab.symoff > start and symtab.symoff < min_pos) min_pos = symtab.symoff;
......@@ -1042,12 +1369,133 @@ fn writeSymbol(self: *MachO, index: usize) !void {
10421369 defer tracy.end();
10431370
10441371 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
1045 const sym = [1]macho.nlist_64{self.symbol_table.items[index]};
1372 const sym = [1]macho.nlist_64{self.local_symbols.items[index]};
10461373 const off = symtab.symoff + @sizeOf(macho.nlist_64) * index;
10471374 log.debug("writing symbol {} at 0x{x}\n", .{ sym[0], off });
10481375 try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off);
10491376}
10501377
1378fn writeOffsetTableEntry(self: *MachO, index: usize) !void {
1379 const sect = &self.sections.items[self.got_section_index.?];
1380 const endian = self.base.options.target.cpu.arch.endian();
1381 var buf: [@sizeOf(u64)]u8 = undefined;
1382 mem.writeInt(u64, &buf, self.offset_table.items[index], endian);
1383 const off = sect.offset + @sizeOf(u64) * index;
1384 log.debug("writing offset table entry 0x{x} at 0x{x}\n", .{ self.offset_table.items[index], off });
1385 try self.base.file.?.pwriteAll(&buf, off);
1386}
1387
1388fn writeAllGlobalSymbols(self: *MachO) !void {
1389 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
1390 const off = symtab.symoff + self.local_symbols.items.len * @sizeOf(macho.nlist_64);
1391 const file_size = self.global_symbols.items.len * @sizeOf(macho.nlist_64);
1392 log.debug("writing global symbols from 0x{x} to 0x{x}\n", .{ off, file_size + off });
1393 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.global_symbols.items), off);
1394}
1395
1396fn writeAllUndefSymbols(self: *MachO) !void {
1397 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
1398 const nlocals = self.local_symbols.items.len;
1399 const nglobals = self.global_symbols.items.len;
1400 const off = symtab.symoff + (nlocals + nglobals) * @sizeOf(macho.nlist_64);
1401 const file_size = self.undef_symbols.items.len * @sizeOf(macho.nlist_64);
1402 log.debug("writing undef symbols from 0x{x} to 0x{x}\n", .{ off, file_size + off });
1403 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undef_symbols.items), off);
1404}
1405
1406fn writeExportTrie(self: *MachO) !void {
1407 assert(self.entry_addr != null);
1408
1409 // TODO implement mechanism for generating a prefix tree of the exported symbols
1410 // single branch export trie
1411 var buf = [_]u8{0} ** 24;
1412 buf[0] = 0; // root node
1413 buf[1] = 1; // 1 branch from root
1414 mem.copy(u8, buf[2..], "_start");
1415 buf[8] = 0;
1416 buf[9] = 9 + 1;
1417
1418 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1419 const addr = self.entry_addr.? - text_segment.vmaddr;
1420 const written = try std.debug.leb.writeULEB128Mem(buf[12..], addr);
1421 buf[10] = @intCast(u8, written) + 1;
1422 buf[11] = 0;
1423
1424 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo;
1425 try self.base.file.?.pwriteAll(buf[0..], dyld_info.export_off);
1426}
1427
1428fn writeStringTable(self: *MachO) !void {
1429 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
1430 const allocated_size = self.allocatedSize(symtab.stroff);
1431 const needed_size = self.string_table.items.len;
1432
1433 if (needed_size > allocated_size) {
1434 symtab.strsize = 0;
1435 symtab.stroff = @intCast(u32, self.findFreeSpace(needed_size, 1));
1436 }
1437 symtab.strsize = @intCast(u32, needed_size);
1438
1439 log.debug("writing string table from 0x{x} to 0x{x}\n", .{ symtab.stroff, symtab.stroff + symtab.strsize });
1440
1441 try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff);
1442
1443 // TODO rework how we preallocate space for the entire __LINKEDIT segment instead of
1444 // doing dynamic updates like this.
1445 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
1446 linkedit.filesize = symtab.stroff + symtab.strsize - linkedit.fileoff;
1447}
1448
1449fn writeCmdHeaders(self: *MachO) !void {
1450 assert(self.cmd_table_dirty);
1451
1452 // Write all load command headers first.
1453 // Since command sizes are up-to-date and accurate, we will correctly
1454 // leave space for any section headers that any of the segment load
1455 // commands might consist of.
1456 var last_cmd_offset: usize = @sizeOf(macho.mach_header_64);
1457 for (self.load_commands.items) |cmd| {
1458 try cmd.write(&self.base.file.?, last_cmd_offset);
1459 last_cmd_offset += cmd.cmdsize();
1460 }
1461 {
1462 // write __text section header
1463 const off = if (self.text_segment_cmd_index) |text_segment_index| blk: {
1464 var i: usize = 0;
1465 var cmdsize: usize = @sizeOf(macho.mach_header_64) + @sizeOf(macho.segment_command_64);
1466 while (i < text_segment_index) : (i += 1) {
1467 cmdsize += self.load_commands.items[i].cmdsize();
1468 }
1469 break :blk cmdsize;
1470 } else {
1471 // If we've landed in here, we are building a MachO object file, so we have
1472 // only one, noname segment to append this section header to.
1473 return error.TODOImplementWritingObjFiles;
1474 };
1475 const idx = self.text_section_index.?;
1476 log.debug("writing text section {} at 0x{x}\n", .{ self.sections.items[idx .. idx + 1], off });
1477 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items[idx .. idx + 1]), off);
1478 }
1479 {
1480 // write __got section header
1481 const off = if (self.data_segment_cmd_index) |data_segment_index| blk: {
1482 var i: usize = 0;
1483 var cmdsize: usize = @sizeOf(macho.mach_header_64) + @sizeOf(macho.segment_command_64);
1484 while (i < data_segment_index) : (i += 1) {
1485 cmdsize += self.load_commands.items[i].cmdsize();
1486 }
1487 break :blk cmdsize;
1488 } else {
1489 // If we've landed in here, we are building a MachO object file, so we have
1490 // only one, noname segment to append this section header to.
1491 return error.TODOImplementWritingObjFiles;
1492 };
1493 const idx = self.got_section_index.?;
1494 log.debug("writing got section {} at 0x{x}\n", .{ self.sections.items[idx .. idx + 1], off });
1495 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items[idx .. idx + 1]), off);
1496 }
1497}
1498
10511499/// Writes Mach-O file header.
10521500/// Should be invoked last as it needs up-to-date values of ncmds and sizeof_cmds bookkeeping
10531501/// variables.
src/main.zig+56-12
......@@ -268,16 +268,19 @@ const usage_build_generic =
268268 \\ -T[script], --script [script] Use a custom linker script
269269 \\ --version-script [path] Provide a version .map file
270270 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
271 \\ --each-lib-rpath Add rpath for each used dynamic library
272271 \\ --version [ver] Dynamic library semver
273272 \\ -rdynamic Add all symbols to the dynamic symbol table
274273 \\ -rpath [path] Add directory to the runtime library search path
274 \\ -feach-lib-rpath Ensure adding rpath for each used dynamic library
275 \\ -fno-each-lib-rpath Prevent adding rpath for each used dynamic library
275276 \\ --eh-frame-hdr Enable C++ exception handling by passing --eh-frame-hdr to linker
277 \\ --emit-relocs Enable output of relocation sections for post build tools
276278 \\ -dynamic Force output to be dynamically linked
277279 \\ -static Force output to be statically linked
278280 \\ -Bsymbolic Bind global references locally
279281 \\ --subsystem [subsystem] (windows) /SUBSYSTEM:<subsystem> to the linker\n"
280282 \\ --stack [size] Override default stack size
283 \\ --image-base [addr] Set base address for executable image
281284 \\ -framework [name] (darwin) link against framework
282285 \\ -F[dir] (darwin) add search path for frameworks
283286 \\
......@@ -434,11 +437,13 @@ fn buildOutputType(
434437 var linker_z_defs = false;
435438 var test_evented_io = false;
436439 var stack_size_override: ?u64 = null;
440 var image_base_override: ?u64 = null;
437441 var use_llvm: ?bool = null;
438442 var use_lld: ?bool = null;
439443 var use_clang: ?bool = null;
440444 var link_eh_frame_hdr = false;
441 var each_lib_rpath = false;
445 var link_emit_relocs = false;
446 var each_lib_rpath: ?bool = null;
442447 var libc_paths_file: ?[]const u8 = null;
443448 var machine_code_model: std.builtin.CodeModel = .default;
444449 var runtime_args_start: ?usize = null;
......@@ -520,7 +525,7 @@ fn buildOutputType(
520525 //}
521526 const args = all_args[2..];
522527 var i: usize = 0;
523 while (i < args.len) : (i += 1) {
528 args_loop: while (i < args.len) : (i += 1) {
524529 const arg = args[i];
525530 if (mem.startsWith(u8, arg, "-")) {
526531 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
......@@ -528,7 +533,10 @@ fn buildOutputType(
528533 return cleanExit();
529534 } else if (mem.eql(u8, arg, "--")) {
530535 if (arg_mode == .run) {
531 runtime_args_start = i + 1;
536 // The index refers to all_args so skip `zig` `run`
537 // and `--`
538 runtime_args_start = i + 3;
539 break :args_loop;
532540 } else {
533541 fatal("unexpected end-of-parameter mark: --", .{});
534542 }
......@@ -626,9 +634,11 @@ fn buildOutputType(
626634 } else if (mem.eql(u8, arg, "--stack")) {
627635 if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
628636 i += 1;
629 stack_size_override = std.fmt.parseInt(u64, args[i], 10) catch |err| {
630 fatal("unable to parse '{}': {}", .{ arg, @errorName(err) });
631 };
637 stack_size_override = parseAnyBaseInt(args[i]);
638 } else if (mem.eql(u8, arg, "--image-base")) {
639 if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
640 i += 1;
641 image_base_override = parseAnyBaseInt(args[i]);
632642 } else if (mem.eql(u8, arg, "--name")) {
633643 if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
634644 i += 1;
......@@ -733,8 +743,10 @@ fn buildOutputType(
733743 if (i + 1 >= args.len) fatal("expected parameter after {}", .{arg});
734744 i += 1;
735745 override_lib_dir = args[i];
736 } else if (mem.eql(u8, arg, "--each-lib-rpath")) {
746 } else if (mem.eql(u8, arg, "-feach-lib-rpath")) {
737747 each_lib_rpath = true;
748 } else if (mem.eql(u8, arg, "-fno-each-lib-rpath")) {
749 each_lib_rpath = false;
738750 } else if (mem.eql(u8, arg, "--enable-cache")) {
739751 enable_cache = true;
740752 } else if (mem.eql(u8, arg, "--test-cmd-bin")) {
......@@ -838,6 +850,8 @@ fn buildOutputType(
838850 function_sections = true;
839851 } else if (mem.eql(u8, arg, "--eh-frame-hdr")) {
840852 link_eh_frame_hdr = true;
853 } else if (mem.eql(u8, arg, "--emit-relocs")) {
854 link_emit_relocs = true;
841855 } else if (mem.eql(u8, arg, "-Bsymbolic")) {
842856 linker_bind_global_refs_locally = true;
843857 } else if (mem.eql(u8, arg, "--verbose-link")) {
......@@ -1143,9 +1157,13 @@ fn buildOutputType(
11431157 if (i >= linker_args.items.len) {
11441158 fatal("expected linker arg after '{}'", .{arg});
11451159 }
1146 stack_size_override = std.fmt.parseInt(u64, linker_args.items[i], 10) catch |err| {
1147 fatal("unable to parse '{}': {}", .{ arg, @errorName(err) });
1148 };
1160 stack_size_override = parseAnyBaseInt(linker_args.items[i]);
1161 } else if (mem.eql(u8, arg, "--image-base")) {
1162 i += 1;
1163 if (i >= linker_args.items.len) {
1164 fatal("expected linker arg after '{}'", .{arg});
1165 }
1166 image_base_override = parseAnyBaseInt(linker_args.items[i]);
11491167 } else {
11501168 warn("unsupported linker arg: {}", .{arg});
11511169 }
......@@ -1206,6 +1224,10 @@ fn buildOutputType(
12061224 fatal("translate-c expects exactly 1 source file (found {})", .{c_source_files.items.len});
12071225 }
12081226
1227 if (root_src_file == null and arg_mode == .zig_test) {
1228 fatal("one zig source file is required to run `zig test`", .{});
1229 }
1230
12091231 const root_name = if (provided_name) |n| n else blk: {
12101232 if (arg_mode == .zig_test) {
12111233 break :blk "test";
......@@ -1446,6 +1468,11 @@ fn buildOutputType(
14461468 cleanup_root_dir = dir;
14471469 root_pkg_memory.root_src_directory = .{ .path = p, .handle = dir };
14481470 root_pkg_memory.root_src_path = try fs.path.relative(arena, p, src_path);
1471 } else if (fs.path.dirname(src_path)) |p| {
1472 const dir = try fs.cwd().openDir(p, .{});
1473 cleanup_root_dir = dir;
1474 root_pkg_memory.root_src_directory = .{ .path = p, .handle = dir };
1475 root_pkg_memory.root_src_path = fs.path.basename(src_path);
14491476 } else {
14501477 root_pkg_memory.root_src_directory = .{ .path = null, .handle = fs.cwd() };
14511478 root_pkg_memory.root_src_path = src_path;
......@@ -1580,7 +1607,9 @@ fn buildOutputType(
15801607 .linker_z_nodelete = linker_z_nodelete,
15811608 .linker_z_defs = linker_z_defs,
15821609 .link_eh_frame_hdr = link_eh_frame_hdr,
1610 .link_emit_relocs = link_emit_relocs,
15831611 .stack_size_override = stack_size_override,
1612 .image_base_override = image_base_override,
15841613 .strip = strip,
15851614 .single_threaded = single_threaded,
15861615 .function_sections = function_sections,
......@@ -2525,7 +2554,7 @@ fn fmtPathFile(
25252554 const source_code = source_file.readToEndAllocOptions(
25262555 fmt.gpa,
25272556 max_src_size,
2528 stat.size,
2557 std.math.cast(usize, stat.size) catch return error.FileTooBig,
25292558 @alignOf(u8),
25302559 null,
25312560 ) catch |err| switch (err) {
......@@ -3037,3 +3066,18 @@ pub fn cleanExit() void {
30373066 process.exit(0);
30383067 }
30393068}
3069
3070fn parseAnyBaseInt(prefixed_bytes: []const u8) u64 {
3071 const base: u8 = if (mem.startsWith(u8, prefixed_bytes, "0x"))
3072 16
3073 else if (mem.startsWith(u8, prefixed_bytes, "0o"))
3074 8
3075 else if (mem.startsWith(u8, prefixed_bytes, "0b"))
3076 2
3077 else
3078 @as(u8, 10);
3079 const bytes = if (base == 10) prefixed_bytes else prefixed_bytes[2..];
3080 return std.fmt.parseInt(u64, bytes, base) catch |err| {
3081 fatal("unable to parse '{}': {}", .{ prefixed_bytes, @errorName(err) });
3082 };
3083}
src/mingw.zig+6-5
......@@ -32,6 +32,8 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
3232 var args = std.ArrayList([]const u8).init(arena);
3333 try add_cc_args(comp, arena, &args);
3434 try args.appendSlice(&[_][]const u8{
35 "-D_SYSCRT=1",
36 "-DCRTDLL=1",
3537 "-U__CRTDLL__",
3638 "-D__MSVCRT__",
3739 // Uncomment these 3 things for crtu
......@@ -53,6 +55,8 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
5355 var args = std.ArrayList([]const u8).init(arena);
5456 try add_cc_args(comp, arena, &args);
5557 try args.appendSlice(&[_][]const u8{
58 "-D_SYSCRT=1",
59 "-DCRTDLL=1",
5660 "-U__CRTDLL__",
5761 "-D__MSVCRT__",
5862 });
......@@ -437,11 +441,8 @@ fn findDef(comp: *Compilation, allocator: *Allocator, lib_name: []const u8) ![]u
437441 const lib_path = switch (target.cpu.arch) {
438442 .i386 => "lib32",
439443 .x86_64 => "lib64",
440 .arm, .armeb => switch (target.cpu.arch.ptrBitWidth()) {
441 32 => "libarm32",
442 64 => "libarm64",
443 else => unreachable,
444 },
444 .arm, .armeb, .thumb, .thumbeb, .aarch64_32 => "libarm32",
445 .aarch64, .aarch64_be => "libarm64",
445446 else => unreachable,
446447 };
447448
src/stage1.zig+5-1
......@@ -39,7 +39,11 @@ pub export fn main(argc: c_int, argv: [*]const [*:0]const u8) c_int {
3939 for (args) |*arg, i| {
4040 arg.* = mem.spanZ(argv[i]);
4141 }
42 stage2.mainArgs(gpa, arena, args) catch |err| fatal("{}", .{@errorName(err)});
42 if (std.builtin.mode == .Debug) {
43 stage2.mainArgs(gpa, arena, args) catch unreachable;
44 } else {
45 stage2.mainArgs(gpa, arena, args) catch |err| fatal("{}", .{@errorName(err)});
46 }
4347 return 0;
4448}
4549
src/stage1/all_types.hpp+27-5
......@@ -18,11 +18,6 @@
1818#include "target.hpp"
1919#include "tokenizer.hpp"
2020
21#ifndef NDEBUG
22#define DBG_MACRO_NO_WARNING
23#include <dbg.h>
24#endif
25
2621struct AstNode;
2722struct ZigFn;
2823struct Scope;
......@@ -1456,6 +1451,7 @@ struct ZigTypeEnum {
14561451 ContainerLayout layout;
14571452 ResolveStatus resolve_status;
14581453
1454 bool has_explicit_tag_type;
14591455 bool non_exhaustive;
14601456 bool resolve_loop_flag;
14611457};
......@@ -1825,6 +1821,7 @@ enum BuiltinFnId {
18251821 BuiltinFnIdWasmMemorySize,
18261822 BuiltinFnIdWasmMemoryGrow,
18271823 BuiltinFnIdSrc,
1824 BuiltinFnIdReduce,
18281825};
18291826
18301827struct BuiltinFnEntry {
......@@ -2440,6 +2437,15 @@ enum AtomicOrder {
24402437 AtomicOrderSeqCst,
24412438};
24422439
2440// synchronized with code in define_builtin_compile_vars
2441enum ReduceOp {
2442 ReduceOp_and,
2443 ReduceOp_or,
2444 ReduceOp_xor,
2445 ReduceOp_min,
2446 ReduceOp_max,
2447};
2448
24432449// synchronized with the code in define_builtin_compile_vars
24442450enum AtomicRmwOp {
24452451 AtomicRmwOp_xchg,
......@@ -2549,6 +2555,7 @@ enum IrInstSrcId {
25492555 IrInstSrcIdEmbedFile,
25502556 IrInstSrcIdCmpxchg,
25512557 IrInstSrcIdFence,
2558 IrInstSrcIdReduce,
25522559 IrInstSrcIdTruncate,
25532560 IrInstSrcIdIntCast,
25542561 IrInstSrcIdFloatCast,
......@@ -2671,6 +2678,7 @@ enum IrInstGenId {
26712678 IrInstGenIdErrName,
26722679 IrInstGenIdCmpxchg,
26732680 IrInstGenIdFence,
2681 IrInstGenIdReduce,
26742682 IrInstGenIdTruncate,
26752683 IrInstGenIdShuffleVector,
26762684 IrInstGenIdSplat,
......@@ -3520,6 +3528,20 @@ struct IrInstGenFence {
35203528 AtomicOrder order;
35213529};
35223530
3531struct IrInstSrcReduce {
3532 IrInstSrc base;
3533
3534 IrInstSrc *op;
3535 IrInstSrc *value;
3536};
3537
3538struct IrInstGenReduce {
3539 IrInstGen base;
3540
3541 ReduceOp op;
3542 IrInstGen *value;
3543};
3544
35233545struct IrInstSrcTruncate {
35243546 IrInstSrc base;
35253547
src/stage1/analyze.cpp+16-8
......@@ -1802,10 +1802,18 @@ Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result) {
18021802 }
18031803 return type_allowed_in_extern(g, child_type, result);
18041804 }
1805 case ZigTypeIdEnum:
1806 *result = type_entry->data.enumeration.layout == ContainerLayoutExtern ||
1807 type_entry->data.enumeration.layout == ContainerLayoutPacked;
1808 return ErrorNone;
1805 case ZigTypeIdEnum: {
1806 if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
1807 return err;
1808 ZigType *tag_int_type = type_entry->data.enumeration.tag_int_type;
1809 if (type_entry->data.enumeration.has_explicit_tag_type) {
1810 return type_allowed_in_extern(g, tag_int_type, result);
1811 } else {
1812 *result = type_entry->data.enumeration.layout == ContainerLayoutExtern ||
1813 type_entry->data.enumeration.layout == ContainerLayoutPacked;
1814 return ErrorNone;
1815 }
1816 }
18091817 case ZigTypeIdUnion:
18101818 *result = type_entry->data.unionation.layout == ContainerLayoutExtern ||
18111819 type_entry->data.unionation.layout == ContainerLayoutPacked;
......@@ -2639,9 +2647,11 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
26392647 if (decl_node->type == NodeTypeContainerDecl) {
26402648 if (decl_node->data.container_decl.init_arg_expr != nullptr) {
26412649 wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr);
2650 enum_type->data.enumeration.has_explicit_tag_type = true;
26422651 }
26432652 } else {
26442653 wanted_tag_int_type = enum_type->data.enumeration.tag_int_type;
2654 enum_type->data.enumeration.has_explicit_tag_type = true;
26452655 }
26462656
26472657 if (wanted_tag_int_type != nullptr) {
......@@ -3120,12 +3130,9 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
31203130 bool create_enum_type = is_auto_enum || (!is_explicit_enum && want_safety);
31213131 bool *covered_enum_fields;
31223132 bool *is_zero_bits = heap::c_allocator.allocate<bool>(field_count);
3123 ZigLLVMDIEnumerator **di_enumerators;
31243133 if (create_enum_type) {
31253134 occupied_tag_values.init(field_count);
31263135
3127 di_enumerators = heap::c_allocator.allocate<ZigLLVMDIEnumerator*>(field_count);
3128
31293136 ZigType *tag_int_type;
31303137 if (enum_type_node != nullptr) {
31313138 tag_int_type = analyze_type_expr(g, scope, enum_type_node);
......@@ -3269,7 +3276,6 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
32693276 }
32703277
32713278 if (create_enum_type) {
3272 di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(union_field->name), i);
32733279 union_field->enum_field = &tag_type->data.enumeration.fields[i];
32743280 union_field->enum_field->name = union_field->name;
32753281 union_field->enum_field->decl_index = i;
......@@ -3336,6 +3342,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
33363342 gen_field_index += 1;
33373343 }
33383344 }
3345 heap::c_allocator.deallocate(is_zero_bits, field_count);
33393346
33403347 bool src_have_tag = is_auto_enum || is_explicit_enum;
33413348
......@@ -3403,6 +3410,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
34033410 union_type->data.unionation.resolve_status = ResolveStatusInvalid;
34043411 }
34053412 }
3413 heap::c_allocator.deallocate(covered_enum_fields, tag_type->data.enumeration.src_field_count);
34063414 }
34073415
34083416 if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) {
src/stage1/codegen.cpp+86-47
......@@ -2584,36 +2584,6 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutableGen *executable, Ir
25842584 return nullptr;
25852585}
25862586
2587enum class ScalarizePredicate {
2588 // Returns true iff all the elements in the vector are 1.
2589 // Equivalent to folding all the bits with `and`.
2590 All,
2591 // Returns true iff there's at least one element in the vector that is 1.
2592 // Equivalent to folding all the bits with `or`.
2593 Any,
2594};
2595
2596// Collapses a <N x i1> vector into a single i1 according to the given predicate
2597static LLVMValueRef scalarize_cmp_result(CodeGen *g, LLVMValueRef val, ScalarizePredicate predicate) {
2598 assert(LLVMGetTypeKind(LLVMTypeOf(val)) == LLVMVectorTypeKind);
2599 LLVMTypeRef scalar_type = LLVMIntType(LLVMGetVectorSize(LLVMTypeOf(val)));
2600 LLVMValueRef casted = LLVMBuildBitCast(g->builder, val, scalar_type, "");
2601
2602 switch (predicate) {
2603 case ScalarizePredicate::Any: {
2604 LLVMValueRef all_zeros = LLVMConstNull(scalar_type);
2605 return LLVMBuildICmp(g->builder, LLVMIntNE, casted, all_zeros, "");
2606 }
2607 case ScalarizePredicate::All: {
2608 LLVMValueRef all_ones = LLVMConstAllOnes(scalar_type);
2609 return LLVMBuildICmp(g->builder, LLVMIntEQ, casted, all_ones, "");
2610 }
2611 }
2612
2613 zig_unreachable();
2614}
2615
2616
26172587static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *operand_type,
26182588 LLVMValueRef val1, LLVMValueRef val2)
26192589{
......@@ -2638,7 +2608,7 @@ static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *operand_type,
26382608 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");
26392609 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");
26402610 if (operand_type->id == ZigTypeIdVector) {
2641 ok_bit = scalarize_cmp_result(g, ok_bit, ScalarizePredicate::All);
2611 ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit);
26422612 }
26432613 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
26442614
......@@ -2669,7 +2639,7 @@ static LLVMValueRef gen_overflow_shr_op(CodeGen *g, ZigType *operand_type,
26692639 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");
26702640 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");
26712641 if (operand_type->id == ZigTypeIdVector) {
2672 ok_bit = scalarize_cmp_result(g, ok_bit, ScalarizePredicate::All);
2642 ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit);
26732643 }
26742644 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
26752645
......@@ -2746,7 +2716,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast
27462716 }
27472717
27482718 if (operand_type->id == ZigTypeIdVector) {
2749 is_zero_bit = scalarize_cmp_result(g, is_zero_bit, ScalarizePredicate::Any);
2719 is_zero_bit = ZigLLVMBuildOrReduce(g->builder, is_zero_bit);
27502720 }
27512721
27522722 LLVMBasicBlockRef div_zero_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivZeroFail");
......@@ -2771,7 +2741,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast
27712741 LLVMValueRef den_is_neg_1 = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, neg_1_value, "");
27722742 LLVMValueRef overflow_fail_bit = LLVMBuildAnd(g->builder, num_is_int_min, den_is_neg_1, "");
27732743 if (operand_type->id == ZigTypeIdVector) {
2774 overflow_fail_bit = scalarize_cmp_result(g, overflow_fail_bit, ScalarizePredicate::Any);
2744 overflow_fail_bit = ZigLLVMBuildOrReduce(g->builder, overflow_fail_bit);
27752745 }
27762746 LLVMBuildCondBr(g->builder, overflow_fail_bit, overflow_fail_block, overflow_ok_block);
27772747
......@@ -2796,7 +2766,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast
27962766 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail");
27972767 LLVMValueRef ok_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, floored, result, "");
27982768 if (operand_type->id == ZigTypeIdVector) {
2799 ok_bit = scalarize_cmp_result(g, ok_bit, ScalarizePredicate::All);
2769 ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit);
28002770 }
28012771 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
28022772
......@@ -2813,7 +2783,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast
28132783 LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivTruncEnd");
28142784 LLVMValueRef ltz = LLVMBuildFCmp(g->builder, LLVMRealOLT, val1, zero, "");
28152785 if (operand_type->id == ZigTypeIdVector) {
2816 ltz = scalarize_cmp_result(g, ltz, ScalarizePredicate::Any);
2786 ltz = ZigLLVMBuildOrReduce(g->builder, ltz);
28172787 }
28182788 LLVMBuildCondBr(g->builder, ltz, ltz_block, gez_block);
28192789
......@@ -2865,7 +2835,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast
28652835 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivExactFail");
28662836 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
28672837 if (operand_type->id == ZigTypeIdVector) {
2868 ok_bit = scalarize_cmp_result(g, ok_bit, ScalarizePredicate::All);
2838 ok_bit = ZigLLVMBuildAndReduce(g->builder, ok_bit);
28692839 }
28702840 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
28712841
......@@ -2929,7 +2899,7 @@ static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast
29292899 }
29302900
29312901 if (operand_type->id == ZigTypeIdVector) {
2932 is_zero_bit = scalarize_cmp_result(g, is_zero_bit, ScalarizePredicate::Any);
2902 is_zero_bit = ZigLLVMBuildOrReduce(g->builder, is_zero_bit);
29332903 }
29342904
29352905 LLVMBasicBlockRef rem_zero_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "RemZeroOk");
......@@ -2986,7 +2956,7 @@ static void gen_shift_rhs_check(CodeGen *g, ZigType *lhs_type, ZigType *rhs_type
29862956 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "CheckOk");
29872957 LLVMValueRef less_than_bit = LLVMBuildICmp(g->builder, LLVMIntULT, value, bit_count_value, "");
29882958 if (rhs_type->id == ZigTypeIdVector) {
2989 less_than_bit = scalarize_cmp_result(g, less_than_bit, ScalarizePredicate::Any);
2959 less_than_bit = ZigLLVMBuildOrReduce(g->builder, less_than_bit);
29902960 }
29912961 LLVMBuildCondBr(g->builder, less_than_bit, ok_block, fail_block);
29922962
......@@ -4415,6 +4385,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn
44154385 }
44164386 }
44174387 LLVMTypeRef frame_with_args_type = LLVMStructType(field_types, field_count, false);
4388 heap::c_allocator.deallocate(field_types, field_count);
44184389 LLVMTypeRef ptr_frame_with_args_type = LLVMPointerType(frame_with_args_type, 0);
44194390
44204391 casted_frame = LLVMBuildBitCast(g->builder, frame_result_loc, ptr_frame_with_args_type, "");
......@@ -4429,6 +4400,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn
44294400 gen_assign_raw(g, arg_ptr, get_pointer_to_type(g, gen_param_types.at(arg_i), true),
44304401 gen_param_values.at(arg_i));
44314402 }
4403 gen_param_types.deinit();
44324404
44334405 if (instruction->modifier == CallModifierAsync) {
44344406 gen_resume(g, fn_val, frame_result_loc, ResumeIdCall);
......@@ -4506,6 +4478,8 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutableGen *executable, IrIn
45064478 LLVMValueRef result_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, "");
45074479 return LLVMBuildLoad(g->builder, result_ptr, "");
45084480 }
4481 } else {
4482 gen_param_types.deinit();
45094483 }
45104484
45114485 if (instruction->new_stack == nullptr || instruction->is_async_call_builtin) {
......@@ -4823,12 +4797,15 @@ static LLVMValueRef ir_render_asm_gen(CodeGen *g, IrExecutableGen *executable, I
48234797 ret_type = get_llvm_type(g, instruction->base.value->type);
48244798 }
48254799 LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, (unsigned)input_and_output_count, false);
4800 heap::c_allocator.deallocate(param_types, input_and_output_count);
48264801
48274802 bool is_volatile = instruction->has_side_effects || (asm_expr->output_list.length == 0);
48284803 LLVMValueRef asm_fn = LLVMGetInlineAsm(function_type, buf_ptr(&llvm_template), buf_len(&llvm_template),
48294804 buf_ptr(&constraint_buf), buf_len(&constraint_buf), is_volatile, false, LLVMInlineAsmDialectATT);
48304805
4831 return LLVMBuildCall(g->builder, asm_fn, param_values, (unsigned)input_and_output_count, "");
4806 LLVMValueRef built_call = LLVMBuildCall(g->builder, asm_fn, param_values, (unsigned)input_and_output_count, "");
4807 heap::c_allocator.deallocate(param_values, input_and_output_count);
4808 return built_call;
48324809}
48334810
48344811static LLVMValueRef gen_non_null_bit(CodeGen *g, ZigType *maybe_type, LLVMValueRef maybe_handle) {
......@@ -5081,6 +5058,8 @@ static LLVMValueRef ir_render_phi(CodeGen *g, IrExecutableGen *executable, IrIns
50815058 incoming_blocks[i] = instruction->incoming_blocks[i]->llvm_exit_block;
50825059 }
50835060 LLVMAddIncoming(phi, incoming_values, incoming_blocks, (unsigned)instruction->incoming_count);
5061 heap::c_allocator.deallocate(incoming_values, instruction->incoming_count);
5062 heap::c_allocator.deallocate(incoming_blocks, instruction->incoming_count);
50845063 return phi;
50855064}
50865065
......@@ -5471,6 +5450,50 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutableGen *executable, I
54715450 return result_loc;
54725451}
54735452
5453static LLVMValueRef ir_render_reduce(CodeGen *g, IrExecutableGen *executable, IrInstGenReduce *instruction) {
5454 LLVMValueRef value = ir_llvm_value(g, instruction->value);
5455
5456 ZigType *value_type = instruction->value->value->type;
5457 assert(value_type->id == ZigTypeIdVector);
5458 ZigType *scalar_type = value_type->data.vector.elem_type;
5459
5460 LLVMValueRef result_val;
5461 switch (instruction->op) {
5462 case ReduceOp_and:
5463 assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool);
5464 result_val = ZigLLVMBuildAndReduce(g->builder, value);
5465 break;
5466 case ReduceOp_or:
5467 assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool);
5468 result_val = ZigLLVMBuildOrReduce(g->builder, value);
5469 break;
5470 case ReduceOp_xor:
5471 assert(scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdBool);
5472 result_val = ZigLLVMBuildXorReduce(g->builder, value);
5473 break;
5474 case ReduceOp_min: {
5475 if (scalar_type->id == ZigTypeIdInt) {
5476 const bool is_signed = scalar_type->data.integral.is_signed;
5477 result_val = ZigLLVMBuildIntMinReduce(g->builder, value, is_signed);
5478 } else if (scalar_type->id == ZigTypeIdFloat) {
5479 result_val = ZigLLVMBuildFPMinReduce(g->builder, value);
5480 } else zig_unreachable();
5481 } break;
5482 case ReduceOp_max: {
5483 if (scalar_type->id == ZigTypeIdInt) {
5484 const bool is_signed = scalar_type->data.integral.is_signed;
5485 result_val = ZigLLVMBuildIntMaxReduce(g->builder, value, is_signed);
5486 } else if (scalar_type->id == ZigTypeIdFloat) {
5487 result_val = ZigLLVMBuildFPMaxReduce(g->builder, value);
5488 } else zig_unreachable();
5489 } break;
5490 default:
5491 zig_unreachable();
5492 }
5493
5494 return result_val;
5495}
5496
54745497static LLVMValueRef ir_render_fence(CodeGen *g, IrExecutableGen *executable, IrInstGenFence *instruction) {
54755498 LLVMAtomicOrdering atomic_order = to_LLVMAtomicOrdering(instruction->order);
54765499 LLVMBuildFence(g->builder, atomic_order, false, "");
......@@ -6675,6 +6698,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutableGen *executabl
66756698 return ir_render_cmpxchg(g, executable, (IrInstGenCmpxchg *)instruction);
66766699 case IrInstGenIdFence:
66776700 return ir_render_fence(g, executable, (IrInstGenFence *)instruction);
6701 case IrInstGenIdReduce:
6702 return ir_render_reduce(g, executable, (IrInstGenReduce *)instruction);
66786703 case IrInstGenIdTruncate:
66796704 return ir_render_truncate(g, executable, (IrInstGenTruncate *)instruction);
66806705 case IrInstGenIdBoolNot:
......@@ -7457,10 +7482,14 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n
74577482 }
74587483 }
74597484 if (make_unnamed_struct) {
7460 return LLVMConstStruct(fields, type_entry->data.structure.gen_field_count,
7485 LLVMValueRef unnamed_struct = LLVMConstStruct(fields, type_entry->data.structure.gen_field_count,
74617486 type_entry->data.structure.layout == ContainerLayoutPacked);
7487 heap::c_allocator.deallocate(fields, type_entry->data.structure.gen_field_count);
7488 return unnamed_struct;
74627489 } else {
7463 return LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, type_entry->data.structure.gen_field_count);
7490 LLVMValueRef named_struct = LLVMConstNamedStruct(get_llvm_type(g, type_entry), fields, type_entry->data.structure.gen_field_count);
7491 heap::c_allocator.deallocate(fields, type_entry->data.structure.gen_field_count);
7492 return named_struct;
74647493 }
74657494 }
74667495 case ZigTypeIdArray:
......@@ -7485,9 +7514,13 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n
74857514 values[len] = gen_const_val(g, type_entry->data.array.sentinel, "");
74867515 }
74877516 if (make_unnamed_struct) {
7488 return LLVMConstStruct(values, full_len, true);
7517 LLVMValueRef unnamed_struct = LLVMConstStruct(values, full_len, true);
7518 heap::c_allocator.deallocate(values, full_len);
7519 return unnamed_struct;
74897520 } else {
7490 return LLVMConstArray(element_type_ref, values, (unsigned)full_len);
7521 LLVMValueRef array = LLVMConstArray(element_type_ref, values, (unsigned)full_len);
7522 heap::c_allocator.deallocate(values, full_len);
7523 return array;
74917524 }
74927525 }
74937526 case ConstArraySpecialBuf: {
......@@ -7509,7 +7542,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n
75097542 ZigValue *elem_value = &const_val->data.x_array.data.s_none.elements[i];
75107543 values[i] = gen_const_val(g, elem_value, "");
75117544 }
7512 return LLVMConstVector(values, len);
7545 LLVMValueRef vector = LLVMConstVector(values, len);
7546 heap::c_allocator.deallocate(values, len);
7547 return vector;
75137548 }
75147549 case ConstArraySpecialBuf: {
75157550 Buf *buf = const_val->data.x_array.data.s_buf;
......@@ -7518,7 +7553,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n
75187553 for (uint64_t i = 0; i < len; i += 1) {
75197554 values[i] = LLVMConstInt(g->builtin_types.entry_u8->llvm_type, buf_ptr(buf)[i], false);
75207555 }
7521 return LLVMConstVector(values, len);
7556 LLVMValueRef vector = LLVMConstVector(values, len);
7557 heap::c_allocator.deallocate(values, len);
7558 return vector;
75227559 }
75237560 }
75247561 zig_unreachable();
......@@ -7740,6 +7777,7 @@ static void generate_error_name_table(CodeGen *g) {
77407777 }
77417778
77427779 LLVMValueRef err_name_table_init = LLVMConstArray(get_llvm_type(g, str_type), values, (unsigned)g->errors_by_index.length);
7780 heap::c_allocator.deallocate(values, g->errors_by_index.length);
77437781
77447782 g->err_name_table = LLVMAddGlobal(g->module, LLVMTypeOf(err_name_table_init),
77457783 get_mangled_name(g, buf_ptr(buf_create_from_str("__zig_err_name_table"))));
......@@ -8631,6 +8669,7 @@ static void define_builtin_fns(CodeGen *g) {
86318669 create_builtin_fn(g, BuiltinFnIdWasmMemorySize, "wasmMemorySize", 1);
86328670 create_builtin_fn(g, BuiltinFnIdWasmMemoryGrow, "wasmMemoryGrow", 2);
86338671 create_builtin_fn(g, BuiltinFnIdSrc, "src", 0);
8672 create_builtin_fn(g, BuiltinFnIdReduce, "reduce", 2);
86348673}
86358674
86368675static const char *bool_to_str(bool b) {
......@@ -8816,7 +8855,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
88168855 buf_append_str(contents, "/// Deprecated: use `std.Target.current.cpu.arch.endian()`\n");
88178856 buf_append_str(contents, "pub const endian = Target.current.cpu.arch.endian();\n");
88188857 buf_appendf(contents, "pub const output_mode = OutputMode.Obj;\n");
8819 buf_appendf(contents, "pub const link_mode = LinkMode.Static;\n");
8858 buf_appendf(contents, "pub const link_mode = LinkMode.%s;\n", ZIG_LINK_MODE);
88208859 buf_appendf(contents, "pub const is_test = false;\n");
88218860 buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));
88228861 buf_appendf(contents, "pub const abi = Abi.%s;\n", cur_abi);
src/stage1/config.h.in+1
......@@ -21,5 +21,6 @@
2121#define ZIG_CLANG_LIBRARIES "@CLANG_LIBRARIES@"
2222#define ZIG_LLVM_CONFIG_EXE "@LLVM_CONFIG_EXE@"
2323#define ZIG_DIA_GUIDS_LIB "@ZIG_DIA_GUIDS_LIB_ESCAPED@"
24#define ZIG_LINK_MODE "@ZIG_LINK_MODE@"
2425
2526#endif
src/stage1/ir.cpp+392-28
......@@ -403,6 +403,8 @@ static void destroy_instruction_src(IrInstSrc *inst) {
403403 return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCmpxchg *>(inst));
404404 case IrInstSrcIdFence:
405405 return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFence *>(inst));
406 case IrInstSrcIdReduce:
407 return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcReduce *>(inst));
406408 case IrInstSrcIdTruncate:
407409 return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTruncate *>(inst));
408410 case IrInstSrcIdIntCast:
......@@ -637,6 +639,8 @@ void destroy_instruction_gen(IrInstGen *inst) {
637639 return heap::c_allocator.destroy(reinterpret_cast<IrInstGenCmpxchg *>(inst));
638640 case IrInstGenIdFence:
639641 return heap::c_allocator.destroy(reinterpret_cast<IrInstGenFence *>(inst));
642 case IrInstGenIdReduce:
643 return heap::c_allocator.destroy(reinterpret_cast<IrInstGenReduce *>(inst));
640644 case IrInstGenIdTruncate:
641645 return heap::c_allocator.destroy(reinterpret_cast<IrInstGenTruncate *>(inst));
642646 case IrInstGenIdShuffleVector:
......@@ -1312,6 +1316,10 @@ static constexpr IrInstSrcId ir_inst_id(IrInstSrcFence *) {
13121316 return IrInstSrcIdFence;
13131317}
13141318
1319static constexpr IrInstSrcId ir_inst_id(IrInstSrcReduce *) {
1320 return IrInstSrcIdReduce;
1321}
1322
13151323static constexpr IrInstSrcId ir_inst_id(IrInstSrcTruncate *) {
13161324 return IrInstSrcIdTruncate;
13171325}
......@@ -1776,6 +1784,10 @@ static constexpr IrInstGenId ir_inst_id(IrInstGenFence *) {
17761784 return IrInstGenIdFence;
17771785}
17781786
1787static constexpr IrInstGenId ir_inst_id(IrInstGenReduce *) {
1788 return IrInstGenIdReduce;
1789}
1790
17791791static constexpr IrInstGenId ir_inst_id(IrInstGenTruncate *) {
17801792 return IrInstGenIdTruncate;
17811793}
......@@ -3503,6 +3515,29 @@ static IrInstGen *ir_build_fence_gen(IrAnalyze *ira, IrInst *source_instr, Atomi
35033515 return &instruction->base;
35043516}
35053517
3518static IrInstSrc *ir_build_reduce(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *op, IrInstSrc *value) {
3519 IrInstSrcReduce *instruction = ir_build_instruction<IrInstSrcReduce>(irb, scope, source_node);
3520 instruction->op = op;
3521 instruction->value = value;
3522
3523 ir_ref_instruction(op, irb->current_basic_block);
3524 ir_ref_instruction(value, irb->current_basic_block);
3525
3526 return &instruction->base;
3527}
3528
3529static IrInstGen *ir_build_reduce_gen(IrAnalyze *ira, IrInst *source_instruction, ReduceOp op, IrInstGen *value, ZigType *result_type) {
3530 IrInstGenReduce *instruction = ir_build_inst_gen<IrInstGenReduce>(&ira->new_irb,
3531 source_instruction->scope, source_instruction->source_node);
3532 instruction->base.value->type = result_type;
3533 instruction->op = op;
3534 instruction->value = value;
3535
3536 ir_ref_inst_gen(value);
3537
3538 return &instruction->base;
3539}
3540
35063541static IrInstSrc *ir_build_truncate(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,
35073542 IrInstSrc *dest_type, IrInstSrc *target)
35083543{
......@@ -6581,6 +6616,21 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod
65816616 IrInstSrc *fence = ir_build_fence(irb, scope, node, arg0_value);
65826617 return ir_lval_wrap(irb, scope, fence, lval, result_loc);
65836618 }
6619 case BuiltinFnIdReduce:
6620 {
6621 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
6622 IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope);
6623 if (arg0_value == irb->codegen->invalid_inst_src)
6624 return arg0_value;
6625
6626 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
6627 IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope);
6628 if (arg1_value == irb->codegen->invalid_inst_src)
6629 return arg1_value;
6630
6631 IrInstSrc *reduce = ir_build_reduce(irb, scope, node, arg0_value, arg1_value);
6632 return ir_lval_wrap(irb, scope, reduce, lval, result_loc);
6633 }
65846634 case BuiltinFnIdDivExact:
65856635 {
65866636 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
......@@ -9607,6 +9657,7 @@ static IrInstSrc *ir_gen_continue(IrBuilderSrc *irb, Scope *continue_scope, AstN
96079657 ScopeRuntime *scope_runtime = runtime_scopes.at(i);
96089658 ir_mark_gen(ir_build_check_runtime_scope(irb, continue_scope, node, scope_runtime->is_comptime, is_comptime));
96099659 }
9660 runtime_scopes.deinit();
96109661
96119662 IrBasicBlockSrc *dest_block = loop_scope->continue_block;
96129663 if (!ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, nullptr, nullptr))
......@@ -15933,6 +15984,24 @@ static bool ir_resolve_comptime(IrAnalyze *ira, IrInstGen *value, bool *out) {
1593315984 return ir_resolve_bool(ira, value, out);
1593415985}
1593515986
15987static bool ir_resolve_reduce_op(IrAnalyze *ira, IrInstGen *value, ReduceOp *out) {
15988 if (type_is_invalid(value->value->type))
15989 return false;
15990
15991 ZigType *reduce_op_type = get_builtin_type(ira->codegen, "ReduceOp");
15992
15993 IrInstGen *casted_value = ir_implicit_cast(ira, value, reduce_op_type);
15994 if (type_is_invalid(casted_value->value->type))
15995 return false;
15996
15997 ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad);
15998 if (!const_val)
15999 return false;
16000
16001 *out = (ReduceOp)bigint_as_u32(&const_val->data.x_enum_tag);
16002 return true;
16003}
16004
1593616005static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstGen *value, AtomicOrder *out) {
1593716006 if (type_is_invalid(value->value->type))
1593816007 return false;
......@@ -21527,6 +21596,7 @@ static IrInstGen *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstSrcPhi *phi_i
2152721596 predecessor->instruction_list.append(instrs_to_move.pop());
2152821597 }
2152921598 predecessor->instruction_list.append(branch_instruction);
21599 instrs_to_move.deinit();
2153021600 }
2153121601 }
2153221602
......@@ -21577,7 +21647,10 @@ static IrInstGen *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstSrcPhi *phi_i
2157721647 }
2157821648
2157921649 if (new_incoming_blocks.length == 1) {
21580 return new_incoming_values.at(0);
21650 IrInstGen *incoming_value = new_incoming_values.at(0);
21651 new_incoming_blocks.deinit();
21652 new_incoming_values.deinit();
21653 return incoming_value;
2158121654 }
2158221655
2158321656 ZigType *resolved_type = nullptr;
......@@ -24140,6 +24213,7 @@ static IrInstGen *ir_analyze_container_init_fields(IrAnalyze *ira, IrInst *sourc
2414024213 first_non_const_instruction = result_loc;
2414124214 }
2414224215 }
24216 heap::c_allocator.deallocate(field_assign_nodes, actual_field_count);
2414324217 if (any_missing)
2414424218 return ira->codegen->invalid_inst_gen;
2414524219
......@@ -24155,6 +24229,7 @@ static IrInstGen *ir_analyze_container_init_fields(IrAnalyze *ira, IrInst *sourc
2415524229 }
2415624230 }
2415724231
24232 const_ptrs.deinit();
2415824233 IrInstGen *result = ir_get_deref(ira, source_instr, result_loc, nullptr);
2415924234
2416024235 if (is_comptime && !instr_is_comptime(result)) {
......@@ -25028,7 +25103,7 @@ static ZigValue *create_ptr_like_type_info(IrAnalyze *ira, IrInst *source_instr,
2502825103 fields[2]->special = ConstValSpecialStatic;
2502925104 fields[2]->type = ira->codegen->builtin_types.entry_bool;
2503025105 fields[2]->data.x_bool = attrs_type->data.pointer.is_volatile;
25031 // alignment: u32
25106 // alignment: comptime_int
2503225107 ensure_field_index(result->type, "alignment", 3);
2503325108 fields[3]->type = ira->codegen->builtin_types.entry_num_lit_int;
2503425109 if (attrs_type->data.pointer.explicit_alignment != 0) {
......@@ -25432,11 +25507,17 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
2543225507 union_field_val->special = ConstValSpecialStatic;
2543325508 union_field_val->type = type_info_union_field_type;
2543425509
25435 ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 2);
25510 ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 3);
25511 // field_type: type
2543625512 inner_fields[1]->special = ConstValSpecialStatic;
2543725513 inner_fields[1]->type = ira->codegen->builtin_types.entry_type;
2543825514 inner_fields[1]->data.x_type = union_field->type_entry;
2543925515
25516 // alignment: comptime_int
25517 inner_fields[2]->special = ConstValSpecialStatic;
25518 inner_fields[2]->type = ira->codegen->builtin_types.entry_num_lit_int;
25519 bigint_init_unsigned(&inner_fields[2]->data.x_bigint, union_field->align);
25520
2544025521 ZigValue *name = create_const_str_lit(ira->codegen, union_field->name)->data.x_ptr.data.ref.pointee;
2544125522 init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(union_field->name), true);
2544225523
......@@ -25503,7 +25584,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
2550325584 struct_field_val->special = ConstValSpecialStatic;
2550425585 struct_field_val->type = type_info_struct_field_type;
2550525586
25506 ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 4);
25587 ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 5);
2550725588
2550825589 inner_fields[1]->special = ConstValSpecialStatic;
2550925590 inner_fields[1]->type = ira->codegen->builtin_types.entry_type;
......@@ -25519,10 +25600,16 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
2551925600 }
2552025601 set_optional_payload(inner_fields[2], struct_field->init_val);
2552125602
25603 // is_comptime: bool
2552225604 inner_fields[3]->special = ConstValSpecialStatic;
2552325605 inner_fields[3]->type = ira->codegen->builtin_types.entry_bool;
2552425606 inner_fields[3]->data.x_bool = struct_field->is_comptime;
2552525607
25608 // alignment: comptime_int
25609 inner_fields[4]->special = ConstValSpecialStatic;
25610 inner_fields[4]->type = ira->codegen->builtin_types.entry_num_lit_int;
25611 bigint_init_unsigned(&inner_fields[4]->data.x_bigint, struct_field->align);
25612
2552625613 ZigValue *name = create_const_str_lit(ira->codegen, struct_field->name)->data.x_ptr.data.ref.pointee;
2552725614 init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(struct_field->name), true);
2552825615
......@@ -25553,7 +25640,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
2555325640 result->special = ConstValSpecialStatic;
2555425641 result->type = ir_type_info_get_type(ira, "Fn", nullptr);
2555525642
25556 ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 5);
25643 ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 6);
2555725644 result->data.x_struct.fields = fields;
2555825645
2555925646 // calling_convention: TypeInfo.CallingConvention
......@@ -25561,38 +25648,42 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
2556125648 fields[0]->special = ConstValSpecialStatic;
2556225649 fields[0]->type = get_builtin_type(ira->codegen, "CallingConvention");
2556325650 bigint_init_unsigned(&fields[0]->data.x_enum_tag, type_entry->data.fn.fn_type_id.cc);
25651 // alignment: u29
25652 ensure_field_index(result->type, "alignment", 1);
25653 fields[1]->special = ConstValSpecialStatic;
25654 fields[1]->type = ira->codegen->builtin_types.entry_num_lit_int;
25655 bigint_init_unsigned(&fields[1]->data.x_bigint, type_entry->data.fn.fn_type_id.alignment);
2556425656 // is_generic: bool
25565 ensure_field_index(result->type, "is_generic", 1);
25657 ensure_field_index(result->type, "is_generic", 2);
2556625658 bool is_generic = type_entry->data.fn.is_generic;
25567 fields[1]->special = ConstValSpecialStatic;
25568 fields[1]->type = ira->codegen->builtin_types.entry_bool;
25569 fields[1]->data.x_bool = is_generic;
25570 // is_varargs: bool
25571 ensure_field_index(result->type, "is_var_args", 2);
25572 bool is_varargs = type_entry->data.fn.fn_type_id.is_var_args;
2557325659 fields[2]->special = ConstValSpecialStatic;
2557425660 fields[2]->type = ira->codegen->builtin_types.entry_bool;
25575 fields[2]->data.x_bool = type_entry->data.fn.fn_type_id.is_var_args;
25576 // return_type: ?type
25577 ensure_field_index(result->type, "return_type", 3);
25661 fields[2]->data.x_bool = is_generic;
25662 // is_varargs: bool
25663 ensure_field_index(result->type, "is_var_args", 3);
25664 bool is_varargs = type_entry->data.fn.fn_type_id.is_var_args;
2557825665 fields[3]->special = ConstValSpecialStatic;
25579 fields[3]->type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
25666 fields[3]->type = ira->codegen->builtin_types.entry_bool;
25667 fields[3]->data.x_bool = is_varargs;
25668 // return_type: ?type
25669 ensure_field_index(result->type, "return_type", 4);
25670 fields[4]->special = ConstValSpecialStatic;
25671 fields[4]->type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_type);
2558025672 if (type_entry->data.fn.fn_type_id.return_type == nullptr)
25581 fields[3]->data.x_optional = nullptr;
25673 fields[4]->data.x_optional = nullptr;
2558225674 else {
2558325675 ZigValue *return_type = ira->codegen->pass1_arena->create<ZigValue>();
2558425676 return_type->special = ConstValSpecialStatic;
2558525677 return_type->type = ira->codegen->builtin_types.entry_type;
2558625678 return_type->data.x_type = type_entry->data.fn.fn_type_id.return_type;
25587 fields[3]->data.x_optional = return_type;
25679 fields[4]->data.x_optional = return_type;
2558825680 }
2558925681 // args: []TypeInfo.FnArg
2559025682 ZigType *type_info_fn_arg_type = ir_type_info_get_type(ira, "FnArg", nullptr);
2559125683 if ((err = type_resolve(ira->codegen, type_info_fn_arg_type, ResolveStatusSizeKnown))) {
2559225684 zig_unreachable();
2559325685 }
25594 size_t fn_arg_count = type_entry->data.fn.fn_type_id.param_count -
25595 (is_varargs && type_entry->data.fn.fn_type_id.cc != CallingConventionC);
25686 size_t fn_arg_count = type_entry->data.fn.fn_type_id.param_count;
2559625687
2559725688 ZigValue *fn_arg_array = ira->codegen->pass1_arena->create<ZigValue>();
2559825689 fn_arg_array->special = ConstValSpecialStatic;
......@@ -25600,7 +25691,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
2560025691 fn_arg_array->data.x_array.special = ConstArraySpecialNone;
2560125692 fn_arg_array->data.x_array.data.s_none.elements = ira->codegen->pass1_arena->allocate<ZigValue>(fn_arg_count);
2560225693
25603 init_const_slice(ira->codegen, fields[4], fn_arg_array, 0, fn_arg_count, false);
25694 init_const_slice(ira->codegen, fields[5], fn_arg_array, 0, fn_arg_count, false);
2560425695
2560525696 for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) {
2560625697 FnTypeParamInfo *fn_param_info = &type_entry->data.fn.fn_type_id.param_info[fn_arg_index];
......@@ -25869,8 +25960,9 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
2586925960 buf_sprintf("sentinels are only allowed on slices and unknown-length pointers"));
2587025961 return ira->codegen->invalid_inst_gen->value->type;
2587125962 }
25872 BigInt *bi = get_const_field_lit_int(ira, source_instr->source_node, payload, "alignment", 3);
25873 if (bi == nullptr)
25963
25964 BigInt *alignment = get_const_field_lit_int(ira, source_instr->source_node, payload, "alignment", 3);
25965 if (alignment == nullptr)
2587425966 return ira->codegen->invalid_inst_gen->value->type;
2587525967
2587625968 bool is_const;
......@@ -25897,7 +25989,7 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
2589725989 is_const,
2589825990 is_volatile,
2589925991 ptr_len,
25900 bigint_as_u32(bi),
25992 bigint_as_u32(alignment),
2590125993 0, // bit_offset_in_host
2590225994 0, // host_int_bytes
2590325995 is_allowzero,
......@@ -26134,6 +26226,10 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
2613426226 }
2613526227 if ((err = get_const_field_bool(ira, source_instr->source_node, field_value, "is_comptime", 3, &field->is_comptime)))
2613626228 return ira->codegen->invalid_inst_gen->value->type;
26229 BigInt *alignment = get_const_field_lit_int(ira, source_instr->source_node, field_value, "alignment", 4);
26230 if (alignment == nullptr)
26231 return ira->codegen->invalid_inst_gen->value->type;
26232 field->align = bigint_as_u32(alignment);
2613726233 }
2613826234
2613926235 return entry;
......@@ -26151,6 +26247,13 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
2615126247 ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag);
2615226248
2615326249 ZigType *tag_type = get_const_field_meta_type(ira, source_instr->source_node, payload, "tag_type", 1);
26250 if (type_is_invalid(tag_type))
26251 return ira->codegen->invalid_inst_gen->value->type;
26252 if (tag_type->id != ZigTypeIdInt) {
26253 ir_add_error(ira, source_instr, buf_sprintf(
26254 "TypeInfo.Enum.tag_type must be an integer type, not '%s'", buf_ptr(&tag_type->name)));
26255 return ira->codegen->invalid_inst_gen->value->type;
26256 }
2615426257
2615526258 ZigValue *fields_value = get_const_field(ira, source_instr->source_node, payload, "fields", 2);
2615626259 if (fields_value == nullptr)
......@@ -26296,14 +26399,113 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
2629626399 return ira->codegen->invalid_inst_gen->value->type;
2629726400 field->type_val = type_value;
2629826401 field->type_entry = type_value->data.x_type;
26402 BigInt *alignment = get_const_field_lit_int(ira, source_instr->source_node, field_value, "alignment", 2);
26403 if (alignment == nullptr)
26404 return ira->codegen->invalid_inst_gen->value->type;
26405 field->align = bigint_as_u32(alignment);
2629926406 }
2630026407 return entry;
2630126408 }
2630226409 case ZigTypeIdFn:
26303 case ZigTypeIdBoundFn:
26304 ir_add_error(ira, source_instr, buf_sprintf(
26305 "@Type not available for 'TypeInfo.%s'", type_id_name(tagTypeId)));
26306 return ira->codegen->invalid_inst_gen->value->type;
26410 case ZigTypeIdBoundFn: {
26411 assert(payload->special == ConstValSpecialStatic);
26412 assert(payload->type == ir_type_info_get_type(ira, "Fn", nullptr));
26413
26414 ZigValue *cc_value = get_const_field(ira, source_instr->source_node, payload, "calling_convention", 0);
26415 if (cc_value == nullptr)
26416 return ira->codegen->invalid_inst_gen->value->type;
26417 assert(cc_value->special == ConstValSpecialStatic);
26418 assert(cc_value->type == get_builtin_type(ira->codegen, "CallingConvention"));
26419 CallingConvention cc = (CallingConvention)bigint_as_u32(&cc_value->data.x_enum_tag);
26420
26421 BigInt *alignment = get_const_field_lit_int(ira, source_instr->source_node, payload, "alignment", 1);
26422 if (alignment == nullptr)
26423 return ira->codegen->invalid_inst_gen->value->type;
26424
26425 Error err;
26426 bool is_generic;
26427 if ((err = get_const_field_bool(ira, source_instr->source_node, payload, "is_generic", 2, &is_generic)))
26428 return ira->codegen->invalid_inst_gen->value->type;
26429 if (is_generic) {
26430 ir_add_error(ira, source_instr, buf_sprintf("TypeInfo.Fn.is_generic must be false for @Type"));
26431 return ira->codegen->invalid_inst_gen->value->type;
26432 }
26433
26434 bool is_var_args;
26435 if ((err = get_const_field_bool(ira, source_instr->source_node, payload, "is_var_args", 3, &is_var_args)))
26436 return ira->codegen->invalid_inst_gen->value->type;
26437 if (is_var_args && cc != CallingConventionC) {
26438 ir_add_error(ira, source_instr, buf_sprintf("varargs functions must have C calling convention"));
26439 return ira->codegen->invalid_inst_gen->value->type;
26440 }
26441
26442 ZigType *return_type = get_const_field_meta_type_optional(ira, source_instr->source_node, payload, "return_type", 4);
26443 if (return_type == nullptr) {
26444 ir_add_error(ira, source_instr, buf_sprintf("TypeInfo.Fn.return_type must be non-null for @Type"));
26445 return ira->codegen->invalid_inst_gen->value->type;
26446 }
26447
26448 ZigValue *args_value = get_const_field(ira, source_instr->source_node, payload, "args", 5);
26449 if (args_value == nullptr)
26450 return ira->codegen->invalid_inst_gen->value->type;
26451 assert(args_value->special == ConstValSpecialStatic);
26452 assert(is_slice(args_value->type));
26453 ZigValue *args_ptr = args_value->data.x_struct.fields[slice_ptr_index];
26454 ZigValue *args_len_value = args_value->data.x_struct.fields[slice_len_index];
26455 size_t args_len = bigint_as_usize(&args_len_value->data.x_bigint);
26456
26457 FnTypeId fn_type_id = {};
26458 fn_type_id.return_type = return_type;
26459 fn_type_id.param_info = heap::c_allocator.allocate<FnTypeParamInfo>(args_len);
26460 fn_type_id.param_count = args_len;
26461 fn_type_id.next_param_index = args_len;
26462 fn_type_id.is_var_args = is_var_args;
26463 fn_type_id.cc = cc;
26464 fn_type_id.alignment = bigint_as_u32(alignment);
26465
26466 assert(args_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray);
26467 assert(args_ptr->data.x_ptr.data.base_array.elem_index == 0);
26468 ZigValue *args_arr = args_ptr->data.x_ptr.data.base_array.array_val;
26469 assert(args_arr->special == ConstValSpecialStatic);
26470 assert(args_arr->data.x_array.special == ConstArraySpecialNone);
26471 for (size_t i = 0; i < args_len; i++) {
26472 ZigValue *arg_value = &args_arr->data.x_array.data.s_none.elements[i];
26473 assert(arg_value->type == ir_type_info_get_type(ira, "FnArg", nullptr));
26474 FnTypeParamInfo *info = &fn_type_id.param_info[i];
26475 Error err;
26476 bool is_generic;
26477 if ((err = get_const_field_bool(ira, source_instr->source_node, arg_value, "is_generic", 0, &is_generic)))
26478 return ira->codegen->invalid_inst_gen->value->type;
26479 if (is_generic) {
26480 ir_add_error(ira, source_instr, buf_sprintf("TypeInfo.FnArg.is_generic must be false for @Type"));
26481 return ira->codegen->invalid_inst_gen->value->type;
26482 }
26483 if ((err = get_const_field_bool(ira, source_instr->source_node, arg_value, "is_noalias", 1, &info->is_noalias)))
26484 return ira->codegen->invalid_inst_gen->value->type;
26485 ZigType *type = get_const_field_meta_type_optional(
26486 ira, source_instr->source_node, arg_value, "arg_type", 2);
26487 if (type == nullptr) {
26488 ir_add_error(ira, source_instr, buf_sprintf("TypeInfo.FnArg.arg_type must be non-null for @Type"));
26489 return ira->codegen->invalid_inst_gen->value->type;
26490 }
26491 info->type = type;
26492 }
26493
26494 ZigType *entry = get_fn_type(ira->codegen, &fn_type_id);
26495
26496 switch (tagTypeId) {
26497 case ZigTypeIdFn:
26498 return entry;
26499 case ZigTypeIdBoundFn: {
26500 ZigType *bound_fn_entry = new_type_table_entry(ZigTypeIdBoundFn);
26501 bound_fn_entry->name = *buf_sprintf("(bound %s)", buf_ptr(&entry->name));
26502 bound_fn_entry->data.bound_fn.fn_type = entry;
26503 return bound_fn_entry;
26504 }
26505 default:
26506 zig_unreachable();
26507 }
26508 }
2630726509 }
2630826510 zig_unreachable();
2630926511}
......@@ -26676,6 +26878,161 @@ static IrInstGen *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstSrcCmpxch
2667626878 success_order, failure_order, instruction->is_weak, result_loc);
2667726879}
2667826880
26881static ErrorMsg *ir_eval_reduce(IrAnalyze *ira, IrInst *source_instr, ReduceOp op, ZigValue *value, ZigValue *out_value) {
26882 assert(value->type->id == ZigTypeIdVector);
26883 ZigType *scalar_type = value->type->data.vector.elem_type;
26884 const size_t len = value->type->data.vector.len;
26885 assert(len > 0);
26886
26887 out_value->type = scalar_type;
26888 out_value->special = ConstValSpecialStatic;
26889
26890 if (scalar_type->id == ZigTypeIdBool) {
26891 ZigValue *first_elem_val = &value->data.x_array.data.s_none.elements[0];
26892
26893 bool result = first_elem_val->data.x_bool;
26894 for (size_t i = 1; i < len; i++) {
26895 ZigValue *elem_val = &value->data.x_array.data.s_none.elements[i];
26896
26897 switch (op) {
26898 case ReduceOp_and:
26899 result = result && elem_val->data.x_bool;
26900 if (!result) break; // Short circuit
26901 break;
26902 case ReduceOp_or:
26903 result = result || elem_val->data.x_bool;
26904 if (result) break; // Short circuit
26905 break;
26906 case ReduceOp_xor:
26907 result = result != elem_val->data.x_bool;
26908 break;
26909 default:
26910 zig_unreachable();
26911 }
26912 }
26913
26914 out_value->data.x_bool = result;
26915 return nullptr;
26916 }
26917
26918 if (op != ReduceOp_min && op != ReduceOp_max) {
26919 ZigValue *first_elem_val = &value->data.x_array.data.s_none.elements[0];
26920
26921 copy_const_val(ira->codegen, out_value, first_elem_val);
26922
26923 for (size_t i = 1; i < len; i++) {
26924 ZigValue *elem_val = &value->data.x_array.data.s_none.elements[i];
26925
26926 IrBinOp bin_op;
26927 switch (op) {
26928 case ReduceOp_and: bin_op = IrBinOpBinAnd; break;
26929 case ReduceOp_or: bin_op = IrBinOpBinOr; break;
26930 case ReduceOp_xor: bin_op = IrBinOpBinXor; break;
26931 default: zig_unreachable();
26932 }
26933
26934 ErrorMsg *msg = ir_eval_math_op_scalar(ira, source_instr, scalar_type,
26935 out_value, bin_op, elem_val, out_value);
26936 if (msg != nullptr)
26937 return msg;
26938 }
26939
26940 return nullptr;
26941 }
26942
26943 ZigValue *candidate_elem_val = &value->data.x_array.data.s_none.elements[0];
26944
26945 ZigValue *dummy_cmp_value = ira->codegen->pass1_arena->create<ZigValue>();
26946 for (size_t i = 1; i < len; i++) {
26947 ZigValue *elem_val = &value->data.x_array.data.s_none.elements[i];
26948
26949 IrBinOp bin_op;
26950 switch (op) {
26951 case ReduceOp_min: bin_op = IrBinOpCmpLessThan; break;
26952 case ReduceOp_max: bin_op = IrBinOpCmpGreaterThan; break;
26953 default: zig_unreachable();
26954 }
26955
26956 ErrorMsg *msg = ir_eval_bin_op_cmp_scalar(ira, source_instr,
26957 elem_val, bin_op, candidate_elem_val, dummy_cmp_value);
26958 if (msg != nullptr)
26959 return msg;
26960
26961 if (dummy_cmp_value->data.x_bool)
26962 candidate_elem_val = elem_val;
26963 }
26964
26965 ira->codegen->pass1_arena->destroy(dummy_cmp_value);
26966 copy_const_val(ira->codegen, out_value, candidate_elem_val);
26967
26968 return nullptr;
26969}
26970
26971static IrInstGen *ir_analyze_instruction_reduce(IrAnalyze *ira, IrInstSrcReduce *instruction) {
26972 IrInstGen *op_inst = instruction->op->child;
26973 if (type_is_invalid(op_inst->value->type))
26974 return ira->codegen->invalid_inst_gen;
26975
26976 IrInstGen *value_inst = instruction->value->child;
26977 if (type_is_invalid(value_inst->value->type))
26978 return ira->codegen->invalid_inst_gen;
26979
26980 ZigType *value_type = value_inst->value->type;
26981 if (value_type->id != ZigTypeIdVector) {
26982 ir_add_error(ira, &value_inst->base,
26983 buf_sprintf("expected vector type, found '%s'",
26984 buf_ptr(&value_type->name)));
26985 return ira->codegen->invalid_inst_gen;
26986 }
26987
26988 ReduceOp op;
26989 if (!ir_resolve_reduce_op(ira, op_inst, &op))
26990 return ira->codegen->invalid_inst_gen;
26991
26992 ZigType *elem_type = value_type->data.vector.elem_type;
26993 switch (elem_type->id) {
26994 case ZigTypeIdInt:
26995 break;
26996 case ZigTypeIdBool:
26997 if (op > ReduceOp_xor) {
26998 ir_add_error(ira, &op_inst->base,
26999 buf_sprintf("invalid operation for '%s' type",
27000 buf_ptr(&elem_type->name)));
27001 return ira->codegen->invalid_inst_gen;
27002 } break;
27003 case ZigTypeIdFloat:
27004 if (op < ReduceOp_min) {
27005 ir_add_error(ira, &op_inst->base,
27006 buf_sprintf("invalid operation for '%s' type",
27007 buf_ptr(&elem_type->name)));
27008 return ira->codegen->invalid_inst_gen;
27009 } break;
27010 default:
27011 // Vectors cannot have child types other than those listed above
27012 zig_unreachable();
27013 }
27014
27015 // special case zero bit types
27016 switch (type_has_one_possible_value(ira->codegen, elem_type)) {
27017 case OnePossibleValueInvalid:
27018 return ira->codegen->invalid_inst_gen;
27019 case OnePossibleValueYes:
27020 return ir_const_move(ira, &instruction->base.base,
27021 get_the_one_possible_value(ira->codegen, elem_type));
27022 case OnePossibleValueNo:
27023 break;
27024 }
27025
27026 if (instr_is_comptime(value_inst)) {
27027 IrInstGen *result = ir_const(ira, &instruction->base.base, elem_type);
27028 if (ir_eval_reduce(ira, &instruction->base.base, op, value_inst->value, result->value))
27029 return ira->codegen->invalid_inst_gen;
27030 return result;
27031 }
27032
27033 return ir_build_reduce_gen(ira, &instruction->base.base, op, value_inst, elem_type);
27034}
27035
2667927036static IrInstGen *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstSrcFence *instruction) {
2668027037 IrInstGen *order_inst = instruction->order->child;
2668127038 if (type_is_invalid(order_inst->value->type))
......@@ -29835,6 +30192,7 @@ static IrInstGen *ir_analyze_bit_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
2983530192 buf_write_value_bytes(ira->codegen, buf, val);
2983630193 if ((err = buf_read_value_bytes(ira, ira->codegen, source_instr->source_node, buf, result->value)))
2983730194 return ira->codegen->invalid_inst_gen;
30195 heap::c_allocator.deallocate(buf, src_size_bytes);
2983830196 return result;
2983930197 }
2984030198
......@@ -30872,6 +31230,8 @@ static IrInstGen *ir_analyze_instruction_bit_reverse(IrAnalyze *ira, IrInstSrcBi
3087231230 ira->codegen->is_big_endian,
3087331231 int_type->data.integral.is_signed);
3087431232
31233 heap::c_allocator.deallocate(comptime_buf, buf_size);
31234 heap::c_allocator.deallocate(result_buf, buf_size);
3087531235 return result;
3087631236 }
3087731237
......@@ -31424,6 +31784,8 @@ static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruc
3142431784 return ir_analyze_instruction_cmpxchg(ira, (IrInstSrcCmpxchg *)instruction);
3142531785 case IrInstSrcIdFence:
3142631786 return ir_analyze_instruction_fence(ira, (IrInstSrcFence *)instruction);
31787 case IrInstSrcIdReduce:
31788 return ir_analyze_instruction_reduce(ira, (IrInstSrcReduce *)instruction);
3142731789 case IrInstSrcIdTruncate:
3142831790 return ir_analyze_instruction_truncate(ira, (IrInstSrcTruncate *)instruction);
3142931791 case IrInstSrcIdIntCast:
......@@ -31811,6 +32173,7 @@ bool ir_inst_gen_has_side_effects(IrInstGen *instruction) {
3181132173 case IrInstGenIdNegation:
3181232174 case IrInstGenIdNegationWrapping:
3181332175 case IrInstGenIdWasmMemorySize:
32176 case IrInstGenIdReduce:
3181432177 return false;
3181532178
3181632179 case IrInstGenIdAsm:
......@@ -31980,6 +32343,7 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) {
3198032343 case IrInstSrcIdSpillEnd:
3198132344 case IrInstSrcIdWasmMemorySize:
3198232345 case IrInstSrcIdSrc:
32346 case IrInstSrcIdReduce:
3198332347 return false;
3198432348
3198532349 case IrInstSrcIdAsm:
src/stage1/ir_print.cpp+35
......@@ -200,6 +200,8 @@ const char* ir_inst_src_type_str(IrInstSrcId id) {
200200 return "SrcCmpxchg";
201201 case IrInstSrcIdFence:
202202 return "SrcFence";
203 case IrInstSrcIdReduce:
204 return "SrcReduce";
203205 case IrInstSrcIdTruncate:
204206 return "SrcTruncate";
205207 case IrInstSrcIdIntCast:
......@@ -436,6 +438,8 @@ const char* ir_inst_gen_type_str(IrInstGenId id) {
436438 return "GenCmpxchg";
437439 case IrInstGenIdFence:
438440 return "GenFence";
441 case IrInstGenIdReduce:
442 return "GenReduce";
439443 case IrInstGenIdTruncate:
440444 return "GenTruncate";
441445 case IrInstGenIdBoolNot:
......@@ -1584,6 +1588,14 @@ static void ir_print_fence(IrPrintSrc *irp, IrInstSrcFence *instruction) {
15841588 fprintf(irp->f, ")");
15851589}
15861590
1591static void ir_print_reduce(IrPrintSrc *irp, IrInstSrcReduce *instruction) {
1592 fprintf(irp->f, "@reduce(");
1593 ir_print_other_inst_src(irp, instruction->op);
1594 fprintf(irp->f, ", ");
1595 ir_print_other_inst_src(irp, instruction->value);
1596 fprintf(irp->f, ")");
1597}
1598
15871599static const char *atomic_order_str(AtomicOrder order) {
15881600 switch (order) {
15891601 case AtomicOrderUnordered: return "Unordered";
......@@ -1600,6 +1612,23 @@ static void ir_print_fence(IrPrintGen *irp, IrInstGenFence *instruction) {
16001612 fprintf(irp->f, "fence %s", atomic_order_str(instruction->order));
16011613}
16021614
1615static const char *reduce_op_str(ReduceOp op) {
1616 switch (op) {
1617 case ReduceOp_and: return "And";
1618 case ReduceOp_or: return "Or";
1619 case ReduceOp_xor: return "Xor";
1620 case ReduceOp_min: return "Min";
1621 case ReduceOp_max: return "Max";
1622 }
1623 zig_unreachable();
1624}
1625
1626static void ir_print_reduce(IrPrintGen *irp, IrInstGenReduce *instruction) {
1627 fprintf(irp->f, "@reduce(.%s, ", reduce_op_str(instruction->op));
1628 ir_print_other_inst_gen(irp, instruction->value);
1629 fprintf(irp->f, ")");
1630}
1631
16031632static void ir_print_truncate(IrPrintSrc *irp, IrInstSrcTruncate *instruction) {
16041633 fprintf(irp->f, "@truncate(");
16051634 ir_print_other_inst_src(irp, instruction->dest_type);
......@@ -2749,6 +2778,9 @@ static void ir_print_inst_src(IrPrintSrc *irp, IrInstSrc *instruction, bool trai
27492778 case IrInstSrcIdFence:
27502779 ir_print_fence(irp, (IrInstSrcFence *)instruction);
27512780 break;
2781 case IrInstSrcIdReduce:
2782 ir_print_reduce(irp, (IrInstSrcReduce *)instruction);
2783 break;
27522784 case IrInstSrcIdTruncate:
27532785 ir_print_truncate(irp, (IrInstSrcTruncate *)instruction);
27542786 break;
......@@ -3097,6 +3129,9 @@ static void ir_print_inst_gen(IrPrintGen *irp, IrInstGen *instruction, bool trai
30973129 case IrInstGenIdFence:
30983130 ir_print_fence(irp, (IrInstGenFence *)instruction);
30993131 break;
3132 case IrInstGenIdReduce:
3133 ir_print_reduce(irp, (IrInstGenReduce *)instruction);
3134 break;
31003135 case IrInstGenIdTruncate:
31013136 ir_print_truncate(irp, (IrInstGenTruncate *)instruction);
31023137 break;
src/stage1/os.cpp+22-1052
......@@ -94,105 +94,6 @@ static clock_serv_t macos_monotonic_clock;
9494extern char **environ;
9595#endif
9696
97#if defined(ZIG_OS_POSIX)
98static void populate_termination(Termination *term, int status) {
99 if (WIFEXITED(status)) {
100 term->how = TerminationIdClean;
101 term->code = WEXITSTATUS(status);
102 } else if (WIFSIGNALED(status)) {
103 term->how = TerminationIdSignaled;
104 term->code = WTERMSIG(status);
105 } else if (WIFSTOPPED(status)) {
106 term->how = TerminationIdStopped;
107 term->code = WSTOPSIG(status);
108 } else {
109 term->how = TerminationIdUnknown;
110 term->code = status;
111 }
112}
113
114static void os_spawn_process_posix(ZigList<const char *> &args, Termination *term) {
115 const char **argv = heap::c_allocator.allocate<const char *>(args.length + 1);
116 for (size_t i = 0; i < args.length; i += 1) {
117 argv[i] = args.at(i);
118 }
119 argv[args.length] = nullptr;
120
121 pid_t pid;
122 int rc = posix_spawnp(&pid, args.at(0), nullptr, nullptr, const_cast<char *const*>(argv), environ);
123 if (rc != 0) {
124 zig_panic("unable to spawn %s: %s", args.at(0), strerror(rc));
125 }
126
127 int status;
128 waitpid(pid, &status, 0);
129 populate_termination(term, status);
130}
131#endif
132
133#if defined(ZIG_OS_WINDOWS)
134
135static void os_windows_create_command_line(Buf *command_line, ZigList<const char *> &args) {
136 buf_resize(command_line, 0);
137 const char *prefix = "\"";
138 for (size_t arg_i = 0; arg_i < args.length; arg_i += 1) {
139 const char *arg = args.at(arg_i);
140 buf_append_str(command_line, prefix);
141 prefix = " \"";
142 size_t arg_len = strlen(arg);
143 for (size_t c_i = 0; c_i < arg_len; c_i += 1) {
144 if (arg[c_i] == '\"') {
145 zig_panic("TODO");
146 }
147 buf_append_char(command_line, arg[c_i]);
148 }
149 buf_append_char(command_line, '\"');
150 }
151}
152
153static void os_spawn_process_windows(ZigList<const char *> &args, Termination *term) {
154 Buf command_line = BUF_INIT;
155 os_windows_create_command_line(&command_line, args);
156
157 PROCESS_INFORMATION piProcInfo = {0};
158 STARTUPINFOW siStartInfo = {0};
159 siStartInfo.cb = sizeof(STARTUPINFOW);
160
161 Slice<uint8_t> exe_slice = str(args.at(0));
162 auto exe_utf16_slice = Slice<WCHAR>::alloc(exe_slice.len + 1);
163 exe_utf16_slice.ptr[utf8_to_utf16le(exe_utf16_slice.ptr, exe_slice)] = 0;
164
165 auto command_line_utf16 = Slice<WCHAR>::alloc(buf_len(&command_line) + 1);
166 command_line_utf16.ptr[utf8_to_utf16le(command_line_utf16.ptr, buf_to_slice(&command_line))] = 0;
167
168 BOOL success = CreateProcessW(exe_utf16_slice.ptr, command_line_utf16.ptr, nullptr, nullptr, TRUE, CREATE_UNICODE_ENVIRONMENT, nullptr, nullptr,
169 &siStartInfo, &piProcInfo);
170
171 if (!success) {
172 zig_panic("CreateProcess failed. exe: %s command_line: %s", args.at(0), buf_ptr(&command_line));
173 }
174
175 WaitForSingleObject(piProcInfo.hProcess, INFINITE);
176
177 DWORD exit_code;
178 if (!GetExitCodeProcess(piProcInfo.hProcess, &exit_code)) {
179 zig_panic("GetExitCodeProcess failed");
180 }
181 term->how = TerminationIdClean;
182 term->code = exit_code;
183}
184#endif
185
186void os_spawn_process(ZigList<const char *> &args, Termination *term) {
187#if defined(ZIG_OS_WINDOWS)
188 os_spawn_process_windows(args, term);
189#elif defined(ZIG_OS_POSIX)
190 os_spawn_process_posix(args, term);
191#else
192#error "missing os_spawn_process implementation"
193#endif
194}
195
19697void os_path_dirname(Buf *full_path, Buf *out_dirname) {
19798 return os_path_split(full_path, out_dirname, nullptr);
19899}
......@@ -280,71 +181,27 @@ void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) {
280181 buf_append_buf(out_full_path, basename);
281182}
282183
283Error os_path_real(Buf *rel_path, Buf *out_abs_path) {
284#if defined(ZIG_OS_WINDOWS)
285 PathSpace rel_path_space = slice_to_prefixed_file_w(buf_to_slice(rel_path));
286 PathSpace out_abs_path_space;
287
288 if (_wfullpath(&out_abs_path_space.data.items[0], &rel_path_space.data.items[0], PATH_MAX_WIDE) == nullptr) {
289 zig_panic("_wfullpath failed");
290 }
291 utf16le_ptr_to_utf8(out_abs_path, &out_abs_path_space.data.items[0]);
292 return ErrorNone;
293#elif defined(ZIG_OS_POSIX)
294 buf_resize(out_abs_path, PATH_MAX + 1);
295 char *result = realpath(buf_ptr(rel_path), buf_ptr(out_abs_path));
296 if (!result) {
297 int err = errno;
298 if (err == EACCES) {
299 return ErrorAccess;
300 } else if (err == ENOENT) {
301 return ErrorFileNotFound;
302 } else if (err == ENOMEM) {
303 return ErrorNoMem;
304 } else {
305 return ErrorFileSystem;
306 }
307 }
308 buf_resize(out_abs_path, strlen(buf_ptr(out_abs_path)));
309 return ErrorNone;
310#else
311#error "missing os_path_real implementation"
312#endif
313}
314
315#if defined(ZIG_OS_WINDOWS)
316// Ported from std/os/path.zig
317static bool isAbsoluteWindows(Slice<uint8_t> path) {
318 if (path.ptr[0] == '/')
319 return true;
320
321 if (path.ptr[0] == '\\') {
322 return true;
323 }
324 if (path.len < 3) {
325 return false;
326 }
327 if (path.ptr[1] == ':') {
328 if (path.ptr[2] == '/')
329 return true;
330 if (path.ptr[2] == '\\')
331 return true;
332 }
333 return false;
334}
335#endif
336
337bool os_path_is_absolute(Buf *path) {
338#if defined(ZIG_OS_WINDOWS)
339 return isAbsoluteWindows(buf_to_slice(path));
340#elif defined(ZIG_OS_POSIX)
341 return buf_ptr(path)[0] == '/';
342#else
343#error "missing os_path_is_absolute implementation"
344#endif
345}
346184
347#if defined(ZIG_OS_WINDOWS)
185#if defined(ZIG_OS_WINDOWS)
186// Ported from std/os/path.zig
187static bool isAbsoluteWindows(Slice<uint8_t> path) {
188 if (path.ptr[0] == '/')
189 return true;
190
191 if (path.ptr[0] == '\\') {
192 return true;
193 }
194 if (path.len < 3) {
195 return false;
196 }
197 if (path.ptr[1] == ':') {
198 if (path.ptr[2] == '/')
199 return true;
200 if (path.ptr[2] == '\\')
201 return true;
202 }
203 return false;
204}
348205
349206enum WindowsPathKind {
350207 WindowsPathKindNone,
......@@ -687,7 +544,7 @@ static Buf os_path_resolve_posix(Buf **paths_ptr, size_t paths_len) {
687544 size_t max_size = 0;
688545 for (size_t i = 0; i < paths_len; i += 1) {
689546 Buf *p = paths_ptr[i];
690 if (os_path_is_absolute(p)) {
547 if (buf_ptr(p)[0] == '/') {
691548 first_index = i;
692549 have_abs = true;
693550 max_size = 0;
......@@ -748,6 +605,7 @@ static Buf os_path_resolve_posix(Buf **paths_ptr, size_t paths_len) {
748605
749606 Buf return_value = BUF_INIT;
750607 buf_init_from_mem(&return_value, (char *)result_ptr, result_index);
608 heap::c_allocator.deallocate(result_ptr, result_len);
751609 return return_value;
752610}
753611#endif
......@@ -786,256 +644,6 @@ Error os_fetch_file(FILE *f, Buf *out_buf) {
786644 zig_unreachable();
787645}
788646
789Error os_file_exists(Buf *full_path, bool *result) {
790#if defined(ZIG_OS_WINDOWS)
791 PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(full_path));
792 *result = GetFileAttributesW(&path_space.data.items[0]) != INVALID_FILE_ATTRIBUTES;
793 return ErrorNone;
794#else
795 *result = access(buf_ptr(full_path), F_OK) != -1;
796 return ErrorNone;
797#endif
798}
799
800#if defined(ZIG_OS_POSIX)
801static Error os_exec_process_posix(ZigList<const char *> &args,
802 Termination *term, Buf *out_stderr, Buf *out_stdout)
803{
804 int stdin_pipe[2];
805 int stdout_pipe[2];
806 int stderr_pipe[2];
807 int err_pipe[2];
808
809 int err;
810 if ((err = pipe(stdin_pipe)))
811 zig_panic("pipe failed");
812 if ((err = pipe(stdout_pipe)))
813 zig_panic("pipe failed");
814 if ((err = pipe(stderr_pipe)))
815 zig_panic("pipe failed");
816 if ((err = pipe(err_pipe)))
817 zig_panic("pipe failed");
818
819 pid_t pid = fork();
820 if (pid == -1)
821 zig_panic("fork failed: %s", strerror(errno));
822 if (pid == 0) {
823 // child
824 if (dup2(stdin_pipe[0], STDIN_FILENO) == -1)
825 zig_panic("dup2 failed");
826
827 if (dup2(stdout_pipe[1], STDOUT_FILENO) == -1)
828 zig_panic("dup2 failed");
829
830 if (dup2(stderr_pipe[1], STDERR_FILENO) == -1)
831 zig_panic("dup2 failed");
832
833 const char **argv = heap::c_allocator.allocate<const char *>(args.length + 1);
834 argv[args.length] = nullptr;
835 for (size_t i = 0; i < args.length; i += 1) {
836 argv[i] = args.at(i);
837 }
838 execvp(argv[0], const_cast<char * const *>(argv));
839 Error report_err = ErrorUnexpected;
840 if (errno == ENOENT) {
841 report_err = ErrorFileNotFound;
842 }
843 if (write(err_pipe[1], &report_err, sizeof(Error)) == -1) {
844 zig_panic("write failed");
845 }
846 exit(1);
847 } else {
848 // parent
849 close(stdin_pipe[0]);
850 close(stdin_pipe[1]);
851 close(stdout_pipe[1]);
852 close(stderr_pipe[1]);
853
854 int status;
855 waitpid(pid, &status, 0);
856 populate_termination(term, status);
857
858 FILE *stdout_f = fdopen(stdout_pipe[0], "rb");
859 FILE *stderr_f = fdopen(stderr_pipe[0], "rb");
860 Error err1 = os_fetch_file(stdout_f, out_stdout);
861 Error err2 = os_fetch_file(stderr_f, out_stderr);
862
863 fclose(stdout_f);
864 fclose(stderr_f);
865
866 if (err1) return err1;
867 if (err2) return err2;
868
869 Error child_err = ErrorNone;
870 if (write(err_pipe[1], &child_err, sizeof(Error)) == -1) {
871 zig_panic("write failed");
872 }
873 close(err_pipe[1]);
874 if (read(err_pipe[0], &child_err, sizeof(Error)) == -1) {
875 zig_panic("write failed");
876 }
877 close(err_pipe[0]);
878 return child_err;
879 }
880}
881#endif
882
883#if defined(ZIG_OS_WINDOWS)
884
885//static void win32_panic(const char *str) {
886// DWORD err = GetLastError();
887// LPSTR messageBuffer = nullptr;
888// FormatMessageA(
889// FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
890// NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
891// zig_panic(str, messageBuffer);
892// LocalFree(messageBuffer);
893//}
894
895static Error os_exec_process_windows(ZigList<const char *> &args,
896 Termination *term, Buf *out_stderr, Buf *out_stdout)
897{
898 Buf command_line = BUF_INIT;
899 os_windows_create_command_line(&command_line, args);
900
901 HANDLE g_hChildStd_IN_Rd = NULL;
902 HANDLE g_hChildStd_IN_Wr = NULL;
903 HANDLE g_hChildStd_OUT_Rd = NULL;
904 HANDLE g_hChildStd_OUT_Wr = NULL;
905 HANDLE g_hChildStd_ERR_Rd = NULL;
906 HANDLE g_hChildStd_ERR_Wr = NULL;
907
908 SECURITY_ATTRIBUTES saAttr;
909 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
910 saAttr.bInheritHandle = TRUE;
911 saAttr.lpSecurityDescriptor = NULL;
912
913 if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)) {
914 zig_panic("StdoutRd CreatePipe");
915 }
916
917 if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) {
918 zig_panic("Stdout SetHandleInformation");
919 }
920
921 if (!CreatePipe(&g_hChildStd_ERR_Rd, &g_hChildStd_ERR_Wr, &saAttr, 0)) {
922 zig_panic("stderr CreatePipe");
923 }
924
925 if (!SetHandleInformation(g_hChildStd_ERR_Rd, HANDLE_FLAG_INHERIT, 0)) {
926 zig_panic("stderr SetHandleInformation");
927 }
928
929 if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) {
930 zig_panic("Stdin CreatePipe");
931 }
932
933 if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0)) {
934 zig_panic("Stdin SetHandleInformation");
935 }
936
937
938 PROCESS_INFORMATION piProcInfo = {0};
939 STARTUPINFO siStartInfo = {0};
940 siStartInfo.cb = sizeof(STARTUPINFO);
941 siStartInfo.hStdError = g_hChildStd_ERR_Wr;
942 siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
943 siStartInfo.hStdInput = g_hChildStd_IN_Rd;
944 siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
945
946 const char *exe = args.at(0);
947 BOOL success = CreateProcess(exe, buf_ptr(&command_line), nullptr, nullptr, TRUE, 0, nullptr, nullptr,
948 &siStartInfo, &piProcInfo);
949
950 if (!success) {
951 if (GetLastError() == ERROR_FILE_NOT_FOUND) {
952 CloseHandle(piProcInfo.hProcess);
953 CloseHandle(piProcInfo.hThread);
954 return ErrorFileNotFound;
955 }
956 zig_panic("CreateProcess failed. exe: %s command_line: %s", exe, buf_ptr(&command_line));
957 }
958
959 if (!CloseHandle(g_hChildStd_IN_Wr)) {
960 zig_panic("stdinwr closehandle");
961 }
962
963 CloseHandle(g_hChildStd_IN_Rd);
964 CloseHandle(g_hChildStd_ERR_Wr);
965 CloseHandle(g_hChildStd_OUT_Wr);
966
967 static const size_t BUF_SIZE = 4 * 1024;
968 {
969 DWORD dwRead;
970 char chBuf[BUF_SIZE];
971
972 buf_resize(out_stdout, 0);
973 for (;;) {
974 success = ReadFile( g_hChildStd_OUT_Rd, chBuf, BUF_SIZE, &dwRead, NULL);
975 if (!success || dwRead == 0) break;
976
977 buf_append_mem(out_stdout, chBuf, dwRead);
978 }
979 CloseHandle(g_hChildStd_OUT_Rd);
980 }
981 {
982 DWORD dwRead;
983 char chBuf[BUF_SIZE];
984
985 buf_resize(out_stderr, 0);
986 for (;;) {
987 success = ReadFile( g_hChildStd_ERR_Rd, chBuf, BUF_SIZE, &dwRead, NULL);
988 if (!success || dwRead == 0) break;
989
990 buf_append_mem(out_stderr, chBuf, dwRead);
991 }
992 CloseHandle(g_hChildStd_ERR_Rd);
993 }
994
995 WaitForSingleObject(piProcInfo.hProcess, INFINITE);
996
997 DWORD exit_code;
998 if (!GetExitCodeProcess(piProcInfo.hProcess, &exit_code)) {
999 zig_panic("GetExitCodeProcess failed");
1000 }
1001 term->how = TerminationIdClean;
1002 term->code = exit_code;
1003
1004 CloseHandle(piProcInfo.hProcess);
1005 CloseHandle(piProcInfo.hThread);
1006
1007 return ErrorNone;
1008}
1009#endif
1010
1011Error os_execv(const char *exe, const char **argv) {
1012#if defined(ZIG_OS_WINDOWS)
1013 return ErrorUnsupportedOperatingSystem;
1014#else
1015 execv(exe, (char *const *)argv);
1016 switch (errno) {
1017 case ENOMEM:
1018 return ErrorSystemResources;
1019 case EIO:
1020 return ErrorFileSystem;
1021 default:
1022 return ErrorUnexpected;
1023 }
1024#endif
1025}
1026
1027Error os_exec_process(ZigList<const char *> &args,
1028 Termination *term, Buf *out_stderr, Buf *out_stdout)
1029{
1030#if defined(ZIG_OS_WINDOWS)
1031 return os_exec_process_windows(args, term, out_stderr, out_stdout);
1032#elif defined(ZIG_OS_POSIX)
1033 return os_exec_process_posix(args, term, out_stderr, out_stdout);
1034#else
1035#error "missing os_exec_process implementation"
1036#endif
1037}
1038
1039647Error os_write_file(Buf *full_path, Buf *contents) {
1040648#if defined(ZIG_OS_WINDOWS)
1041649 PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(full_path));
......@@ -1074,35 +682,6 @@ static Error copy_open_files(FILE *src_f, FILE *dest_f) {
1074682 }
1075683}
1076684
1077Error os_dump_file(Buf *src_path, FILE *dest_file) {
1078 Error err;
1079
1080#if defined(ZIG_OS_WINDOWS)
1081 PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(src_path));
1082 FILE *src_f = _wfopen(&path_space.data.items[0], L"rb");
1083#else
1084 FILE *src_f = fopen(buf_ptr(src_path), "rb");
1085#endif
1086 if (!src_f) {
1087 int err = errno;
1088 if (err == ENOENT) {
1089 return ErrorFileNotFound;
1090 } else if (err == EACCES || err == EPERM) {
1091 return ErrorAccess;
1092 } else {
1093 return ErrorFileSystem;
1094 }
1095 }
1096 copy_open_files(src_f, dest_file);
1097 if ((err = copy_open_files(src_f, dest_file))) {
1098 fclose(src_f);
1099 return err;
1100 }
1101
1102 fclose(src_f);
1103 return ErrorNone;
1104}
1105
1106685#if defined(ZIG_OS_WINDOWS)
1107686static void windows_filetime_to_os_timestamp(FILETIME *ft, OsTimeStamp *mtime) {
1108687 mtime->sec = (((ULONGLONG) ft->dwHighDateTime) << 32) + ft->dwLowDateTime;
......@@ -1116,88 +695,6 @@ static FILETIME windows_os_timestamp_to_filetime(OsTimeStamp mtime) {
1116695}
1117696#endif
1118697
1119static Error set_file_times(OsFile file, OsTimeStamp ts) {
1120#if defined(ZIG_OS_WINDOWS)
1121 FILETIME ft = windows_os_timestamp_to_filetime(ts);
1122 if (SetFileTime(file, nullptr, &ft, &ft) == 0) {
1123 return ErrorUnexpected;
1124 }
1125 return ErrorNone;
1126#else
1127 struct timespec times[2] = {
1128 { (time_t)ts.sec, (long)ts.nsec },
1129 { (time_t)ts.sec, (long)ts.nsec },
1130 };
1131 if (futimens(file, times) == -1) {
1132 switch (errno) {
1133 case EBADF:
1134 zig_panic("futimens EBADF");
1135 default:
1136 return ErrorUnexpected;
1137 }
1138 }
1139 return ErrorNone;
1140#endif
1141}
1142
1143Error os_update_file(Buf *src_path, Buf *dst_path) {
1144 Error err;
1145
1146 OsFile src_file;
1147 OsFileAttr src_attr;
1148 if ((err = os_file_open_r(src_path, &src_file, &src_attr))) {
1149 return err;
1150 }
1151
1152 OsFile dst_file;
1153 OsFileAttr dst_attr;
1154 if ((err = os_file_open_w(dst_path, &dst_file, &dst_attr, src_attr.mode))) {
1155 os_file_close(&src_file);
1156 return err;
1157 }
1158
1159 if (src_attr.size == dst_attr.size &&
1160 src_attr.mode == dst_attr.mode &&
1161 src_attr.mtime.sec == dst_attr.mtime.sec &&
1162 src_attr.mtime.nsec == dst_attr.mtime.nsec)
1163 {
1164 os_file_close(&src_file);
1165 os_file_close(&dst_file);
1166 return ErrorNone;
1167 }
1168#if defined(ZIG_OS_WINDOWS)
1169 if (SetEndOfFile(dst_file) == 0) {
1170 return ErrorUnexpected;
1171 }
1172#else
1173 if (ftruncate(dst_file, 0) == -1) {
1174 return ErrorUnexpected;
1175 }
1176#endif
1177#if defined(ZIG_OS_WINDOWS)
1178 FILE *src_libc_file = _fdopen(_open_osfhandle((intptr_t)src_file, _O_RDONLY), "rb");
1179 FILE *dst_libc_file = _fdopen(_open_osfhandle((intptr_t)dst_file, 0), "wb");
1180#else
1181 FILE *src_libc_file = fdopen(src_file, "rb");
1182 FILE *dst_libc_file = fdopen(dst_file, "wb");
1183#endif
1184 assert(src_libc_file);
1185 assert(dst_libc_file);
1186
1187 if ((err = copy_open_files(src_libc_file, dst_libc_file))) {
1188 fclose(src_libc_file);
1189 fclose(dst_libc_file);
1190 return err;
1191 }
1192 if (fflush(dst_libc_file) == -1) {
1193 return ErrorUnexpected;
1194 }
1195 err = set_file_times(dst_file, src_attr.mtime);
1196 fclose(src_libc_file);
1197 fclose(dst_libc_file);
1198 return err;
1199}
1200
1201698Error os_copy_file(Buf *src_path, Buf *dest_path) {
1202699#if defined(ZIG_OS_WINDOWS)
1203700 PathSpace src_path_space = slice_to_prefixed_file_w(buf_to_slice(src_path));
......@@ -1358,14 +855,6 @@ bool os_stderr_tty(void) {
1358855#endif
1359856}
1360857
1361Error os_delete_file(Buf *path) {
1362 if (remove(buf_ptr(path))) {
1363 return ErrorFileSystem;
1364 } else {
1365 return ErrorNone;
1366 }
1367}
1368
1369858Error os_rename(Buf *src_path, Buf *dest_path) {
1370859 if (buf_eql_buf(src_path, dest_path)) {
1371860 return ErrorNone;
......@@ -1384,30 +873,6 @@ Error os_rename(Buf *src_path, Buf *dest_path) {
1384873 return ErrorNone;
1385874}
1386875
1387OsTimeStamp os_timestamp_calendar(void) {
1388 OsTimeStamp result;
1389#if defined(ZIG_OS_WINDOWS)
1390 FILETIME ft;
1391 GetSystemTimeAsFileTime(&ft);
1392 windows_filetime_to_os_timestamp(&ft, &result);
1393#elif defined(__MACH__)
1394 mach_timespec_t mts;
1395
1396 kern_return_t err = clock_get_time(macos_calendar_clock, &mts);
1397 assert(!err);
1398
1399 result.sec = mts.tv_sec;
1400 result.nsec = mts.tv_nsec;
1401#else
1402 struct timespec tms;
1403 clock_gettime(CLOCK_REALTIME, &tms);
1404
1405 result.sec = tms.tv_sec;
1406 result.nsec = tms.tv_nsec;
1407#endif
1408 return result;
1409}
1410
1411876OsTimeStamp os_timestamp_monotonic(void) {
1412877 OsTimeStamp result;
1413878#if defined(ZIG_OS_WINDOWS)
......@@ -1501,49 +966,8 @@ Error os_make_dir(Buf *path) {
1501966#endif
1502967}
1503968
1504static void init_rand() {
1505#if defined(ZIG_OS_WINDOWS)
1506 char bytes[sizeof(unsigned)];
1507 unsigned seed;
1508 RtlGenRandom(bytes, sizeof(unsigned));
1509 memcpy(&seed, bytes, sizeof(unsigned));
1510 srand(seed);
1511#elif defined(ZIG_OS_LINUX)
1512 unsigned char *ptr_random = (unsigned char*)getauxval(AT_RANDOM);
1513 unsigned seed;
1514 memcpy(&seed, ptr_random, sizeof(seed));
1515 srand(seed);
1516#elif defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
1517 unsigned seed;
1518 size_t len = sizeof(seed);
1519 int mib[2] = { CTL_KERN, KERN_ARND };
1520 if (sysctl(mib, 2, &seed, &len, NULL, 0) != 0) {
1521 zig_panic("unable to query random data from sysctl");
1522 }
1523 srand(seed);
1524#else
1525 int fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC);
1526 if (fd == -1) {
1527 zig_panic("unable to open /dev/urandom");
1528 }
1529 char bytes[sizeof(unsigned)];
1530 ssize_t amt_read;
1531 while ((amt_read = read(fd, bytes, sizeof(unsigned))) == -1) {
1532 if (errno == EINTR) continue;
1533 zig_panic("unable to read /dev/urandom");
1534 }
1535 if (amt_read != sizeof(unsigned)) {
1536 zig_panic("unable to read enough bytes from /dev/urandom");
1537 }
1538 close(fd);
1539 unsigned seed;
1540 memcpy(&seed, bytes, sizeof(unsigned));
1541 srand(seed);
1542#endif
1543}
1544969
1545970int os_init(void) {
1546 init_rand();
1547971#if defined(ZIG_OS_WINDOWS)
1548972 _setmode(fileno(stdout), _O_BINARY);
1549973 _setmode(fileno(stderr), _O_BINARY);
......@@ -1580,71 +1004,6 @@ int os_init(void) {
15801004 return 0;
15811005}
15821006
1583Error os_self_exe_path(Buf *out_path) {
1584#if defined(ZIG_OS_WINDOWS)
1585 PathSpace path_space;
1586 DWORD copied_amt = GetModuleFileNameW(nullptr, &path_space.data.items[0], PATH_MAX_WIDE);
1587 if (copied_amt <= 0) {
1588 return ErrorFileNotFound;
1589 }
1590 utf16le_ptr_to_utf8(out_path, &path_space.data.items[0]);
1591 return ErrorNone;
1592
1593#elif defined(ZIG_OS_DARWIN)
1594 // How long is the executable's path?
1595 uint32_t u32_len = 0;
1596 int ret1 = _NSGetExecutablePath(nullptr, &u32_len);
1597 assert(ret1 != 0);
1598
1599 Buf *tmp = buf_alloc_fixed(u32_len);
1600
1601 // Fill the executable path.
1602 int ret2 = _NSGetExecutablePath(buf_ptr(tmp), &u32_len);
1603 assert(ret2 == 0);
1604
1605 // According to libuv project, PATH_MAX*2 works around a libc bug where
1606 // the resolved path is sometimes bigger than PATH_MAX.
1607 buf_resize(out_path, PATH_MAX*2);
1608 char *real_path = realpath(buf_ptr(tmp), buf_ptr(out_path));
1609 if (!real_path) {
1610 buf_init_from_buf(out_path, tmp);
1611 return ErrorNone;
1612 }
1613
1614 // Resize out_path for the correct length.
1615 buf_resize(out_path, strlen(buf_ptr(out_path)));
1616
1617 return ErrorNone;
1618#elif defined(ZIG_OS_LINUX)
1619 buf_resize(out_path, PATH_MAX);
1620 ssize_t amt = readlink("/proc/self/exe", buf_ptr(out_path), buf_len(out_path));
1621 if (amt == -1) {
1622 return ErrorUnexpected;
1623 }
1624 buf_resize(out_path, amt);
1625 return ErrorNone;
1626#elif defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_DRAGONFLY)
1627 buf_resize(out_path, PATH_MAX);
1628 int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
1629 size_t cb = PATH_MAX;
1630 if (sysctl(mib, 4, buf_ptr(out_path), &cb, nullptr, 0) != 0) {
1631 return ErrorUnexpected;
1632 }
1633 buf_resize(out_path, cb - 1);
1634 return ErrorNone;
1635#elif defined(ZIG_OS_NETBSD)
1636 buf_resize(out_path, PATH_MAX);
1637 int mib[4] = { CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME };
1638 size_t cb = PATH_MAX;
1639 if (sysctl(mib, 4, buf_ptr(out_path), &cb, nullptr, 0) != 0) {
1640 return ErrorUnexpected;
1641 }
1642 buf_resize(out_path, cb - 1);
1643 return ErrorNone;
1644#endif
1645 return ErrorFileNotFound;
1646}
1647
16481007#define VT_RED "\x1b[31;1m"
16491008#define VT_GREEN "\x1b[32;1m"
16501009#define VT_CYAN "\x1b[36;1m"
......@@ -1954,392 +1313,3 @@ PathSpace slice_to_prefixed_file_w(Slice<uint8_t> path) {
19541313 return path_space;
19551314}
19561315#endif
1957
1958// Ported from std.os.getAppDataDir
1959Error os_get_app_data_dir(Buf *out_path, const char *appname) {
1960#if defined(ZIG_OS_WINDOWS)
1961 WCHAR *dir_path_ptr;
1962 switch (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &dir_path_ptr)) {
1963 case S_OK:
1964 // defer os.windows.CoTaskMemFree(@ptrCast(*c_void, dir_path_ptr));
1965 utf16le_ptr_to_utf8(out_path, dir_path_ptr);
1966 CoTaskMemFree(dir_path_ptr);
1967 buf_appendf(out_path, "\\%s", appname);
1968 return ErrorNone;
1969 case E_OUTOFMEMORY:
1970 return ErrorNoMem;
1971 default:
1972 return ErrorUnexpected;
1973 }
1974 zig_unreachable();
1975#elif defined(ZIG_OS_DARWIN)
1976 const char *home_dir = getenv("HOME");
1977 if (home_dir == nullptr) {
1978 // TODO use /etc/passwd
1979 return ErrorFileNotFound;
1980 }
1981 buf_resize(out_path, 0);
1982 buf_appendf(out_path, "%s/Library/Application Support/%s", home_dir, appname);
1983 return ErrorNone;
1984#elif defined(ZIG_OS_POSIX)
1985 const char *cache_dir = getenv("XDG_CACHE_HOME");
1986 if (cache_dir == nullptr) {
1987 cache_dir = getenv("HOME");
1988 if (cache_dir == nullptr) {
1989 // TODO use /etc/passwd
1990 return ErrorFileNotFound;
1991 }
1992 if (cache_dir[0] == 0) {
1993 return ErrorFileNotFound;
1994 }
1995 buf_init_from_str(out_path, cache_dir);
1996 if (buf_ptr(out_path)[buf_len(out_path) - 1] != '/') {
1997 buf_append_char(out_path, '/');
1998 }
1999 buf_appendf(out_path, ".cache/%s", appname);
2000 } else {
2001 if (cache_dir[0] == 0) {
2002 return ErrorFileNotFound;
2003 }
2004 buf_init_from_str(out_path, cache_dir);
2005 if (buf_ptr(out_path)[buf_len(out_path) - 1] != '/') {
2006 buf_append_char(out_path, '/');
2007 }
2008 buf_appendf(out_path, "%s", appname);
2009 }
2010 return ErrorNone;
2011#endif
2012}
2013
2014#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD) || defined(ZIG_OS_DRAGONFLY)
2015static int self_exe_shared_libs_callback(struct dl_phdr_info *info, size_t size, void *data) {
2016 ZigList<Buf *> *libs = reinterpret_cast< ZigList<Buf *> *>(data);
2017 if (info->dlpi_name[0] == '/') {
2018 libs->append(buf_create_from_str(info->dlpi_name));
2019 }
2020 return 0;
2021}
2022#endif
2023
2024Error os_self_exe_shared_libs(ZigList<Buf *> &paths) {
2025#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD) || defined(ZIG_OS_DRAGONFLY)
2026 paths.resize(0);
2027 dl_iterate_phdr(self_exe_shared_libs_callback, &paths);
2028 return ErrorNone;
2029#elif defined(ZIG_OS_DARWIN)
2030 paths.resize(0);
2031 uint32_t img_count = _dyld_image_count();
2032 for (uint32_t i = 0; i != img_count; i += 1) {
2033 const char *name = _dyld_get_image_name(i);
2034 paths.append(buf_create_from_str(name));
2035 }
2036 return ErrorNone;
2037#elif defined(ZIG_OS_WINDOWS)
2038 // zig is built statically on windows, so we can return an empty list
2039 paths.resize(0);
2040 return ErrorNone;
2041#else
2042#error unimplemented
2043#endif
2044}
2045
2046Error os_file_open_rw(Buf *full_path, OsFile *out_file, OsFileAttr *attr, bool need_write, uint32_t mode) {
2047#if defined(ZIG_OS_WINDOWS)
2048 PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(full_path));
2049 HANDLE result = CreateFileW(&path_space.data.items[0],
2050 need_write ? (GENERIC_READ|GENERIC_WRITE) : GENERIC_READ,
2051 need_write ? 0 : FILE_SHARE_READ,
2052 nullptr,
2053 need_write ? OPEN_ALWAYS : OPEN_EXISTING,
2054 FILE_ATTRIBUTE_NORMAL, nullptr);
2055
2056 if (result == INVALID_HANDLE_VALUE) {
2057 DWORD err = GetLastError();
2058 switch (err) {
2059 case ERROR_SHARING_VIOLATION:
2060 return ErrorSharingViolation;
2061 case ERROR_ALREADY_EXISTS:
2062 return ErrorPathAlreadyExists;
2063 case ERROR_FILE_EXISTS:
2064 return ErrorPathAlreadyExists;
2065 case ERROR_FILE_NOT_FOUND:
2066 return ErrorFileNotFound;
2067 case ERROR_PATH_NOT_FOUND:
2068 return ErrorFileNotFound;
2069 case ERROR_ACCESS_DENIED:
2070 return ErrorAccess;
2071 case ERROR_PIPE_BUSY:
2072 return ErrorPipeBusy;
2073 default:
2074 return ErrorUnexpected;
2075 }
2076 }
2077 *out_file = result;
2078
2079 if (attr != nullptr) {
2080 BY_HANDLE_FILE_INFORMATION file_info;
2081 if (!GetFileInformationByHandle(result, &file_info)) {
2082 CloseHandle(result);
2083 return ErrorUnexpected;
2084 }
2085 windows_filetime_to_os_timestamp(&file_info.ftLastWriteTime, &attr->mtime);
2086 attr->inode = (((uint64_t)file_info.nFileIndexHigh) << 32) | file_info.nFileIndexLow;
2087 attr->mode = 0;
2088 attr->size = (((uint64_t)file_info.nFileSizeHigh) << 32) | file_info.nFileSizeLow;
2089 }
2090
2091 return ErrorNone;
2092#else
2093 for (;;) {
2094 int fd = open(buf_ptr(full_path),
2095 need_write ? (O_RDWR|O_CLOEXEC|O_CREAT) : (O_RDONLY|O_CLOEXEC), mode);
2096 if (fd == -1) {
2097 switch (errno) {
2098 case EINTR:
2099 continue;
2100 case EINVAL:
2101 zig_unreachable();
2102 case EFAULT:
2103 zig_unreachable();
2104 case EACCES:
2105 case EPERM:
2106 return ErrorAccess;
2107 case EISDIR:
2108 return ErrorIsDir;
2109 case ENOENT:
2110 return ErrorFileNotFound;
2111 default:
2112 return ErrorFileSystem;
2113 }
2114 }
2115 struct stat statbuf;
2116 if (fstat(fd, &statbuf) == -1) {
2117 close(fd);
2118 return ErrorFileSystem;
2119 }
2120 if (S_ISDIR(statbuf.st_mode)) {
2121 close(fd);
2122 return ErrorIsDir;
2123 }
2124 *out_file = fd;
2125
2126 if (attr != nullptr) {
2127 attr->inode = statbuf.st_ino;
2128#if defined(ZIG_OS_DARWIN)
2129 attr->mtime.sec = statbuf.st_mtimespec.tv_sec;
2130 attr->mtime.nsec = statbuf.st_mtimespec.tv_nsec;
2131#else
2132 attr->mtime.sec = statbuf.st_mtim.tv_sec;
2133 attr->mtime.nsec = statbuf.st_mtim.tv_nsec;
2134#endif
2135 attr->mode = statbuf.st_mode;
2136 attr->size = statbuf.st_size;
2137 }
2138 return ErrorNone;
2139 }
2140#endif
2141}
2142
2143Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) {
2144 return os_file_open_rw(full_path, out_file, attr, false, 0);
2145}
2146
2147Error os_file_open_w(Buf *full_path, OsFile *out_file, OsFileAttr *attr, uint32_t mode) {
2148 return os_file_open_rw(full_path, out_file, attr, true, mode);
2149}
2150
2151Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) {
2152#if defined(ZIG_OS_WINDOWS)
2153 PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(full_path));
2154 for (;;) {
2155 HANDLE result = CreateFileW(&path_space.data.items[0], GENERIC_READ | GENERIC_WRITE,
2156 0, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
2157
2158 if (result == INVALID_HANDLE_VALUE) {
2159 DWORD err = GetLastError();
2160 switch (err) {
2161 case ERROR_SHARING_VIOLATION:
2162 // TODO wait for the lock instead of sleeping
2163 Sleep(10);
2164 continue;
2165 case ERROR_ALREADY_EXISTS:
2166 return ErrorPathAlreadyExists;
2167 case ERROR_FILE_EXISTS:
2168 return ErrorPathAlreadyExists;
2169 case ERROR_FILE_NOT_FOUND:
2170 return ErrorFileNotFound;
2171 case ERROR_PATH_NOT_FOUND:
2172 return ErrorFileNotFound;
2173 case ERROR_ACCESS_DENIED:
2174 return ErrorAccess;
2175 case ERROR_PIPE_BUSY:
2176 return ErrorPipeBusy;
2177 default:
2178 return ErrorUnexpected;
2179 }
2180 }
2181 *out_file = result;
2182 return ErrorNone;
2183 }
2184#else
2185 int fd;
2186 for (;;) {
2187 fd = open(buf_ptr(full_path), O_RDWR|O_CLOEXEC|O_CREAT, 0666);
2188 if (fd == -1) {
2189 switch (errno) {
2190 case EINTR:
2191 continue;
2192 case EINVAL:
2193 zig_unreachable();
2194 case EFAULT:
2195 zig_unreachable();
2196 case EACCES:
2197 case EPERM:
2198 return ErrorAccess;
2199 case EISDIR:
2200 return ErrorIsDir;
2201 case ENOENT:
2202 return ErrorFileNotFound;
2203 case ENOTDIR:
2204 return ErrorNotDir;
2205 default:
2206 return ErrorFileSystem;
2207 }
2208 }
2209 break;
2210 }
2211 for (;;) {
2212 struct flock lock;
2213 lock.l_type = F_WRLCK;
2214 lock.l_whence = SEEK_SET;
2215 lock.l_start = 0;
2216 lock.l_len = 0;
2217 if (fcntl(fd, F_SETLKW, &lock) == -1) {
2218 switch (errno) {
2219 case EINTR:
2220 continue;
2221 case EBADF:
2222 zig_unreachable();
2223 case EFAULT:
2224 zig_unreachable();
2225 case EINVAL:
2226 zig_unreachable();
2227 default:
2228 close(fd);
2229 return ErrorFileSystem;
2230 }
2231 }
2232 break;
2233 }
2234 *out_file = fd;
2235 return ErrorNone;
2236#endif
2237}
2238
2239Error os_file_read(OsFile file, void *ptr, size_t *len) {
2240#if defined(ZIG_OS_WINDOWS)
2241 DWORD amt_read;
2242 if (ReadFile(file, ptr, *len, &amt_read, nullptr) == 0)
2243 return ErrorUnexpected;
2244 *len = amt_read;
2245 return ErrorNone;
2246#else
2247 for (;;) {
2248 ssize_t rc = read(file, ptr, *len);
2249 if (rc == -1) {
2250 switch (errno) {
2251 case EINTR:
2252 continue;
2253 case EBADF:
2254 zig_unreachable();
2255 case EFAULT:
2256 zig_unreachable();
2257 case EISDIR:
2258 return ErrorIsDir;
2259 default:
2260 return ErrorFileSystem;
2261 }
2262 }
2263 *len = rc;
2264 return ErrorNone;
2265 }
2266#endif
2267}
2268
2269Error os_file_read_all(OsFile file, Buf *contents) {
2270 Error err;
2271 size_t index = 0;
2272 for (;;) {
2273 size_t amt = buf_len(contents) - index;
2274
2275 if (amt < 4096) {
2276 buf_resize(contents, buf_len(contents) + (4096 - amt));
2277 amt = buf_len(contents) - index;
2278 }
2279
2280 if ((err = os_file_read(file, buf_ptr(contents) + index, &amt)))
2281 return err;
2282
2283 if (amt == 0) {
2284 buf_resize(contents, index);
2285 return ErrorNone;
2286 }
2287
2288 index += amt;
2289 }
2290}
2291
2292Error os_file_overwrite(OsFile file, Buf *contents) {
2293#if defined(ZIG_OS_WINDOWS)
2294 if (SetFilePointer(file, 0, nullptr, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
2295 return ErrorFileSystem;
2296 if (!SetEndOfFile(file))
2297 return ErrorFileSystem;
2298 DWORD bytes_written;
2299 if (!WriteFile(file, buf_ptr(contents), buf_len(contents), &bytes_written, nullptr))
2300 return ErrorFileSystem;
2301 return ErrorNone;
2302#else
2303 if (lseek(file, 0, SEEK_SET) == -1)
2304 return ErrorUnexpectedSeekFailure;
2305 if (ftruncate(file, 0) == -1)
2306 return ErrorUnexpectedFileTruncationFailure;
2307 for (;;) {
2308 if (write(file, buf_ptr(contents), buf_len(contents)) == -1) {
2309 switch (errno) {
2310 case EINTR:
2311 continue;
2312 case EINVAL:
2313 zig_unreachable();
2314 case EBADF:
2315 zig_unreachable();
2316 case EFAULT:
2317 zig_unreachable();
2318 case EDQUOT:
2319 return ErrorDiskQuota;
2320 case ENOSPC:
2321 return ErrorDiskSpace;
2322 case EFBIG:
2323 return ErrorFileTooBig;
2324 case EIO:
2325 return ErrorFileSystem;
2326 case EPERM:
2327 return ErrorAccess;
2328 default:
2329 return ErrorUnexpectedWriteFailure;
2330 }
2331 }
2332 return ErrorNone;
2333 }
2334#endif
2335}
2336
2337void os_file_close(OsFile *file) {
2338#if defined(ZIG_OS_WINDOWS)
2339 CloseHandle(*file);
2340 *file = NULL;
2341#else
2342 close(*file);
2343 *file = -1;
2344#endif
2345}
src/stage1/os.hpp-52
......@@ -70,66 +70,25 @@ enum TermColor {
7070 TermColorReset,
7171};
7272
73enum TerminationId {
74 TerminationIdClean,
75 TerminationIdSignaled,
76 TerminationIdStopped,
77 TerminationIdUnknown,
78};
79
80struct Termination {
81 TerminationId how;
82 int code;
83};
84
85#if defined(ZIG_OS_WINDOWS)
86#define OsFile void *
87#else
88#define OsFile int
89#endif
90
9173struct OsTimeStamp {
9274 int64_t sec;
9375 int64_t nsec;
9476};
9577
96struct OsFileAttr {
97 OsTimeStamp mtime;
98 uint64_t size;
99 uint64_t inode;
100 uint32_t mode;
101};
102
10378int os_init(void);
10479
105void os_spawn_process(ZigList<const char *> &args, Termination *term);
106Error os_exec_process(ZigList<const char *> &args,
107 Termination *term, Buf *out_stderr, Buf *out_stdout);
108Error os_execv(const char *exe, const char **argv);
109
11080void os_path_dirname(Buf *full_path, Buf *out_dirname);
11181void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename);
11282void os_path_extname(Buf *full_path, Buf *out_basename, Buf *out_extname);
11383void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path);
114Error os_path_real(Buf *rel_path, Buf *out_abs_path);
11584Buf os_path_resolve(Buf **paths_ptr, size_t paths_len);
11685bool os_path_is_absolute(Buf *path);
11786
11887Error ATTRIBUTE_MUST_USE os_make_path(Buf *path);
11988Error ATTRIBUTE_MUST_USE os_make_dir(Buf *path);
12089
121Error ATTRIBUTE_MUST_USE os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr);
122Error ATTRIBUTE_MUST_USE os_file_open_w(Buf *full_path, OsFile *out_file, OsFileAttr *attr, uint32_t mode);
123Error ATTRIBUTE_MUST_USE os_file_open_lock_rw(Buf *full_path, OsFile *out_file);
124Error ATTRIBUTE_MUST_USE os_file_read(OsFile file, void *ptr, size_t *len);
125Error ATTRIBUTE_MUST_USE os_file_read_all(OsFile file, Buf *contents);
126Error ATTRIBUTE_MUST_USE os_file_overwrite(OsFile file, Buf *contents);
127void os_file_close(OsFile *file);
128
12990Error ATTRIBUTE_MUST_USE os_write_file(Buf *full_path, Buf *contents);
13091Error ATTRIBUTE_MUST_USE os_copy_file(Buf *src_path, Buf *dest_path);
131Error ATTRIBUTE_MUST_USE os_update_file(Buf *src_path, Buf *dest_path);
132Error ATTRIBUTE_MUST_USE os_dump_file(Buf *src_path, FILE *dest_file);
13392
13493Error ATTRIBUTE_MUST_USE os_fetch_file(FILE *file, Buf *out_contents);
13594Error ATTRIBUTE_MUST_USE os_fetch_file_path(Buf *full_path, Buf *out_contents);
......@@ -139,22 +98,11 @@ Error ATTRIBUTE_MUST_USE os_get_cwd(Buf *out_cwd);
13998bool os_stderr_tty(void);
14099void os_stderr_set_color(TermColor color);
141100
142Error os_delete_file(Buf *path);
143
144Error ATTRIBUTE_MUST_USE os_file_exists(Buf *full_path, bool *result);
145
146101Error os_rename(Buf *src_path, Buf *dest_path);
147102OsTimeStamp os_timestamp_monotonic(void);
148OsTimeStamp os_timestamp_calendar(void);
149103
150104bool os_is_sep(uint8_t c);
151105
152Error ATTRIBUTE_MUST_USE os_self_exe_path(Buf *out_path);
153
154Error ATTRIBUTE_MUST_USE os_get_app_data_dir(Buf *out_path, const char *appname);
155
156Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths);
157
158106const size_t PATH_MAX_WIDE = 32767;
159107
160108struct PathSpace {
src/stage1/zig0.cpp+10
......@@ -430,6 +430,16 @@ int main(int argc, char **argv) {
430430 return print_error_usage(arg0);
431431 }
432432
433 if (override_lib_dir == nullptr) {
434 fprintf(stderr, "missing --override-lib-dir\n");
435 return print_error_usage(arg0);
436 }
437
438 if (emit_bin_path == nullptr) {
439 fprintf(stderr, "missing -femit-bin=\n");
440 return print_error_usage(arg0);
441 }
442
433443 ZigStage1 *stage1 = zig_stage1_create(optimize_mode,
434444 nullptr, 0,
435445 in_file, strlen(in_file),
src/target.zig+1-1
......@@ -130,7 +130,6 @@ pub fn osRequiresLibC(target: std.Target) bool {
130130
131131pub fn libcNeedsLibUnwind(target: std.Target) bool {
132132 return switch (target.os.tag) {
133 .windows,
134133 .macosx,
135134 .ios,
136135 .watchos,
......@@ -138,6 +137,7 @@ pub fn libcNeedsLibUnwind(target: std.Target) bool {
138137 .freestanding,
139138 => false,
140139
140 .windows => target.abi != .msvc,
141141 else => true,
142142 };
143143}
src/test.zig+15
......@@ -56,6 +56,12 @@ pub const TestContext = struct {
5656 },
5757 };
5858
59 pub const File = struct {
60 /// Contents of the importable file. Doesn't yet support incremental updates.
61 src: [:0]const u8,
62 path: []const u8,
63 };
64
5965 pub const TestType = enum {
6066 Zig,
6167 ZIR,
......@@ -78,6 +84,8 @@ pub const TestContext = struct {
7884 extension: TestType,
7985 cbe: bool = false,
8086
87 files: std.ArrayList(File),
88
8189 /// Adds a subcase in which the module is updated with `src`, and the
8290 /// resulting ZIR is validated against `result`.
8391 pub fn addTransform(self: *Case, src: [:0]const u8, result: [:0]const u8) void {
......@@ -156,6 +164,7 @@ pub const TestContext = struct {
156164 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
157165 .output_mode = .Exe,
158166 .extension = T,
167 .files = std.ArrayList(File).init(ctx.cases.allocator),
159168 }) catch unreachable;
160169 return &ctx.cases.items[ctx.cases.items.len - 1];
161170 }
......@@ -182,6 +191,7 @@ pub const TestContext = struct {
182191 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
183192 .output_mode = .Obj,
184193 .extension = T,
194 .files = std.ArrayList(File).init(ctx.cases.allocator),
185195 }) catch unreachable;
186196 return &ctx.cases.items[ctx.cases.items.len - 1];
187197 }
......@@ -204,6 +214,7 @@ pub const TestContext = struct {
204214 .output_mode = .Obj,
205215 .extension = T,
206216 .cbe = true,
217 .files = std.ArrayList(File).init(ctx.cases.allocator),
207218 }) catch unreachable;
208219 return &ctx.cases.items[ctx.cases.items.len - 1];
209220 }
......@@ -505,6 +516,10 @@ pub const TestContext = struct {
505516 });
506517 defer comp.destroy();
507518
519 for (case.files.items) |file| {
520 try tmp.dir.writeFile(file.path, file.src);
521 }
522
508523 for (case.updates.items) |update, update_index| {
509524 var update_node = root_node.start("update", 3);
510525 update_node.activate();
src/translate_c.zig+380-165
......@@ -5527,58 +5527,41 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
55275527const ParseError = Error || error{ParseError};
55285528
55295529fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
5530 const node = try parseCPrefixOpExpr(c, m, scope);
5531 switch (m.next().?) {
5532 .QuestionMark => {
5533 // must come immediately after expr
5534 _ = try appendToken(c, .RParen, ")");
5535 const if_node = try transCreateNodeIf(c);
5536 if_node.condition = node;
5537 if_node.body = try parseCPrimaryExpr(c, m, scope);
5538 if (m.next().? != .Colon) {
5539 try m.fail(c, "unable to translate C expr: expected ':'", .{});
5540 return error.ParseError;
5541 }
5542 if_node.@"else" = try transCreateNodeElse(c);
5543 if_node.@"else".?.body = try parseCPrimaryExpr(c, m, scope);
5544 return &if_node.base;
5545 },
5546 .Comma => {
5547 _ = try appendToken(c, .Semicolon, ";");
5548 var block_scope = try Scope.Block.init(c, scope, true);
5549 defer block_scope.deinit();
5550
5551 var last = node;
5552 while (true) {
5553 // suppress result
5554 const lhs = try transCreateNodeIdentifier(c, "_");
5555 const op_token = try appendToken(c, .Equal, "=");
5556 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
5557 op_node.* = .{
5558 .base = .{ .tag = .Assign },
5559 .op_token = op_token,
5560 .lhs = lhs,
5561 .rhs = last,
5562 };
5563 try block_scope.statements.append(&op_node.base);
5530 // TODO parseCAssignExpr here
5531 const node = try parseCCondExpr(c, m, scope);
5532 if (m.next().? != .Comma) {
5533 m.i -= 1;
5534 return node;
5535 }
5536 _ = try appendToken(c, .Semicolon, ";");
5537 var block_scope = try Scope.Block.init(c, scope, true);
5538 defer block_scope.deinit();
55645539
5565 last = try parseCPrefixOpExpr(c, m, scope);
5566 _ = try appendToken(c, .Semicolon, ";");
5567 if (m.next().? != .Comma) {
5568 m.i -= 1;
5569 break;
5570 }
5571 }
5540 var last = node;
5541 while (true) {
5542 // suppress result
5543 const lhs = try transCreateNodeIdentifier(c, "_");
5544 const op_token = try appendToken(c, .Equal, "=");
5545 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
5546 op_node.* = .{
5547 .base = .{ .tag = .Assign },
5548 .op_token = op_token,
5549 .lhs = lhs,
5550 .rhs = last,
5551 };
5552 try block_scope.statements.append(&op_node.base);
55725553
5573 const break_node = try transCreateNodeBreak(c, block_scope.label, last);
5574 try block_scope.statements.append(&break_node.base);
5575 return try block_scope.complete(c);
5576 },
5577 else => {
5554 last = try parseCCondExpr(c, m, scope);
5555 _ = try appendToken(c, .Semicolon, ";");
5556 if (m.next().? != .Comma) {
55785557 m.i -= 1;
5579 return node;
5580 },
5558 break;
5559 }
55815560 }
5561
5562 const break_node = try transCreateNodeBreak(c, block_scope.label, last);
5563 try block_scope.statements.append(&break_node.base);
5564 return try block_scope.complete(c);
55825565}
55835566
55845567fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!*ast.Node {
......@@ -5805,7 +5788,7 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
58055788 return bytes[0..i];
58065789}
58075790
5808fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
5791fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
58095792 const tok = m.next().?;
58105793 const slice = m.slice();
58115794 switch (tok) {
......@@ -5952,6 +5935,30 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N
59525935 }
59535936}
59545937
5938fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
5939 var node = try parseCPrimaryExprInner(c, m, scope);
5940 // In C the preprocessor would handle concatting strings while expanding macros.
5941 // This should do approximately the same by concatting any strings and identifiers
5942 // after a primary expression.
5943 while (true) {
5944 var op_token: ast.TokenIndex = undefined;
5945 var op_id: ast.Node.Tag = undefined;
5946 switch (m.peek().?) {
5947 .StringLiteral, .Identifier => {},
5948 else => break,
5949 }
5950 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
5951 op_node.* = .{
5952 .base = .{ .tag = .ArrayCat },
5953 .op_token = try appendToken(c, .PlusPlus, "++"),
5954 .lhs = node,
5955 .rhs = try parseCPrimaryExprInner(c, m, scope),
5956 };
5957 node = &op_node.base;
5958 }
5959 return node;
5960}
5961
59555962fn nodeIsInfixOp(tag: ast.Node.Tag) bool {
59565963 return switch (tag) {
59575964 .Add,
......@@ -6053,31 +6060,268 @@ fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node {
60536060 return &group_node.base;
60546061}
60556062
6056fn parseCSuffixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6057 var node = try parseCPrimaryExpr(c, m, scope);
6063fn macroGroup(c: *Context, node: *ast.Node) !*ast.Node {
6064 if (!nodeIsInfixOp(node.tag)) return node;
6065
6066 const group_node = try c.arena.create(ast.Node.GroupedExpression);
6067 group_node.* = .{
6068 .lparen = try appendToken(c, .LParen, "("),
6069 .expr = node,
6070 .rparen = try appendToken(c, .RParen, ")"),
6071 };
6072 return &group_node.base;
6073}
6074
6075fn parseCCondExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6076 const node = try parseCOrExpr(c, m, scope);
6077 if (m.peek().? != .QuestionMark) {
6078 return node;
6079 }
6080 _ = m.next();
6081
6082 // must come immediately after expr
6083 _ = try appendToken(c, .RParen, ")");
6084 const if_node = try transCreateNodeIf(c);
6085 if_node.condition = node;
6086 if_node.body = try parseCOrExpr(c, m, scope);
6087 if (m.next().? != .Colon) {
6088 try m.fail(c, "unable to translate C expr: expected ':'", .{});
6089 return error.ParseError;
6090 }
6091 if_node.@"else" = try transCreateNodeElse(c);
6092 if_node.@"else".?.body = try parseCCondExpr(c, m, scope);
6093 return &if_node.base;
6094}
6095
6096fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6097 var node = try parseCAndExpr(c, m, scope);
6098 while (m.next().? == .PipePipe) {
6099 const lhs_node = try macroIntToBool(c, node);
6100 const op_token = try appendToken(c, .Keyword_or, "or");
6101 const rhs_node = try parseCAndExpr(c, m, scope);
6102 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6103 op_node.* = .{
6104 .base = .{ .tag = .BoolOr },
6105 .op_token = op_token,
6106 .lhs = lhs_node,
6107 .rhs = try macroIntToBool(c, rhs_node),
6108 };
6109 node = &op_node.base;
6110 }
6111 m.i -= 1;
6112 return node;
6113}
6114
6115fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6116 var node = try parseCBitOrExpr(c, m, scope);
6117 while (m.next().? == .AmpersandAmpersand) {
6118 const lhs_node = try macroIntToBool(c, node);
6119 const op_token = try appendToken(c, .Keyword_and, "and");
6120 const rhs_node = try parseCBitOrExpr(c, m, scope);
6121 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6122 op_node.* = .{
6123 .base = .{ .tag = .BoolAnd },
6124 .op_token = op_token,
6125 .lhs = lhs_node,
6126 .rhs = try macroIntToBool(c, rhs_node),
6127 };
6128 node = &op_node.base;
6129 }
6130 m.i -= 1;
6131 return node;
6132}
6133
6134fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6135 var node = try parseCBitXorExpr(c, m, scope);
6136 while (m.next().? == .Pipe) {
6137 const lhs_node = try macroBoolToInt(c, node);
6138 const op_token = try appendToken(c, .Pipe, "|");
6139 const rhs_node = try parseCBitXorExpr(c, m, scope);
6140 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6141 op_node.* = .{
6142 .base = .{ .tag = .BitOr },
6143 .op_token = op_token,
6144 .lhs = lhs_node,
6145 .rhs = try macroBoolToInt(c, rhs_node),
6146 };
6147 node = &op_node.base;
6148 }
6149 m.i -= 1;
6150 return node;
6151}
6152
6153fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6154 var node = try parseCBitAndExpr(c, m, scope);
6155 while (m.next().? == .Caret) {
6156 const lhs_node = try macroBoolToInt(c, node);
6157 const op_token = try appendToken(c, .Caret, "^");
6158 const rhs_node = try parseCBitAndExpr(c, m, scope);
6159 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6160 op_node.* = .{
6161 .base = .{ .tag = .BitXor },
6162 .op_token = op_token,
6163 .lhs = lhs_node,
6164 .rhs = try macroBoolToInt(c, rhs_node),
6165 };
6166 node = &op_node.base;
6167 }
6168 m.i -= 1;
6169 return node;
6170}
6171
6172fn parseCBitAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6173 var node = try parseCEqExpr(c, m, scope);
6174 while (m.next().? == .Ampersand) {
6175 const lhs_node = try macroBoolToInt(c, node);
6176 const op_token = try appendToken(c, .Ampersand, "&");
6177 const rhs_node = try parseCEqExpr(c, m, scope);
6178 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6179 op_node.* = .{
6180 .base = .{ .tag = .BitAnd },
6181 .op_token = op_token,
6182 .lhs = lhs_node,
6183 .rhs = try macroBoolToInt(c, rhs_node),
6184 };
6185 node = &op_node.base;
6186 }
6187 m.i -= 1;
6188 return node;
6189}
6190
6191fn parseCEqExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6192 var node = try parseCRelExpr(c, m, scope);
60586193 while (true) {
60596194 var op_token: ast.TokenIndex = undefined;
60606195 var op_id: ast.Node.Tag = undefined;
6061 var bool_op = false;
6062 switch (m.next().?) {
6063 .Period => {
6064 if (m.next().? != .Identifier) {
6065 try m.fail(c, "unable to translate C expr: expected identifier", .{});
6066 return error.ParseError;
6067 }
6196 switch (m.peek().?) {
6197 .BangEqual => {
6198 op_token = try appendToken(c, .BangEqual, "!=");
6199 op_id = .BangEqual;
6200 },
6201 .EqualEqual => {
6202 op_token = try appendToken(c, .EqualEqual, "==");
6203 op_id = .EqualEqual;
6204 },
6205 else => return node,
6206 }
6207 _ = m.next();
6208 const lhs_node = try macroBoolToInt(c, node);
6209 const rhs_node = try parseCRelExpr(c, m, scope);
6210 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6211 op_node.* = .{
6212 .base = .{ .tag = op_id },
6213 .op_token = op_token,
6214 .lhs = lhs_node,
6215 .rhs = try macroBoolToInt(c, rhs_node),
6216 };
6217 node = &op_node.base;
6218 }
6219}
60686220
6069 node = try transCreateNodeFieldAccess(c, node, m.slice());
6070 continue;
6221fn parseCRelExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6222 var node = try parseCShiftExpr(c, m, scope);
6223 while (true) {
6224 var op_token: ast.TokenIndex = undefined;
6225 var op_id: ast.Node.Tag = undefined;
6226 switch (m.peek().?) {
6227 .AngleBracketRight => {
6228 op_token = try appendToken(c, .AngleBracketRight, ">");
6229 op_id = .GreaterThan;
60716230 },
6072 .Arrow => {
6073 if (m.next().? != .Identifier) {
6074 try m.fail(c, "unable to translate C expr: expected identifier", .{});
6075 return error.ParseError;
6076 }
6077 const deref = try transCreateNodePtrDeref(c, node);
6078 node = try transCreateNodeFieldAccess(c, deref, m.slice());
6079 continue;
6231 .AngleBracketRightEqual => {
6232 op_token = try appendToken(c, .AngleBracketRightEqual, ">=");
6233 op_id = .GreaterOrEqual;
6234 },
6235 .AngleBracketLeft => {
6236 op_token = try appendToken(c, .AngleBracketLeft, "<");
6237 op_id = .LessThan;
60806238 },
6239 .AngleBracketLeftEqual => {
6240 op_token = try appendToken(c, .AngleBracketLeftEqual, "<=");
6241 op_id = .LessOrEqual;
6242 },
6243 else => return node,
6244 }
6245 _ = m.next();
6246 const lhs_node = try macroBoolToInt(c, node);
6247 const rhs_node = try parseCShiftExpr(c, m, scope);
6248 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6249 op_node.* = .{
6250 .base = .{ .tag = op_id },
6251 .op_token = op_token,
6252 .lhs = lhs_node,
6253 .rhs = try macroBoolToInt(c, rhs_node),
6254 };
6255 node = &op_node.base;
6256 }
6257}
6258
6259fn parseCShiftExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6260 var node = try parseCAddSubExpr(c, m, scope);
6261 while (true) {
6262 var op_token: ast.TokenIndex = undefined;
6263 var op_id: ast.Node.Tag = undefined;
6264 switch (m.peek().?) {
6265 .AngleBracketAngleBracketLeft => {
6266 op_token = try appendToken(c, .AngleBracketAngleBracketLeft, "<<");
6267 op_id = .BitShiftLeft;
6268 },
6269 .AngleBracketAngleBracketRight => {
6270 op_token = try appendToken(c, .AngleBracketAngleBracketRight, ">>");
6271 op_id = .BitShiftRight;
6272 },
6273 else => return node,
6274 }
6275 _ = m.next();
6276 const lhs_node = try macroBoolToInt(c, node);
6277 const rhs_node = try parseCAddSubExpr(c, m, scope);
6278 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6279 op_node.* = .{
6280 .base = .{ .tag = op_id },
6281 .op_token = op_token,
6282 .lhs = lhs_node,
6283 .rhs = try macroBoolToInt(c, rhs_node),
6284 };
6285 node = &op_node.base;
6286 }
6287}
6288
6289fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6290 var node = try parseCMulExpr(c, m, scope);
6291 while (true) {
6292 var op_token: ast.TokenIndex = undefined;
6293 var op_id: ast.Node.Tag = undefined;
6294 switch (m.peek().?) {
6295 .Plus => {
6296 op_token = try appendToken(c, .Plus, "+");
6297 op_id = .Add;
6298 },
6299 .Minus => {
6300 op_token = try appendToken(c, .Minus, "-");
6301 op_id = .Sub;
6302 },
6303 else => return node,
6304 }
6305 _ = m.next();
6306 const lhs_node = try macroBoolToInt(c, node);
6307 const rhs_node = try parseCMulExpr(c, m, scope);
6308 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6309 op_node.* = .{
6310 .base = .{ .tag = op_id },
6311 .op_token = op_token,
6312 .lhs = lhs_node,
6313 .rhs = try macroBoolToInt(c, rhs_node),
6314 };
6315 node = &op_node.base;
6316 }
6317}
6318
6319fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6320 var node = try parseCUnaryExpr(c, m, scope);
6321 while (true) {
6322 var op_token: ast.TokenIndex = undefined;
6323 var op_id: ast.Node.Tag = undefined;
6324 switch (m.next().?) {
60816325 .Asterisk => {
60826326 if (m.peek().? == .RParen) {
60836327 // type *)
......@@ -6105,59 +6349,57 @@ fn parseCSuffixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.
61056349 op_id = .BitShiftLeft;
61066350 }
61076351 },
6108 .AngleBracketAngleBracketLeft => {
6109 op_token = try appendToken(c, .AngleBracketAngleBracketLeft, "<<");
6110 op_id = .BitShiftLeft;
6111 },
6112 .AngleBracketAngleBracketRight => {
6113 op_token = try appendToken(c, .AngleBracketAngleBracketRight, ">>");
6114 op_id = .BitShiftRight;
6115 },
6116 .Pipe => {
6117 op_token = try appendToken(c, .Pipe, "|");
6118 op_id = .BitOr;
6119 },
6120 .Ampersand => {
6121 op_token = try appendToken(c, .Ampersand, "&");
6122 op_id = .BitAnd;
6123 },
6124 .Plus => {
6125 op_token = try appendToken(c, .Plus, "+");
6126 op_id = .Add;
6127 },
6128 .Minus => {
6129 op_token = try appendToken(c, .Minus, "-");
6130 op_id = .Sub;
6131 },
6132 .AmpersandAmpersand => {
6133 op_token = try appendToken(c, .Keyword_and, "and");
6134 op_id = .BoolAnd;
6135 bool_op = true;
6136 },
6137 .PipePipe => {
6138 op_token = try appendToken(c, .Keyword_or, "or");
6139 op_id = .BoolOr;
6140 bool_op = true;
6352 .Slash => {
6353 op_id = .Div;
6354 op_token = try appendToken(c, .Slash, "/");
61416355 },
6142 .AngleBracketRight => {
6143 op_token = try appendToken(c, .AngleBracketRight, ">");
6144 op_id = .GreaterThan;
6356 .Percent => {
6357 op_id = .Mod;
6358 op_token = try appendToken(c, .Percent, "%");
61456359 },
6146 .AngleBracketRightEqual => {
6147 op_token = try appendToken(c, .AngleBracketRightEqual, ">=");
6148 op_id = .GreaterOrEqual;
6360 else => {
6361 m.i -= 1;
6362 return node;
61496363 },
6150 .AngleBracketLeft => {
6151 op_token = try appendToken(c, .AngleBracketLeft, "<");
6152 op_id = .LessThan;
6364 }
6365 const lhs_node = try macroBoolToInt(c, node);
6366 const rhs_node = try parseCUnaryExpr(c, m, scope);
6367 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6368 op_node.* = .{
6369 .base = .{ .tag = op_id },
6370 .op_token = op_token,
6371 .lhs = lhs_node,
6372 .rhs = try macroBoolToInt(c, rhs_node),
6373 };
6374 node = &op_node.base;
6375 }
6376}
6377
6378fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6379 var node = try parseCPrimaryExpr(c, m, scope);
6380 while (true) {
6381 switch (m.next().?) {
6382 .Period => {
6383 if (m.next().? != .Identifier) {
6384 try m.fail(c, "unable to translate C expr: expected identifier", .{});
6385 return error.ParseError;
6386 }
6387
6388 node = try transCreateNodeFieldAccess(c, node, m.slice());
6389 continue;
61536390 },
6154 .AngleBracketLeftEqual => {
6155 op_token = try appendToken(c, .AngleBracketLeftEqual, "<=");
6156 op_id = .LessOrEqual;
6391 .Arrow => {
6392 if (m.next().? != .Identifier) {
6393 try m.fail(c, "unable to translate C expr: expected identifier", .{});
6394 return error.ParseError;
6395 }
6396 const deref = try transCreateNodePtrDeref(c, node);
6397 node = try transCreateNodeFieldAccess(c, deref, m.slice());
6398 continue;
61576399 },
61586400 .LBracket => {
61596401 const arr_node = try transCreateNodeArrayAccess(c, node);
6160 arr_node.index_expr = try parseCPrefixOpExpr(c, m, scope);
6402 arr_node.index_expr = try parseCExpr(c, m, scope);
61616403 arr_node.rtoken = try appendToken(c, .RBracket, "]");
61626404 node = &arr_node.base;
61636405 if (m.next().? != .RBracket) {
......@@ -6171,7 +6413,7 @@ fn parseCSuffixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.
61716413 var call_params = std.ArrayList(*ast.Node).init(c.gpa);
61726414 defer call_params.deinit();
61736415 while (true) {
6174 const arg = try parseCPrefixOpExpr(c, m, scope);
6416 const arg = try parseCCondExpr(c, m, scope);
61756417 try call_params.append(arg);
61766418 switch (m.next().?) {
61776419 .Comma => _ = try appendToken(c, .Comma, ","),
......@@ -6204,7 +6446,7 @@ fn parseCSuffixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.
62046446 defer init_vals.deinit();
62056447
62066448 while (true) {
6207 const val = try parseCPrefixOpExpr(c, m, scope);
6449 const val = try parseCCondExpr(c, m, scope);
62086450 try init_vals.append(val);
62096451 switch (m.next().?) {
62106452 .Comma => _ = try appendToken(c, .Comma, ","),
......@@ -6239,90 +6481,57 @@ fn parseCSuffixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.
62396481 node = &zero_init_call.base;
62406482 continue;
62416483 },
6242 .BangEqual => {
6243 op_token = try appendToken(c, .BangEqual, "!=");
6244 op_id = .BangEqual;
6245 },
6246 .EqualEqual => {
6247 op_token = try appendToken(c, .EqualEqual, "==");
6248 op_id = .EqualEqual;
6249 },
6250 .Slash => {
6251 op_id = .Div;
6252 op_token = try appendToken(c, .Slash, "/");
6253 },
6254 .Percent => {
6255 op_id = .Mod;
6256 op_token = try appendToken(c, .Percent, "%");
6257 },
6258 .StringLiteral => {
6259 op_id = .ArrayCat;
6260 op_token = try appendToken(c, .PlusPlus, "++");
6261
6262 m.i -= 1;
6263 },
6264 .Identifier => {
6265 op_id = .ArrayCat;
6266 op_token = try appendToken(c, .PlusPlus, "++");
6267
6268 m.i -= 1;
6484 .PlusPlus, .MinusMinus => {
6485 try m.fail(c, "TODO postfix inc/dec expr", .{});
6486 return error.ParseError;
62696487 },
62706488 else => {
62716489 m.i -= 1;
62726490 return node;
62736491 },
62746492 }
6275 const cast_fn = if (bool_op) macroIntToBool else macroBoolToInt;
6276 const lhs_node = try cast_fn(c, node);
6277 const rhs_node = try parseCPrefixOpExpr(c, m, scope);
6278 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6279 op_node.* = .{
6280 .base = .{ .tag = op_id },
6281 .op_token = op_token,
6282 .lhs = lhs_node,
6283 .rhs = try cast_fn(c, rhs_node),
6284 };
6285 node = &op_node.base;
62866493 }
62876494}
62886495
6289fn parseCPrefixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
6496fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
62906497 switch (m.next().?) {
62916498 .Bang => {
62926499 const node = try transCreateNodeSimplePrefixOp(c, .BoolNot, .Bang, "!");
6293 node.rhs = try parseCPrefixOpExpr(c, m, scope);
6500 node.rhs = try macroIntToBool(c, try parseCUnaryExpr(c, m, scope));
62946501 return &node.base;
62956502 },
62966503 .Minus => {
62976504 const node = try transCreateNodeSimplePrefixOp(c, .Negation, .Minus, "-");
6298 node.rhs = try parseCPrefixOpExpr(c, m, scope);
6505 node.rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
62996506 return &node.base;
63006507 },
6301 .Plus => return try parseCPrefixOpExpr(c, m, scope),
6508 .Plus => return try parseCUnaryExpr(c, m, scope),
63026509 .Tilde => {
63036510 const node = try transCreateNodeSimplePrefixOp(c, .BitNot, .Tilde, "~");
6304 node.rhs = try parseCPrefixOpExpr(c, m, scope);
6511 node.rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
63056512 return &node.base;
63066513 },
63076514 .Asterisk => {
6308 const node = try parseCPrefixOpExpr(c, m, scope);
6515 const node = try macroGroup(c, try parseCUnaryExpr(c, m, scope));
63096516 return try transCreateNodePtrDeref(c, node);
63106517 },
63116518 .Ampersand => {
63126519 const node = try transCreateNodeSimplePrefixOp(c, .AddressOf, .Ampersand, "&");
6313 node.rhs = try parseCPrefixOpExpr(c, m, scope);
6520 node.rhs = try macroGroup(c, try parseCUnaryExpr(c, m, scope));
63146521 return &node.base;
63156522 },
63166523 .Keyword_sizeof => {
63176524 const inner = if (m.peek().? == .LParen) blk: {
63186525 _ = m.next();
6319 const inner = try parseCExpr(c, m, scope);
6526 // C grammar says this should be 'type-name' but we have to
6527 // use parseCMulExpr to correctly handle pointer types.
6528 const inner = try parseCMulExpr(c, m, scope);
63206529 if (m.next().? != .RParen) {
63216530 try m.fail(c, "unable to translate C expr: expected ')'", .{});
63226531 return error.ParseError;
63236532 }
63246533 break :blk inner;
6325 } else try parseCPrefixOpExpr(c, m, scope);
6534 } else try parseCUnaryExpr(c, m, scope);
63266535
63276536 //(@import("std").meta.sizeof(dest, x))
63286537 const import_fn_call = try c.createBuiltinCall("@import", 1);
......@@ -6344,7 +6553,9 @@ fn parseCPrefixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.
63446553 try m.fail(c, "unable to translate C expr: expected '('", .{});
63456554 return error.ParseError;
63466555 }
6347 const inner = try parseCExpr(c, m, scope);
6556 // C grammar says this should be 'type-name' but we have to
6557 // use parseCMulExpr to correctly handle pointer types.
6558 const inner = try parseCMulExpr(c, m, scope);
63486559 if (m.next().? != .RParen) {
63496560 try m.fail(c, "unable to translate C expr: expected ')'", .{});
63506561 return error.ParseError;
......@@ -6355,9 +6566,13 @@ fn parseCPrefixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.
63556566 builtin_call.rparen_token = try appendToken(c, .RParen, ")");
63566567 return &builtin_call.base;
63576568 },
6569 .PlusPlus, .MinusMinus => {
6570 try m.fail(c, "TODO unary inc/dec expr", .{});
6571 return error.ParseError;
6572 },
63586573 else => {
63596574 m.i -= 1;
6360 return try parseCSuffixOpExpr(c, m, scope);
6575 return try parseCPostfixExpr(c, m, scope);
63616576 },
63626577 }
63636578}
src/type.zig+112
......@@ -89,6 +89,8 @@ pub const Type = extern union {
8989 .anyerror_void_error_union, .error_union => return .ErrorUnion,
9090
9191 .anyframe_T, .@"anyframe" => return .AnyFrame,
92
93 .empty_struct => return .Struct,
9294 }
9395 }
9496
......@@ -439,6 +441,7 @@ pub const Type = extern union {
439441 },
440442 .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
441443 .error_set_single => return self.copyPayloadShallow(allocator, Payload.ErrorSetSingle),
444 .empty_struct => return self.copyPayloadShallow(allocator, Payload.EmptyStruct),
442445 }
443446 }
444447
......@@ -505,6 +508,8 @@ pub const Type = extern union {
505508 .@"null" => return out_stream.writeAll("@Type(.Null)"),
506509 .@"undefined" => return out_stream.writeAll("@Type(.Undefined)"),
507510
511 // TODO this should print the structs name
512 .empty_struct => return out_stream.writeAll("struct {}"),
508513 .@"anyframe" => return out_stream.writeAll("anyframe"),
509514 .anyerror_void_error_union => return out_stream.writeAll("anyerror!void"),
510515 .const_slice_u8 => return out_stream.writeAll("[]const u8"),
......@@ -788,6 +793,7 @@ pub const Type = extern union {
788793 .@"null",
789794 .@"undefined",
790795 .enum_literal,
796 .empty_struct,
791797 => false,
792798 };
793799 }
......@@ -910,6 +916,7 @@ pub const Type = extern union {
910916 .@"null",
911917 .@"undefined",
912918 .enum_literal,
919 .empty_struct,
913920 => unreachable,
914921 };
915922 }
......@@ -932,6 +939,7 @@ pub const Type = extern union {
932939 .@"undefined" => unreachable,
933940 .enum_literal => unreachable,
934941 .single_const_pointer_to_comptime_int => unreachable,
942 .empty_struct => unreachable,
935943
936944 .u8,
937945 .i8,
......@@ -1107,6 +1115,7 @@ pub const Type = extern union {
11071115 .anyerror_void_error_union,
11081116 .error_set,
11091117 .error_set_single,
1118 .empty_struct,
11101119 => false,
11111120
11121121 .single_const_pointer,
......@@ -1181,6 +1190,7 @@ pub const Type = extern union {
11811190 .anyerror_void_error_union,
11821191 .error_set,
11831192 .error_set_single,
1193 .empty_struct,
11841194 => false,
11851195
11861196 .const_slice,
......@@ -1252,6 +1262,7 @@ pub const Type = extern union {
12521262 .anyerror_void_error_union,
12531263 .error_set,
12541264 .error_set_single,
1265 .empty_struct,
12551266 => false,
12561267
12571268 .single_const_pointer,
......@@ -1332,6 +1343,7 @@ pub const Type = extern union {
13321343 .anyerror_void_error_union,
13331344 .error_set,
13341345 .error_set_single,
1346 .empty_struct,
13351347 => false,
13361348
13371349 .pointer => {
......@@ -1407,6 +1419,7 @@ pub const Type = extern union {
14071419 .anyerror_void_error_union,
14081420 .error_set,
14091421 .error_set_single,
1422 .empty_struct,
14101423 => false,
14111424
14121425 .pointer => {
......@@ -1524,6 +1537,7 @@ pub const Type = extern union {
15241537 .anyerror_void_error_union,
15251538 .error_set,
15261539 .error_set_single,
1540 .empty_struct,
15271541 => unreachable,
15281542
15291543 .array => self.cast(Payload.Array).?.elem_type,
......@@ -1651,6 +1665,7 @@ pub const Type = extern union {
16511665 .anyerror_void_error_union,
16521666 .error_set,
16531667 .error_set_single,
1668 .empty_struct,
16541669 => unreachable,
16551670
16561671 .array => self.cast(Payload.Array).?.len,
......@@ -1716,6 +1731,7 @@ pub const Type = extern union {
17161731 .anyerror_void_error_union,
17171732 .error_set,
17181733 .error_set_single,
1734 .empty_struct,
17191735 => unreachable,
17201736
17211737 .single_const_pointer,
......@@ -1798,6 +1814,7 @@ pub const Type = extern union {
17981814 .anyerror_void_error_union,
17991815 .error_set,
18001816 .error_set_single,
1817 .empty_struct,
18011818 => false,
18021819
18031820 .int_signed,
......@@ -1872,6 +1889,7 @@ pub const Type = extern union {
18721889 .anyerror_void_error_union,
18731890 .error_set,
18741891 .error_set_single,
1892 .empty_struct,
18751893 => false,
18761894
18771895 .int_unsigned,
......@@ -1936,6 +1954,7 @@ pub const Type = extern union {
19361954 .anyerror_void_error_union,
19371955 .error_set,
19381956 .error_set_single,
1957 .empty_struct,
19391958 => unreachable,
19401959
19411960 .int_unsigned => .{ .signed = false, .bits = self.cast(Payload.IntUnsigned).?.bits },
......@@ -2018,6 +2037,7 @@ pub const Type = extern union {
20182037 .anyerror_void_error_union,
20192038 .error_set,
20202039 .error_set_single,
2040 .empty_struct,
20212041 => false,
20222042
20232043 .usize,
......@@ -2129,6 +2149,7 @@ pub const Type = extern union {
21292149 .anyerror_void_error_union,
21302150 .error_set,
21312151 .error_set_single,
2152 .empty_struct,
21322153 => unreachable,
21332154 };
21342155 }
......@@ -2206,6 +2227,7 @@ pub const Type = extern union {
22062227 .anyerror_void_error_union,
22072228 .error_set,
22082229 .error_set_single,
2230 .empty_struct,
22092231 => unreachable,
22102232 }
22112233 }
......@@ -2282,6 +2304,7 @@ pub const Type = extern union {
22822304 .anyerror_void_error_union,
22832305 .error_set,
22842306 .error_set_single,
2307 .empty_struct,
22852308 => unreachable,
22862309 }
22872310 }
......@@ -2358,6 +2381,7 @@ pub const Type = extern union {
23582381 .anyerror_void_error_union,
23592382 .error_set,
23602383 .error_set_single,
2384 .empty_struct,
23612385 => unreachable,
23622386 };
23632387 }
......@@ -2431,6 +2455,7 @@ pub const Type = extern union {
24312455 .anyerror_void_error_union,
24322456 .error_set,
24332457 .error_set_single,
2458 .empty_struct,
24342459 => unreachable,
24352460 };
24362461 }
......@@ -2504,6 +2529,7 @@ pub const Type = extern union {
25042529 .anyerror_void_error_union,
25052530 .error_set,
25062531 .error_set_single,
2532 .empty_struct,
25072533 => unreachable,
25082534 };
25092535 }
......@@ -2577,6 +2603,7 @@ pub const Type = extern union {
25772603 .anyerror_void_error_union,
25782604 .error_set,
25792605 .error_set_single,
2606 .empty_struct,
25802607 => false,
25812608 };
25822609 }
......@@ -2636,6 +2663,7 @@ pub const Type = extern union {
26362663 .error_set_single,
26372664 => return null,
26382665
2666 .empty_struct => return Value.initTag(.empty_struct_value),
26392667 .void => return Value.initTag(.void_value),
26402668 .noreturn => return Value.initTag(.unreachable_value),
26412669 .@"null" => return Value.initTag(.null_value),
......@@ -2743,6 +2771,7 @@ pub const Type = extern union {
27432771 .anyerror_void_error_union,
27442772 .error_set,
27452773 .error_set_single,
2774 .empty_struct,
27462775 => return false,
27472776
27482777 .c_const_pointer,
......@@ -2760,6 +2789,80 @@ pub const Type = extern union {
27602789 (self.isSinglePointer() and self.elemType().zigTypeTag() == .Array);
27612790 }
27622791
2792 /// Asserts that the type is a container. (note: ErrorSet is not a container).
2793 pub fn getContainerScope(self: Type) *Module.Scope.Container {
2794 return switch (self.tag()) {
2795 .f16,
2796 .f32,
2797 .f64,
2798 .f128,
2799 .c_longdouble,
2800 .comptime_int,
2801 .comptime_float,
2802 .u8,
2803 .i8,
2804 .u16,
2805 .i16,
2806 .u32,
2807 .i32,
2808 .u64,
2809 .i64,
2810 .usize,
2811 .isize,
2812 .c_short,
2813 .c_ushort,
2814 .c_int,
2815 .c_uint,
2816 .c_long,
2817 .c_ulong,
2818 .c_longlong,
2819 .c_ulonglong,
2820 .bool,
2821 .type,
2822 .anyerror,
2823 .fn_noreturn_no_args,
2824 .fn_void_no_args,
2825 .fn_naked_noreturn_no_args,
2826 .fn_ccc_void_no_args,
2827 .function,
2828 .single_const_pointer_to_comptime_int,
2829 .const_slice_u8,
2830 .c_void,
2831 .void,
2832 .noreturn,
2833 .@"null",
2834 .@"undefined",
2835 .int_unsigned,
2836 .int_signed,
2837 .array,
2838 .array_sentinel,
2839 .array_u8,
2840 .array_u8_sentinel_0,
2841 .single_const_pointer,
2842 .single_mut_pointer,
2843 .many_const_pointer,
2844 .many_mut_pointer,
2845 .const_slice,
2846 .mut_slice,
2847 .optional,
2848 .optional_single_mut_pointer,
2849 .optional_single_const_pointer,
2850 .enum_literal,
2851 .error_union,
2852 .@"anyframe",
2853 .anyframe_T,
2854 .anyerror_void_error_union,
2855 .error_set,
2856 .error_set_single,
2857 .c_const_pointer,
2858 .c_mut_pointer,
2859 .pointer,
2860 => unreachable,
2861
2862 .empty_struct => self.cast(Type.Payload.EmptyStruct).?.scope,
2863 };
2864 }
2865
27632866 /// This enum does not directly correspond to `std.builtin.TypeId` because
27642867 /// it has extra enum tags in it, as a way of using less memory. For example,
27652868 /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types
......@@ -2835,6 +2938,7 @@ pub const Type = extern union {
28352938 anyframe_T,
28362939 error_set,
28372940 error_set_single,
2941 empty_struct,
28382942
28392943 pub const last_no_payload_tag = Tag.const_slice_u8;
28402944 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
......@@ -2942,6 +3046,14 @@ pub const Type = extern union {
29423046 /// memory is owned by `Module`
29433047 name: []const u8,
29443048 };
3049
3050 /// Mostly used for namespace like structs with zero fields.
3051 /// Most commonly used for files.
3052 pub const EmptyStruct = struct {
3053 base: Payload = .{ .tag = .empty_struct },
3054
3055 scope: *Module.Scope.Container,
3056 };
29453057 };
29463058};
29473059
src/value.zig+16-1
......@@ -68,6 +68,7 @@ pub const Value = extern union {
6868 one,
6969 void_value,
7070 unreachable_value,
71 empty_struct_value,
7172 empty_array,
7273 null_value,
7374 bool_true,
......@@ -182,6 +183,7 @@ pub const Value = extern union {
182183 .null_value,
183184 .bool_true,
184185 .bool_false,
186 .empty_struct_value,
185187 => unreachable,
186188
187189 .ty => {
......@@ -312,6 +314,8 @@ pub const Value = extern union {
312314 .enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"),
313315 .anyframe_type => return out_stream.writeAll("anyframe"),
314316
317 // TODO this should print `NAME{}`
318 .empty_struct_value => return out_stream.writeAll("struct {}{}"),
315319 .null_value => return out_stream.writeAll("null"),
316320 .undef => return out_stream.writeAll("undefined"),
317321 .zero => return out_stream.writeAll("0"),
......@@ -475,6 +479,7 @@ pub const Value = extern union {
475479 .float_128,
476480 .enum_literal,
477481 .@"error",
482 .empty_struct_value,
478483 => unreachable,
479484 };
480485 }
......@@ -543,6 +548,7 @@ pub const Value = extern union {
543548 .enum_literal,
544549 .error_set,
545550 .@"error",
551 .empty_struct_value,
546552 => unreachable,
547553
548554 .undef => unreachable,
......@@ -626,6 +632,7 @@ pub const Value = extern union {
626632 .enum_literal,
627633 .error_set,
628634 .@"error",
635 .empty_struct_value,
629636 => unreachable,
630637
631638 .undef => unreachable,
......@@ -709,6 +716,7 @@ pub const Value = extern union {
709716 .enum_literal,
710717 .error_set,
711718 .@"error",
719 .empty_struct_value,
712720 => unreachable,
713721
714722 .undef => unreachable,
......@@ -820,6 +828,7 @@ pub const Value = extern union {
820828 .enum_literal,
821829 .error_set,
822830 .@"error",
831 .empty_struct_value,
823832 => unreachable,
824833
825834 .zero,
......@@ -833,7 +842,7 @@ pub const Value = extern union {
833842 .int_u64 => {
834843 const x = self.cast(Payload.Int_u64).?.int;
835844 if (x == 0) return 0;
836 return std.math.log2(x) + 1;
845 return @intCast(usize, std.math.log2(x) + 1);
837846 },
838847 .int_i64 => {
839848 @panic("TODO implement i64 intBitCountTwosComp");
......@@ -907,6 +916,7 @@ pub const Value = extern union {
907916 .enum_literal,
908917 .error_set,
909918 .@"error",
919 .empty_struct_value,
910920 => unreachable,
911921
912922 .zero,
......@@ -1078,6 +1088,7 @@ pub const Value = extern union {
10781088 .enum_literal,
10791089 .error_set,
10801090 .@"error",
1091 .empty_struct_value,
10811092 => unreachable,
10821093
10831094 .zero,
......@@ -1152,6 +1163,7 @@ pub const Value = extern union {
11521163 .enum_literal,
11531164 .error_set,
11541165 .@"error",
1166 .empty_struct_value,
11551167 => unreachable,
11561168
11571169 .zero,
......@@ -1300,6 +1312,7 @@ pub const Value = extern union {
13001312 .enum_literal,
13011313 .error_set,
13021314 .@"error",
1315 .empty_struct_value,
13031316 => unreachable,
13041317
13051318 .ref_val => self.cast(Payload.RefVal).?.val,
......@@ -1383,6 +1396,7 @@ pub const Value = extern union {
13831396 .enum_literal,
13841397 .error_set,
13851398 .@"error",
1399 .empty_struct_value,
13861400 => unreachable,
13871401
13881402 .empty_array => unreachable, // out of bounds array index
......@@ -1483,6 +1497,7 @@ pub const Value = extern union {
14831497 .enum_literal,
14841498 .error_set,
14851499 .@"error",
1500 .empty_struct_value,
14861501 => false,
14871502
14881503 .undef => unreachable,
src/zig_llvm.cpp+28
......@@ -1126,6 +1126,34 @@ LLVMValueRef ZigLLVMBuildAtomicRMW(LLVMBuilderRef B, enum ZigLLVM_AtomicRMWBinOp
11261126 singleThread ? SyncScope::SingleThread : SyncScope::System));
11271127}
11281128
1129LLVMValueRef ZigLLVMBuildAndReduce(LLVMBuilderRef B, LLVMValueRef Val) {
1130 return wrap(unwrap(B)->CreateAndReduce(unwrap(Val)));
1131}
1132
1133LLVMValueRef ZigLLVMBuildOrReduce(LLVMBuilderRef B, LLVMValueRef Val) {
1134 return wrap(unwrap(B)->CreateOrReduce(unwrap(Val)));
1135}
1136
1137LLVMValueRef ZigLLVMBuildXorReduce(LLVMBuilderRef B, LLVMValueRef Val) {
1138 return wrap(unwrap(B)->CreateXorReduce(unwrap(Val)));
1139}
1140
1141LLVMValueRef ZigLLVMBuildIntMaxReduce(LLVMBuilderRef B, LLVMValueRef Val, bool is_signed) {
1142 return wrap(unwrap(B)->CreateIntMaxReduce(unwrap(Val), is_signed));
1143}
1144
1145LLVMValueRef ZigLLVMBuildIntMinReduce(LLVMBuilderRef B, LLVMValueRef Val, bool is_signed) {
1146 return wrap(unwrap(B)->CreateIntMinReduce(unwrap(Val), is_signed));
1147}
1148
1149LLVMValueRef ZigLLVMBuildFPMaxReduce(LLVMBuilderRef B, LLVMValueRef Val) {
1150 return wrap(unwrap(B)->CreateFPMaxReduce(unwrap(Val)));
1151}
1152
1153LLVMValueRef ZigLLVMBuildFPMinReduce(LLVMBuilderRef B, LLVMValueRef Val) {
1154 return wrap(unwrap(B)->CreateFPMinReduce(unwrap(Val)));
1155}
1156
11291157static_assert((Triple::ArchType)ZigLLVM_UnknownArch == Triple::UnknownArch, "");
11301158static_assert((Triple::ArchType)ZigLLVM_arm == Triple::arm, "");
11311159static_assert((Triple::ArchType)ZigLLVM_armeb == Triple::armeb, "");
src/zig_llvm.h+8
......@@ -455,6 +455,14 @@ LLVMValueRef ZigLLVMBuildAtomicRMW(LLVMBuilderRef B, enum ZigLLVM_AtomicRMWBinOp
455455 LLVMValueRef PTR, LLVMValueRef Val,
456456 LLVMAtomicOrdering ordering, LLVMBool singleThread);
457457
458LLVMValueRef ZigLLVMBuildAndReduce(LLVMBuilderRef B, LLVMValueRef Val);
459LLVMValueRef ZigLLVMBuildOrReduce(LLVMBuilderRef B, LLVMValueRef Val);
460LLVMValueRef ZigLLVMBuildXorReduce(LLVMBuilderRef B, LLVMValueRef Val);
461LLVMValueRef ZigLLVMBuildIntMaxReduce(LLVMBuilderRef B, LLVMValueRef Val, bool is_signed);
462LLVMValueRef ZigLLVMBuildIntMinReduce(LLVMBuilderRef B, LLVMValueRef Val, bool is_signed);
463LLVMValueRef ZigLLVMBuildFPMaxReduce(LLVMBuilderRef B, LLVMValueRef Val);
464LLVMValueRef ZigLLVMBuildFPMinReduce(LLVMBuilderRef B, LLVMValueRef Val);
465
458466#define ZigLLVM_DIFlags_Zero 0U
459467#define ZigLLVM_DIFlags_Private 1U
460468#define ZigLLVM_DIFlags_Protected 2U
src/zir.zig+4
......@@ -161,6 +161,8 @@ pub const Inst = struct {
161161 @"fn",
162162 /// Returns a function type.
163163 fntype,
164 /// @import(operand)
165 import,
164166 /// Integer literal.
165167 int,
166168 /// Convert an integer value to another integer type, asserting that the destination type
......@@ -315,6 +317,7 @@ pub const Inst = struct {
315317 .ensure_err_payload_void,
316318 .anyframe_type,
317319 .bitnot,
320 .import,
318321 => UnOp,
319322
320323 .add,
......@@ -489,6 +492,7 @@ pub const Inst = struct {
489492 .error_set,
490493 .slice,
491494 .slice_start,
495 .import,
492496 => false,
493497
494498 .@"break",
src/zir_sema.zig+32
......@@ -134,6 +134,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
134134 .error_set => return analyzeInstErrorSet(mod, scope, old_inst.castTag(.error_set).?),
135135 .slice => return analyzeInstSlice(mod, scope, old_inst.castTag(.slice).?),
136136 .slice_start => return analyzeInstSliceStart(mod, scope, old_inst.castTag(.slice_start).?),
137 .import => return analyzeInstImport(mod, scope, old_inst.castTag(.import).?),
137138 }
138139}
139140
......@@ -1047,6 +1048,19 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr
10471048 .val = Value.initPayload(&ref_payload.base),
10481049 });
10491050 },
1051 .Struct => {
1052 const container_scope = child_type.getContainerScope();
1053 if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
1054 // TODO if !decl.is_pub and inDifferentFiles() "{} is private"
1055 return mod.analyzeDeclRef(scope, fieldptr.base.src, decl);
1056 }
1057
1058 if (&container_scope.file_scope.base == mod.root_scope) {
1059 return mod.fail(scope, fieldptr.base.src, "root source file has no member called '{}'", .{field_name});
1060 } else {
1061 return mod.fail(scope, fieldptr.base.src, "container '{}' has no member called '{}'", .{ child_type, field_name });
1062 }
1063 },
10501064 else => return mod.fail(scope, fieldptr.base.src, "type '{}' does not support field access", .{child_type}),
10511065 }
10521066 },
......@@ -1190,6 +1204,24 @@ fn analyzeInstSliceStart(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) Inn
11901204 return mod.analyzeSlice(scope, inst.base.src, array_ptr, start, null, null);
11911205}
11921206
1207fn analyzeInstImport(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
1208 const operand = try resolveConstString(mod, scope, inst.positionals.operand);
1209
1210 const file_scope = mod.analyzeImport(scope, inst.base.src, operand) catch |err| switch (err) {
1211 // error.ImportOutsidePkgPath => {
1212 // return mod.fail(scope, inst.base.src, "import of file outside package path: '{}'", .{operand});
1213 // },
1214 error.FileNotFound => {
1215 return mod.fail(scope, inst.base.src, "unable to find '{}'", .{operand});
1216 },
1217 else => {
1218 // TODO user friendly error to string
1219 return mod.fail(scope, inst.base.src, "unable to open '{}': {}", .{ operand, @errorName(err) });
1220 },
1221 };
1222 return mod.constType(scope, inst.base.src, file_scope.root_container.ty);
1223}
1224
11931225fn analyzeInstShl(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
11941226 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstShl", .{});
11951227}
test/compile_errors.zig+182-47
......@@ -2,20 +2,175 @@ const tests = @import("tests.zig");
22const std = @import("std");
33
44pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.add("slice sentinel mismatch",
5 cases.add("@Type for exhaustive enum with undefined tag type",
6 \\const TypeInfo = @import("builtin").TypeInfo;
7 \\const Tag = @Type(.{
8 \\ .Enum = .{
9 \\ .layout = .Auto,
10 \\ .tag_type = undefined,
11 \\ .fields = &[_]TypeInfo.EnumField{},
12 \\ .decls = &[_]TypeInfo.Declaration{},
13 \\ .is_exhaustive = false,
14 \\ },
15 \\});
616 \\export fn entry() void {
7 \\ const x = @import("std").meta.Vector(3, f32){ 25, 75, 5, 0 };
17 \\ _ = @intToEnum(Tag, 0);
818 \\}
919 , &[_][]const u8{
10 "tmp.zig:2:62: error: index 3 outside vector of size 3",
20 "tmp.zig:2:20: error: use of undefined value here causes undefined behavior",
1121 });
1222
13 cases.add("slice sentinel mismatch",
23 cases.add("extern struct with non-extern-compatible integer tag type",
24 \\pub const E = enum(u31) { A, B, C };
25 \\pub const S = extern struct {
26 \\ e: E,
27 \\};
1428 \\export fn entry() void {
15 \\ const y: [:1]const u8 = &[_:2]u8{ 1, 2 };
29 \\ const s: S = undefined;
1630 \\}
1731 , &[_][]const u8{
18 "tmp.zig:2:37: error: expected type '[:1]const u8', found '*const [2:2]u8'",
32 "tmp.zig:3:5: error: extern structs cannot contain fields of type 'E'",
33 });
34
35 cases.add("@Type for exhaustive enum with non-integer tag type",
36 \\const TypeInfo = @import("builtin").TypeInfo;
37 \\const Tag = @Type(.{
38 \\ .Enum = .{
39 \\ .layout = .Auto,
40 \\ .tag_type = bool,
41 \\ .fields = &[_]TypeInfo.EnumField{},
42 \\ .decls = &[_]TypeInfo.Declaration{},
43 \\ .is_exhaustive = false,
44 \\ },
45 \\});
46 \\export fn entry() void {
47 \\ _ = @intToEnum(Tag, 0);
48 \\}
49 , &[_][]const u8{
50 "tmp.zig:2:20: error: TypeInfo.Enum.tag_type must be an integer type, not 'bool'",
51 });
52
53 cases.add("extern struct with extern-compatible but inferred integer tag type",
54 \\pub const E = enum {
55 \\@"0",@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"10",@"11",@"12",
56 \\@"13",@"14",@"15",@"16",@"17",@"18",@"19",@"20",@"21",@"22",@"23",
57 \\@"24",@"25",@"26",@"27",@"28",@"29",@"30",@"31",@"32",@"33",@"34",
58 \\@"35",@"36",@"37",@"38",@"39",@"40",@"41",@"42",@"43",@"44",@"45",
59 \\@"46",@"47",@"48",@"49",@"50",@"51",@"52",@"53",@"54",@"55",@"56",
60 \\@"57",@"58",@"59",@"60",@"61",@"62",@"63",@"64",@"65",@"66",@"67",
61 \\@"68",@"69",@"70",@"71",@"72",@"73",@"74",@"75",@"76",@"77",@"78",
62 \\@"79",@"80",@"81",@"82",@"83",@"84",@"85",@"86",@"87",@"88",@"89",
63 \\@"90",@"91",@"92",@"93",@"94",@"95",@"96",@"97",@"98",@"99",@"100",
64 \\@"101",@"102",@"103",@"104",@"105",@"106",@"107",@"108",@"109",
65 \\@"110",@"111",@"112",@"113",@"114",@"115",@"116",@"117",@"118",
66 \\@"119",@"120",@"121",@"122",@"123",@"124",@"125",@"126",@"127",
67 \\@"128",@"129",@"130",@"131",@"132",@"133",@"134",@"135",@"136",
68 \\@"137",@"138",@"139",@"140",@"141",@"142",@"143",@"144",@"145",
69 \\@"146",@"147",@"148",@"149",@"150",@"151",@"152",@"153",@"154",
70 \\@"155",@"156",@"157",@"158",@"159",@"160",@"161",@"162",@"163",
71 \\@"164",@"165",@"166",@"167",@"168",@"169",@"170",@"171",@"172",
72 \\@"173",@"174",@"175",@"176",@"177",@"178",@"179",@"180",@"181",
73 \\@"182",@"183",@"184",@"185",@"186",@"187",@"188",@"189",@"190",
74 \\@"191",@"192",@"193",@"194",@"195",@"196",@"197",@"198",@"199",
75 \\@"200",@"201",@"202",@"203",@"204",@"205",@"206",@"207",@"208",
76 \\@"209",@"210",@"211",@"212",@"213",@"214",@"215",@"216",@"217",
77 \\@"218",@"219",@"220",@"221",@"222",@"223",@"224",@"225",@"226",
78 \\@"227",@"228",@"229",@"230",@"231",@"232",@"233",@"234",@"235",
79 \\@"236",@"237",@"238",@"239",@"240",@"241",@"242",@"243",@"244",
80 \\@"245",@"246",@"247",@"248",@"249",@"250",@"251",@"252",@"253",
81 \\@"254",@"255"
82 \\};
83 \\pub const S = extern struct {
84 \\ e: E,
85 \\};
86 \\export fn entry() void {
87 \\ if (@TagType(E) != u8) @compileError("did not infer u8 tag type");
88 \\ const s: S = undefined;
89 \\}
90 , &[_][]const u8{
91 "tmp.zig:31:5: error: extern structs cannot contain fields of type 'E'",
92 });
93
94 cases.add("@Type for tagged union with extra enum field",
95 \\const TypeInfo = @import("builtin").TypeInfo;
96 \\const Tag = @Type(.{
97 \\ .Enum = .{
98 \\ .layout = .Auto,
99 \\ .tag_type = u2,
100 \\ .fields = &[_]TypeInfo.EnumField{
101 \\ .{ .name = "signed", .value = 0 },
102 \\ .{ .name = "unsigned", .value = 1 },
103 \\ .{ .name = "arst", .value = 2 },
104 \\ },
105 \\ .decls = &[_]TypeInfo.Declaration{},
106 \\ .is_exhaustive = true,
107 \\ },
108 \\});
109 \\const Tagged = @Type(.{
110 \\ .Union = .{
111 \\ .layout = .Auto,
112 \\ .tag_type = Tag,
113 \\ .fields = &[_]TypeInfo.UnionField{
114 \\ .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) },
115 \\ .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) },
116 \\ },
117 \\ .decls = &[_]TypeInfo.Declaration{},
118 \\ },
119 \\});
120 \\export fn entry() void {
121 \\ var tagged = Tagged{ .signed = -1 };
122 \\ tagged = .{ .unsigned = 1 };
123 \\}
124 , &[_][]const u8{
125 "tmp.zig:15:23: error: enum field missing: 'arst'",
126 "tmp.zig:27:24: note: referenced here",
127 });
128 cases.add("@Type(.Fn) with is_generic = true",
129 \\const Foo = @Type(.{
130 \\ .Fn = .{
131 \\ .calling_convention = .Unspecified,
132 \\ .alignment = 0,
133 \\ .is_generic = true,
134 \\ .is_var_args = false,
135 \\ .return_type = u0,
136 \\ .args = &[_]@import("builtin").TypeInfo.FnArg{},
137 \\ },
138 \\});
139 \\comptime { _ = Foo; }
140 , &[_][]const u8{
141 "tmp.zig:1:20: error: TypeInfo.Fn.is_generic must be false for @Type",
142 });
143
144 cases.add("@Type(.Fn) with is_var_args = true and non-C callconv",
145 \\const Foo = @Type(.{
146 \\ .Fn = .{
147 \\ .calling_convention = .Unspecified,
148 \\ .alignment = 0,
149 \\ .is_generic = false,
150 \\ .is_var_args = true,
151 \\ .return_type = u0,
152 \\ .args = &[_]@import("builtin").TypeInfo.FnArg{},
153 \\ },
154 \\});
155 \\comptime { _ = Foo; }
156 , &[_][]const u8{
157 "tmp.zig:1:20: error: varargs functions must have C calling convention",
158 });
159
160 cases.add("@Type(.Fn) with return_type = null",
161 \\const Foo = @Type(.{
162 \\ .Fn = .{
163 \\ .calling_convention = .Unspecified,
164 \\ .alignment = 0,
165 \\ .is_generic = false,
166 \\ .is_var_args = false,
167 \\ .return_type = null,
168 \\ .args = &[_]@import("builtin").TypeInfo.FnArg{},
169 \\ },
170 \\});
171 \\comptime { _ = Foo; }
172 , &[_][]const u8{
173 "tmp.zig:1:20: error: TypeInfo.Fn.return_type must be non-null for @Type",
19174 });
20175
21176 cases.add("@Type for union with opaque field",
......@@ -25,7 +180,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
25180 \\ .layout = .Auto,
26181 \\ .tag_type = null,
27182 \\ .fields = &[_]TypeInfo.UnionField{
28 \\ .{ .name = "foo", .field_type = @Type(.Opaque) },
183 \\ .{ .name = "foo", .field_type = @Type(.Opaque), .alignment = 1 },
29184 \\ },
30185 \\ .decls = &[_]TypeInfo.Declaration{},
31186 \\ },
......@@ -38,6 +193,22 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
38193 "tmp.zig:13:17: note: referenced here",
39194 });
40195
196 cases.add("slice sentinel mismatch",
197 \\export fn entry() void {
198 \\ const x = @import("std").meta.Vector(3, f32){ 25, 75, 5, 0 };
199 \\}
200 , &[_][]const u8{
201 "tmp.zig:2:62: error: index 3 outside vector of size 3",
202 });
203
204 cases.add("slice sentinel mismatch",
205 \\export fn entry() void {
206 \\ const y: [:1]const u8 = &[_:2]u8{ 1, 2 };
207 \\}
208 , &[_][]const u8{
209 "tmp.zig:2:37: error: expected type '[:1]const u8', found '*const [2:2]u8'",
210 });
211
41212 cases.add("@Type for union with zero fields",
42213 \\const TypeInfo = @import("builtin").TypeInfo;
43214 \\const Untagged = @Type(.{
......@@ -94,9 +265,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
94265 \\ .layout = .Auto,
95266 \\ .tag_type = Tag,
96267 \\ .fields = &[_]TypeInfo.UnionField{
97 \\ .{ .name = "signed", .field_type = i32 },
98 \\ .{ .name = "unsigned", .field_type = u32 },
99 \\ .{ .name = "arst", .field_type = f32 },
268 \\ .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) },
269 \\ .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) },
270 \\ .{ .name = "arst", .field_type = f32, .alignment = @alignOf(f32) },
100271 \\ },
101272 \\ .decls = &[_]TypeInfo.Declaration{},
102273 \\ },
......@@ -111,42 +282,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
111282 "tmp.zig:27:24: note: referenced here",
112283 });
113284
114 cases.add("@Type for tagged union with extra enum field",
115 \\const TypeInfo = @import("builtin").TypeInfo;
116 \\const Tag = @Type(.{
117 \\ .Enum = .{
118 \\ .layout = .Auto,
119 \\ .tag_type = u2,
120 \\ .fields = &[_]TypeInfo.EnumField{
121 \\ .{ .name = "signed", .value = 0 },
122 \\ .{ .name = "unsigned", .value = 1 },
123 \\ .{ .name = "arst", .field_type = 2 },
124 \\ },
125 \\ .decls = &[_]TypeInfo.Declaration{},
126 \\ .is_exhaustive = true,
127 \\ },
128 \\});
129 \\const Tagged = @Type(.{
130 \\ .Union = .{
131 \\ .layout = .Auto,
132 \\ .tag_type = Tag,
133 \\ .fields = &[_]TypeInfo.UnionField{
134 \\ .{ .name = "signed", .field_type = i32 },
135 \\ .{ .name = "unsigned", .field_type = u32 },
136 \\ },
137 \\ .decls = &[_]TypeInfo.Declaration{},
138 \\ },
139 \\});
140 \\export fn entry() void {
141 \\ var tagged = Tagged{ .signed = -1 };
142 \\ tagged = .{ .unsigned = 1 };
143 \\}
144 , &[_][]const u8{
145 "tmp.zig:9:32: error: no member named 'field_type' in struct 'std.builtin.EnumField'",
146 "tmp.zig:18:21: note: referenced here",
147 "tmp.zig:27:18: note: referenced here",
148 });
149
150285 cases.add("@Type with undefined",
151286 \\comptime {
152287 \\ _ = @Type(.{ .Array = .{ .len = 0, .child = u8, .sentinel = undefined } });
......@@ -7556,7 +7691,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
75567691 });
75577692
75587693 cases.add( // fixed bug #2032
7559 "compile diagnostic string for top level decl type",
7694 "compile diagnostic string for top level decl type",
75607695 \\export fn entry() void {
75617696 \\ var foo: u32 = @This(){};
75627697 \\}
test/stage1/behavior/bugs/1467.zig created+7
......@@ -0,0 +1,7 @@
1pub const E = enum(u32) { A, B, C };
2pub const S = extern struct {
3 e: E,
4};
5test "bug 1467" {
6 const s: S = undefined;
7}
test/stage1/behavior/type.zig+35-8
......@@ -320,8 +320,8 @@ test "Type.Union" {
320320 .layout = .Auto,
321321 .tag_type = null,
322322 .fields = &[_]TypeInfo.UnionField{
323 .{ .name = "int", .field_type = i32 },
324 .{ .name = "float", .field_type = f32 },
323 .{ .name = "int", .field_type = i32, .alignment = @alignOf(f32) },
324 .{ .name = "float", .field_type = f32, .alignment = @alignOf(f32) },
325325 },
326326 .decls = &[_]TypeInfo.Declaration{},
327327 },
......@@ -336,8 +336,8 @@ test "Type.Union" {
336336 .layout = .Packed,
337337 .tag_type = null,
338338 .fields = &[_]TypeInfo.UnionField{
339 .{ .name = "signed", .field_type = i32 },
340 .{ .name = "unsigned", .field_type = u32 },
339 .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) },
340 .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) },
341341 },
342342 .decls = &[_]TypeInfo.Declaration{},
343343 },
......@@ -363,8 +363,8 @@ test "Type.Union" {
363363 .layout = .Auto,
364364 .tag_type = Tag,
365365 .fields = &[_]TypeInfo.UnionField{
366 .{ .name = "signed", .field_type = i32 },
367 .{ .name = "unsigned", .field_type = u32 },
366 .{ .name = "signed", .field_type = i32, .alignment = @alignOf(i32) },
367 .{ .name = "unsigned", .field_type = u32, .alignment = @alignOf(u32) },
368368 },
369369 .decls = &[_]TypeInfo.Declaration{},
370370 },
......@@ -392,7 +392,7 @@ test "Type.Union from Type.Enum" {
392392 .layout = .Auto,
393393 .tag_type = Tag,
394394 .fields = &[_]TypeInfo.UnionField{
395 .{ .name = "working_as_expected", .field_type = u32 },
395 .{ .name = "working_as_expected", .field_type = u32, .alignment = @alignOf(u32) },
396396 },
397397 .decls = &[_]TypeInfo.Declaration{},
398398 },
......@@ -408,7 +408,7 @@ test "Type.Union from regular enum" {
408408 .layout = .Auto,
409409 .tag_type = E,
410410 .fields = &[_]TypeInfo.UnionField{
411 .{ .name = "working_as_expected", .field_type = u32 },
411 .{ .name = "working_as_expected", .field_type = u32, .alignment = @alignOf(u32) },
412412 },
413413 .decls = &[_]TypeInfo.Declaration{},
414414 },
......@@ -416,3 +416,30 @@ test "Type.Union from regular enum" {
416416 _ = T;
417417 _ = @typeInfo(T).Union;
418418}
419
420test "Type.Fn" {
421 // wasm doesn't support align attributes on functions
422 if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;
423
424 const foo = struct {
425 fn func(a: usize, b: bool) align(4) callconv(.C) usize {
426 return 0;
427 }
428 }.func;
429 const Foo = @Type(@typeInfo(@TypeOf(foo)));
430 const foo_2: Foo = foo;
431}
432
433test "Type.BoundFn" {
434 // wasm doesn't support align attributes on functions
435 if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;
436
437 const TestStruct = packed struct {
438 pub fn foo(self: *const @This()) align(4) callconv(.Unspecified) void {}
439 };
440 const test_instance: TestStruct = undefined;
441 testing.expect(std.meta.eql(
442 @typeName(@TypeOf(test_instance.foo)),
443 @typeName(@Type(@typeInfo(@TypeOf(test_instance.foo)))),
444 ));
445}
test/stage1/behavior/type_info.zig+19-2
......@@ -211,7 +211,9 @@ fn testUnion() void {
211211 expect(notag_union_info.Union.tag_type == null);
212212 expect(notag_union_info.Union.layout == .Auto);
213213 expect(notag_union_info.Union.fields.len == 2);
214 expect(notag_union_info.Union.fields[0].alignment == @alignOf(void));
214215 expect(notag_union_info.Union.fields[1].field_type == u32);
216 expect(notag_union_info.Union.fields[1].alignment == @alignOf(u32));
215217
216218 const TestExternUnion = extern union {
217219 foo: *c_void,
......@@ -229,13 +231,18 @@ test "type info: struct info" {
229231}
230232
231233fn testStruct() void {
234 const unpacked_struct_info = @typeInfo(TestUnpackedStruct);
235 expect(unpacked_struct_info.Struct.fields[0].alignment == @alignOf(u32));
236
232237 const struct_info = @typeInfo(TestStruct);
233238 expect(struct_info == .Struct);
234239 expect(struct_info.Struct.layout == .Packed);
235240 expect(struct_info.Struct.fields.len == 4);
241 expect(struct_info.Struct.fields[0].alignment == 2 * @alignOf(usize));
236242 expect(struct_info.Struct.fields[2].field_type == *TestStruct);
237243 expect(struct_info.Struct.fields[2].default_value == null);
238244 expect(struct_info.Struct.fields[3].default_value.? == 4);
245 expect(struct_info.Struct.fields[3].alignment == 1);
239246 expect(struct_info.Struct.decls.len == 2);
240247 expect(struct_info.Struct.decls[0].is_pub);
241248 expect(!struct_info.Struct.decls[0].data.Fn.is_extern);
......@@ -244,8 +251,12 @@ fn testStruct() void {
244251 expect(struct_info.Struct.decls[0].data.Fn.fn_type == fn (*const TestStruct) void);
245252}
246253
254const TestUnpackedStruct = struct {
255 fieldA: u32 = 4,
256};
257
247258const TestStruct = packed struct {
248 fieldA: usize,
259 fieldA: usize align(2 * @alignOf(usize)),
249260 fieldB: void,
250261 fieldC: *Self,
251262 fieldD: u32 = 4,
......@@ -255,6 +266,8 @@ const TestStruct = packed struct {
255266};
256267
257268test "type info: function type info" {
269 // wasm doesn't support align attributes on functions
270 if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;
258271 testFunction();
259272 comptime testFunction();
260273}
......@@ -262,11 +275,14 @@ test "type info: function type info" {
262275fn testFunction() void {
263276 const fn_info = @typeInfo(@TypeOf(foo));
264277 expect(fn_info == .Fn);
278 expect(fn_info.Fn.alignment == 0);
265279 expect(fn_info.Fn.calling_convention == .C);
266280 expect(!fn_info.Fn.is_generic);
267281 expect(fn_info.Fn.args.len == 2);
268282 expect(fn_info.Fn.is_var_args);
269283 expect(fn_info.Fn.return_type.? == usize);
284 const fn_aligned_info = @typeInfo(@TypeOf(fooAligned));
285 expect(fn_aligned_info.Fn.alignment == 4);
270286
271287 const test_instance: TestStruct = undefined;
272288 const bound_fn_info = @typeInfo(@TypeOf(test_instance.foo));
......@@ -274,7 +290,8 @@ fn testFunction() void {
274290 expect(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct);
275291}
276292
277extern fn foo(a: usize, b: bool, ...) usize;
293extern fn foo(a: usize, b: bool, ...) callconv(.C) usize;
294extern fn fooAligned(a: usize, b: bool, ...) align(4) callconv(.C) usize;
278295
279296test "typeInfo with comptime parameter in struct fn def" {
280297 const S = struct {
test/stage1/behavior/vector.zig+40
......@@ -484,3 +484,43 @@ test "vector shift operators" {
484484 S.doTheTest();
485485 comptime S.doTheTest();
486486}
487
488test "vector reduce operation" {
489 const S = struct {
490 fn doTheTestReduce(comptime op: builtin.ReduceOp, x: anytype, expected: anytype) void {
491 const N = @typeInfo(@TypeOf(x)).Array.len;
492 const TX = @typeInfo(@TypeOf(x)).Array.child;
493
494 var r = @reduce(op, @as(Vector(N, TX), x));
495 expectEqual(expected, r);
496 }
497 fn doTheTest() void {
498 doTheTestReduce(.And, [4]bool{ true, false, true, true }, @as(bool, false));
499 doTheTestReduce(.Or, [4]bool{ false, true, false, false }, @as(bool, true));
500 doTheTestReduce(.Xor, [4]bool{ true, true, true, false }, @as(bool, true));
501
502 doTheTestReduce(.And, [4]u1{ 1, 0, 1, 1 }, @as(u1, 0));
503 doTheTestReduce(.Or, [4]u1{ 0, 1, 0, 0 }, @as(u1, 1));
504 doTheTestReduce(.Xor, [4]u1{ 1, 1, 1, 0 }, @as(u1, 1));
505
506 doTheTestReduce(.And, [4]u32{ 0xffffffff, 0xffff5555, 0xaaaaffff, 0x10101010 }, @as(u32, 0x1010));
507 doTheTestReduce(.Or, [4]u32{ 0xffff0000, 0xff00, 0xf0, 0xf }, ~@as(u32, 0));
508 doTheTestReduce(.Xor, [4]u32{ 0x00000000, 0x33333333, 0x88888888, 0x44444444 }, ~@as(u32, 0));
509
510 doTheTestReduce(.Min, [4]i32{ 1234567, -386, 0, 3 }, @as(i32, -386));
511 doTheTestReduce(.Max, [4]i32{ 1234567, -386, 0, 3 }, @as(i32, 1234567));
512
513 doTheTestReduce(.Min, [4]u32{ 99, 9999, 9, 99999 }, @as(u32, 9));
514 doTheTestReduce(.Max, [4]u32{ 99, 9999, 9, 99999 }, @as(u32, 99999));
515
516 doTheTestReduce(.Min, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, -100.0));
517 doTheTestReduce(.Max, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, 10.0e9));
518
519 doTheTestReduce(.Min, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, -100.0));
520 doTheTestReduce(.Max, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, 10.0e9));
521 }
522 };
523
524 S.doTheTest();
525 comptime S.doTheTest();
526}
test/stage2/arm.zig created+116
......@@ -0,0 +1,116 @@
1const std = @import("std");
2const TestContext = @import("../../src/test.zig").TestContext;
3
4const linux_arm = std.zig.CrossTarget{
5 .cpu_arch = .arm,
6 .os_tag = .linux,
7};
8
9pub fn addCases(ctx: *TestContext) !void {
10 {
11 var case = ctx.exe("hello world", linux_arm);
12 // Regular old hello world
13 case.addCompareOutput(
14 \\export fn _start() noreturn {
15 \\ print();
16 \\ exit();
17 \\}
18 \\
19 \\fn print() void {
20 \\ asm volatile ("svc #0"
21 \\ :
22 \\ : [number] "{r7}" (4),
23 \\ [arg1] "{r0}" (1),
24 \\ [arg2] "{r1}" (@ptrToInt("Hello, World!\n")),
25 \\ [arg3] "{r2}" (14)
26 \\ : "memory"
27 \\ );
28 \\ return;
29 \\}
30 \\
31 \\fn exit() noreturn {
32 \\ asm volatile ("svc #0"
33 \\ :
34 \\ : [number] "{r7}" (1),
35 \\ [arg1] "{r0}" (0)
36 \\ : "memory"
37 \\ );
38 \\ unreachable;
39 \\}
40 ,
41 "Hello, World!\n",
42 );
43 }
44
45 {
46 var case = ctx.exe("parameters and return values", linux_arm);
47 // Testing simple parameters and return values
48 //
49 // TODO: The parameters to the asm statement in print() had to
50 // be in a specific order because otherwise the write to r0
51 // would overwrite the len parameter which resides in r0
52 case.addCompareOutput(
53 \\export fn _start() noreturn {
54 \\ print(id(14));
55 \\ exit();
56 \\}
57 \\
58 \\fn id(x: u32) u32 {
59 \\ return x;
60 \\}
61 \\
62 \\fn print(len: u32) void {
63 \\ asm volatile ("svc #0"
64 \\ :
65 \\ : [number] "{r7}" (4),
66 \\ [arg3] "{r2}" (len),
67 \\ [arg1] "{r0}" (1),
68 \\ [arg2] "{r1}" (@ptrToInt("Hello, World!\n"))
69 \\ : "memory"
70 \\ );
71 \\ return;
72 \\}
73 \\
74 \\fn exit() noreturn {
75 \\ asm volatile ("svc #0"
76 \\ :
77 \\ : [number] "{r7}" (1),
78 \\ [arg1] "{r0}" (0)
79 \\ : "memory"
80 \\ );
81 \\ unreachable;
82 \\}
83 ,
84 "Hello, World!\n",
85 );
86 }
87
88 {
89 var case = ctx.exe("non-leaf functions", linux_arm);
90 // Testing non-leaf functions
91 case.addCompareOutput(
92 \\export fn _start() noreturn {
93 \\ foo();
94 \\ exit();
95 \\}
96 \\
97 \\fn foo() void {
98 \\ bar();
99 \\}
100 \\
101 \\fn bar() void {}
102 \\
103 \\fn exit() noreturn {
104 \\ asm volatile ("svc #0"
105 \\ :
106 \\ : [number] "{r7}" (1),
107 \\ [arg1] "{r0}" (0)
108 \\ : "memory"
109 \\ );
110 \\ unreachable;
111 \\}
112 ,
113 "",
114 );
115 }
116}
test/stage2/test.zig+96-58
......@@ -21,11 +21,6 @@ const linux_riscv64 = std.zig.CrossTarget{
2121 .os_tag = .linux,
2222};
2323
24const linux_arm = std.zig.CrossTarget{
25 .cpu_arch = .arm,
26 .os_tag = .linux,
27};
28
2924const wasi = std.zig.CrossTarget{
3025 .cpu_arch = .wasm32,
3126 .os_tag = .wasi,
......@@ -35,6 +30,7 @@ pub fn addCases(ctx: *TestContext) !void {
3530 try @import("zir.zig").addCases(ctx);
3631 try @import("cbe.zig").addCases(ctx);
3732 try @import("spu-ii.zig").addCases(ctx);
33 try @import("arm.zig").addCases(ctx);
3834
3935 {
4036 var case = ctx.exe("hello world with updates", linux_x64);
......@@ -76,7 +72,7 @@ pub fn addCases(ctx: *TestContext) !void {
7672 \\ );
7773 \\ unreachable;
7874 \\}
79 ,
75 ,
8076 "Hello, World!\n",
8177 );
8278 // Now change the message only
......@@ -108,7 +104,7 @@ pub fn addCases(ctx: *TestContext) !void {
108104 \\ );
109105 \\ unreachable;
110106 \\}
111 ,
107 ,
112108 "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n",
113109 );
114110 // Now we print it twice.
......@@ -151,10 +147,13 @@ pub fn addCases(ctx: *TestContext) !void {
151147 {
152148 var case = ctx.exe("hello world", macosx_x64);
153149 case.addError("", &[_][]const u8{":1:1: error: no entry point found"});
154 }
155150
156 {
157 var case = ctx.exe("hello world", linux_riscv64);
151 // Incorrect return type
152 case.addError(
153 \\export fn _start() noreturn {
154 \\}
155 , &[_][]const u8{":2:1: error: expected noreturn, found void"});
156
158157 // Regular old hello world
159158 case.addCompareOutput(
160159 \\export fn _start() noreturn {
......@@ -164,23 +163,23 @@ pub fn addCases(ctx: *TestContext) !void {
164163 \\}
165164 \\
166165 \\fn print() void {
167 \\ asm volatile ("ecall"
166 \\ asm volatile ("syscall"
168167 \\ :
169 \\ : [number] "{a7}" (64),
170 \\ [arg1] "{a0}" (1),
171 \\ [arg2] "{a1}" (@ptrToInt("Hello, World!\n")),
172 \\ [arg3] "{a2}" ("Hello, World!\n".len)
173 \\ : "rcx", "r11", "memory"
168 \\ : [number] "{rax}" (0x2000004),
169 \\ [arg1] "{rdi}" (1),
170 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
171 \\ [arg3] "{rdx}" (14)
172 \\ : "memory"
174173 \\ );
175174 \\ return;
176175 \\}
177176 \\
178177 \\fn exit() noreturn {
179 \\ asm volatile ("ecall"
178 \\ asm volatile ("syscall"
180179 \\ :
181 \\ : [number] "{a7}" (94),
182 \\ [arg1] "{a0}" (0)
183 \\ : "rcx", "r11", "memory"
180 \\ : [number] "{rax}" (0x2000001),
181 \\ [arg1] "{rdi}" (0)
182 \\ : "memory"
184183 \\ );
185184 \\ unreachable;
186185 \\}
......@@ -190,36 +189,37 @@ pub fn addCases(ctx: *TestContext) !void {
190189 }
191190
192191 {
193 var case = ctx.exe("hello world", linux_arm);
192 var case = ctx.exe("hello world", linux_riscv64);
194193 // Regular old hello world
195194 case.addCompareOutput(
196195 \\export fn _start() noreturn {
197196 \\ print();
197 \\
198198 \\ exit();
199199 \\}
200200 \\
201201 \\fn print() void {
202 \\ asm volatile ("svc #0"
202 \\ asm volatile ("ecall"
203203 \\ :
204 \\ : [number] "{r7}" (4),
205 \\ [arg1] "{r0}" (1),
206 \\ [arg2] "{r1}" (@ptrToInt("Hello, World!\n")),
207 \\ [arg3] "{r2}" (14)
208 \\ : "memory"
204 \\ : [number] "{a7}" (64),
205 \\ [arg1] "{a0}" (1),
206 \\ [arg2] "{a1}" (@ptrToInt("Hello, World!\n")),
207 \\ [arg3] "{a2}" ("Hello, World!\n".len)
208 \\ : "rcx", "r11", "memory"
209209 \\ );
210210 \\ return;
211211 \\}
212212 \\
213213 \\fn exit() noreturn {
214 \\ asm volatile ("svc #0"
214 \\ asm volatile ("ecall"
215215 \\ :
216 \\ : [number] "{r7}" (1),
217 \\ [arg1] "{r0}" (0)
218 \\ : "memory"
216 \\ : [number] "{a7}" (94),
217 \\ [arg1] "{a0}" (0)
218 \\ : "rcx", "r11", "memory"
219219 \\ );
220220 \\ unreachable;
221221 \\}
222 ,
222 ,
223223 "Hello, World!\n",
224224 );
225225 }
......@@ -244,7 +244,7 @@ pub fn addCases(ctx: *TestContext) !void {
244244 \\ );
245245 \\ unreachable;
246246 \\}
247 ,
247 ,
248248 "Hello, World!\n",
249249 );
250250 }
......@@ -271,7 +271,7 @@ pub fn addCases(ctx: *TestContext) !void {
271271 \\ );
272272 \\ unreachable;
273273 \\}
274 ,
274 ,
275275 "",
276276 );
277277 }
......@@ -298,7 +298,7 @@ pub fn addCases(ctx: *TestContext) !void {
298298 \\ );
299299 \\ unreachable;
300300 \\}
301 ,
301 ,
302302 "",
303303 );
304304 }
......@@ -329,7 +329,7 @@ pub fn addCases(ctx: *TestContext) !void {
329329 \\ );
330330 \\ unreachable;
331331 \\}
332 ,
332 ,
333333 "",
334334 );
335335
......@@ -362,7 +362,7 @@ pub fn addCases(ctx: *TestContext) !void {
362362 \\ );
363363 \\ unreachable;
364364 \\}
365 ,
365 ,
366366 "",
367367 );
368368
......@@ -398,7 +398,7 @@ pub fn addCases(ctx: *TestContext) !void {
398398 \\ );
399399 \\ unreachable;
400400 \\}
401 ,
401 ,
402402 "",
403403 );
404404
......@@ -435,7 +435,7 @@ pub fn addCases(ctx: *TestContext) !void {
435435 \\ );
436436 \\ unreachable;
437437 \\}
438 ,
438 ,
439439 "",
440440 );
441441
......@@ -465,7 +465,7 @@ pub fn addCases(ctx: *TestContext) !void {
465465 \\ );
466466 \\ unreachable;
467467 \\}
468 ,
468 ,
469469 "",
470470 );
471471
......@@ -499,7 +499,7 @@ pub fn addCases(ctx: *TestContext) !void {
499499 \\ );
500500 \\ unreachable;
501501 \\}
502 ,
502 ,
503503 "",
504504 );
505505
......@@ -523,7 +523,7 @@ pub fn addCases(ctx: *TestContext) !void {
523523 \\ );
524524 \\ unreachable;
525525 \\}
526 ,
526 ,
527527 "",
528528 );
529529
......@@ -562,7 +562,7 @@ pub fn addCases(ctx: *TestContext) !void {
562562 \\ );
563563 \\ unreachable;
564564 \\}
565 ,
565 ,
566566 "hello\nhello\nhello\nhello\n",
567567 );
568568
......@@ -599,7 +599,7 @@ pub fn addCases(ctx: *TestContext) !void {
599599 \\ );
600600 \\ unreachable;
601601 \\}
602 ,
602 ,
603603 "",
604604 );
605605
......@@ -641,7 +641,7 @@ pub fn addCases(ctx: *TestContext) !void {
641641 \\ );
642642 \\ unreachable;
643643 \\}
644 ,
644 ,
645645 "",
646646 );
647647
......@@ -693,7 +693,7 @@ pub fn addCases(ctx: *TestContext) !void {
693693 \\ );
694694 \\ unreachable;
695695 \\}
696 ,
696 ,
697697 "",
698698 );
699699
......@@ -755,7 +755,7 @@ pub fn addCases(ctx: *TestContext) !void {
755755 \\ );
756756 \\ unreachable;
757757 \\}
758 ,
758 ,
759759 "",
760760 );
761761
......@@ -788,7 +788,7 @@ pub fn addCases(ctx: *TestContext) !void {
788788 \\ );
789789 \\ unreachable;
790790 \\}
791 ,
791 ,
792792 "",
793793 );
794794
......@@ -820,7 +820,7 @@ pub fn addCases(ctx: *TestContext) !void {
820820 \\ );
821821 \\ unreachable;
822822 \\}
823 ,
823 ,
824824 "",
825825 );
826826
......@@ -845,7 +845,7 @@ pub fn addCases(ctx: *TestContext) !void {
845845 \\ );
846846 \\ unreachable;
847847 \\}
848 ,
848 ,
849849 "",
850850 );
851851
......@@ -871,7 +871,7 @@ pub fn addCases(ctx: *TestContext) !void {
871871 \\ );
872872 \\ unreachable;
873873 \\}
874 ,
874 ,
875875 "",
876876 );
877877
......@@ -904,11 +904,49 @@ pub fn addCases(ctx: *TestContext) !void {
904904 \\ );
905905 \\ unreachable;
906906 \\}
907 ,
907 ,
908908 "hello\nhello\nhello\nhello\nhello\n",
909909 );
910910 }
911911
912 {
913 var case = ctx.exe("basic import", linux_x64);
914 case.addCompareOutput(
915 \\export fn _start() noreturn {
916 \\ @import("print.zig").print();
917 \\ exit();
918 \\}
919 \\
920 \\fn exit() noreturn {
921 \\ asm volatile ("syscall"
922 \\ :
923 \\ : [number] "{rax}" (231),
924 \\ [arg1] "{rdi}" (@as(usize, 0))
925 \\ : "rcx", "r11", "memory"
926 \\ );
927 \\ unreachable;
928 \\}
929 ,
930 "Hello, World!\n",
931 );
932 try case.files.append(.{
933 .src =
934 \\pub fn print() void {
935 \\ asm volatile ("syscall"
936 \\ :
937 \\ : [number] "{rax}" (@as(usize, 1)),
938 \\ [arg1] "{rdi}" (@as(usize, 1)),
939 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
940 \\ [arg3] "{rdx}" (@as(usize, 14))
941 \\ : "rcx", "r11", "memory"
942 \\ );
943 \\ return;
944 \\}
945 ,
946 .path = "print.zig",
947 });
948 }
949
912950 {
913951 var case = ctx.exe("wasm function calls", wasi);
914952
......@@ -923,7 +961,7 @@ pub fn addCases(ctx: *TestContext) !void {
923961 \\ bar();
924962 \\}
925963 \\fn bar() void {}
926 ,
964 ,
927965 "42\n",
928966 );
929967
......@@ -941,7 +979,7 @@ pub fn addCases(ctx: *TestContext) !void {
941979 \\ bar();
942980 \\}
943981 \\fn bar() void {}
944 ,
982 ,
945983 "42\n",
946984 );
947985
......@@ -957,10 +995,10 @@ pub fn addCases(ctx: *TestContext) !void {
957995 \\ bar();
958996 \\}
959997 \\fn bar() void {}
960 ,
961 // This is what you get when you take the bits of the IEE-754
962 // representation of 42.0 and reinterpret them as an unsigned
963 // integer. Guess that's a bug in wasmtime.
998 ,
999 // This is what you get when you take the bits of the IEE-754
1000 // representation of 42.0 and reinterpret them as an unsigned
1001 // integer. Guess that's a bug in wasmtime.
9641002 "1109917696\n",
9651003 );
9661004 }
test/translate_c.zig+17-1
......@@ -3,6 +3,22 @@ const std = @import("std");
33const CrossTarget = std.zig.CrossTarget;
44
55pub fn addCases(cases: *tests.TranslateCContext) void {
6 cases.add("macro expressions respect C operator precedence",
7 \\#define FOO *((foo) + 2)
8 \\#define VALUE (1 + 2 * 3 + 4 * 5 + 6 << 7 | 8 == 9)
9 \\#define _AL_READ3BYTES(p) ((*(unsigned char *)(p)) \
10 \\ | (*((unsigned char *)(p) + 1) << 8) \
11 \\ | (*((unsigned char *)(p) + 2) << 16))
12 , &[_][]const u8{
13 \\pub const FOO = (foo + 2).*;
14 ,
15 \\pub const VALUE = ((((1 + (2 * 3)) + (4 * 5)) + 6) << 7) | @boolToInt(8 == 9);
16 ,
17 \\pub inline fn _AL_READ3BYTES(p: anytype) @TypeOf(((@import("std").meta.cast([*c]u8, p)).* | (((@import("std").meta.cast([*c]u8, p)) + 1).* << 8)) | (((@import("std").meta.cast([*c]u8, p)) + 2).* << 16)) {
18 \\ return ((@import("std").meta.cast([*c]u8, p)).* | (((@import("std").meta.cast([*c]u8, p)) + 1).* << 8)) | (((@import("std").meta.cast([*c]u8, p)) + 2).* << 16);
19 \\}
20 });
21
622 cases.add("extern variable in block scope",
723 \\float bar;
824 \\int foo() {
......@@ -2978,7 +2994,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
29782994 cases.add("string concatenation in macros: three strings",
29792995 \\#define FOO "a" "b" "c"
29802996 , &[_][]const u8{
2981 \\pub const FOO = "a" ++ ("b" ++ "c");
2997 \\pub const FOO = "a" ++ "b" ++ "c";
29822998 });
29832999
29843000 cases.add("multibyte character literals",