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

master
Andrew Kelley 2020-01-22 12:12:36 -05:00
commit 97b2ac598b
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
43 changed files with 1430 additions and 935 deletions

View File

@ -45,7 +45,6 @@ message("Configuring zig version ${ZIG_VERSION}")
set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")
set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries")
set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL "Disable copying lib/ files to install prefix")
set(ZIG_ENABLE_MEM_PROFILE off CACHE BOOL "Activate memory usage instrumentation")
if(ZIG_STATIC)
@ -414,19 +413,26 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
else()
set(LIBUSERLAND_RELEASE_MODE "true")
endif()
if(ZIG_SKIP_INSTALL_LIB_FILES)
set(ZIG_BUILD_INSTALL_STEP "")
else()
set(ZIG_BUILD_INSTALL_STEP "install")
set(BUILD_LIBUSERLAND_ARGS "build"
--override-lib-dir "${CMAKE_SOURCE_DIR}/lib"
"-Doutput-dir=${CMAKE_BINARY_DIR}"
"-Drelease=${LIBUSERLAND_RELEASE_MODE}"
"-Dlib-files-only"
--prefix "${CMAKE_INSTALL_PREFIX}"
libuserland
)
# When using Visual Studio build system generator we default to libuserland install.
if(MSVC)
set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL "Disable copying lib/ files to install prefix")
if(NOT ZIG_SKIP_INSTALL_LIB_FILES)
set(BUILD_LIBUSERLAND_ARGS ${BUILD_LIBUSERLAND_ARGS} install)
endif()
endif()
add_custom_target(zig_build_libuserland ALL
COMMAND zig0 build
--override-lib-dir "${CMAKE_SOURCE_DIR}/lib"
libuserland ${ZIG_BUILD_INSTALL_STEP}
"-Doutput-dir=${CMAKE_BINARY_DIR}"
"-Drelease=${LIBUSERLAND_RELEASE_MODE}"
"-Dlib-files-only"
--prefix "${CMAKE_INSTALL_PREFIX}"
COMMAND zig0 ${BUILD_LIBUSERLAND_ARGS}
DEPENDS zig0
BYPRODUCTS "${LIBUSERLAND}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
@ -444,4 +450,15 @@ elseif(MINGW)
target_link_libraries(zig ntdll)
endif()
add_dependencies(zig zig_build_libuserland)
install(TARGETS zig DESTINATION bin)
# CODE has no effect with Visual Studio build system generator.
if(NOT MSVC)
get_target_property(zig0_BINARY_DIR zig0 BINARY_DIR)
install(CODE "set(zig0_EXE \"${zig0_BINARY_DIR}/zig0\")")
install(CODE "set(INSTALL_LIBUSERLAND_ARGS \"${BUILD_LIBUSERLAND_ARGS}\" install)")
install(CODE "set(BUILD_LIBUSERLAND_ARGS \"${BUILD_LIBUSERLAND_ARGS}\")")
install(CODE "set(CMAKE_SOURCE_DIR \"${CMAKE_SOURCE_DIR}\")")
install(SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/cmake/install.cmake)
endif()

View File

@ -51,23 +51,28 @@ knowledge of Zig internals.**
### Editing Source Code
First, build the Stage 1 compiler as described in [the Building section](#building).
First, build the Stage 1 compiler as described in [Building from Source](README.md#Building-from-Source).
One modification you may want to make is adding `-DZIG_SKIP_INSTALL_LIB_FILES=ON`
to the cmake line. If you use the build directory as a working directory to run
tests with, zig will find the lib files in the source directory, and they will not
be "installed" every time you run `make`. This will allow you to make modifications
directly to the standard library, for example, and have them effective immediately.
Note that if you already ran `make` or `make install` with the default cmake
settings, there will already be a `lib/` directory in your build directory. When
executed from the build directory, zig will find this instead of the source lib/
directory. Remove the unwanted directory so that the desired one can be found.
Zig locates lib files relative to executable path by searching up the
filesystem tree for a sub-path of `lib/zig/std/std.zig` or `lib/std/std.zig`.
Typically the former is an install and the latter a git working tree which
contains the build directory.
During development it is not necessary to perform installs when modifying
stage1 or userland sources and in fact it is faster and simpler to run,
test and debug from a git working tree.
- `make` is typically sufficient to build zig during development iterations.
- `make install` performs a build __and__ install.
- `msbuild -p:Configuration=Release INSTALL.vcxproj` on Windows performs a
build and install. To avoid install, pass cmake option `-DZIG_SKIP_INSTALL_LIB_FILES=ON`.
To test changes, do the following from the build directory:
1. Run `make install` (on POSIX) or
1. Run `make` (on POSIX) or
`msbuild -p:Configuration=Release INSTALL.vcxproj` (on Windows).
2. `bin/zig build test` (on POSIX) or `bin\zig.exe build test` (on Windows).
2. `$BUILD_DIR/zig build test` (on POSIX) or
`$BUILD_DIR/Release\zig.exe build test` (on Windows).
That runs the whole test suite, which does a lot of extra testing that you
likely won't always need, and can take upwards of 1 hour. This is what the
@ -85,8 +90,8 @@ Another example is choosing a different set of things to test. For example,
not the other ones. Combining this suggestion with the previous one, you could
do this:
`bin/zig build test-std -Dskip-release` (on POSIX) or
`bin\zig.exe build test-std -Dskip-release` (on Windows).
`$BUILD_DIR/bin/zig build test-std -Dskip-release` (on POSIX) or
`$BUILD_DIR/Release\zig.exe build test-std -Dskip-release` (on Windows).
This will run only the standard library tests, in debug mode only, for all
targets (it will cross-compile the tests for non-native targets but not run

37
cmake/install.cmake Normal file
View File

@ -0,0 +1,37 @@
message("-- Installing: ${CMAKE_INSTALL_PREFIX}/lib")
if(NOT EXISTS ${zig0_EXE})
message("::")
message(":: ERROR: Executable not found")
message(":: (execute_process)")
message("::")
message(":: executable: ${zig0_EXE}")
message("::")
message(FATAL_ERROR)
endif()
execute_process(COMMAND ${zig0_EXE} ${INSTALL_LIBUSERLAND_ARGS}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
RESULT_VARIABLE _result
)
if(_result)
message("::")
message(":: ERROR: ${_result}")
message(":: (execute_process)")
string(REPLACE ";" " " s_INSTALL_LIBUSERLAND_ARGS "${INSTALL_LIBUSERLAND_ARGS}")
message("::")
message(":: argv: ${zig0_EXE} ${s_INSTALL_LIBUSERLAND_ARGS} install")
set(_args ${zig0_EXE} ${INSTALL_LIBUSERLAND_ARGS})
list(LENGTH _args _len)
math(EXPR _len "${_len} - 1")
message("::")
foreach(_i RANGE 0 ${_len})
list(GET _args ${_i} _arg)
message(":: argv[${_i}]: ${_arg}")
endforeach()
message("::")
message(FATAL_ERROR)
endif()

View File

@ -2893,6 +2893,47 @@ test "switch using enum literals" {
}
{#code_end#}
{#header_close#}
{#header_open|Non-exhaustive enum#}
<p>
A Non-exhaustive enum can be created by adding a trailing '_' field.
It must specify a tag type and cannot consume every enumeration value.
</p>
<p>
{#link|@intToEnum#} on a non-exhaustive enum cannot fail.
</p>
<p>
A switch on a non-exhaustive enum can include a '_' prong as an alternative to an {#syntax#}else{#endsyntax#} prong
with the difference being that it makes it a compile error if all the known tag names are not handled by the switch.
</p>
{#code_begin|test#}
const std = @import("std");
const assert = std.debug.assert;
const Number = enum(u8) {
One,
Two,
Three,
_,
};
test "switch on non-exhaustive enum" {
const number = Number.One;
const result = switch (number) {
.One => true,
.Two,
.Three => false,
_ => false,
};
assert(result);
const is_one = switch (number) {
.One => true,
else => false,
};
assert(is_one);
}
{#code_end#}
{#header_close#}
{#header_close#}
{#header_open|union#}
@ -6815,6 +6856,19 @@ async fn func(y: *i32) void {
</p>
{#header_close#}
{#header_open|@bitSizeOf#}
<pre>{#syntax#}@bitSizeOf(comptime T: type) comptime_int{#endsyntax#}</pre>
<p>
This function returns the number of bits it takes to store {#syntax#}T{#endsyntax#} in memory.
The result is a target-specific compile time constant.
</p>
<p>
This function measures the size at runtime. For types that are disallowed at runtime, such as
{#syntax#}comptime_int{#endsyntax#} and {#syntax#}type{#endsyntax#}, the result is {#syntax#}0{#endsyntax#}.
</p>
{#see_also|@sizeOf|@typeInfo#}
{#header_close#}
{#header_open|@breakpoint#}
<pre>{#syntax#}@breakpoint(){#endsyntax#}</pre>
<p>
@ -8044,7 +8098,7 @@ test "@setRuntimeSafety" {
This function measures the size at runtime. For types that are disallowed at runtime, such as
{#syntax#}comptime_int{#endsyntax#} and {#syntax#}type{#endsyntax#}, the result is {#syntax#}0{#endsyntax#}.
</p>
{#see_also|@typeInfo#}
{#see_also|@bitSizeOf|@typeInfo#}
{#header_close#}
{#header_open|@sliceToBytes#}

View File

@ -1687,7 +1687,9 @@ pub const LibExeObjStep = struct {
}
pub fn addAssemblyFile(self: *LibExeObjStep, path: []const u8) void {
self.link_objects.append(LinkObject{ .AssemblyFile = self.builder.dupe(path) }) catch unreachable;
self.link_objects.append(LinkObject{
.AssemblyFile = .{ .path = self.builder.dupe(path) },
}) catch unreachable;
}
pub fn addAssemblyFileFromWriteFileStep(self: *LibExeObjStep, wfs: *WriteFileStep, basename: []const u8) void {

View File

@ -205,6 +205,7 @@ pub const TypeInfo = union(enum) {
name: []const u8,
offset: ?comptime_int,
field_type: type,
default_value: var,
};
/// This data structure is used by the Zig language code generation and
@ -253,6 +254,7 @@ pub const TypeInfo = union(enum) {
tag_type: type,
fields: []EnumField,
decls: []Declaration,
is_exhaustive: bool,
};
/// This data structure is used by the Zig language code generation and

View File

@ -185,7 +185,7 @@ pub extern "c" fn getaddrinfo(
noalias service: [*:0]const u8,
noalias hints: *const addrinfo,
noalias res: **addrinfo,
) c_int;
) EAI;
pub extern "c" fn freeaddrinfo(res: *addrinfo) void;
@ -197,9 +197,9 @@ pub extern "c" fn getnameinfo(
noalias serv: [*]u8,
servlen: socklen_t,
flags: u32,
) c_int;
) EAI;
pub extern "c" fn gai_strerror(errcode: c_int) [*:0]const u8;
pub extern "c" fn gai_strerror(errcode: EAI) [*:0]const u8;
pub extern "c" fn poll(fds: [*]pollfd, nfds: nfds_t, timeout: c_int) c_int;

View File

@ -70,47 +70,52 @@ pub const AI_NUMERICHOST = 0x00000004;
/// prevent service name resolution
pub const AI_NUMERICSERV = 0x00001000;
/// address family for hostname not supported
pub const EAI_ADDRFAMILY = 1;
pub const EAI = extern enum(c_int) {
/// address family for hostname not supported
ADDRFAMILY = 1,
/// temporary failure in name resolution
pub const EAI_AGAIN = 2;
/// temporary failure in name resolution
AGAIN = 2,
/// invalid value for ai_flags
pub const EAI_BADFLAGS = 3;
/// invalid value for ai_flags
BADFLAGS = 3,
/// non-recoverable failure in name resolution
pub const EAI_FAIL = 4;
/// non-recoverable failure in name resolution
FAIL = 4,
/// ai_family not supported
pub const EAI_FAMILY = 5;
/// ai_family not supported
FAMILY = 5,
/// memory allocation failure
pub const EAI_MEMORY = 6;
/// memory allocation failure
MEMORY = 6,
/// no address associated with hostname
pub const EAI_NODATA = 7;
/// no address associated with hostname
NODATA = 7,
/// hostname nor servname provided, or not known
pub const EAI_NONAME = 8;
/// hostname nor servname provided, or not known
NONAME = 8,
/// servname not supported for ai_socktype
pub const EAI_SERVICE = 9;
/// servname not supported for ai_socktype
SERVICE = 9,
/// ai_socktype not supported
pub const EAI_SOCKTYPE = 10;
/// ai_socktype not supported
SOCKTYPE = 10,
/// system error returned in errno
pub const EAI_SYSTEM = 11;
/// system error returned in errno
SYSTEM = 11,
/// invalid value for hints
pub const EAI_BADHINTS = 12;
/// invalid value for hints
BADHINTS = 12,
/// resolved protocol is unknown
pub const EAI_PROTOCOL = 13;
/// resolved protocol is unknown
PROTOCOL = 13,
/// argument buffer overflow
OVERFLOW = 14,
_,
};
/// argument buffer overflow
pub const EAI_OVERFLOW = 14;
pub const EAI_MAX = 15;
pub const pthread_mutex_t = extern struct {

View File

@ -23,47 +23,51 @@ pub const pthread_attr_t = extern struct {
__align: c_long,
};
/// address family for hostname not supported
pub const EAI_ADDRFAMILY = 1;
pub const EAI = extern enum(c_int) {
/// address family for hostname not supported
ADDRFAMILY = 1,
/// name could not be resolved at this time
pub const EAI_AGAIN = 2;
/// name could not be resolved at this time
AGAIN = 2,
/// flags parameter had an invalid value
pub const EAI_BADFLAGS = 3;
/// flags parameter had an invalid value
BADFLAGS = 3,
/// non-recoverable failure in name resolution
pub const EAI_FAIL = 4;
/// non-recoverable failure in name resolution
FAIL = 4,
/// address family not recognized
pub const EAI_FAMILY = 5;
/// address family not recognized
FAMILY = 5,
/// memory allocation failure
pub const EAI_MEMORY = 6;
/// memory allocation failure
MEMORY = 6,
/// no address associated with hostname
pub const EAI_NODATA = 7;
/// no address associated with hostname
NODATA = 7,
/// name does not resolve
pub const EAI_NONAME = 8;
/// name does not resolve
NONAME = 8,
/// service not recognized for socket type
pub const EAI_SERVICE = 9;
/// service not recognized for socket type
SERVICE = 9,
/// intended socket type was not recognized
pub const EAI_SOCKTYPE = 10;
/// intended socket type was not recognized
SOCKTYPE = 10,
/// system error returned in errno
pub const EAI_SYSTEM = 11;
/// system error returned in errno
SYSTEM = 11,
/// invalid value for hints
pub const EAI_BADHINTS = 12;
/// invalid value for hints
BADHINTS = 12,
/// resolved protocol is unknown
pub const EAI_PROTOCOL = 13;
/// resolved protocol is unknown
PROTOCOL = 13,
/// argument buffer overflow
pub const EAI_OVERFLOW = 14;
/// argument buffer overflow
OVERFLOW = 14,
_,
};
pub const EAI_MAX = 15;

View File

@ -32,25 +32,29 @@ pub const NI_NAMEREQD = 0x08;
pub const NI_DGRAM = 0x10;
pub const NI_NUMERICSCOPE = 0x100;
pub const EAI_BADFLAGS = -1;
pub const EAI_NONAME = -2;
pub const EAI_AGAIN = -3;
pub const EAI_FAIL = -4;
pub const EAI_FAMILY = -6;
pub const EAI_SOCKTYPE = -7;
pub const EAI_SERVICE = -8;
pub const EAI_MEMORY = -10;
pub const EAI_SYSTEM = -11;
pub const EAI_OVERFLOW = -12;
pub const EAI = extern enum(c_int) {
BADFLAGS = -1,
NONAME = -2,
AGAIN = -3,
FAIL = -4,
FAMILY = -6,
SOCKTYPE = -7,
SERVICE = -8,
MEMORY = -10,
SYSTEM = -11,
OVERFLOW = -12,
pub const EAI_NODATA = -5;
pub const EAI_ADDRFAMILY = -9;
pub const EAI_INPROGRESS = -100;
pub const EAI_CANCELED = -101;
pub const EAI_NOTCANCELED = -102;
pub const EAI_ALLDONE = -103;
pub const EAI_INTR = -104;
pub const EAI_IDN_ENCODE = -105;
NODATA = -5,
ADDRFAMILY = -9,
INPROGRESS = -100,
CANCELED = -101,
NOTCANCELED = -102,
ALLDONE = -103,
INTR = -104,
IDN_ENCODE = -105,
_,
};
pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize;
pub extern "c" fn sched_getaffinity(pid: c_int, size: usize, set: *cpu_set_t) c_int;

View File

@ -277,7 +277,7 @@ pub const WindowsDynLib = struct {
}
pub fn openC(path_c: [*:0]const u8) !WindowsDynLib {
const path_w = try windows.cStrToPrefixedFileW(path);
const path_w = try windows.cStrToPrefixedFileW(path_c);
return openW(&path_w);
}

View File

@ -431,7 +431,7 @@ pub fn formatType(
},
else => return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }),
},
.Many => {
.Many, .C => {
if (ptr_info.child == u8) {
if (fmt.len > 0 and fmt[0] == 's') {
const len = mem.len(u8, value);
@ -449,9 +449,6 @@ pub fn formatType(
}
return format(context, Errors, output, "{}@{x}", .{ @typeName(ptr_info.child), @ptrToInt(value.ptr) });
},
.C => {
return format(context, Errors, output, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) });
},
},
.Array => |info| {
const Slice = @Type(builtin.TypeInfo{
@ -1285,8 +1282,16 @@ test "pointer" {
}
test "cstr" {
try testFmt("cstr: Test C\n", "cstr: {s}\n", .{"Test C"});
try testFmt("cstr: Test C \n", "cstr: {s:10}\n", .{"Test C"});
try testFmt(
"cstr: Test C\n",
"cstr: {s}\n",
.{@ptrCast([*c]const u8, "Test C")},
);
try testFmt(
"cstr: Test C \n",
"cstr: {s:10}\n",
.{@ptrCast([*c]const u8, "Test C")},
);
}
test "filesize" {

View File

@ -47,11 +47,11 @@ const hashes = [_]Hash{
.name = "adler32",
},
Hash{
.ty = hash.crc.Crc32WithPoly(hash.crc.Polynomial.IEEE),
.ty = hash.crc.Crc32WithPoly(.IEEE),
.name = "crc32-slicing-by-8",
},
Hash{
.ty = hash.crc.Crc32SmallWithPoly(hash.crc.Polynomial.IEEE),
.ty = hash.crc.Crc32SmallWithPoly(.IEEE),
.name = "crc32-half-byte-lookup",
},
Hash{

View File

@ -9,17 +9,18 @@ const std = @import("../std.zig");
const debug = std.debug;
const testing = std.testing;
pub const Polynomial = struct {
pub const IEEE = 0xedb88320;
pub const Castagnoli = 0x82f63b78;
pub const Koopman = 0xeb31d82e;
pub const Polynomial = enum(u32) {
IEEE = 0xedb88320,
Castagnoli = 0x82f63b78,
Koopman = 0xeb31d82e,
_,
};
// IEEE is by far the most common CRC and so is aliased by default.
pub const Crc32 = Crc32WithPoly(Polynomial.IEEE);
pub const Crc32 = Crc32WithPoly(.IEEE);
// slicing-by-8 crc32 implementation.
pub fn Crc32WithPoly(comptime poly: u32) type {
pub fn Crc32WithPoly(comptime poly: Polynomial) type {
return struct {
const Self = @This();
const lookup_tables = comptime block: {
@ -31,7 +32,7 @@ pub fn Crc32WithPoly(comptime poly: u32) type {
var j: usize = 0;
while (j < 8) : (j += 1) {
if (crc & 1 == 1) {
crc = (crc >> 1) ^ poly;
crc = (crc >> 1) ^ @enumToInt(poly);
} else {
crc = (crc >> 1);
}
@ -100,7 +101,7 @@ pub fn Crc32WithPoly(comptime poly: u32) type {
}
test "crc32 ieee" {
const Crc32Ieee = Crc32WithPoly(Polynomial.IEEE);
const Crc32Ieee = Crc32WithPoly(.IEEE);
testing.expect(Crc32Ieee.hash("") == 0x00000000);
testing.expect(Crc32Ieee.hash("a") == 0xe8b7be43);
@ -108,7 +109,7 @@ test "crc32 ieee" {
}
test "crc32 castagnoli" {
const Crc32Castagnoli = Crc32WithPoly(Polynomial.Castagnoli);
const Crc32Castagnoli = Crc32WithPoly(.Castagnoli);
testing.expect(Crc32Castagnoli.hash("") == 0x00000000);
testing.expect(Crc32Castagnoli.hash("a") == 0xc1d04330);
@ -116,7 +117,7 @@ test "crc32 castagnoli" {
}
// half-byte lookup table implementation.
pub fn Crc32SmallWithPoly(comptime poly: u32) type {
pub fn Crc32SmallWithPoly(comptime poly: Polynomial) type {
return struct {
const Self = @This();
const lookup_table = comptime block: {
@ -127,7 +128,7 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type {
var j: usize = 0;
while (j < 8) : (j += 1) {
if (crc & 1 == 1) {
crc = (crc >> 1) ^ poly;
crc = (crc >> 1) ^ @enumToInt(poly);
} else {
crc = (crc >> 1);
}
@ -164,7 +165,7 @@ pub fn Crc32SmallWithPoly(comptime poly: u32) type {
}
test "small crc32 ieee" {
const Crc32Ieee = Crc32SmallWithPoly(Polynomial.IEEE);
const Crc32Ieee = Crc32SmallWithPoly(.IEEE);
testing.expect(Crc32Ieee.hash("") == 0x00000000);
testing.expect(Crc32Ieee.hash("a") == 0xe8b7be43);
@ -172,7 +173,7 @@ test "small crc32 ieee" {
}
test "small crc32 castagnoli" {
const Crc32Castagnoli = Crc32SmallWithPoly(Polynomial.Castagnoli);
const Crc32Castagnoli = Crc32SmallWithPoly(.Castagnoli);
testing.expect(Crc32Castagnoli.hash("") == 0x00000000);
testing.expect(Crc32Castagnoli.hash("a") == 0xc1d04330);

View File

@ -452,18 +452,18 @@ pub fn getAddressList(allocator: *mem.Allocator, name: []const u8, port: u16) !*
};
var res: *os.addrinfo = undefined;
switch (os.system.getaddrinfo(name_c.ptr, @ptrCast([*:0]const u8, port_c.ptr), &hints, &res)) {
0 => {},
c.EAI_ADDRFAMILY => return error.HostLacksNetworkAddresses,
c.EAI_AGAIN => return error.TemporaryNameServerFailure,
c.EAI_BADFLAGS => unreachable, // Invalid hints
c.EAI_FAIL => return error.NameServerFailure,
c.EAI_FAMILY => return error.AddressFamilyNotSupported,
c.EAI_MEMORY => return error.OutOfMemory,
c.EAI_NODATA => return error.HostLacksNetworkAddresses,
c.EAI_NONAME => return error.UnknownHostName,
c.EAI_SERVICE => return error.ServiceUnavailable,
c.EAI_SOCKTYPE => unreachable, // Invalid socket type requested in hints
c.EAI_SYSTEM => switch (os.errno(-1)) {
@intToEnum(os.system.EAI, 0) => {},
.ADDRFAMILY => return error.HostLacksNetworkAddresses,
.AGAIN => return error.TemporaryNameServerFailure,
.BADFLAGS => unreachable, // Invalid hints
.FAIL => return error.NameServerFailure,
.FAMILY => return error.AddressFamilyNotSupported,
.MEMORY => return error.OutOfMemory,
.NODATA => return error.HostLacksNetworkAddresses,
.NONAME => return error.UnknownHostName,
.SERVICE => return error.ServiceUnavailable,
.SOCKTYPE => unreachable, // Invalid socket type requested in hints
.SYSTEM => switch (os.errno(-1)) {
else => |e| return os.unexpectedErrno(e),
},
else => unreachable,

View File

@ -18,7 +18,7 @@ pub usingnamespace switch (builtin.arch) {
else => struct {},
};
const is_mips = builtin.arch == .mipsel;
const is_mips = builtin.arch.isMIPS();
pub const pid_t = i32;
pub const fd_t = i32;

View File

@ -16,42 +16,42 @@ comptime {
else => {},
}
@export(@import("compiler_rt/comparesf2.zig").__lesf2, .{ .name = "__lesf2", .linkage = linkage });
@export(@import("compiler_rt/comparedf2.zig").__ledf2, .{ .name = "__ledf2", .linkage = linkage });
@export(@import("compiler_rt/comparetf2.zig").__letf2, .{ .name = "__letf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__lesf2, .{ .name = "__lesf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__ledf2, .{ .name = "__ledf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__letf2, .{ .name = "__letf2", .linkage = linkage });
@export(@import("compiler_rt/comparesf2.zig").__gesf2, .{ .name = "__gesf2", .linkage = linkage });
@export(@import("compiler_rt/comparedf2.zig").__gedf2, .{ .name = "__gedf2", .linkage = linkage });
@export(@import("compiler_rt/comparetf2.zig").__getf2, .{ .name = "__getf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__gesf2, .{ .name = "__gesf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__gedf2, .{ .name = "__gedf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__getf2, .{ .name = "__getf2", .linkage = linkage });
if (!is_test) {
@export(@import("compiler_rt/comparesf2.zig").__lesf2, .{ .name = "__cmpsf2", .linkage = linkage });
@export(@import("compiler_rt/comparedf2.zig").__ledf2, .{ .name = "__cmpdf2", .linkage = linkage });
@export(@import("compiler_rt/comparetf2.zig").__letf2, .{ .name = "__cmptf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__lesf2, .{ .name = "__cmpsf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__ledf2, .{ .name = "__cmpdf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__letf2, .{ .name = "__cmptf2", .linkage = linkage });
@export(@import("compiler_rt/comparesf2.zig").__eqsf2, .{ .name = "__eqsf2", .linkage = linkage });
@export(@import("compiler_rt/comparedf2.zig").__eqdf2, .{ .name = "__eqdf2", .linkage = linkage });
@export(@import("compiler_rt/comparetf2.zig").__letf2, .{ .name = "__eqtf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__eqsf2, .{ .name = "__eqsf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__eqdf2, .{ .name = "__eqdf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__letf2, .{ .name = "__eqtf2", .linkage = linkage });
@export(@import("compiler_rt/comparesf2.zig").__ltsf2, .{ .name = "__ltsf2", .linkage = linkage });
@export(@import("compiler_rt/comparedf2.zig").__ltdf2, .{ .name = "__ltdf2", .linkage = linkage });
@export(@import("compiler_rt/comparetf2.zig").__letf2, .{ .name = "__lttf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__ltsf2, .{ .name = "__ltsf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__ltdf2, .{ .name = "__ltdf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__letf2, .{ .name = "__lttf2", .linkage = linkage });
@export(@import("compiler_rt/comparesf2.zig").__nesf2, .{ .name = "__nesf2", .linkage = linkage });
@export(@import("compiler_rt/comparedf2.zig").__nedf2, .{ .name = "__nedf2", .linkage = linkage });
@export(@import("compiler_rt/comparetf2.zig").__letf2, .{ .name = "__netf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__nesf2, .{ .name = "__nesf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__nedf2, .{ .name = "__nedf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__letf2, .{ .name = "__netf2", .linkage = linkage });
@export(@import("compiler_rt/comparesf2.zig").__gtsf2, .{ .name = "__gtsf2", .linkage = linkage });
@export(@import("compiler_rt/comparedf2.zig").__gtdf2, .{ .name = "__gtdf2", .linkage = linkage });
@export(@import("compiler_rt/comparetf2.zig").__getf2, .{ .name = "__gttf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__gtsf2, .{ .name = "__gtsf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__gtdf2, .{ .name = "__gtdf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__getf2, .{ .name = "__gttf2", .linkage = linkage });
@export(@import("compiler_rt/extendXfYf2.zig").__extendhfsf2, .{ .name = "__gnu_h2f_ieee", .linkage = linkage });
@export(@import("compiler_rt/truncXfYf2.zig").__truncsfhf2, .{ .name = "__gnu_f2h_ieee", .linkage = linkage });
}
@export(@import("compiler_rt/comparesf2.zig").__unordsf2, .{ .name = "__unordsf2", .linkage = linkage });
@export(@import("compiler_rt/comparedf2.zig").__unorddf2, .{ .name = "__unorddf2", .linkage = linkage });
@export(@import("compiler_rt/comparetf2.zig").__unordtf2, .{ .name = "__unordtf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__unordsf2, .{ .name = "__unordsf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__unorddf2, .{ .name = "__unorddf2", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__unordtf2, .{ .name = "__unordtf2", .linkage = linkage });
@export(@import("compiler_rt/addXf3.zig").__addsf3, .{ .name = "__addsf3", .linkage = linkage });
@export(@import("compiler_rt/addXf3.zig").__adddf3, .{ .name = "__adddf3", .linkage = linkage });
@ -146,8 +146,10 @@ comptime {
@export(@import("compiler_rt/negXf2.zig").__negsf2, .{ .name = "__negsf2", .linkage = linkage });
@export(@import("compiler_rt/negXf2.zig").__negdf2, .{ .name = "__negdf2", .linkage = linkage });
if (is_arm_arch and !is_arm_64 and !is_test) {
@export(@import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr0, .{ .name = "__aeabi_unwind_cpp_pr0", .linkage = strong_linkage });
@export(@import("compiler_rt/clzsi2.zig").__clzsi2, .{ .name = "__clzsi2", .linkage = linkage });
if (builtin.arch.isARM() and !is_test) {
@export(@import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr0, .{ .name = "__aeabi_unwind_cpp_pr0", .linkage = linkage });
@export(@import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr1, .{ .name = "__aeabi_unwind_cpp_pr1", .linkage = linkage });
@export(@import("compiler_rt/arm.zig").__aeabi_unwind_cpp_pr2, .{ .name = "__aeabi_unwind_cpp_pr2", .linkage = linkage });
@ -177,7 +179,9 @@ comptime {
@export(@import("compiler_rt/arm.zig").__aeabi_memclr, .{ .name = "__aeabi_memclr4", .linkage = linkage });
@export(@import("compiler_rt/arm.zig").__aeabi_memclr, .{ .name = "__aeabi_memclr8", .linkage = linkage });
@export(@import("compiler_rt/arm.zig").__aeabi_read_tp, .{ .name = "__aeabi_read_tp", .linkage = linkage });
if (builtin.os == .linux) {
@export(@import("compiler_rt/arm.zig").__aeabi_read_tp, .{ .name = "__aeabi_read_tp", .linkage = linkage });
}
@export(@import("compiler_rt/extendXfYf2.zig").__aeabi_f2d, .{ .name = "__aeabi_f2d", .linkage = linkage });
@export(@import("compiler_rt/floatsiXf.zig").__aeabi_i2d, .{ .name = "__aeabi_i2d", .linkage = linkage });
@ -222,20 +226,29 @@ comptime {
@export(@import("compiler_rt/divsf3.zig").__aeabi_fdiv, .{ .name = "__aeabi_fdiv", .linkage = linkage });
@export(@import("compiler_rt/divdf3.zig").__aeabi_ddiv, .{ .name = "__aeabi_ddiv", .linkage = linkage });
@export(@import("compiler_rt/arm/aeabi_fcmp.zig").__aeabi_fcmpeq, .{ .name = "__aeabi_fcmpeq", .linkage = linkage });
@export(@import("compiler_rt/arm/aeabi_fcmp.zig").__aeabi_fcmplt, .{ .name = "__aeabi_fcmplt", .linkage = linkage });
@export(@import("compiler_rt/arm/aeabi_fcmp.zig").__aeabi_fcmple, .{ .name = "__aeabi_fcmple", .linkage = linkage });
@export(@import("compiler_rt/arm/aeabi_fcmp.zig").__aeabi_fcmpge, .{ .name = "__aeabi_fcmpge", .linkage = linkage });
@export(@import("compiler_rt/arm/aeabi_fcmp.zig").__aeabi_fcmpgt, .{ .name = "__aeabi_fcmpgt", .linkage = linkage });
@export(@import("compiler_rt/comparesf2.zig").__aeabi_fcmpun, .{ .name = "__aeabi_fcmpun", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__aeabi_fcmpeq, .{ .name = "__aeabi_fcmpeq", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__aeabi_fcmplt, .{ .name = "__aeabi_fcmplt", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__aeabi_fcmple, .{ .name = "__aeabi_fcmple", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__aeabi_fcmpge, .{ .name = "__aeabi_fcmpge", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__aeabi_fcmpgt, .{ .name = "__aeabi_fcmpgt", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__aeabi_fcmpun, .{ .name = "__aeabi_fcmpun", .linkage = linkage });
@export(@import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmpeq, .{ .name = "__aeabi_dcmpeq", .linkage = linkage });
@export(@import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmplt, .{ .name = "__aeabi_dcmplt", .linkage = linkage });
@export(@import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmple, .{ .name = "__aeabi_dcmple", .linkage = linkage });
@export(@import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmpge, .{ .name = "__aeabi_dcmpge", .linkage = linkage });
@export(@import("compiler_rt/arm/aeabi_dcmp.zig").__aeabi_dcmpgt, .{ .name = "__aeabi_dcmpgt", .linkage = linkage });
@export(@import("compiler_rt/comparedf2.zig").__aeabi_dcmpun, .{ .name = "__aeabi_dcmpun", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__aeabi_dcmpeq, .{ .name = "__aeabi_dcmpeq", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__aeabi_dcmplt, .{ .name = "__aeabi_dcmplt", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__aeabi_dcmple, .{ .name = "__aeabi_dcmple", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__aeabi_dcmpge, .{ .name = "__aeabi_dcmpge", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__aeabi_dcmpgt, .{ .name = "__aeabi_dcmpgt", .linkage = linkage });
@export(@import("compiler_rt/compareXf2.zig").__aeabi_dcmpun, .{ .name = "__aeabi_dcmpun", .linkage = linkage });
}
if (builtin.arch == .i386 and builtin.abi == .msvc) {
// Don't let LLVM apply the stdcall name mangling on those MSVC builtins
@export(@import("compiler_rt/aulldiv.zig")._alldiv, .{ .name = "\x01__alldiv", .linkage = strong_linkage });
@export(@import("compiler_rt/aulldiv.zig")._aulldiv, .{ .name = "\x01__aulldiv", .linkage = strong_linkage });
@export(@import("compiler_rt/aullrem.zig")._allrem, .{ .name = "\x01__allrem", .linkage = strong_linkage });
@export(@import("compiler_rt/aullrem.zig")._aullrem, .{ .name = "\x01__aullrem", .linkage = strong_linkage });
}
if (builtin.os == .windows) {
// Default stack-probe functions emitted by LLVM
if (is_mingw) {
@ -254,13 +267,6 @@ comptime {
switch (builtin.arch) {
.i386 => {
// Don't let LLVM apply the stdcall name mangling on those MSVC
// builtin functions
@export(@import("compiler_rt/aulldiv.zig")._alldiv, .{ .name = "\x01__alldiv", .linkage = strong_linkage });
@export(@import("compiler_rt/aulldiv.zig")._aulldiv, .{ .name = "\x01__aulldiv", .linkage = strong_linkage });
@export(@import("compiler_rt/aullrem.zig")._allrem, .{ .name = "\x01__allrem", .linkage = strong_linkage });
@export(@import("compiler_rt/aullrem.zig")._aullrem, .{ .name = "\x01__aullrem", .linkage = strong_linkage });
@export(@import("compiler_rt/divti3.zig").__divti3, .{ .name = "__divti3", .linkage = linkage });
@export(@import("compiler_rt/modti3.zig").__modti3, .{ .name = "__modti3", .linkage = linkage });
@export(@import("compiler_rt/multi3.zig").__multi3, .{ .name = "__multi3", .linkage = linkage });
@ -295,16 +301,12 @@ comptime {
@export(@import("compiler_rt/mulodi4.zig").__mulodi4, .{ .name = "__mulodi4", .linkage = linkage });
}
const std = @import("std");
const assert = std.debug.assert;
const testing = std.testing;
// Avoid dragging in the runtime safety mechanisms into this .o file,
// unless we're trying to test this file.
pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
@setCold(true);
if (is_test) {
std.debug.panic("{}", .{msg});
@import("std").debug.panic("{}", .{msg});
} else {
unreachable;
}
@ -320,23 +322,3 @@ extern var __stack_chk_guard: usize = blk: {
buf[@sizeOf(usize) - 2] = '\n';
break :blk @bitCast(usize, buf);
};
const is_arm_64 = switch (builtin.arch) {
builtin.Arch.aarch64,
builtin.Arch.aarch64_be,
=> true,
else => false,
};
const is_arm_arch = switch (builtin.arch) {
builtin.Arch.arm,
builtin.Arch.armeb,
builtin.Arch.aarch64,
builtin.Arch.aarch64_be,
builtin.Arch.thumb,
builtin.Arch.thumbeb,
=> true,
else => false,
};
const is_arm_32 = is_arm_arch and !is_arm_64;

View File

@ -1,6 +1,5 @@
// ARM specific builtins
const builtin = @import("builtin");
const is_test = builtin.is_test;
const __divmodsi4 = @import("int.zig").__divmodsi4;
const __udivmodsi4 = @import("int.zig").__udivmodsi4;
@ -33,18 +32,14 @@ pub fn __aeabi_memclr(dest: [*]u8, n: usize) callconv(.AAPCS) void {
_ = memset(dest, 0, n);
}
pub fn __aeabi_unwind_cpp_pr0() callconv(.C) void {
unreachable;
}
pub fn __aeabi_unwind_cpp_pr1() callconv(.C) void {
unreachable;
}
pub fn __aeabi_unwind_cpp_pr2() callconv(.C) void {
unreachable;
}
// Dummy functions to avoid errors during the linking phase
pub fn __aeabi_unwind_cpp_pr0() callconv(.C) void {}
pub fn __aeabi_unwind_cpp_pr1() callconv(.C) void {}
pub fn __aeabi_unwind_cpp_pr2() callconv(.C) void {}
// This function can only clobber r0 according to the ABI
pub fn __aeabi_read_tp() callconv(.Naked) void {
@setRuntimeSafety(false);
asm volatile (
\\ mrc p15, 0, r0, c13, c0, 3
\\ bx lr
@ -56,6 +51,7 @@ pub fn __aeabi_read_tp() callconv(.Naked) void {
// calling convention is always respected
pub fn __aeabi_uidivmod() callconv(.Naked) void {
@setRuntimeSafety(false);
// Divide r0 by r1; the quotient goes in r0, the remainder in r1
asm volatile (
\\ push {lr}
@ -73,6 +69,7 @@ pub fn __aeabi_uidivmod() callconv(.Naked) void {
}
pub fn __aeabi_uldivmod() callconv(.Naked) void {
@setRuntimeSafety(false);
// Divide r1:r0 by r3:r2; the quotient goes in r1:r0, the remainder in r3:r2
asm volatile (
\\ push {r4, lr}
@ -92,6 +89,7 @@ pub fn __aeabi_uldivmod() callconv(.Naked) void {
}
pub fn __aeabi_idivmod() callconv(.Naked) void {
@setRuntimeSafety(false);
// Divide r0 by r1; the quotient goes in r0, the remainder in r1
asm volatile (
\\ push {lr}
@ -109,6 +107,7 @@ pub fn __aeabi_idivmod() callconv(.Naked) void {
}
pub fn __aeabi_ldivmod() callconv(.Naked) void {
@setRuntimeSafety(false);
// Divide r1:r0 by r3:r2; the quotient goes in r1:r0, the remainder in r3:r2
asm volatile (
\\ push {r4, lr}

View File

@ -1,95 +0,0 @@
// Ported from:
//
// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/arm/aeabi_dcmp.S
const ConditionalOperator = enum {
Eq,
Lt,
Le,
Ge,
Gt,
};
pub fn __aeabi_dcmpeq() callconv(.Naked) noreturn {
@setRuntimeSafety(false);
@call(.{ .modifier = .always_inline }, aeabi_dcmp, .{.Eq});
unreachable;
}
pub fn __aeabi_dcmplt() callconv(.Naked) noreturn {
@setRuntimeSafety(false);
@call(.{ .modifier = .always_inline }, aeabi_dcmp, .{.Lt});
unreachable;
}
pub fn __aeabi_dcmple() callconv(.Naked) noreturn {
@setRuntimeSafety(false);
@call(.{ .modifier = .always_inline }, aeabi_dcmp, .{.Le});
unreachable;
}
pub fn __aeabi_dcmpge() callconv(.Naked) noreturn {
@setRuntimeSafety(false);
@call(.{ .modifier = .always_inline }, aeabi_dcmp, .{.Ge});
unreachable;
}
pub fn __aeabi_dcmpgt() callconv(.Naked) noreturn {
@setRuntimeSafety(false);
@call(.{ .modifier = .always_inline }, aeabi_dcmp, .{.Gt});
unreachable;
}
fn aeabi_dcmp(comptime cond: ConditionalOperator) void {
@setRuntimeSafety(false);
asm volatile (
\\ push { r4, lr }
);
switch (cond) {
.Eq => asm volatile (
\\ bl __eqdf2
\\ cmp r0, #0
\\ beq 1f
\\ movs r0, #0
\\ pop { r4, pc }
\\ 1:
),
.Lt => asm volatile (
\\ bl __ltdf2
\\ cmp r0, #0
\\ blt 1f
\\ movs r0, #0
\\ pop { r4, pc }
\\ 1:
),
.Le => asm volatile (
\\ bl __ledf2
\\ cmp r0, #0
\\ ble 1f
\\ movs r0, #0
\\ pop { r4, pc }
\\ 1:
),
.Ge => asm volatile (
\\ bl __ltdf2
\\ cmp r0, #0
\\ bge 1f
\\ movs r0, #0
\\ pop { r4, pc }
\\ 1:
),
.Gt => asm volatile (
\\ bl __gtdf2
\\ cmp r0, #0
\\ bgt 1f
\\ movs r0, #0
\\ pop { r4, pc }
\\ 1:
),
}
asm volatile (
\\ movs r0, #1
\\ pop { r4, pc }
);
}

View File

@ -1,95 +0,0 @@
// Ported from:
//
// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/arm/aeabi_fcmp.S
const ConditionalOperator = enum {
Eq,
Lt,
Le,
Ge,
Gt,
};
pub fn __aeabi_fcmpeq() callconv(.Naked) noreturn {
@setRuntimeSafety(false);
@call(.{ .modifier = .always_inline }, aeabi_fcmp, .{.Eq});
unreachable;
}
pub fn __aeabi_fcmplt() callconv(.Naked) noreturn {
@setRuntimeSafety(false);
@call(.{ .modifier = .always_inline }, aeabi_fcmp, .{.Lt});
unreachable;
}
pub fn __aeabi_fcmple() callconv(.Naked) noreturn {
@setRuntimeSafety(false);
@call(.{ .modifier = .always_inline }, aeabi_fcmp, .{.Le});
unreachable;
}
pub fn __aeabi_fcmpge() callconv(.Naked) noreturn {
@setRuntimeSafety(false);
@call(.{ .modifier = .always_inline }, aeabi_fcmp, .{.Ge});
unreachable;
}
pub fn __aeabi_fcmpgt() callconv(.Naked) noreturn {
@setRuntimeSafety(false);
@call(.{ .modifier = .always_inline }, aeabi_fcmp, .{.Gt});
unreachable;
}
fn aeabi_fcmp(comptime cond: ConditionalOperator) void {
@setRuntimeSafety(false);
asm volatile (
\\ push { r4, lr }
);
switch (cond) {
.Eq => asm volatile (
\\ bl __eqsf2
\\ cmp r0, #0
\\ beq 1f
\\ movs r0, #0
\\ pop { r4, pc }
\\ 1:
),
.Lt => asm volatile (
\\ bl __ltsf2
\\ cmp r0, #0
\\ blt 1f
\\ movs r0, #0
\\ pop { r4, pc }
\\ 1:
),
.Le => asm volatile (
\\ bl __lesf2
\\ cmp r0, #0
\\ ble 1f
\\ movs r0, #0
\\ pop { r4, pc }
\\ 1:
),
.Ge => asm volatile (
\\ bl __ltsf2
\\ cmp r0, #0
\\ bge 1f
\\ movs r0, #0
\\ pop { r4, pc }
\\ 1:
),
.Gt => asm volatile (
\\ bl __gtsf2
\\ cmp r0, #0
\\ bgt 1f
\\ movs r0, #0
\\ pop { r4, pc }
\\ 1:
),
}
asm volatile (
\\ movs r0, #1
\\ pop { r4, pc }
);
}

View File

@ -0,0 +1,116 @@
const builtin = @import("builtin");
fn __clzsi2_generic(a: i32) callconv(.C) i32 {
@setRuntimeSafety(builtin.is_test);
var x = @bitCast(u32, a);
var n: i32 = 32;
// Count first bit set using binary search, from Hacker's Delight
var y: u32 = 0;
inline for ([_]i32{ 16, 8, 4, 2, 1 }) |shift| {
y = x >> shift;
if (y != 0) {
n = n - shift;
x = y;
}
}
return n - @bitCast(i32, x);
}
fn __clzsi2_thumb1() callconv(.Naked) void {
@setRuntimeSafety(builtin.is_test);
// Similar to the generic version with the last two rounds replaced by a LUT
asm volatile (
\\ movs r1, #32
\\ lsrs r2, r0, #16
\\ beq 1f
\\ subs r1, #16
\\ movs r0, r2
\\ 1:
\\ lsrs r2, r0, #8
\\ beq 1f
\\ subs r1, #8
\\ movs r0, r2
\\ 1:
\\ lsrs r2, r0, #4
\\ beq 1f
\\ subs r1, #4
\\ movs r0, r2
\\ 1:
\\ ldr r3, =LUT
\\ ldrb r0, [r3, r0]
\\ subs r0, r1, r0
\\ bx lr
\\ .p2align 2
\\ LUT:
\\ .byte 4,3,2,2,1,1,1,1,0,0,0,0,0,0,0,0
);
unreachable;
}
fn __clzsi2_arm32() callconv(.Naked) void {
@setRuntimeSafety(builtin.is_test);
asm volatile (
\\ // Assumption: n != 0
\\ // r0: n
\\ // r1: count of leading zeros in n + 1
\\ // r2: scratch register for shifted r0
\\ mov r1, #1
\\
\\ // Basic block:
\\ // if ((r0 >> SHIFT) == 0)
\\ // r1 += SHIFT;
\\ // else
\\ // r0 >>= SHIFT;
\\ // for descending powers of two as SHIFT.
\\ lsrs r2, r0, #16
\\ movne r0, r2
\\ addeq r1, #16
\\
\\ lsrs r2, r0, #8
\\ movne r0, r2
\\ addeq r1, #8
\\
\\ lsrs r2, r0, #4
\\ movne r0, r2
\\ addeq r1, #4
\\
\\ lsrs r2, r0, #2
\\ movne r0, r2
\\ addeq r1, #2
\\
\\ // The basic block invariants at this point are (r0 >> 2) == 0 and
\\ // r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1.
\\ //
\\ // r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1)f
\\ // ---+----------------+----------------+------------+--------------
\\ // 1 | 1 | 0 | 0 | 1
\\ // 2 | 0 | 1 | -1 | 0
\\ // 3 | 0 | 1 | -1 | 0
\\ //
\\ // The r1's initial value of 1 compensates for the 1 here.
\\ sub r0, r1, r0, lsr #1
\\ bx lr
);
unreachable;
}
pub const __clzsi2 = blk: {
if (builtin.arch.isARM()) {
break :blk __clzsi2_arm32;
} else if (builtin.arch.isThumb()) {
break :blk __clzsi2_thumb1;
} else {
break :blk __clzsi2_generic;
}
};
test "test clzsi2" {
_ = @import("clzsi2_test.zig");
}

View File

@ -0,0 +1,292 @@
const clzsi2 = @import("clzsi2.zig");
const testing = @import("std").testing;
fn test__clzsi2(a: u32, expected: i32) void {
var nakedClzsi2 = clzsi2.__clzsi2;
var actualClzsi2 = @ptrCast(fn (a: i32) callconv(.C) i32, nakedClzsi2);
var x = @intCast(i32, a);
var result = actualClzsi2(x);
testing.expectEqual(expected, result);
}
test "clzsi2" {
test__clzsi2(0x00800000, 8);
test__clzsi2(0x01000000, 7);
test__clzsi2(0x02000000, 6);
test__clzsi2(0x03000000, 6);
test__clzsi2(0x04000000, 5);
test__clzsi2(0x05000000, 5);
test__clzsi2(0x06000000, 5);
test__clzsi2(0x07000000, 5);
test__clzsi2(0x08000000, 4);
test__clzsi2(0x09000000, 4);
test__clzsi2(0x0A000000, 4);
test__clzsi2(0x0B000000, 4);
test__clzsi2(0x0C000000, 4);
test__clzsi2(0x0D000000, 4);
test__clzsi2(0x0E000000, 4);
test__clzsi2(0x0F000000, 4);
test__clzsi2(0x10000000, 3);
test__clzsi2(0x11000000, 3);
test__clzsi2(0x12000000, 3);
test__clzsi2(0x13000000, 3);
test__clzsi2(0x14000000, 3);
test__clzsi2(0x15000000, 3);
test__clzsi2(0x16000000, 3);
test__clzsi2(0x17000000, 3);
test__clzsi2(0x18000000, 3);
test__clzsi2(0x19000000, 3);
test__clzsi2(0x1A000000, 3);
test__clzsi2(0x1B000000, 3);
test__clzsi2(0x1C000000, 3);
test__clzsi2(0x1D000000, 3);
test__clzsi2(0x1E000000, 3);
test__clzsi2(0x1F000000, 3);
test__clzsi2(0x20000000, 2);
test__clzsi2(0x21000000, 2);
test__clzsi2(0x22000000, 2);
test__clzsi2(0x23000000, 2);
test__clzsi2(0x24000000, 2);
test__clzsi2(0x25000000, 2);
test__clzsi2(0x26000000, 2);
test__clzsi2(0x27000000, 2);
test__clzsi2(0x28000000, 2);
test__clzsi2(0x29000000, 2);
test__clzsi2(0x2A000000, 2);
test__clzsi2(0x2B000000, 2);
test__clzsi2(0x2C000000, 2);
test__clzsi2(0x2D000000, 2);
test__clzsi2(0x2E000000, 2);
test__clzsi2(0x2F000000, 2);
test__clzsi2(0x30000000, 2);
test__clzsi2(0x31000000, 2);
test__clzsi2(0x32000000, 2);
test__clzsi2(0x33000000, 2);
test__clzsi2(0x34000000, 2);
test__clzsi2(0x35000000, 2);
test__clzsi2(0x36000000, 2);
test__clzsi2(0x37000000, 2);
test__clzsi2(0x38000000, 2);
test__clzsi2(0x39000000, 2);
test__clzsi2(0x3A000000, 2);
test__clzsi2(0x3B000000, 2);
test__clzsi2(0x3C000000, 2);
test__clzsi2(0x3D000000, 2);
test__clzsi2(0x3E000000, 2);
test__clzsi2(0x3F000000, 2);
test__clzsi2(0x40000000, 1);
test__clzsi2(0x41000000, 1);
test__clzsi2(0x42000000, 1);
test__clzsi2(0x43000000, 1);
test__clzsi2(0x44000000, 1);
test__clzsi2(0x45000000, 1);
test__clzsi2(0x46000000, 1);
test__clzsi2(0x47000000, 1);
test__clzsi2(0x48000000, 1);
test__clzsi2(0x49000000, 1);
test__clzsi2(0x4A000000, 1);
test__clzsi2(0x4B000000, 1);
test__clzsi2(0x4C000000, 1);
test__clzsi2(0x4D000000, 1);
test__clzsi2(0x4E000000, 1);
test__clzsi2(0x4F000000, 1);
test__clzsi2(0x50000000, 1);
test__clzsi2(0x51000000, 1);
test__clzsi2(0x52000000, 1);
test__clzsi2(0x53000000, 1);
test__clzsi2(0x54000000, 1);
test__clzsi2(0x55000000, 1);
test__clzsi2(0x56000000, 1);
test__clzsi2(0x57000000, 1);
test__clzsi2(0x58000000, 1);
test__clzsi2(0x59000000, 1);
test__clzsi2(0x5A000000, 1);
test__clzsi2(0x5B000000, 1);
test__clzsi2(0x5C000000, 1);
test__clzsi2(0x5D000000, 1);
test__clzsi2(0x5E000000, 1);
test__clzsi2(0x5F000000, 1);
test__clzsi2(0x60000000, 1);
test__clzsi2(0x61000000, 1);
test__clzsi2(0x62000000, 1);
test__clzsi2(0x63000000, 1);
test__clzsi2(0x64000000, 1);
test__clzsi2(0x65000000, 1);
test__clzsi2(0x66000000, 1);
test__clzsi2(0x67000000, 1);
test__clzsi2(0x68000000, 1);
test__clzsi2(0x69000000, 1);
test__clzsi2(0x6A000000, 1);
test__clzsi2(0x6B000000, 1);
test__clzsi2(0x6C000000, 1);
test__clzsi2(0x6D000000, 1);
test__clzsi2(0x6E000000, 1);
test__clzsi2(0x6F000000, 1);
test__clzsi2(0x70000000, 1);
test__clzsi2(0x71000000, 1);
test__clzsi2(0x72000000, 1);
test__clzsi2(0x73000000, 1);
test__clzsi2(0x74000000, 1);
test__clzsi2(0x75000000, 1);
test__clzsi2(0x76000000, 1);
test__clzsi2(0x77000000, 1);
test__clzsi2(0x78000000, 1);
test__clzsi2(0x79000000, 1);
test__clzsi2(0x7A000000, 1);
test__clzsi2(0x7B000000, 1);
test__clzsi2(0x7C000000, 1);
test__clzsi2(0x7D000000, 1);
test__clzsi2(0x7E000000, 1);
test__clzsi2(0x7F000000, 1);
test__clzsi2(0x80000000, 0);
test__clzsi2(0x81000000, 0);
test__clzsi2(0x82000000, 0);
test__clzsi2(0x83000000, 0);
test__clzsi2(0x84000000, 0);
test__clzsi2(0x85000000, 0);
test__clzsi2(0x86000000, 0);
test__clzsi2(0x87000000, 0);
test__clzsi2(0x88000000, 0);
test__clzsi2(0x89000000, 0);
test__clzsi2(0x8A000000, 0);
test__clzsi2(0x8B000000, 0);
test__clzsi2(0x8C000000, 0);
test__clzsi2(0x8D000000, 0);
test__clzsi2(0x8E000000, 0);
test__clzsi2(0x8F000000, 0);
test__clzsi2(0x90000000, 0);
test__clzsi2(0x91000000, 0);
test__clzsi2(0x92000000, 0);
test__clzsi2(0x93000000, 0);
test__clzsi2(0x94000000, 0);
test__clzsi2(0x95000000, 0);
test__clzsi2(0x96000000, 0);
test__clzsi2(0x97000000, 0);
test__clzsi2(0x98000000, 0);
test__clzsi2(0x99000000, 0);
test__clzsi2(0x9A000000, 0);
test__clzsi2(0x9B000000, 0);
test__clzsi2(0x9C000000, 0);
test__clzsi2(0x9D000000, 0);
test__clzsi2(0x9E000000, 0);
test__clzsi2(0x9F000000, 0);
test__clzsi2(0xA0000000, 0);
test__clzsi2(0xA1000000, 0);
test__clzsi2(0xA2000000, 0);
test__clzsi2(0xA3000000, 0);
test__clzsi2(0xA4000000, 0);
test__clzsi2(0xA5000000, 0);
test__clzsi2(0xA6000000, 0);
test__clzsi2(0xA7000000, 0);
test__clzsi2(0xA8000000, 0);
test__clzsi2(0xA9000000, 0);
test__clzsi2(0xAA000000, 0);
test__clzsi2(0xAB000000, 0);
test__clzsi2(0xAC000000, 0);
test__clzsi2(0xAD000000, 0);
test__clzsi2(0xAE000000, 0);
test__clzsi2(0xAF000000, 0);
test__clzsi2(0xB0000000, 0);
test__clzsi2(0xB1000000, 0);
test__clzsi2(0xB2000000, 0);
test__clzsi2(0xB3000000, 0);
test__clzsi2(0xB4000000, 0);
test__clzsi2(0xB5000000, 0);
test__clzsi2(0xB6000000, 0);
test__clzsi2(0xB7000000, 0);
test__clzsi2(0xB8000000, 0);
test__clzsi2(0xB9000000, 0);
test__clzsi2(0xBA000000, 0);
test__clzsi2(0xBB000000, 0);
test__clzsi2(0xBC000000, 0);
test__clzsi2(0xBD000000, 0);
test__clzsi2(0xBE000000, 0);
test__clzsi2(0xBF000000, 0);
test__clzsi2(0xC0000000, 0);
test__clzsi2(0xC1000000, 0);
test__clzsi2(0xC2000000, 0);
test__clzsi2(0xC3000000, 0);
test__clzsi2(0xC4000000, 0);
test__clzsi2(0xC5000000, 0);
test__clzsi2(0xC6000000, 0);
test__clzsi2(0xC7000000, 0);
test__clzsi2(0xC8000000, 0);
test__clzsi2(0xC9000000, 0);
test__clzsi2(0xCA000000, 0);
test__clzsi2(0xCB000000, 0);
test__clzsi2(0xCC000000, 0);
test__clzsi2(0xCD000000, 0);
test__clzsi2(0xCE000000, 0);
test__clzsi2(0xCF000000, 0);
test__clzsi2(0xD0000000, 0);
test__clzsi2(0xD1000000, 0);
test__clzsi2(0xD2000000, 0);
test__clzsi2(0xD3000000, 0);
test__clzsi2(0xD4000000, 0);
test__clzsi2(0xD5000000, 0);
test__clzsi2(0xD6000000, 0);
test__clzsi2(0xD7000000, 0);
test__clzsi2(0xD8000000, 0);
test__clzsi2(0xD9000000, 0);
test__clzsi2(0xDA000000, 0);
test__clzsi2(0xDB000000, 0);
test__clzsi2(0xDC000000, 0);
test__clzsi2(0xDD000000, 0);
test__clzsi2(0xDE000000, 0);
test__clzsi2(0xDF000000, 0);
test__clzsi2(0xE0000000, 0);
test__clzsi2(0xE1000000, 0);
test__clzsi2(0xE2000000, 0);
test__clzsi2(0xE3000000, 0);
test__clzsi2(0xE4000000, 0);
test__clzsi2(0xE5000000, 0);
test__clzsi2(0xE6000000, 0);
test__clzsi2(0xE7000000, 0);
test__clzsi2(0xE8000000, 0);
test__clzsi2(0xE9000000, 0);
test__clzsi2(0xEA000000, 0);
test__clzsi2(0xEB000000, 0);
test__clzsi2(0xEC000000, 0);
test__clzsi2(0xED000000, 0);
test__clzsi2(0xEE000000, 0);
test__clzsi2(0xEF000000, 0);
test__clzsi2(0xF0000000, 0);
test__clzsi2(0xF1000000, 0);
test__clzsi2(0xF2000000, 0);
test__clzsi2(0xF3000000, 0);
test__clzsi2(0xF4000000, 0);
test__clzsi2(0xF5000000, 0);
test__clzsi2(0xF6000000, 0);
test__clzsi2(0xF7000000, 0);
test__clzsi2(0xF8000000, 0);
test__clzsi2(0xF9000000, 0);
test__clzsi2(0xFA000000, 0);
test__clzsi2(0xFB000000, 0);
test__clzsi2(0xFC000000, 0);
test__clzsi2(0xFD000000, 0);
test__clzsi2(0xFE000000, 0);
test__clzsi2(0xFF000000, 0);
test__clzsi2(0x00000001, 31);
test__clzsi2(0x00000002, 30);
test__clzsi2(0x00000004, 29);
test__clzsi2(0x00000008, 28);
test__clzsi2(0x00000010, 27);
test__clzsi2(0x00000020, 26);
test__clzsi2(0x00000040, 25);
test__clzsi2(0x00000080, 24);
test__clzsi2(0x00000100, 23);
test__clzsi2(0x00000200, 22);
test__clzsi2(0x00000400, 21);
test__clzsi2(0x00000800, 20);
test__clzsi2(0x00001000, 19);
test__clzsi2(0x00002000, 18);
test__clzsi2(0x00004000, 17);
test__clzsi2(0x00008000, 16);
test__clzsi2(0x00010000, 15);
test__clzsi2(0x00020000, 14);
test__clzsi2(0x00040000, 13);
test__clzsi2(0x00080000, 12);
test__clzsi2(0x00100000, 11);
test__clzsi2(0x00200000, 10);
test__clzsi2(0x00400000, 9);
}

View File

@ -0,0 +1,253 @@
// Ported from:
//
// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/comparesf2.c
const std = @import("std");
const builtin = @import("builtin");
const LE = extern enum(i32) {
Less = -1,
Equal = 0,
Greater = 1,
Unordered = 1,
};
const GE = extern enum(i32) {
Less = -1,
Equal = 0,
Greater = 1,
Unordered = -1,
};
pub fn cmp(comptime T: type, comptime RT: type, a: T, b: T) RT {
@setRuntimeSafety(builtin.is_test);
const srep_t = @IntType(true, T.bit_count);
const rep_t = @IntType(false, T.bit_count);
const significandBits = std.math.floatMantissaBits(T);
const exponentBits = std.math.floatExponentBits(T);
const signBit = (@as(rep_t, 1) << (significandBits + exponentBits));
const absMask = signBit - 1;
const infRep = @bitCast(rep_t, std.math.inf(T));
const aInt = @bitCast(srep_t, a);
const bInt = @bitCast(srep_t, b);
const aAbs = @bitCast(rep_t, aInt) & absMask;
const bAbs = @bitCast(rep_t, bInt) & absMask;
// If either a or b is NaN, they are unordered.
if (aAbs > infRep or bAbs > infRep) return .Unordered;
// If a and b are both zeros, they are equal.
if ((aAbs | bAbs) == 0) return .Equal;
// If at least one of a and b is positive, we get the same result comparing
// a and b as signed integers as we would with a fp_ting-point compare.
if ((aInt & bInt) >= 0) {
if (aInt < bInt) {
return .Less;
} else if (aInt == bInt) {
return .Equal;
} else return .Greater;
}
// Otherwise, both are negative, so we need to flip the sense of the
// comparison to get the correct result. (This assumes a twos- or ones-
// complement integer representation; if integers are represented in a
// sign-magnitude representation, then this flip is incorrect).
else {
if (aInt > bInt) {
return .Less;
} else if (aInt == bInt) {
return .Equal;
} else return .Greater;
}
}
pub fn unordcmp(comptime T: type, a: T, b: T) i32 {
@setRuntimeSafety(builtin.is_test);
const rep_t = @IntType(false, T.bit_count);
const significandBits = std.math.floatMantissaBits(T);
const exponentBits = std.math.floatExponentBits(T);
const signBit = (@as(rep_t, 1) << (significandBits + exponentBits));
const absMask = signBit - 1;
const infRep = @bitCast(rep_t, std.math.inf(T));
const aAbs: rep_t = @bitCast(rep_t, a) & absMask;
const bAbs: rep_t = @bitCast(rep_t, b) & absMask;
return @boolToInt(aAbs > infRep or bAbs > infRep);
}
// Comparison between f32
pub fn __lesf2(a: f32, b: f32) callconv(.C) i32 {
@setRuntimeSafety(builtin.is_test);
return @bitCast(i32, @call(.{ .modifier = .always_inline }, cmp, .{ f32, LE, a, b }));
}
pub fn __gesf2(a: f32, b: f32) callconv(.C) i32 {
@setRuntimeSafety(builtin.is_test);
return @bitCast(i32, @call(.{ .modifier = .always_inline }, cmp, .{ f32, GE, a, b }));
}
pub fn __eqsf2(a: f32, b: f32) callconv(.C) i32 {
return __lesf2(a, b);
}
pub fn __ltsf2(a: f32, b: f32) callconv(.C) i32 {
return __lesf2(a, b);
}
pub fn __nesf2(a: f32, b: f32) callconv(.C) i32 {
return __lesf2(a, b);
}
pub fn __gtsf2(a: f32, b: f32) callconv(.C) i32 {
return __gesf2(a, b);
}
// Comparison between f64
pub fn __ledf2(a: f64, b: f64) callconv(.C) i32 {
@setRuntimeSafety(builtin.is_test);
return @bitCast(i32, @call(.{ .modifier = .always_inline }, cmp, .{ f64, LE, a, b }));
}
pub fn __gedf2(a: f64, b: f64) callconv(.C) i32 {
@setRuntimeSafety(builtin.is_test);
return @bitCast(i32, @call(.{ .modifier = .always_inline }, cmp, .{ f64, GE, a, b }));
}
pub fn __eqdf2(a: f64, b: f64) callconv(.C) i32 {
return __ledf2(a, b);
}
pub fn __ltdf2(a: f64, b: f64) callconv(.C) i32 {
return __ledf2(a, b);
}
pub fn __nedf2(a: f64, b: f64) callconv(.C) i32 {
return __ledf2(a, b);
}
pub fn __gtdf2(a: f64, b: f64) callconv(.C) i32 {
return __gedf2(a, b);
}
// Comparison between f128
pub fn __letf2(a: f128, b: f128) callconv(.C) i32 {
@setRuntimeSafety(builtin.is_test);
return @bitCast(i32, @call(.{ .modifier = .always_inline }, cmp, .{ f128, LE, a, b }));
}
pub fn __getf2(a: f128, b: f128) callconv(.C) i32 {
@setRuntimeSafety(builtin.is_test);
return @bitCast(i32, @call(.{ .modifier = .always_inline }, cmp, .{ f128, GE, a, b }));
}
pub fn __eqtf2(a: f128, b: f128) callconv(.C) i32 {
return __letf2(a, b);
}
pub fn __lttf2(a: f128, b: f128) callconv(.C) i32 {
return __letf2(a, b);
}
pub fn __netf2(a: f128, b: f128) callconv(.C) i32 {
return __letf2(a, b);
}
pub fn __gttf2(a: f128, b: f128) callconv(.C) i32 {
return __getf2(a, b);
}
// Unordered comparison between f32/f64/f128
pub fn __unordsf2(a: f32, b: f32) callconv(.C) i32 {
@setRuntimeSafety(builtin.is_test);
return @call(.{ .modifier = .always_inline }, unordcmp, .{ f32, a, b });
}
pub fn __unorddf2(a: f64, b: f64) callconv(.C) i32 {
@setRuntimeSafety(builtin.is_test);
return @call(.{ .modifier = .always_inline }, unordcmp, .{ f64, a, b });
}
pub fn __unordtf2(a: f128, b: f128) callconv(.C) i32 {
@setRuntimeSafety(builtin.is_test);
return @call(.{ .modifier = .always_inline }, unordcmp, .{ f128, a, b });
}
// ARM EABI intrinsics
pub fn __aeabi_fcmpeq(a: f32, b: f32) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
return @boolToInt(@call(.{ .modifier = .always_inline }, __eqsf2, .{ a, b }) == 0);
}
pub fn __aeabi_fcmplt(a: f32, b: f32) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
return @boolToInt(@call(.{ .modifier = .always_inline }, __ltsf2, .{ a, b }) < 0);
}
pub fn __aeabi_fcmple(a: f32, b: f32) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
return @boolToInt(@call(.{ .modifier = .always_inline }, __lesf2, .{ a, b }) <= 0);
}
pub fn __aeabi_fcmpge(a: f32, b: f32) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
return @boolToInt(@call(.{ .modifier = .always_inline }, __gesf2, .{ a, b }) >= 0);
}
pub fn __aeabi_fcmpgt(a: f32, b: f32) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
return @boolToInt(@call(.{ .modifier = .always_inline }, __gtsf2, .{ a, b }) > 0);
}
pub fn __aeabi_fcmpun(a: f32, b: f32) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
return @call(.{ .modifier = .always_inline }, __unordsf2, .{ a, b });
}
pub fn __aeabi_dcmpeq(a: f64, b: f64) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
return @boolToInt(@call(.{ .modifier = .always_inline }, __eqdf2, .{ a, b }) == 0);
}
pub fn __aeabi_dcmplt(a: f64, b: f64) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
return @boolToInt(@call(.{ .modifier = .always_inline }, __ltdf2, .{ a, b }) < 0);
}
pub fn __aeabi_dcmple(a: f64, b: f64) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
return @boolToInt(@call(.{ .modifier = .always_inline }, __ledf2, .{ a, b }) <= 0);
}
pub fn __aeabi_dcmpge(a: f64, b: f64) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
return @boolToInt(@call(.{ .modifier = .always_inline }, __gedf2, .{ a, b }) >= 0);
}
pub fn __aeabi_dcmpgt(a: f64, b: f64) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
return @boolToInt(@call(.{ .modifier = .always_inline }, __gtdf2, .{ a, b }) > 0);
}
pub fn __aeabi_dcmpun(a: f64, b: f64) callconv(.AAPCS) i32 {
@setRuntimeSafety(false);
return @call(.{ .modifier = .always_inline }, __unorddf2, .{ a, b });
}
test "comparesf2" {
_ = @import("comparesf2_test.zig");
}
test "comparedf2" {
_ = @import("comparedf2_test.zig");
}

View File

@ -1,127 +0,0 @@
// Ported from:
//
// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/comparedf2.c
const std = @import("std");
const builtin = @import("builtin");
const is_test = builtin.is_test;
const fp_t = f64;
const rep_t = u64;
const srep_t = i64;
const typeWidth = rep_t.bit_count;
const significandBits = std.math.floatMantissaBits(fp_t);
const exponentBits = std.math.floatExponentBits(fp_t);
const signBit = (@as(rep_t, 1) << (significandBits + exponentBits));
const absMask = signBit - 1;
const implicitBit = @as(rep_t, 1) << significandBits;
const significandMask = implicitBit - 1;
const exponentMask = absMask ^ significandMask;
const infRep = @bitCast(rep_t, std.math.inf(fp_t));
// TODO https://github.com/ziglang/zig/issues/641
// and then make the return types of some of these functions the enum instead of c_int
const LE_LESS = @as(c_int, -1);
const LE_EQUAL = @as(c_int, 0);
const LE_GREATER = @as(c_int, 1);
const LE_UNORDERED = @as(c_int, 1);
pub fn __ledf2(a: fp_t, b: fp_t) callconv(.C) c_int {
@setRuntimeSafety(is_test);
const aInt: srep_t = @bitCast(srep_t, a);
const bInt: srep_t = @bitCast(srep_t, b);
const aAbs: rep_t = @bitCast(rep_t, aInt) & absMask;
const bAbs: rep_t = @bitCast(rep_t, bInt) & absMask;
// If either a or b is NaN, they are unordered.
if (aAbs > infRep or bAbs > infRep) return LE_UNORDERED;
// If a and b are both zeros, they are equal.
if ((aAbs | bAbs) == 0) return LE_EQUAL;
// If at least one of a and b is positive, we get the same result comparing
// a and b as signed integers as we would with a fp_ting-point compare.
if ((aInt & bInt) >= 0) {
if (aInt < bInt) {
return LE_LESS;
} else if (aInt == bInt) {
return LE_EQUAL;
} else return LE_GREATER;
}
// Otherwise, both are negative, so we need to flip the sense of the
// comparison to get the correct result. (This assumes a twos- or ones-
// complement integer representation; if integers are represented in a
// sign-magnitude representation, then this flip is incorrect).
else {
if (aInt > bInt) {
return LE_LESS;
} else if (aInt == bInt) {
return LE_EQUAL;
} else return LE_GREATER;
}
}
// TODO https://github.com/ziglang/zig/issues/641
// and then make the return types of some of these functions the enum instead of c_int
const GE_LESS = @as(c_int, -1);
const GE_EQUAL = @as(c_int, 0);
const GE_GREATER = @as(c_int, 1);
const GE_UNORDERED = @as(c_int, -1); // Note: different from LE_UNORDERED
pub fn __gedf2(a: fp_t, b: fp_t) callconv(.C) c_int {
@setRuntimeSafety(is_test);
const aInt: srep_t = @bitCast(srep_t, a);
const bInt: srep_t = @bitCast(srep_t, b);
const aAbs: rep_t = @bitCast(rep_t, aInt) & absMask;
const bAbs: rep_t = @bitCast(rep_t, bInt) & absMask;
if (aAbs > infRep or bAbs > infRep) return GE_UNORDERED;
if ((aAbs | bAbs) == 0) return GE_EQUAL;
if ((aInt & bInt) >= 0) {
if (aInt < bInt) {
return GE_LESS;
} else if (aInt == bInt) {
return GE_EQUAL;
} else return GE_GREATER;
} else {
if (aInt > bInt) {
return GE_LESS;
} else if (aInt == bInt) {
return GE_EQUAL;
} else return GE_GREATER;
}
}
pub fn __unorddf2(a: fp_t, b: fp_t) callconv(.C) c_int {
@setRuntimeSafety(is_test);
const aAbs: rep_t = @bitCast(rep_t, a) & absMask;
const bAbs: rep_t = @bitCast(rep_t, b) & absMask;
return @boolToInt(aAbs > infRep or bAbs > infRep);
}
pub fn __eqdf2(a: fp_t, b: fp_t) callconv(.C) c_int {
return __ledf2(a, b);
}
pub fn __ltdf2(a: fp_t, b: fp_t) callconv(.C) c_int {
return __ledf2(a, b);
}
pub fn __nedf2(a: fp_t, b: fp_t) callconv(.C) c_int {
return __ledf2(a, b);
}
pub fn __gtdf2(a: fp_t, b: fp_t) callconv(.C) c_int {
return __gedf2(a, b);
}
pub fn __aeabi_dcmpun(a: fp_t, b: fp_t) callconv(.AAPCS) c_int {
@setRuntimeSafety(false);
return @call(.{ .modifier = .always_inline }, __unorddf2, .{ a, b });
}
test "import comparedf2" {
_ = @import("comparedf2_test.zig");
}

View File

@ -6,7 +6,7 @@ const std = @import("std");
const builtin = @import("builtin");
const is_test = builtin.is_test;
const comparedf2 = @import("comparedf2.zig");
const comparedf2 = @import("compareXf2.zig");
const TestVector = struct {
a: f64,

View File

@ -1,127 +0,0 @@
// Ported from:
//
// https://github.com/llvm/llvm-project/commit/d674d96bc56c0f377879d01c9d8dfdaaa7859cdb/compiler-rt/lib/builtins/comparesf2.c
const std = @import("std");
const builtin = @import("builtin");
const is_test = builtin.is_test;
const fp_t = f32;
const rep_t = u32;
const srep_t = i32;
const typeWidth = rep_t.bit_count;
const significandBits = std.math.floatMantissaBits(fp_t);
const exponentBits = std.math.floatExponentBits(fp_t);
const signBit = (@as(rep_t, 1) << (significandBits + exponentBits));
const absMask = signBit - 1;
const implicitBit = @as(rep_t, 1) << significandBits;
const significandMask = implicitBit - 1;
const exponentMask = absMask ^ significandMask;
const infRep = @bitCast(rep_t, std.math.inf(fp_t));
// TODO https://github.com/ziglang/zig/issues/641
// and then make the return types of some of these functions the enum instead of c_int
const LE_LESS = @as(c_int, -1);
const LE_EQUAL = @as(c_int, 0);
const LE_GREATER = @as(c_int, 1);
const LE_UNORDERED = @as(c_int, 1);
pub fn __lesf2(a: fp_t, b: fp_t) callconv(.C) c_int {
@setRuntimeSafety(is_test);
const aInt: srep_t = @bitCast(srep_t, a);
const bInt: srep_t = @bitCast(srep_t, b);
const aAbs: rep_t = @bitCast(rep_t, aInt) & absMask;
const bAbs: rep_t = @bitCast(rep_t, bInt) & absMask;
// If either a or b is NaN, they are unordered.
if (aAbs > infRep or bAbs > infRep) return LE_UNORDERED;
// If a and b are both zeros, they are equal.
if ((aAbs | bAbs) == 0) return LE_EQUAL;
// If at least one of a and b is positive, we get the same result comparing
// a and b as signed integers as we would with a fp_ting-point compare.
if ((aInt & bInt) >= 0) {
if (aInt < bInt) {
return LE_LESS;
} else if (aInt == bInt) {
return LE_EQUAL;
} else return LE_GREATER;
}
// Otherwise, both are negative, so we need to flip the sense of the
// comparison to get the correct result. (This assumes a twos- or ones-
// complement integer representation; if integers are represented in a
// sign-magnitude representation, then this flip is incorrect).
else {
if (aInt > bInt) {
return LE_LESS;
} else if (aInt == bInt) {
return LE_EQUAL;
} else return LE_GREATER;
}
}
// TODO https://github.com/ziglang/zig/issues/641
// and then make the return types of some of these functions the enum instead of c_int
const GE_LESS = @as(c_int, -1);
const GE_EQUAL = @as(c_int, 0);
const GE_GREATER = @as(c_int, 1);
const GE_UNORDERED = @as(c_int, -1); // Note: different from LE_UNORDERED
pub fn __gesf2(a: fp_t, b: fp_t) callconv(.C) c_int {
@setRuntimeSafety(is_test);
const aInt: srep_t = @bitCast(srep_t, a);
const bInt: srep_t = @bitCast(srep_t, b);
const aAbs: rep_t = @bitCast(rep_t, aInt) & absMask;
const bAbs: rep_t = @bitCast(rep_t, bInt) & absMask;
if (aAbs > infRep or bAbs > infRep) return GE_UNORDERED;
if ((aAbs | bAbs) == 0) return GE_EQUAL;
if ((aInt & bInt) >= 0) {
if (aInt < bInt) {
return GE_LESS;
} else if (aInt == bInt) {
return GE_EQUAL;
} else return GE_GREATER;
} else {
if (aInt > bInt) {
return GE_LESS;
} else if (aInt == bInt) {
return GE_EQUAL;
} else return GE_GREATER;
}
}
pub fn __unordsf2(a: fp_t, b: fp_t) callconv(.C) c_int {
@setRuntimeSafety(is_test);
const aAbs: rep_t = @bitCast(rep_t, a) & absMask;
const bAbs: rep_t = @bitCast(rep_t, b) & absMask;
return @boolToInt(aAbs > infRep or bAbs > infRep);
}
pub fn __eqsf2(a: fp_t, b: fp_t) callconv(.C) c_int {
return __lesf2(a, b);
}
pub fn __ltsf2(a: fp_t, b: fp_t) callconv(.C) c_int {
return __lesf2(a, b);
}
pub fn __nesf2(a: fp_t, b: fp_t) callconv(.C) c_int {
return __lesf2(a, b);
}
pub fn __gtsf2(a: fp_t, b: fp_t) callconv(.C) c_int {
return __gesf2(a, b);
}
pub fn __aeabi_fcmpun(a: fp_t, b: fp_t) callconv(.AAPCS) c_int {
@setRuntimeSafety(false);
return @call(.{ .modifier = .always_inline }, __unordsf2, .{ a, b });
}
test "import comparesf2" {
_ = @import("comparesf2_test.zig");
}

View File

@ -6,7 +6,7 @@ const std = @import("std");
const builtin = @import("builtin");
const is_test = builtin.is_test;
const comparesf2 = @import("comparesf2.zig");
const comparesf2 = @import("compareXf2.zig");
const TestVector = struct {
a: f32,

View File

@ -1,99 +0,0 @@
// TODO https://github.com/ziglang/zig/issues/641
// and then make the return types of some of these functions the enum instead of c_int
const LE_LESS = @as(c_int, -1);
const LE_EQUAL = @as(c_int, 0);
const LE_GREATER = @as(c_int, 1);
const LE_UNORDERED = @as(c_int, 1);
const rep_t = u128;
const srep_t = i128;
const typeWidth = rep_t.bit_count;
const significandBits = 112;
const exponentBits = (typeWidth - significandBits - 1);
const signBit = (@as(rep_t, 1) << (significandBits + exponentBits));
const absMask = signBit - 1;
const implicitBit = @as(rep_t, 1) << significandBits;
const significandMask = implicitBit - 1;
const exponentMask = absMask ^ significandMask;
const infRep = exponentMask;
const builtin = @import("builtin");
const is_test = builtin.is_test;
pub fn __letf2(a: f128, b: f128) callconv(.C) c_int {
@setRuntimeSafety(is_test);
const aInt = @bitCast(rep_t, a);
const bInt = @bitCast(rep_t, b);
const aAbs: rep_t = aInt & absMask;
const bAbs: rep_t = bInt & absMask;
// If either a or b is NaN, they are unordered.
if (aAbs > infRep or bAbs > infRep) return LE_UNORDERED;
// If a and b are both zeros, they are equal.
if ((aAbs | bAbs) == 0) return LE_EQUAL;
// If at least one of a and b is positive, we get the same result comparing
// a and b as signed integers as we would with a floating-point compare.
return if ((aInt & bInt) >= 0)
if (aInt < bInt)
LE_LESS
else if (aInt == bInt)
LE_EQUAL
else
LE_GREATER
else
// Otherwise, both are negative, so we need to flip the sense of the
// comparison to get the correct result. (This assumes a twos- or ones-
// complement integer representation; if integers are represented in a
// sign-magnitude representation, then this flip is incorrect).
if (aInt > bInt)
LE_LESS
else if (aInt == bInt)
LE_EQUAL
else
LE_GREATER;
}
// TODO https://github.com/ziglang/zig/issues/641
// and then make the return types of some of these functions the enum instead of c_int
const GE_LESS = @as(c_int, -1);
const GE_EQUAL = @as(c_int, 0);
const GE_GREATER = @as(c_int, 1);
const GE_UNORDERED = @as(c_int, -1); // Note: different from LE_UNORDERED
pub fn __getf2(a: f128, b: f128) callconv(.C) c_int {
@setRuntimeSafety(is_test);
const aInt = @bitCast(srep_t, a);
const bInt = @bitCast(srep_t, b);
const aAbs = @bitCast(rep_t, aInt) & absMask;
const bAbs = @bitCast(rep_t, bInt) & absMask;
if (aAbs > infRep or bAbs > infRep) return GE_UNORDERED;
if ((aAbs | bAbs) == 0) return GE_EQUAL;
return if ((aInt & bInt) >= 0)
if (aInt < bInt)
GE_LESS
else if (aInt == bInt)
GE_EQUAL
else
GE_GREATER
else if (aInt > bInt)
GE_LESS
else if (aInt == bInt)
GE_EQUAL
else
GE_GREATER;
}
pub fn __unordtf2(a: f128, b: f128) callconv(.C) c_int {
@setRuntimeSafety(is_test);
const aAbs = @bitCast(rep_t, a) & absMask;
const bAbs = @bitCast(rep_t, b) & absMask;
return @boolToInt(aAbs > infRep or bAbs > infRep);
}

View File

@ -8,16 +8,7 @@ const uefi = std.os.uefi;
var starting_stack_ptr: [*]usize = undefined;
const is_wasm = switch (builtin.arch) {
.wasm32, .wasm64 => true,
else => false,
};
const is_mips = switch (builtin.arch) {
.mips, .mipsel, .mips64, .mips64el => true,
else => false,
};
const start_sym_name = if (is_mips) "__start" else "_start";
const start_sym_name = if (builtin.arch.isMIPS()) "__start" else "_start";
comptime {
if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) {
@ -35,7 +26,7 @@ comptime {
}
} else if (builtin.os == .uefi) {
if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" });
} else if (is_wasm and builtin.os == .freestanding) {
} else if (builtin.arch.isWasm() and builtin.os == .freestanding) {
if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name });
} else if (builtin.os != .other and builtin.os != .freestanding) {
if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name });

View File

@ -125,6 +125,16 @@ pub const Target = union(enum) {
v5,
v5te,
v4t,
pub fn version(version: Arm32) comptime_int {
return switch (version) {
.v8_5a, .v8_4a, .v8_3a, .v8_2a, .v8_1a, .v8, .v8r, .v8m_baseline, .v8m_mainline, .v8_1m_mainline => 8,
.v7, .v7em, .v7m, .v7s, .v7k, .v7ve => 7,
.v6, .v6m, .v6k, .v6t2 => 6,
.v5, .v5te => 5,
.v4t => 4,
};
}
};
pub const Arm64 = enum {
v8_5a,
@ -146,6 +156,34 @@ pub const Target = union(enum) {
r6,
};
pub fn isARM(arch: Arch) bool {
return switch (arch) {
.arm, .armeb => true,
else => false,
};
}
pub fn isThumb(arch: Arch) bool {
return switch (arch) {
.thumb, .thumbeb => true,
else => false,
};
}
pub fn isWasm(arch: Arch) bool {
return switch (arch) {
.wasm32, .wasm64 => true,
else => false,
};
}
pub fn isMIPS(arch: Arch) bool {
return switch (arch) {
.mips, .mipsel, .mips64, .mips64el => true,
else => false,
};
}
pub fn toElfMachine(arch: Arch) std.elf.EM {
return switch (arch) {
.avr => ._AVR,

View File

@ -289,8 +289,7 @@ pub fn translate(
tree.errors = ast.Tree.ErrorList.init(arena);
tree.root_node = try arena.create(ast.Node.Root);
tree.root_node.* = ast.Node.Root{
.base = ast.Node{ .id = ast.Node.Id.Root },
tree.root_node.* = .{
.decls = ast.Node.Root.DeclList.init(arena),
// initialized with the eof token at the end
.eof_token = undefined,
@ -440,7 +439,6 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
.PrivateExtern => return failDecl(c, fn_decl_loc, fn_name, "unsupported storage class: private extern", .{}),
.Auto => unreachable, // Not legal on functions
.Register => unreachable, // Not legal on functions
else => unreachable,
},
};
@ -877,25 +875,23 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
// types, while that's not ISO-C compliant many compilers allow this and
// default to the usual integer type used for all the enums.
// TODO only emit this tag type if the enum tag type is not the default.
// I don't know what the default is, need to figure out how clang is deciding.
// it appears to at least be different across gcc/msvc
if (int_type.ptr != null and
!isCBuiltinType(int_type, .UInt) and
!isCBuiltinType(int_type, .Int))
{
_ = try appendToken(c, .LParen, "(");
container_node.init_arg_expr = .{
.Type = transQualType(rp, int_type, enum_loc) catch |err| switch (err) {
// default to c_int since msvc and gcc default to different types
_ = try appendToken(c, .LParen, "(");
container_node.init_arg_expr = .{
.Type = if (int_type.ptr != null and
!isCBuiltinType(int_type, .UInt) and
!isCBuiltinType(int_type, .Int))
transQualType(rp, int_type, enum_loc) catch |err| switch (err) {
error.UnsupportedType => {
try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});
return null;
},
else => |e| return e,
},
};
_ = try appendToken(c, .RParen, ")");
}
}
else
try transCreateNodeIdentifier(c, "c_int"),
};
_ = try appendToken(c, .RParen, ")");
container_node.lbrace_token = try appendToken(c, .LBrace, "{");
@ -953,6 +949,19 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
tld_node.semicolon_token = try appendToken(c, .Semicolon, ";");
try addTopLevelDecl(c, field_name, &tld_node.base);
}
// make non exhaustive
const field_node = try c.a().create(ast.Node.ContainerField);
field_node.* = .{
.doc_comments = null,
.comptime_token = null,
.name_token = try appendIdentifier(c, "_"),
.type_expr = null,
.value_expr = null,
.align_expr = null,
};
try container_node.fields_and_decls.push(&field_node.base);
_ = try appendToken(c, .Comma, ",");
container_node.rbrace_token = try appendToken(c, .RBrace, "}");
break :blk &container_node.base;
@ -1231,18 +1240,6 @@ fn transBinaryOperator(
op_id = .BitOr;
op_token = try appendToken(rp.c, .Pipe, "|");
},
.Assign,
.MulAssign,
.DivAssign,
.RemAssign,
.AddAssign,
.SubAssign,
.ShlAssign,
.ShrAssign,
.AndAssign,
.XorAssign,
.OrAssign,
=> unreachable,
else => unreachable,
}
@ -1678,7 +1675,6 @@ fn transStringLiteral(
"TODO: support string literal kind {}",
.{kind},
),
else => unreachable,
}
}
@ -2206,6 +2202,19 @@ fn transDoWhileLoop(
.id = .Loop,
};
// if (!cond) break;
const if_node = try transCreateNodeIf(rp.c);
var cond_scope = Scope{
.parent = scope,
.id = .Condition,
};
const prefix_op = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!");
prefix_op.rhs = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true);
_ = try appendToken(rp.c, .RParen, ")");
if_node.condition = &prefix_op.base;
if_node.body = &(try transCreateNodeBreak(rp.c, null)).base;
_ = try appendToken(rp.c, .Semicolon, ";");
const body_node = if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == .CompoundStmtClass) blk: {
// there's already a block in C, so we'll append our condition to it.
// c: do {
@ -2217,10 +2226,7 @@ fn transDoWhileLoop(
// zig: b;
// zig: if (!cond) break;
// zig: }
const body = (try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?;
// if this is used as an expression in Zig it needs to be immediately followed by a semicolon
_ = try appendToken(rp.c, .Semicolon, ";");
break :blk body;
break :blk (try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?;
} else blk: {
// the C statement is without a block, so we need to create a block to contain it.
// c: do
@ -2236,19 +2242,6 @@ fn transDoWhileLoop(
break :blk block;
};
// if (!cond) break;
const if_node = try transCreateNodeIf(rp.c);
var cond_scope = Scope{
.parent = scope,
.id = .Condition,
};
const prefix_op = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!");
prefix_op.rhs = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true);
_ = try appendToken(rp.c, .RParen, ")");
if_node.condition = &prefix_op.base;
if_node.body = &(try transCreateNodeBreak(rp.c, null)).base;
_ = try appendToken(rp.c, .Semicolon, ";");
try body_node.statements.push(&if_node.base);
if (new)
body_node.rbrace = try appendToken(rp.c, .RBrace, "}");
@ -4783,8 +4776,7 @@ fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex {
fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {
const token_index = try appendIdentifier(c, name);
const identifier = try c.a().create(ast.Node.Identifier);
identifier.* = ast.Node.Identifier{
.base = ast.Node{ .id = ast.Node.Id.Identifier },
identifier.* = .{
.token = token_index,
};
return &identifier.base;
@ -4923,8 +4915,7 @@ fn transMacroFnDefine(c: *Context, it: *ctok.TokenList.Iterator, name: []const u
const token_index = try appendToken(c, .Keyword_var, "var");
const identifier = try c.a().create(ast.Node.Identifier);
identifier.* = ast.Node.Identifier{
.base = ast.Node{ .id = ast.Node.Id.Identifier },
identifier.* = .{
.token = token_index,
};

View File

@ -358,6 +358,8 @@ struct LazyValueSizeOf {
IrAnalyze *ira;
IrInstruction *target_type;
bool bit_size;
};
struct LazyValueSliceType {
@ -1383,6 +1385,7 @@ struct ZigTypeEnum {
ContainerLayout layout;
ResolveStatus resolve_status;
bool non_exhaustive;
bool resolve_loop_flag;
};
@ -1754,6 +1757,7 @@ enum BuiltinFnId {
BuiltinFnIdFrameSize,
BuiltinFnIdAs,
BuiltinFnIdCall,
BuiltinFnIdBitSizeof,
};
struct BuiltinFnEntry {
@ -3146,6 +3150,7 @@ struct IrInstructionAsmGen {
struct IrInstructionSizeOf {
IrInstruction base;
bool bit_size;
IrInstruction *type_value;
};
@ -3665,6 +3670,7 @@ struct IrInstructionCheckSwitchProngs {
IrInstructionCheckSwitchProngsRange *ranges;
size_t range_count;
bool have_else_prong;
bool have_underscore_prong;
};
struct IrInstructionCheckStatementIsVoid {

View File

@ -2569,15 +2569,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
return ErrorSemanticAnalyzeFail;
}
enum_type->data.enumeration.src_field_count = field_count;
enum_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
enum_type->data.enumeration.fields_by_name.init(field_count);
Scope *scope = &enum_type->data.enumeration.decls_scope->base;
HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
occupied_tag_values.init(field_count);
ZigType *tag_int_type;
if (enum_type->data.enumeration.layout == ContainerLayoutExtern) {
tag_int_type = get_c_int_type(g, CIntTypeInt);
@ -2612,13 +2605,14 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
buf_ptr(&wanted_tag_int_type->name)));
add_error_note(g, msg, decl_node->data.container_decl.init_arg_expr,
buf_sprintf("any integral type of size 8, 16, 32, 64 or 128 bit is valid"));
return ErrorNone;
return ErrorSemanticAnalyzeFail;
}
}
tag_int_type = wanted_tag_int_type;
}
}
enum_type->data.enumeration.non_exhaustive = false;
enum_type->data.enumeration.tag_int_type = tag_int_type;
enum_type->size_in_bits = tag_int_type->size_in_bits;
enum_type->abi_size = tag_int_type->abi_size;
@ -2627,6 +2621,31 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
BigInt bi_one;
bigint_init_unsigned(&bi_one, 1);
AstNode *last_field_node = decl_node->data.container_decl.fields.at(field_count - 1);
if (buf_eql_str(last_field_node->data.struct_field.name, "_")) {
field_count -= 1;
if (field_count > 1 && log2_u64(field_count) == enum_type->size_in_bits) {
add_node_error(g, last_field_node, buf_sprintf("non-exhaustive enum specifies every value"));
enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
}
if (decl_node->data.container_decl.init_arg_expr == nullptr) {
add_node_error(g, last_field_node, buf_sprintf("non-exhaustive enum must specify size"));
enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
}
if (last_field_node->data.struct_field.value != nullptr) {
add_node_error(g, last_field_node, buf_sprintf("value assigned to '_' field of non-exhaustive enum"));
enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
}
enum_type->data.enumeration.non_exhaustive = true;
}
enum_type->data.enumeration.src_field_count = field_count;
enum_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
enum_type->data.enumeration.fields_by_name.init(field_count);
HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
occupied_tag_values.init(field_count);
TypeEnumField *last_enum_field = nullptr;
for (uint32_t field_i = 0; field_i < field_count; field_i += 1) {
@ -2648,6 +2667,11 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
buf_sprintf("consider 'union(enum)' here"));
}
if (buf_eql_str(type_enum_field->name, "_")) {
add_node_error(g, field_node, buf_sprintf("'_' field of non-exhaustive enum must be last"));
enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
}
auto field_entry = enum_type->data.enumeration.fields_by_name.put_unique(type_enum_field->name, type_enum_field);
if (field_entry != nullptr) {
ErrorMsg *msg = add_node_error(g, field_node,
@ -8288,7 +8312,7 @@ static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type, ResolveStatu
uint32_t field_count = enum_type->data.enumeration.src_field_count;
assert(enum_type->data.enumeration.fields);
assert(field_count == 0 || enum_type->data.enumeration.fields != nullptr);
ZigLLVMDIEnumerator **di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count);
for (uint32_t i = 0; i < field_count; i += 1) {

View File

@ -3356,7 +3356,7 @@ static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable,
LLVMValueRef tag_int_value = gen_widen_or_shorten(g, ir_want_runtime_safety(g, &instruction->base),
instruction->target->value->type, tag_int_type, target_val);
if (ir_want_runtime_safety(g, &instruction->base) && wanted_type->data.enumeration.layout != ContainerLayoutExtern) {
if (ir_want_runtime_safety(g, &instruction->base) && !wanted_type->data.enumeration.non_exhaustive) {
LLVMBasicBlockRef bad_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadValue");
LLVMBasicBlockRef ok_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "OkValue");
size_t field_count = wanted_type->data.enumeration.src_field_count;
@ -5065,6 +5065,11 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable
{
ZigType *enum_type = instruction->target->value->type;
assert(enum_type->id == ZigTypeIdEnum);
if (enum_type->data.enumeration.non_exhaustive) {
add_node_error(g, instruction->base.source_node,
buf_sprintf("TODO @tagName on non-exhaustive enum https://github.com/ziglang/zig/issues/3991"));
codegen_report_errors_and_exit(g);
}
LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type);
@ -8299,6 +8304,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdFrameSize, "frameSize", 1);
create_builtin_fn(g, BuiltinFnIdAs, "as", 2);
create_builtin_fn(g, BuiltinFnIdCall, "call", 3);
create_builtin_fn(g, BuiltinFnIdBitSizeof, "bitSizeOf", 1);
}
static const char *bool_to_str(bool b) {

View File

@ -2392,9 +2392,10 @@ static IrInstruction *ir_build_asm_gen(IrAnalyze *ira, Scope *scope, AstNode *so
return &instruction->base;
}
static IrInstruction *ir_build_size_of(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value) {
static IrInstruction *ir_build_size_of(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value, bool bit_size) {
IrInstructionSizeOf *instruction = ir_build_instruction<IrInstructionSizeOf>(irb, scope, source_node);
instruction->type_value = type_value;
instruction->bit_size = bit_size;
ir_ref_instruction(type_value, irb->current_basic_block);
@ -3451,7 +3452,7 @@ static IrInstruction *ir_build_err_to_int(IrBuilder *irb, Scope *scope, AstNode
static IrInstruction *ir_build_check_switch_prongs(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *target_value, IrInstructionCheckSwitchProngsRange *ranges, size_t range_count,
bool have_else_prong)
bool have_else_prong, bool have_underscore_prong)
{
IrInstructionCheckSwitchProngs *instruction = ir_build_instruction<IrInstructionCheckSwitchProngs>(
irb, scope, source_node);
@ -3459,6 +3460,7 @@ static IrInstruction *ir_build_check_switch_prongs(IrBuilder *irb, Scope *scope,
instruction->ranges = ranges;
instruction->range_count = range_count;
instruction->have_else_prong = have_else_prong;
instruction->have_underscore_prong = have_underscore_prong;
ir_ref_instruction(target_value, irb->current_basic_block);
for (size_t i = 0; i < range_count; i += 1) {
@ -5249,13 +5251,14 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
return ir_lval_wrap(irb, scope, set_float_mode, lval, result_loc);
}
case BuiltinFnIdSizeof:
case BuiltinFnIdBitSizeof:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *size_of = ir_build_size_of(irb, scope, node, arg0_value);
IrInstruction *size_of = ir_build_size_of(irb, scope, node, arg0_value, builtin_fn->id == BuiltinFnIdBitSizeof);
return ir_lval_wrap(irb, scope, size_of, lval, result_loc);
}
case BuiltinFnIdImport:
@ -6027,8 +6030,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *actual_tag = ir_build_union_tag(irb, scope, node, arg0_value);
IrInstruction *tag_name = ir_build_tag_name(irb, scope, node, actual_tag);
IrInstruction *tag_name = ir_build_tag_name(irb, scope, node, arg0_value);
return ir_lval_wrap(irb, scope, tag_name, lval, result_loc);
}
case BuiltinFnIdTagType:
@ -8090,34 +8092,11 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime);
Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope);
AstNode *else_prong = nullptr;
AstNode *underscore_prong = nullptr;
for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) {
AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
size_t prong_item_count = prong_node->data.switch_prong.items.length;
if (prong_item_count == 0) {
ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);
if (else_prong) {
ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
buf_sprintf("multiple else prongs in switch expression"));
add_error_note(irb->codegen, msg, else_prong,
buf_sprintf("previous else prong is here"));
return irb->codegen->invalid_instruction;
}
else_prong = prong_node;
IrBasicBlock *prev_block = irb->current_basic_block;
if (peer_parent->peers.length > 0) {
peer_parent->peers.last()->next_bb = else_block;
}
peer_parent->peers.append(this_peer_result_loc);
ir_set_cursor_at_end_and_append_block(irb, else_block);
if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, &incoming_blocks, &incoming_values,
&switch_else_var, LValNone, &this_peer_result_loc->base))
{
return irb->codegen->invalid_instruction;
}
ir_set_cursor_at_end(irb, prev_block);
} else if (prong_node->data.switch_prong.any_items_are_range) {
if (prong_node->data.switch_prong.any_items_are_range) {
ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);
IrInstruction *ok_bit = nullptr;
@ -8195,6 +8174,56 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
}
ir_set_cursor_at_end_and_append_block(irb, range_block_no);
} else {
if (prong_item_count == 0) {
if (else_prong) {
ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
buf_sprintf("multiple else prongs in switch expression"));
add_error_note(irb->codegen, msg, else_prong,
buf_sprintf("previous else prong is here"));
return irb->codegen->invalid_instruction;
}
else_prong = prong_node;
} else if (prong_item_count == 1 &&
prong_node->data.switch_prong.items.at(0)->type == NodeTypeSymbol &&
buf_eql_str(prong_node->data.switch_prong.items.at(0)->data.symbol_expr.symbol, "_")) {
if (underscore_prong) {
ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
buf_sprintf("multiple '_' prongs in switch expression"));
add_error_note(irb->codegen, msg, underscore_prong,
buf_sprintf("previous '_' prong is here"));
return irb->codegen->invalid_instruction;
}
underscore_prong = prong_node;
} else {
continue;
}
if (underscore_prong && else_prong) {
ErrorMsg *msg = add_node_error(irb->codegen, prong_node,
buf_sprintf("else and '_' prong in switch expression"));
if (underscore_prong == prong_node)
add_error_note(irb->codegen, msg, else_prong,
buf_sprintf("else prong is here"));
else
add_error_note(irb->codegen, msg, underscore_prong,
buf_sprintf("'_' prong is here"));
return irb->codegen->invalid_instruction;
}
ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);
IrBasicBlock *prev_block = irb->current_basic_block;
if (peer_parent->peers.length > 0) {
peer_parent->peers.last()->next_bb = else_block;
}
peer_parent->peers.append(this_peer_result_loc);
ir_set_cursor_at_end_and_append_block(irb, else_block);
if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, &incoming_blocks, &incoming_values,
&switch_else_var, LValNone, &this_peer_result_loc->base))
{
return irb->codegen->invalid_instruction;
}
ir_set_cursor_at_end(irb, prev_block);
}
}
@ -8206,6 +8235,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
continue;
if (prong_node->data.switch_prong.any_items_are_range)
continue;
if (underscore_prong == prong_node)
continue;
ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);
@ -8249,7 +8280,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
}
IrInstruction *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value,
check_ranges.items, check_ranges.length, else_prong != nullptr);
check_ranges.items, check_ranges.length, else_prong != nullptr, underscore_prong != nullptr);
IrInstruction *br_instruction;
if (cases.length == 0) {
@ -8269,7 +8300,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
peer_parent->peers.at(i)->base.source_instruction = peer_parent->base.source_instruction;
}
if (!else_prong) {
if (!else_prong && !underscore_prong) {
if (peer_parent->peers.length != 0) {
peer_parent->peers.last()->next_bb = else_block;
}
@ -12790,7 +12821,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
return ira->codegen->invalid_instruction;
TypeEnumField *field = find_enum_field_by_tag(wanted_type, &val->data.x_bigint);
if (field == nullptr && wanted_type->data.enumeration.layout != ContainerLayoutExtern) {
if (field == nullptr && !wanted_type->data.enumeration.non_exhaustive) {
Buf *val_buf = buf_alloc();
bigint_append_buf(val_buf, &val->data.x_bigint, 10);
ErrorMsg *msg = ir_add_error(ira, source_instr,
@ -21065,6 +21096,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, IrInstructi
lazy_size_of->ira = ira; ira_ref(ira);
result->value->data.x_lazy = &lazy_size_of->base;
lazy_size_of->base.id = LazyValueIdSizeOf;
lazy_size_of->bit_size = instruction->bit_size;
lazy_size_of->target_type = instruction->type_value->child;
if (ir_resolve_type_lazy(ira, lazy_size_of->target_type) == nullptr)
@ -21356,10 +21388,6 @@ static IrInstruction *ir_analyze_union_tag(IrAnalyze *ira, IrInstruction *source
if (type_is_invalid(value->value->type))
return ira->codegen->invalid_instruction;
if (value->value->type->id == ZigTypeIdEnum) {
return value;
}
if (value->value->type->id != ZigTypeIdUnion) {
ir_add_error(ira, value,
buf_sprintf("expected enum or union type, found '%s'", buf_ptr(&value->value->type->name)));
@ -21427,12 +21455,6 @@ static IrInstruction *ir_analyze_instruction_switch_br(IrAnalyze *ira,
if (type_is_invalid(case_value->value->type))
return ir_unreach_error(ira);
if (case_value->value->type->id == ZigTypeIdEnum) {
case_value = ir_analyze_union_tag(ira, &switch_br_instruction->base, case_value);
if (type_is_invalid(case_value->value->type))
return ir_unreach_error(ira);
}
IrInstruction *casted_case_value = ir_implicit_cast(ira, case_value, target_value->value->type);
if (type_is_invalid(casted_case_value->value->type))
return ir_unreach_error(ira);
@ -21477,12 +21499,6 @@ static IrInstruction *ir_analyze_instruction_switch_br(IrAnalyze *ira,
if (type_is_invalid(new_value->value->type))
continue;
if (new_value->value->type->id == ZigTypeIdEnum) {
new_value = ir_analyze_union_tag(ira, &switch_br_instruction->base, new_value);
if (type_is_invalid(new_value->value->type))
continue;
}
IrInstruction *casted_new_value = ir_implicit_cast(ira, new_value, target_value->value->type);
if (type_is_invalid(casted_new_value->value->type))
continue;
@ -21598,7 +21614,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
case ZigTypeIdEnum: {
if ((err = type_resolve(ira->codegen, target_type, ResolveStatusZeroBitsKnown)))
return ira->codegen->invalid_instruction;
if (target_type->data.enumeration.src_field_count < 2) {
if (target_type->data.enumeration.src_field_count == 1) {
TypeEnumField *only_field = &target_type->data.enumeration.fields[0];
IrInstruction *result = ir_const(ira, &switch_target_instruction->base, target_type);
bigint_init_bigint(&result->value->data.x_enum_tag, &only_field->value);
@ -22319,11 +22335,39 @@ static IrInstruction *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIns
if (type_is_invalid(target->value->type))
return ira->codegen->invalid_instruction;
if (target->value->type->id == ZigTypeIdEnumLiteral) {
IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
Buf *field_name = target->value->data.x_enum_literal;
ZigValue *array_val = create_const_str_lit(ira->codegen, field_name)->data.x_ptr.data.ref.pointee;
init_const_slice(ira->codegen, result->value, array_val, 0, buf_len(field_name), true);
return result;
}
if (target->value->type->id == ZigTypeIdUnion) {
target = ir_analyze_union_tag(ira, &instruction->base, target);
if (type_is_invalid(target->value->type))
return ira->codegen->invalid_instruction;
}
assert(target->value->type->id == ZigTypeIdEnum);
if (target->value->type->data.enumeration.src_field_count == 1 &&
!target->value->type->data.enumeration.non_exhaustive) {
TypeEnumField *only_field = &target->value->type->data.enumeration.fields[0];
ZigValue *array_val = create_const_str_lit(ira->codegen, only_field->name)->data.x_ptr.data.ref.pointee;
IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
init_const_slice(ira->codegen, result->value, array_val, 0, buf_len(only_field->name), true);
return result;
}
if (instr_is_comptime(target)) {
if ((err = type_resolve(ira->codegen, target->value->type, ResolveStatusZeroBitsKnown)))
return ira->codegen->invalid_instruction;
if (target->value->type->data.enumeration.non_exhaustive) {
add_node_error(ira->codegen, instruction->base.source_node,
buf_sprintf("TODO @tagName on non-exhaustive enum https://github.com/ziglang/zig/issues/3991"));
return ira->codegen->invalid_instruction;
}
TypeEnumField *field = find_enum_field_by_tag(target->value->type, &target->value->data.x_bigint);
ZigValue *array_val = create_const_str_lit(ira->codegen, field->name)->data.x_ptr.data.ref.pointee;
IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
@ -23074,7 +23118,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
result->special = ConstValSpecialStatic;
result->type = ir_type_info_get_type(ira, "Enum", nullptr);
ZigValue **fields = alloc_const_vals_ptrs(4);
ZigValue **fields = alloc_const_vals_ptrs(5);
result->data.x_struct.fields = fields;
// layout: ContainerLayout
@ -23120,6 +23164,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
{
return err;
}
// is_exhaustive: bool
ensure_field_index(result->type, "is_exhaustive", 4);
fields[4]->special = ConstValSpecialStatic;
fields[4]->type = ira->codegen->builtin_types.entry_bool;
fields[4]->data.x_bool = !type_entry->data.enumeration.non_exhaustive;
break;
}
@ -23335,7 +23384,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
struct_field_val->special = ConstValSpecialStatic;
struct_field_val->type = type_info_struct_field_type;
ZigValue **inner_fields = alloc_const_vals_ptrs(3);
ZigValue **inner_fields = alloc_const_vals_ptrs(4);
inner_fields[1]->special = ConstValSpecialStatic;
inner_fields[1]->type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_num_lit_int);
@ -23358,6 +23407,12 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr
inner_fields[2]->type = ira->codegen->builtin_types.entry_type;
inner_fields[2]->data.x_type = struct_field->type_entry;
// default_value: var
inner_fields[3]->special = ConstValSpecialStatic;
inner_fields[3]->type = get_optional_type(ira->codegen, struct_field->type_entry);
memoize_field_init_val(ira->codegen, type_entry, struct_field);
set_optional_payload(inner_fields[3], struct_field->init_val);
ZigValue *name = create_const_str_lit(ira->codegen, struct_field->name)->data.x_ptr.data.ref.pointee;
init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(struct_field->name), true);
@ -26433,10 +26488,27 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
bigint_incr(&field_index);
}
}
if (!instruction->have_else_prong) {
if (switch_type->data.enumeration.layout == ContainerLayoutExtern) {
if (instruction->have_underscore_prong) {
if (!switch_type->data.enumeration.non_exhaustive){
ir_add_error(ira, &instruction->base,
buf_sprintf("switch on an extern enum must have an else prong"));
buf_sprintf("switch on non-exhaustive enum has `_` prong"));
}
for (uint32_t i = 0; i < switch_type->data.enumeration.src_field_count; i += 1) {
TypeEnumField *enum_field = &switch_type->data.enumeration.fields[i];
if (buf_eql_str(enum_field->name, "_"))
continue;
auto entry = field_prev_uses.maybe_get(enum_field->value);
if (!entry) {
ir_add_error(ira, &instruction->base,
buf_sprintf("enumeration value '%s.%s' not handled in switch", buf_ptr(&switch_type->name),
buf_ptr(enum_field->name)));
}
}
} else if (!instruction->have_else_prong) {
if (switch_type->data.enumeration.non_exhaustive) {
ir_add_error(ira, &instruction->base,
buf_sprintf("switch on non-exhaustive enum must include `else` or `_` prong"));
}
for (uint32_t i = 0; i < switch_type->data.enumeration.src_field_count; i += 1) {
TypeEnumField *enum_field = &switch_type->data.enumeration.fields[i];
@ -29415,7 +29487,10 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {
val->special = ConstValSpecialStatic;
assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt);
bigint_init_unsigned(&val->data.x_bigint, abi_size);
if (lazy_size_of->bit_size)
bigint_init_unsigned(&val->data.x_bigint, size_in_bits);
else
bigint_init_unsigned(&val->data.x_bigint, abi_size);
// We can't free the lazy value here, because multiple other ZigValues might be pointing to it.
return ErrorNone;

View File

@ -1039,7 +1039,10 @@ static void ir_print_asm_gen(IrPrint *irp, IrInstructionAsmGen *instruction) {
}
static void ir_print_size_of(IrPrint *irp, IrInstructionSizeOf *instruction) {
fprintf(irp->f, "@sizeOf(");
if (instruction->bit_size)
fprintf(irp->f, "@bitSizeOf(");
else
fprintf(irp->f, "@sizeOf(");
ir_print_other_instruction(irp, instruction->type_value);
fprintf(irp->f, ")");
}

View File

@ -2,6 +2,56 @@ const tests = @import("tests.zig");
const builtin = @import("builtin");
pub fn addCases(cases: *tests.CompileErrorContext) void {
cases.addTest("non-exhaustive enums",
\\const A = enum {
\\ a,
\\ b,
\\ _ = 1,
\\};
\\const B = enum(u1) {
\\ a,
\\ _,
\\ b,
\\};
\\const C = enum(u1) {
\\ a,
\\ b,
\\ _,
\\};
\\pub export fn entry() void {
\\ _ = A;
\\ _ = B;
\\ _ = C;
\\}
, &[_][]const u8{
"tmp.zig:4:5: error: non-exhaustive enum must specify size",
"error: value assigned to '_' field of non-exhaustive enum",
"error: non-exhaustive enum specifies every value",
"error: '_' field of non-exhaustive enum must be last",
});
cases.addTest("switching with non-exhaustive enums",
\\const E = enum(u8) {
\\ a,
\\ b,
\\ _,
\\};
\\pub export fn entry() void {
\\ var e: E = .b;
\\ switch (e) { // error: switch not handling the tag `b`
\\ .a => {},
\\ _ => {},
\\ }
\\ switch (e) { // error: switch on non-exhaustive enum must include `else` or `_` prong
\\ .a => {},
\\ .b => {},
\\ }
\\}
, &[_][]const u8{
"tmp.zig:8:5: error: enumeration value 'E.b' not handled in switch",
"tmp.zig:12:5: error: switch on non-exhaustive enum must include `else` or `_` prong",
});
cases.addTest("@export with empty name string",
\\pub export fn entry() void { }
\\comptime {
@ -139,25 +189,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:13: error: pointer type '[*]align(4) u8' requires aligned address",
});
cases.add("switch on extern enum missing else prong",
\\const i = extern enum {
\\ n = 0,
\\ o = 2,
\\ p = 4,
\\ q = 4,
\\};
\\pub fn main() void {
\\ var x = @intToEnum(i, 52);
\\ switch (x) {
\\ .n,
\\ .o,
\\ .p => unreachable,
\\ }
\\}
, &[_][]const u8{
"tmp.zig:9:5: error: switch on an extern enum must have an else prong",
});
cases.add("invalid float literal",
\\const std = @import("std");
\\

View File

@ -618,7 +618,6 @@ test "peer resolution of string literals" {
.b => "two",
.c => "three",
.d => "four",
else => unreachable,
};
expect(mem.eql(u8, cmd, "two"));
}

View File

@ -11,16 +11,9 @@ test "extern enum" {
};
fn doTheTest(y: c_int) void {
var x = i.o;
expect(@enumToInt(x) == 2);
x = @intToEnum(i, 12);
expect(@enumToInt(x) == 12);
x = @intToEnum(i, y);
expect(@enumToInt(x) == 52);
switch (x) {
.n,
.o,
.p => unreachable,
else => {},
.n, .p => unreachable,
.o => {},
}
}
};
@ -28,6 +21,70 @@ test "extern enum" {
comptime S.doTheTest(52);
}
test "non-exhaustive enum" {
const S = struct {
const E = enum(u8) {
a,
b,
_,
};
fn doTheTest(y: u8) void {
var e: E = .b;
expect(switch (e) {
.a => false,
.b => true,
_ => false,
});
e = @intToEnum(E, 12);
expect(switch (e) {
.a => false,
.b => false,
_ => true,
});
expect(switch (e) {
.a => false,
.b => false,
else => true,
});
e = .b;
expect(switch (e) {
.a => false,
else => true,
});
expect(@typeInfo(E).Enum.fields.len == 2);
e = @intToEnum(E, 12);
expect(@enumToInt(e) == 12);
e = @intToEnum(E, y);
expect(@enumToInt(e) == 52);
expect(@typeInfo(E).Enum.is_exhaustive == false);
}
};
S.doTheTest(52);
comptime S.doTheTest(52);
}
test "empty non-exhaustive enum" {
const S = struct {
const E = enum(u8) {
_,
};
fn doTheTest(y: u8) void {
var e = @intToEnum(E, y);
expect(switch (e) {
_ => true,
});
expect(@enumToInt(e) == y);
expect(@typeInfo(E).Enum.fields.len == 0);
expect(@typeInfo(E).Enum.is_exhaustive == false);
}
};
S.doTheTest(42);
comptime S.doTheTest(42);
}
test "enum type" {
const foo1 = Foo{ .One = 13 };
const foo2 = Foo{
@ -1057,3 +1114,8 @@ test "enum with one member default to u0 tag type" {
};
comptime expect(@TagType(E0) == u0);
}
test "tagName on enum literals" {
expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
comptime expect(mem.eql(u8, @tagName(.FooBar), "FooBar"));
}

View File

@ -124,3 +124,14 @@ fn fn1(alpha: bool) void {
test "lazy @sizeOf result is checked for definedness" {
const f = fn1;
}
test "@bitSizeOf" {
expect(@bitSizeOf(u2) == 2);
expect(@bitSizeOf(u8) == @sizeOf(u8) * 8);
expect(@bitSizeOf(struct {
a: u2
}) == 8);
expect(@bitSizeOf(packed struct {
a: u2
}) == 2);
}

View File

@ -237,9 +237,11 @@ fn testStruct() void {
const struct_info = @typeInfo(TestStruct);
expect(@as(TypeId, struct_info) == TypeId.Struct);
expect(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed);
expect(struct_info.Struct.fields.len == 3);
expect(struct_info.Struct.fields.len == 4);
expect(struct_info.Struct.fields[1].offset == null);
expect(struct_info.Struct.fields[2].field_type == *TestStruct);
expect(struct_info.Struct.fields[2].default_value == null);
expect(struct_info.Struct.fields[3].default_value.? == 4);
expect(struct_info.Struct.decls.len == 2);
expect(struct_info.Struct.decls[0].is_pub);
expect(!struct_info.Struct.decls[0].data.Fn.is_extern);
@ -254,6 +256,7 @@ const TestStruct = packed struct {
fieldA: usize,
fieldB: void,
fieldC: *Self,
fieldD: u32 = 4,
pub fn foo(self: *const Self) void {}
};

View File

@ -629,3 +629,12 @@ test "union initializer generates padding only if needed" {
var v = U{ .A = 532 };
expect(v.A == 532);
}
test "runtime tag name with single field" {
const U = union(enum) {
A: i32,
};
var v = U{ .A = 42 };
expect(std.mem.eql(u8, @tagName(v), "A"));
}

View File

@ -629,6 +629,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ VAL21 = 6917529027641081853,
\\ VAL22 = 0,
\\ VAL23 = -1,
\\ _,
\\};
});
}
@ -988,8 +989,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\enum enum_ty { FOO };
, &[_][]const u8{
\\pub const FOO = @enumToInt(enum_enum_ty.FOO);
\\pub const enum_enum_ty = extern enum {
\\pub const enum_enum_ty = extern enum(c_int) {
\\ FOO,
\\ _,
\\};
\\pub extern var my_enum: enum_enum_ty;
});
@ -1102,28 +1104,31 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const a = @enumToInt(enum_unnamed_1.a);
\\pub const b = @enumToInt(enum_unnamed_1.b);
\\pub const c = @enumToInt(enum_unnamed_1.c);
\\const enum_unnamed_1 = extern enum {
\\const enum_unnamed_1 = extern enum(c_int) {
\\ a,
\\ b,
\\ c,
\\ _,
\\};
\\pub const d = enum_unnamed_1;
\\pub const e = @enumToInt(enum_unnamed_2.e);
\\pub const f = @enumToInt(enum_unnamed_2.f);
\\pub const g = @enumToInt(enum_unnamed_2.g);
\\const enum_unnamed_2 = extern enum {
\\const enum_unnamed_2 = extern enum(c_int) {
\\ e = 0,
\\ f = 4,
\\ g = 5,
\\ _,
\\};
\\pub export var h: enum_unnamed_2 = @intToEnum(enum_unnamed_2, e);
\\pub const i = @enumToInt(enum_unnamed_3.i);
\\pub const j = @enumToInt(enum_unnamed_3.j);
\\pub const k = @enumToInt(enum_unnamed_3.k);
\\const enum_unnamed_3 = extern enum {
\\const enum_unnamed_3 = extern enum(c_int) {
\\ i,
\\ j,
\\ k,
\\ _,
\\};
\\pub const struct_Baz = extern struct {
\\ l: enum_unnamed_3,
@ -1132,10 +1137,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const n = @enumToInt(enum_i.n);
\\pub const o = @enumToInt(enum_i.o);
\\pub const p = @enumToInt(enum_i.p);
\\pub const enum_i = extern enum {
\\pub const enum_i = extern enum(c_int) {
\\ n,
\\ o,
\\ p,
\\ _,
\\};
,
\\pub const Baz = struct_Baz;
@ -1563,9 +1569,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
, &[_][]const u8{
\\pub const One = @enumToInt(enum_unnamed_1.One);
\\pub const Two = @enumToInt(enum_unnamed_1.Two);
\\const enum_unnamed_1 = extern enum {
\\const enum_unnamed_1 = extern enum(c_int) {
\\ One,
\\ Two,
\\ _,
\\};
});
@ -1665,10 +1672,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
\\}
, &[_][]const u8{
\\pub const enum_Foo = extern enum {
\\pub const enum_Foo = extern enum(c_int) {
\\ A,
\\ B,
\\ C,
\\ _,
\\};
\\pub const SomeTypedef = c_int;
\\pub export fn and_or_non_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void) c_int {
@ -1710,9 +1718,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ y: c_int,
\\};
,
\\pub const enum_Bar = extern enum {
\\pub const enum_Bar = extern enum(c_int) {
\\ A,
\\ B,
\\ _,
\\};
\\pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void;
,
@ -1973,10 +1982,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ return 4;
\\}
, &[_][]const u8{
\\pub const enum_SomeEnum = extern enum {
\\pub const enum_SomeEnum = extern enum(c_int) {
\\ A,
\\ B,
\\ C,
\\ _,
\\};
\\pub export fn if_none_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void, arg_d: enum_SomeEnum) c_int {
\\ var a = arg_a;
@ -2414,10 +2424,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const FooA = @enumToInt(enum_Foo.A);
\\pub const FooB = @enumToInt(enum_Foo.B);
\\pub const Foo1 = @enumToInt(enum_Foo.@"1");
\\pub const enum_Foo = extern enum {
\\pub const enum_Foo = extern enum(c_int) {
\\ A = 2,
\\ B = 5,
\\ @"1" = 6,
\\ _,
\\};
,
\\pub const Foo = enum_Foo;