| author | |
| committer | |
| log | 52b8239a22aa37fe3914427cd4e2905231769e59 |
| tree | cd60ca825c14b5befbcddf674bdb7d3feda81d23 |
| parent | 338f155a02b72117ff710f72c8578e7d2f8eb296 |
| parent | 533bfc68bf8b4ad7ffbe5814a622f200dc345b69 |
84 files changed, 1591 insertions(+), 734 deletions(-)
doc/langref.html.in+15-15| ... | @@ -2156,7 +2156,7 @@ test "pointer casting" { | ... | @@ -2156,7 +2156,7 @@ test "pointer casting" { |
| 2156 | 2156 | ||
| 2157 | test "pointer child type" { | 2157 | test "pointer child type" { |
| 2158 | // pointer types have a `child` field which tells you the type they point to. | 2158 | // pointer types have a `child` field which tells you the type they point to. |
| 2159 | assert((*u32).Child == u32); | 2159 | assert(@typeInfo(*u32).Pointer.child == u32); |
| 2160 | } | 2160 | } |
| 2161 | {#code_end#} | 2161 | {#code_end#} |
| 2162 | {#header_open|Alignment#} | 2162 | {#header_open|Alignment#} |
| ... | @@ -2184,7 +2184,7 @@ test "variable alignment" { | ... | @@ -2184,7 +2184,7 @@ test "variable alignment" { |
| 2184 | assert(@TypeOf(&x) == *i32); | 2184 | assert(@TypeOf(&x) == *i32); |
| 2185 | assert(*i32 == *align(align_of_i32) i32); | 2185 | assert(*i32 == *align(align_of_i32) i32); |
| 2186 | if (std.Target.current.cpu.arch == .x86_64) { | 2186 | if (std.Target.current.cpu.arch == .x86_64) { |
| 2187 | assert((*i32).alignment == 4); | 2187 | assert(@typeInfo(*i32).Pointer.alignment == 4); |
| 2188 | } | 2188 | } |
| 2189 | } | 2189 | } |
| 2190 | {#code_end#} | 2190 | {#code_end#} |
| ... | @@ -2202,7 +2202,7 @@ const assert = @import("std").debug.assert; | ... | @@ -2202,7 +2202,7 @@ const assert = @import("std").debug.assert; |
| 2202 | var foo: u8 align(4) = 100; | 2202 | var foo: u8 align(4) = 100; |
| 2203 | 2203 | ||
| 2204 | test "global variable alignment" { | 2204 | test "global variable alignment" { |
| 2205 | assert(@TypeOf(&foo).alignment == 4); | 2205 | assert(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4); |
| 2206 | assert(@TypeOf(&foo) == *align(4) u8); | 2206 | assert(@TypeOf(&foo) == *align(4) u8); |
| 2207 | const as_pointer_to_array: *[1]u8 = &foo; | 2207 | const as_pointer_to_array: *[1]u8 = &foo; |
| 2208 | const as_slice: []u8 = as_pointer_to_array; | 2208 | const as_slice: []u8 = as_pointer_to_array; |
| ... | @@ -4310,8 +4310,8 @@ test "fn type inference" { | ... | @@ -4310,8 +4310,8 @@ test "fn type inference" { |
| 4310 | const assert = @import("std").debug.assert; | 4310 | const assert = @import("std").debug.assert; |
| 4311 | 4311 | ||
| 4312 | test "fn reflection" { | 4312 | test "fn reflection" { |
| 4313 | assert(@TypeOf(assert).ReturnType == void); | 4313 | assert(@typeInfo(@TypeOf(assert)).Fn.return_type.? == void); |
| 4314 | assert(@TypeOf(assert).is_var_args == false); | 4314 | assert(@typeInfo(@TypeOf(assert)).Fn.is_var_args == false); |
| 4315 | } | 4315 | } |
| 4316 | {#code_end#} | 4316 | {#code_end#} |
| 4317 | {#header_close#} | 4317 | {#header_close#} |
| ... | @@ -4611,10 +4611,10 @@ test "error union" { | ... | @@ -4611,10 +4611,10 @@ test "error union" { |
| 4611 | foo = error.SomeError; | 4611 | foo = error.SomeError; |
| 4612 | 4612 | ||
| 4613 | // Use compile-time reflection to access the payload type of an error union: | 4613 | // Use compile-time reflection to access the payload type of an error union: |
| 4614 | comptime assert(@TypeOf(foo).Payload == i32); | 4614 | comptime assert(@typeInfo(@TypeOf(foo)).ErrorUnion.payload == i32); |
| 4615 | 4615 | ||
| 4616 | // Use compile-time reflection to access the error set type of an error union: | 4616 | // Use compile-time reflection to access the error set type of an error union: |
| 4617 | comptime assert(@TypeOf(foo).ErrorSet == anyerror); | 4617 | comptime assert(@typeInfo(@TypeOf(foo)).ErrorUnion.error_set == anyerror); |
| 4618 | } | 4618 | } |
| 4619 | {#code_end#} | 4619 | {#code_end#} |
| 4620 | {#header_open|Merging Error Sets#} | 4620 | {#header_open|Merging Error Sets#} |
| ... | @@ -4991,7 +4991,7 @@ test "optional type" { | ... | @@ -4991,7 +4991,7 @@ test "optional type" { |
| 4991 | foo = 1234; | 4991 | foo = 1234; |
| 4992 | 4992 | ||
| 4993 | // Use compile-time reflection to access the child type of the optional: | 4993 | // Use compile-time reflection to access the child type of the optional: |
| 4994 | comptime assert(@TypeOf(foo).Child == i32); | 4994 | comptime assert(@typeInfo(@TypeOf(foo)).Optional.child == i32); |
| 4995 | } | 4995 | } |
| 4996 | {#code_end#} | 4996 | {#code_end#} |
| 4997 | {#header_close#} | 4997 | {#header_close#} |
| ... | @@ -6889,7 +6889,7 @@ fn func(y: *i32) void { | ... | @@ -6889,7 +6889,7 @@ fn func(y: *i32) void { |
| 6889 | This builtin function atomically dereferences a pointer and returns the value. | 6889 | This builtin function atomically dereferences a pointer and returns the value. |
| 6890 | </p> | 6890 | </p> |
| 6891 | <p> | 6891 | <p> |
| 6892 | {#syntax#}T{#endsyntax#} must be a {#syntax#}bool{#endsyntax#}, a float, | 6892 | {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float, |
| 6893 | an integer or an enum. | 6893 | an integer or an enum. |
| 6894 | </p> | 6894 | </p> |
| 6895 | {#header_close#} | 6895 | {#header_close#} |
| ... | @@ -6899,7 +6899,7 @@ fn func(y: *i32) void { | ... | @@ -6899,7 +6899,7 @@ fn func(y: *i32) void { |
| 6899 | This builtin function atomically modifies memory and then returns the previous value. | 6899 | This builtin function atomically modifies memory and then returns the previous value. |
| 6900 | </p> | 6900 | </p> |
| 6901 | <p> | 6901 | <p> |
| 6902 | {#syntax#}T{#endsyntax#} must be a {#syntax#}bool{#endsyntax#}, a float, | 6902 | {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float, |
| 6903 | an integer or an enum. | 6903 | an integer or an enum. |
| 6904 | </p> | 6904 | </p> |
| 6905 | <p> | 6905 | <p> |
| ... | @@ -6925,7 +6925,7 @@ fn func(y: *i32) void { | ... | @@ -6925,7 +6925,7 @@ fn func(y: *i32) void { |
| 6925 | This builtin function atomically stores a value. | 6925 | This builtin function atomically stores a value. |
| 6926 | </p> | 6926 | </p> |
| 6927 | <p> | 6927 | <p> |
| 6928 | {#syntax#}T{#endsyntax#} must be a {#syntax#}bool{#endsyntax#}, a float, | 6928 | {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float, |
| 6929 | an integer or an enum. | 6929 | an integer or an enum. |
| 6930 | </p> | 6930 | </p> |
| 6931 | {#header_close#} | 6931 | {#header_close#} |
| ... | @@ -7208,10 +7208,10 @@ fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_v | ... | @@ -7208,10 +7208,10 @@ fn cmpxchgStrongButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_v |
| 7208 | more efficiently in machine instructions. | 7208 | more efficiently in machine instructions. |
| 7209 | </p> | 7209 | </p> |
| 7210 | <p> | 7210 | <p> |
| 7211 | {#syntax#}T{#endsyntax#} must be a {#syntax#}bool{#endsyntax#}, a float, | 7211 | {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float, |
| 7212 | an integer or an enum. | 7212 | an integer or an enum. |
| 7213 | </p> | 7213 | </p> |
| 7214 | <p>{#syntax#}@TypeOf(ptr).alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p> | 7214 | <p>{#syntax#}@typeInfo(@TypeOf(ptr)).Pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p> |
| 7215 | {#see_also|Compile Variables|cmpxchgWeak#} | 7215 | {#see_also|Compile Variables|cmpxchgWeak#} |
| 7216 | {#header_close#} | 7216 | {#header_close#} |
| 7217 | {#header_open|@cmpxchgWeak#} | 7217 | {#header_open|@cmpxchgWeak#} |
| ... | @@ -7237,10 +7237,10 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val | ... | @@ -7237,10 +7237,10 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val |
| 7237 | However if you need a stronger guarantee, use {#link|@cmpxchgStrong#}. | 7237 | However if you need a stronger guarantee, use {#link|@cmpxchgStrong#}. |
| 7238 | </p> | 7238 | </p> |
| 7239 | <p> | 7239 | <p> |
| 7240 | {#syntax#}T{#endsyntax#} must be a {#syntax#}bool{#endsyntax#}, a float, | 7240 | {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float, |
| 7241 | an integer or an enum. | 7241 | an integer or an enum. |
| 7242 | </p> | 7242 | </p> |
| 7243 | <p>{#syntax#}@TypeOf(ptr).alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p> | 7243 | <p>{#syntax#}@typeInfo(@TypeOf(ptr)).Pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p> |
| 7244 | {#see_also|Compile Variables|cmpxchgStrong#} | 7244 | {#see_also|Compile Variables|cmpxchgStrong#} |
| 7245 | {#header_close#} | 7245 | {#header_close#} |
| 7246 | 7246 |
lib/std/array_list.zig+10-2| ... | @@ -46,7 +46,11 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { | ... | @@ -46,7 +46,11 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 46 | /// Deinitialize with `deinit` or use `toOwnedSlice`. | 46 | /// Deinitialize with `deinit` or use `toOwnedSlice`. |
| 47 | pub fn initCapacity(allocator: *Allocator, num: usize) !Self { | 47 | pub fn initCapacity(allocator: *Allocator, num: usize) !Self { |
| 48 | var self = Self.init(allocator); | 48 | var self = Self.init(allocator); |
| 49 | try self.ensureCapacity(num); | 49 | |
| 50 | const new_memory = try self.allocator.allocAdvanced(T, alignment, num, .at_least); | ||
| 51 | self.items.ptr = new_memory.ptr; | ||
| 52 | self.capacity = new_memory.len; | ||
| 53 | |||
| 50 | return self; | 54 | return self; |
| 51 | } | 55 | } |
| 52 | 56 | ||
| ... | @@ -366,7 +370,11 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ | ... | @@ -366,7 +370,11 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 366 | /// Deinitialize with `deinit` or use `toOwnedSlice`. | 370 | /// Deinitialize with `deinit` or use `toOwnedSlice`. |
| 367 | pub fn initCapacity(allocator: *Allocator, num: usize) !Self { | 371 | pub fn initCapacity(allocator: *Allocator, num: usize) !Self { |
| 368 | var self = Self{}; | 372 | var self = Self{}; |
| 369 | try self.ensureCapacity(allocator, num); | 373 | |
| 374 | const new_memory = try self.allocator.allocAdvanced(T, alignment, num, .at_least); | ||
| 375 | self.items.ptr = new_memory.ptr; | ||
| 376 | self.capacity = new_memory.len; | ||
| 377 | |||
| 370 | return self; | 378 | return self; |
| 371 | } | 379 | } |
| 372 | 380 |
lib/std/child_process.zig+3-5| ... | @@ -275,9 +275,7 @@ pub const ChildProcess = struct { | ... | @@ -275,9 +275,7 @@ pub const ChildProcess = struct { |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | fn handleWaitResult(self: *ChildProcess, status: u32) void { | 277 | fn handleWaitResult(self: *ChildProcess, status: u32) void { |
| 278 | // TODO https://github.com/ziglang/zig/issues/3190 | 278 | self.term = self.cleanupAfterWait(status); |
| 279 | var term = self.cleanupAfterWait(status); | ||
| 280 | self.term = term; | ||
| 281 | } | 279 | } |
| 282 | 280 | ||
| 283 | fn cleanupStreams(self: *ChildProcess) void { | 281 | fn cleanupStreams(self: *ChildProcess) void { |
| ... | @@ -487,8 +485,8 @@ pub const ChildProcess = struct { | ... | @@ -487,8 +485,8 @@ pub const ChildProcess = struct { |
| 487 | const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore); | 485 | const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore); |
| 488 | 486 | ||
| 489 | const nul_handle = if (any_ignore) | 487 | const nul_handle = if (any_ignore) |
| 490 | windows.OpenFile(&[_]u16{ 'N', 'U', 'L' }, .{ | 488 | // "\Device\Null" or "\??\NUL" |
| 491 | .dir = std.fs.cwd().fd, | 489 | windows.OpenFile(&[_]u16{ '\\', 'D', 'e', 'v', 'i', 'c', 'e', '\\', 'N', 'u', 'l', 'l' }, .{ |
| 492 | .access_mask = windows.GENERIC_READ | windows.SYNCHRONIZE, | 490 | .access_mask = windows.GENERIC_READ | windows.SYNCHRONIZE, |
| 493 | .share_access = windows.FILE_SHARE_READ, | 491 | .share_access = windows.FILE_SHARE_READ, |
| 494 | .creation = windows.OPEN_EXISTING, | 492 | .creation = windows.OPEN_EXISTING, |
lib/std/coff.zig+66| ... | @@ -18,11 +18,77 @@ const IMAGE_FILE_MACHINE_I386 = 0x014c; | ... | @@ -18,11 +18,77 @@ const IMAGE_FILE_MACHINE_I386 = 0x014c; |
| 18 | const IMAGE_FILE_MACHINE_IA64 = 0x0200; | 18 | const IMAGE_FILE_MACHINE_IA64 = 0x0200; |
| 19 | const IMAGE_FILE_MACHINE_AMD64 = 0x8664; | 19 | const IMAGE_FILE_MACHINE_AMD64 = 0x8664; |
| 20 | 20 | ||
| 21 | pub const MachineType = enum(u16) { | ||
| 22 | Unknown = 0x0, | ||
| 23 | /// Matsushita AM33 | ||
| 24 | AM33 = 0x1d3, | ||
| 25 | /// x64 | ||
| 26 | X64 = 0x8664, | ||
| 27 | /// ARM little endian | ||
| 28 | ARM = 0x1c0, | ||
| 29 | /// ARM64 little endian | ||
| 30 | ARM64 = 0xaa64, | ||
| 31 | /// ARM Thumb-2 little endian | ||
| 32 | ARMNT = 0x1c4, | ||
| 33 | /// EFI byte code | ||
| 34 | EBC = 0xebc, | ||
| 35 | /// Intel 386 or later processors and compatible processors | ||
| 36 | I386 = 0x14c, | ||
| 37 | /// Intel Itanium processor family | ||
| 38 | IA64 = 0x200, | ||
| 39 | /// Mitsubishi M32R little endian | ||
| 40 | M32R = 0x9041, | ||
| 41 | /// MIPS16 | ||
| 42 | MIPS16 = 0x266, | ||
| 43 | /// MIPS with FPU | ||
| 44 | MIPSFPU = 0x366, | ||
| 45 | /// MIPS16 with FPU | ||
| 46 | MIPSFPU16 = 0x466, | ||
| 47 | /// Power PC little endian | ||
| 48 | POWERPC = 0x1f0, | ||
| 49 | /// Power PC with floating point support | ||
| 50 | POWERPCFP = 0x1f1, | ||
| 51 | /// MIPS little endian | ||
| 52 | R4000 = 0x166, | ||
| 53 | /// RISC-V 32-bit address space | ||
| 54 | RISCV32 = 0x5032, | ||
| 55 | /// RISC-V 64-bit address space | ||
| 56 | RISCV64 = 0x5064, | ||
| 57 | /// RISC-V 128-bit address space | ||
| 58 | RISCV128 = 0x5128, | ||
| 59 | /// Hitachi SH3 | ||
| 60 | SH3 = 0x1a2, | ||
| 61 | /// Hitachi SH3 DSP | ||
| 62 | SH3DSP = 0x1a3, | ||
| 63 | /// Hitachi SH4 | ||
| 64 | SH4 = 0x1a6, | ||
| 65 | /// Hitachi SH5 | ||
| 66 | SH5 = 0x1a8, | ||
| 67 | /// Thumb | ||
| 68 | Thumb = 0x1c2, | ||
| 69 | /// MIPS little-endian WCE v2 | ||
| 70 | WCEMIPSV2 = 0x169, | ||
| 71 | }; | ||
| 72 | |||
| 21 | // OptionalHeader.magic values | 73 | // OptionalHeader.magic values |
| 22 | // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=vs.85).aspx | 74 | // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680339(v=vs.85).aspx |
| 23 | const IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b; | 75 | const IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b; |
| 24 | const IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b; | 76 | const IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b; |
| 25 | 77 | ||
| 78 | // Image Characteristics | ||
| 79 | pub const IMAGE_FILE_RELOCS_STRIPPED = 0x1; | ||
| 80 | pub const IMAGE_FILE_DEBUG_STRIPPED = 0x200; | ||
| 81 | pub const IMAGE_FILE_EXECUTABLE_IMAGE = 0x2; | ||
| 82 | pub const IMAGE_FILE_32BIT_MACHINE = 0x100; | ||
| 83 | pub const IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x20; | ||
| 84 | |||
| 85 | // Section flags | ||
| 86 | pub const IMAGE_SCN_CNT_INITIALIZED_DATA = 0x40; | ||
| 87 | pub const IMAGE_SCN_MEM_READ = 0x40000000; | ||
| 88 | pub const IMAGE_SCN_CNT_CODE = 0x20; | ||
| 89 | pub const IMAGE_SCN_MEM_EXECUTE = 0x20000000; | ||
| 90 | pub const IMAGE_SCN_MEM_WRITE = 0x80000000; | ||
| 91 | |||
| 26 | const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; | 92 | const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; |
| 27 | const IMAGE_DEBUG_TYPE_CODEVIEW = 2; | 93 | const IMAGE_DEBUG_TYPE_CODEVIEW = 2; |
| 28 | const DEBUG_DIRECTORY = 6; | 94 | const DEBUG_DIRECTORY = 6; |
lib/std/debug/leb128.zig+24-23| ... | @@ -9,10 +9,10 @@ const testing = std.testing; | ... | @@ -9,10 +9,10 @@ const testing = std.testing; |
| 9 | /// Read a single unsigned LEB128 value from the given reader as type T, | 9 | /// Read a single unsigned LEB128 value from the given reader as type T, |
| 10 | /// or error.Overflow if the value cannot fit. | 10 | /// or error.Overflow if the value cannot fit. |
| 11 | pub fn readULEB128(comptime T: type, reader: anytype) !T { | 11 | pub fn readULEB128(comptime T: type, reader: anytype) !T { |
| 12 | const U = if (T.bit_count < 8) u8 else T; | 12 | const U = if (@typeInfo(T).Int.bits < 8) u8 else T; |
| 13 | const ShiftT = std.math.Log2Int(U); | 13 | const ShiftT = std.math.Log2Int(U); |
| 14 | 14 | ||
| 15 | const max_group = (U.bit_count + 6) / 7; | 15 | const max_group = (@typeInfo(U).Int.bits + 6) / 7; |
| 16 | 16 | ||
| 17 | var value = @as(U, 0); | 17 | var value = @as(U, 0); |
| 18 | var group = @as(ShiftT, 0); | 18 | var group = @as(ShiftT, 0); |
| ... | @@ -40,7 +40,7 @@ pub fn readULEB128(comptime T: type, reader: anytype) !T { | ... | @@ -40,7 +40,7 @@ pub fn readULEB128(comptime T: type, reader: anytype) !T { |
| 40 | /// Write a single unsigned integer as unsigned LEB128 to the given writer. | 40 | /// Write a single unsigned integer as unsigned LEB128 to the given writer. |
| 41 | pub fn writeULEB128(writer: anytype, uint_value: anytype) !void { | 41 | pub fn writeULEB128(writer: anytype, uint_value: anytype) !void { |
| 42 | const T = @TypeOf(uint_value); | 42 | const T = @TypeOf(uint_value); |
| 43 | const U = if (T.bit_count < 8) u8 else T; | 43 | const U = if (@typeInfo(T).Int.bits < 8) u8 else T; |
| 44 | var value = @intCast(U, uint_value); | 44 | var value = @intCast(U, uint_value); |
| 45 | 45 | ||
| 46 | while (true) { | 46 | while (true) { |
| ... | @@ -68,7 +68,7 @@ pub fn readULEB128Mem(comptime T: type, ptr: *[]const u8) !T { | ... | @@ -68,7 +68,7 @@ pub fn readULEB128Mem(comptime T: type, ptr: *[]const u8) !T { |
| 68 | /// returning the number of bytes written. | 68 | /// returning the number of bytes written. |
| 69 | pub fn writeULEB128Mem(ptr: []u8, uint_value: anytype) !usize { | 69 | pub fn writeULEB128Mem(ptr: []u8, uint_value: anytype) !usize { |
| 70 | const T = @TypeOf(uint_value); | 70 | const T = @TypeOf(uint_value); |
| 71 | const max_group = (T.bit_count + 6) / 7; | 71 | const max_group = (@typeInfo(T).Int.bits + 6) / 7; |
| 72 | var buf = std.io.fixedBufferStream(ptr); | 72 | var buf = std.io.fixedBufferStream(ptr); |
| 73 | try writeULEB128(buf.writer(), uint_value); | 73 | try writeULEB128(buf.writer(), uint_value); |
| 74 | return buf.pos; | 74 | return buf.pos; |
| ... | @@ -77,11 +77,11 @@ pub fn writeULEB128Mem(ptr: []u8, uint_value: anytype) !usize { | ... | @@ -77,11 +77,11 @@ pub fn writeULEB128Mem(ptr: []u8, uint_value: anytype) !usize { |
| 77 | /// Read a single signed LEB128 value from the given reader as type T, | 77 | /// Read a single signed LEB128 value from the given reader as type T, |
| 78 | /// or error.Overflow if the value cannot fit. | 78 | /// or error.Overflow if the value cannot fit. |
| 79 | pub fn readILEB128(comptime T: type, reader: anytype) !T { | 79 | pub fn readILEB128(comptime T: type, reader: anytype) !T { |
| 80 | const S = if (T.bit_count < 8) i8 else T; | 80 | const S = if (@typeInfo(T).Int.bits < 8) i8 else T; |
| 81 | const U = std.meta.Int(false, S.bit_count); | 81 | const U = std.meta.Int(false, @typeInfo(S).Int.bits); |
| 82 | const ShiftU = std.math.Log2Int(U); | 82 | const ShiftU = std.math.Log2Int(U); |
| 83 | 83 | ||
| 84 | const max_group = (U.bit_count + 6) / 7; | 84 | const max_group = (@typeInfo(U).Int.bits + 6) / 7; |
| 85 | 85 | ||
| 86 | var value = @as(U, 0); | 86 | var value = @as(U, 0); |
| 87 | var group = @as(ShiftU, 0); | 87 | var group = @as(ShiftU, 0); |
| ... | @@ -97,7 +97,7 @@ pub fn readILEB128(comptime T: type, reader: anytype) !T { | ... | @@ -97,7 +97,7 @@ pub fn readILEB128(comptime T: type, reader: anytype) !T { |
| 97 | if (@bitCast(S, temp) >= 0) return error.Overflow; | 97 | if (@bitCast(S, temp) >= 0) return error.Overflow; |
| 98 | 98 | ||
| 99 | // and all the overflowed bits are 1 | 99 | // and all the overflowed bits are 1 |
| 100 | const remaining_shift = @intCast(u3, U.bit_count - @as(u16, shift)); | 100 | const remaining_shift = @intCast(u3, @typeInfo(U).Int.bits - @as(u16, shift)); |
| 101 | const remaining_bits = @bitCast(i8, byte | 0x80) >> remaining_shift; | 101 | const remaining_bits = @bitCast(i8, byte | 0x80) >> remaining_shift; |
| 102 | if (remaining_bits != -1) return error.Overflow; | 102 | if (remaining_bits != -1) return error.Overflow; |
| 103 | } | 103 | } |
| ... | @@ -127,8 +127,8 @@ pub fn readILEB128(comptime T: type, reader: anytype) !T { | ... | @@ -127,8 +127,8 @@ pub fn readILEB128(comptime T: type, reader: anytype) !T { |
| 127 | /// Write a single signed integer as signed LEB128 to the given writer. | 127 | /// Write a single signed integer as signed LEB128 to the given writer. |
| 128 | pub fn writeILEB128(writer: anytype, int_value: anytype) !void { | 128 | pub fn writeILEB128(writer: anytype, int_value: anytype) !void { |
| 129 | const T = @TypeOf(int_value); | 129 | const T = @TypeOf(int_value); |
| 130 | const S = if (T.bit_count < 8) i8 else T; | 130 | const S = if (@typeInfo(T).Int.bits < 8) i8 else T; |
| 131 | const U = std.meta.Int(false, S.bit_count); | 131 | const U = std.meta.Int(false, @typeInfo(S).Int.bits); |
| 132 | 132 | ||
| 133 | var value = @intCast(S, int_value); | 133 | var value = @intCast(S, int_value); |
| 134 | 134 | ||
| ... | @@ -173,7 +173,7 @@ pub fn writeILEB128Mem(ptr: []u8, int_value: anytype) !usize { | ... | @@ -173,7 +173,7 @@ pub fn writeILEB128Mem(ptr: []u8, int_value: anytype) !usize { |
| 173 | /// different value without shifting all the following code. | 173 | /// different value without shifting all the following code. |
| 174 | pub fn writeUnsignedFixed(comptime l: usize, ptr: *[l]u8, int: std.meta.Int(false, l * 7)) void { | 174 | pub fn writeUnsignedFixed(comptime l: usize, ptr: *[l]u8, int: std.meta.Int(false, l * 7)) void { |
| 175 | const T = @TypeOf(int); | 175 | const T = @TypeOf(int); |
| 176 | const U = if (T.bit_count < 8) u8 else T; | 176 | const U = if (@typeInfo(T).Int.bits < 8) u8 else T; |
| 177 | var value = @intCast(U, int); | 177 | var value = @intCast(U, int); |
| 178 | 178 | ||
| 179 | comptime var i = 0; | 179 | comptime var i = 0; |
| ... | @@ -346,28 +346,29 @@ test "deserialize unsigned LEB128" { | ... | @@ -346,28 +346,29 @@ test "deserialize unsigned LEB128" { |
| 346 | 346 | ||
| 347 | fn test_write_leb128(value: anytype) !void { | 347 | fn test_write_leb128(value: anytype) !void { |
| 348 | const T = @TypeOf(value); | 348 | const T = @TypeOf(value); |
| 349 | const t_signed = @typeInfo(T).Int.is_signed; | ||
| 349 | 350 | ||
| 350 | const writeStream = if (T.is_signed) writeILEB128 else writeULEB128; | 351 | const writeStream = if (t_signed) writeILEB128 else writeULEB128; |
| 351 | const writeMem = if (T.is_signed) writeILEB128Mem else writeULEB128Mem; | 352 | const writeMem = if (t_signed) writeILEB128Mem else writeULEB128Mem; |
| 352 | const readStream = if (T.is_signed) readILEB128 else readULEB128; | 353 | const readStream = if (t_signed) readILEB128 else readULEB128; |
| 353 | const readMem = if (T.is_signed) readILEB128Mem else readULEB128Mem; | 354 | const readMem = if (t_signed) readILEB128Mem else readULEB128Mem; |
| 354 | 355 | ||
| 355 | // decode to a larger bit size too, to ensure sign extension | 356 | // decode to a larger bit size too, to ensure sign extension |
| 356 | // is working as expected | 357 | // is working as expected |
| 357 | const larger_type_bits = ((T.bit_count + 8) / 8) * 8; | 358 | const larger_type_bits = ((@typeInfo(T).Int.bits + 8) / 8) * 8; |
| 358 | const B = std.meta.Int(T.is_signed, larger_type_bits); | 359 | const B = std.meta.Int(t_signed, larger_type_bits); |
| 359 | 360 | ||
| 360 | const bytes_needed = bn: { | 361 | const bytes_needed = bn: { |
| 361 | const S = std.meta.Int(T.is_signed, @sizeOf(T) * 8); | 362 | const S = std.meta.Int(t_signed, @sizeOf(T) * 8); |
| 362 | if (T.bit_count <= 7) break :bn @as(u16, 1); | 363 | if (@typeInfo(T).Int.bits <= 7) break :bn @as(u16, 1); |
| 363 | 364 | ||
| 364 | const unused_bits = if (value < 0) @clz(T, ~value) else @clz(T, value); | 365 | const unused_bits = if (value < 0) @clz(T, ~value) else @clz(T, value); |
| 365 | const used_bits: u16 = (T.bit_count - unused_bits) + @boolToInt(T.is_signed); | 366 | const used_bits: u16 = (@typeInfo(T).Int.bits - unused_bits) + @boolToInt(t_signed); |
| 366 | if (used_bits <= 7) break :bn @as(u16, 1); | 367 | if (used_bits <= 7) break :bn @as(u16, 1); |
| 367 | break :bn ((used_bits + 6) / 7); | 368 | break :bn ((used_bits + 6) / 7); |
| 368 | }; | 369 | }; |
| 369 | 370 | ||
| 370 | const max_groups = if (T.bit_count == 0) 1 else (T.bit_count + 6) / 7; | 371 | const max_groups = if (@typeInfo(T).Int.bits == 0) 1 else (@typeInfo(T).Int.bits + 6) / 7; |
| 371 | 372 | ||
| 372 | var buf: [max_groups]u8 = undefined; | 373 | var buf: [max_groups]u8 = undefined; |
| 373 | var fbs = std.io.fixedBufferStream(&buf); | 374 | var fbs = std.io.fixedBufferStream(&buf); |
| ... | @@ -414,7 +415,7 @@ test "serialize unsigned LEB128" { | ... | @@ -414,7 +415,7 @@ test "serialize unsigned LEB128" { |
| 414 | const T = std.meta.Int(false, t); | 415 | const T = std.meta.Int(false, t); |
| 415 | const min = std.math.minInt(T); | 416 | const min = std.math.minInt(T); |
| 416 | const max = std.math.maxInt(T); | 417 | const max = std.math.maxInt(T); |
| 417 | var i = @as(std.meta.Int(false, T.bit_count + 1), min); | 418 | var i = @as(std.meta.Int(false, @typeInfo(T).Int.bits + 1), min); |
| 418 | 419 | ||
| 419 | while (i <= max) : (i += 1) try test_write_leb128(@intCast(T, i)); | 420 | while (i <= max) : (i += 1) try test_write_leb128(@intCast(T, i)); |
| 420 | } | 421 | } |
| ... | @@ -432,7 +433,7 @@ test "serialize signed LEB128" { | ... | @@ -432,7 +433,7 @@ test "serialize signed LEB128" { |
| 432 | const T = std.meta.Int(true, t); | 433 | const T = std.meta.Int(true, t); |
| 433 | const min = std.math.minInt(T); | 434 | const min = std.math.minInt(T); |
| 434 | const max = std.math.maxInt(T); | 435 | const max = std.math.maxInt(T); |
| 435 | var i = @as(std.meta.Int(true, T.bit_count + 1), min); | 436 | var i = @as(std.meta.Int(true, @typeInfo(T).Int.bits + 1), min); |
| 436 | 437 | ||
| 437 | while (i <= max) : (i += 1) try test_write_leb128(@intCast(T, i)); | 438 | while (i <= max) : (i += 1) try test_write_leb128(@intCast(T, i)); |
| 438 | } | 439 | } |
lib/std/fmt.zig+13-10| ... | @@ -82,6 +82,8 @@ fn peekIsAlign(comptime fmt: []const u8) bool { | ... | @@ -82,6 +82,8 @@ fn peekIsAlign(comptime fmt: []const u8) bool { |
| 82 | /// This allows user types to be formatted in a logical manner instead of dumping all fields of the type. | 82 | /// This allows user types to be formatted in a logical manner instead of dumping all fields of the type. |
| 83 | /// | 83 | /// |
| 84 | /// A user type may be a `struct`, `vector`, `union` or `enum` type. | 84 | /// A user type may be a `struct`, `vector`, `union` or `enum` type. |
| 85 | /// | ||
| 86 | /// To print literal curly braces, escape them by writing them twice, e.g. `{{` or `}}`. | ||
| 85 | pub fn format( | 87 | pub fn format( |
| 86 | writer: anytype, | 88 | writer: anytype, |
| 87 | comptime fmt: []const u8, | 89 | comptime fmt: []const u8, |
| ... | @@ -91,7 +93,7 @@ pub fn format( | ... | @@ -91,7 +93,7 @@ pub fn format( |
| 91 | if (@typeInfo(@TypeOf(args)) != .Struct) { | 93 | if (@typeInfo(@TypeOf(args)) != .Struct) { |
| 92 | @compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(args))); | 94 | @compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(args))); |
| 93 | } | 95 | } |
| 94 | if (args.len > ArgSetType.bit_count) { | 96 | if (args.len > @typeInfo(ArgSetType).Int.bits) { |
| 95 | @compileError("32 arguments max are supported per format call"); | 97 | @compileError("32 arguments max are supported per format call"); |
| 96 | } | 98 | } |
| 97 | 99 | ||
| ... | @@ -325,7 +327,7 @@ pub fn formatType( | ... | @@ -325,7 +327,7 @@ pub fn formatType( |
| 325 | max_depth: usize, | 327 | max_depth: usize, |
| 326 | ) @TypeOf(writer).Error!void { | 328 | ) @TypeOf(writer).Error!void { |
| 327 | if (comptime std.mem.eql(u8, fmt, "*")) { | 329 | if (comptime std.mem.eql(u8, fmt, "*")) { |
| 328 | try writer.writeAll(@typeName(@TypeOf(value).Child)); | 330 | try writer.writeAll(@typeName(@typeInfo(@TypeOf(value)).Pointer.child)); |
| 329 | try writer.writeAll("@"); | 331 | try writer.writeAll("@"); |
| 330 | try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, writer); | 332 | try formatInt(@ptrToInt(value), 16, false, FormatOptions{}, writer); |
| 331 | return; | 333 | return; |
| ... | @@ -430,12 +432,12 @@ pub fn formatType( | ... | @@ -430,12 +432,12 @@ pub fn formatType( |
| 430 | if (info.child == u8) { | 432 | if (info.child == u8) { |
| 431 | return formatText(value, fmt, options, writer); | 433 | return formatText(value, fmt, options, writer); |
| 432 | } | 434 | } |
| 433 | return format(writer, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }); | 435 | return format(writer, "{}@{x}", .{ @typeName(@typeInfo(T).Pointer.child), @ptrToInt(value) }); |
| 434 | }, | 436 | }, |
| 435 | .Enum, .Union, .Struct => { | 437 | .Enum, .Union, .Struct => { |
| 436 | return formatType(value.*, fmt, options, writer, max_depth); | 438 | return formatType(value.*, fmt, options, writer, max_depth); |
| 437 | }, | 439 | }, |
| 438 | else => return format(writer, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }), | 440 | else => return format(writer, "{}@{x}", .{ @typeName(@typeInfo(T).Pointer.child), @ptrToInt(value) }), |
| 439 | }, | 441 | }, |
| 440 | .Many, .C => { | 442 | .Many, .C => { |
| 441 | if (ptr_info.sentinel) |sentinel| { | 443 | if (ptr_info.sentinel) |sentinel| { |
| ... | @@ -446,7 +448,7 @@ pub fn formatType( | ... | @@ -446,7 +448,7 @@ pub fn formatType( |
| 446 | return formatText(mem.span(value), fmt, options, writer); | 448 | return formatText(mem.span(value), fmt, options, writer); |
| 447 | } | 449 | } |
| 448 | } | 450 | } |
| 449 | return format(writer, "{}@{x}", .{ @typeName(T.Child), @ptrToInt(value) }); | 451 | return format(writer, "{}@{x}", .{ @typeName(@typeInfo(T).Pointer.child), @ptrToInt(value) }); |
| 450 | }, | 452 | }, |
| 451 | .Slice => { | 453 | .Slice => { |
| 452 | if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) { | 454 | if (fmt.len > 0 and ((fmt[0] == 'x') or (fmt[0] == 'X'))) { |
| ... | @@ -536,7 +538,7 @@ pub fn formatIntValue( | ... | @@ -536,7 +538,7 @@ pub fn formatIntValue( |
| 536 | radix = 10; | 538 | radix = 10; |
| 537 | uppercase = false; | 539 | uppercase = false; |
| 538 | } else if (comptime std.mem.eql(u8, fmt, "c")) { | 540 | } else if (comptime std.mem.eql(u8, fmt, "c")) { |
| 539 | if (@TypeOf(int_value).bit_count <= 8) { | 541 | if (@typeInfo(@TypeOf(int_value)).Int.bits <= 8) { |
| 540 | return formatAsciiChar(@as(u8, int_value), options, writer); | 542 | return formatAsciiChar(@as(u8, int_value), options, writer); |
| 541 | } else { | 543 | } else { |
| 542 | @compileError("Cannot print integer that is larger than 8 bits as a ascii"); | 544 | @compileError("Cannot print integer that is larger than 8 bits as a ascii"); |
| ... | @@ -945,7 +947,7 @@ pub fn formatInt( | ... | @@ -945,7 +947,7 @@ pub fn formatInt( |
| 945 | } else | 947 | } else |
| 946 | value; | 948 | value; |
| 947 | 949 | ||
| 948 | if (@TypeOf(int_value).is_signed) { | 950 | if (@typeInfo(@TypeOf(int_value)).Int.is_signed) { |
| 949 | return formatIntSigned(int_value, base, uppercase, options, writer); | 951 | return formatIntSigned(int_value, base, uppercase, options, writer); |
| 950 | } else { | 952 | } else { |
| 951 | return formatIntUnsigned(int_value, base, uppercase, options, writer); | 953 | return formatIntUnsigned(int_value, base, uppercase, options, writer); |
| ... | @@ -987,9 +989,10 @@ fn formatIntUnsigned( | ... | @@ -987,9 +989,10 @@ fn formatIntUnsigned( |
| 987 | writer: anytype, | 989 | writer: anytype, |
| 988 | ) !void { | 990 | ) !void { |
| 989 | assert(base >= 2); | 991 | assert(base >= 2); |
| 990 | var buf: [math.max(@TypeOf(value).bit_count, 1)]u8 = undefined; | 992 | const value_info = @typeInfo(@TypeOf(value)).Int; |
| 991 | const min_int_bits = comptime math.max(@TypeOf(value).bit_count, @TypeOf(base).bit_count); | 993 | var buf: [math.max(value_info.bits, 1)]u8 = undefined; |
| 992 | const MinInt = std.meta.Int(@TypeOf(value).is_signed, min_int_bits); | 994 | const min_int_bits = comptime math.max(value_info.bits, @typeInfo(@TypeOf(base)).Int.bits); |
| 995 | const MinInt = std.meta.Int(value_info.is_signed, min_int_bits); | ||
| 993 | var a: MinInt = value; | 996 | var a: MinInt = value; |
| 994 | var index: usize = buf.len; | 997 | var index: usize = buf.len; |
| 995 | 998 |
lib/std/fmt/parse_float.zig+1-1| ... | @@ -374,7 +374,7 @@ test "fmt.parseFloat" { | ... | @@ -374,7 +374,7 @@ test "fmt.parseFloat" { |
| 374 | const epsilon = 1e-7; | 374 | const epsilon = 1e-7; |
| 375 | 375 | ||
| 376 | inline for ([_]type{ f16, f32, f64, f128 }) |T| { | 376 | inline for ([_]type{ f16, f32, f64, f128 }) |T| { |
| 377 | const Z = std.meta.Int(false, T.bit_count); | 377 | const Z = std.meta.Int(false, @typeInfo(T).Float.bits); |
| 378 | 378 | ||
| 379 | testing.expectError(error.InvalidCharacter, parseFloat(T, "")); | 379 | testing.expectError(error.InvalidCharacter, parseFloat(T, "")); |
| 380 | testing.expectError(error.InvalidCharacter, parseFloat(T, " 1")); | 380 | testing.expectError(error.InvalidCharacter, parseFloat(T, " 1")); |
lib/std/fs.zig+9-3| ... | @@ -1437,26 +1437,32 @@ pub const Dir = struct { | ... | @@ -1437,26 +1437,32 @@ pub const Dir = struct { |
| 1437 | /// On success, caller owns returned buffer. | 1437 | /// On success, caller owns returned buffer. |
| 1438 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. | 1438 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. |
| 1439 | pub fn readFileAlloc(self: Dir, allocator: *mem.Allocator, file_path: []const u8, max_bytes: usize) ![]u8 { | 1439 | pub fn readFileAlloc(self: Dir, allocator: *mem.Allocator, file_path: []const u8, max_bytes: usize) ![]u8 { |
| 1440 | return self.readFileAllocOptions(allocator, file_path, max_bytes, @alignOf(u8), null); | 1440 | return self.readFileAllocOptions(allocator, file_path, max_bytes, null, @alignOf(u8), null); |
| 1441 | } | 1441 | } |
| 1442 | 1442 | ||
| 1443 | /// On success, caller owns returned buffer. | 1443 | /// On success, caller owns returned buffer. |
| 1444 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. | 1444 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. |
| 1445 | /// If `size_hint` is specified the initial buffer size is calculated using | ||
| 1446 | /// that value, otherwise the effective file size is used instead. | ||
| 1445 | /// Allows specifying alignment and a sentinel value. | 1447 | /// Allows specifying alignment and a sentinel value. |
| 1446 | pub fn readFileAllocOptions( | 1448 | pub fn readFileAllocOptions( |
| 1447 | self: Dir, | 1449 | self: Dir, |
| 1448 | allocator: *mem.Allocator, | 1450 | allocator: *mem.Allocator, |
| 1449 | file_path: []const u8, | 1451 | file_path: []const u8, |
| 1450 | max_bytes: usize, | 1452 | max_bytes: usize, |
| 1453 | size_hint: ?usize, | ||
| 1451 | comptime alignment: u29, | 1454 | comptime alignment: u29, |
| 1452 | comptime optional_sentinel: ?u8, | 1455 | comptime optional_sentinel: ?u8, |
| 1453 | ) !(if (optional_sentinel) |s| [:s]align(alignment) u8 else []align(alignment) u8) { | 1456 | ) !(if (optional_sentinel) |s| [:s]align(alignment) u8 else []align(alignment) u8) { |
| 1454 | var file = try self.openFile(file_path, .{}); | 1457 | var file = try self.openFile(file_path, .{}); |
| 1455 | defer file.close(); | 1458 | defer file.close(); |
| 1456 | 1459 | ||
| 1457 | const stat_size = try file.getEndPos(); | 1460 | // If the file size doesn't fit a usize it'll be certainly greater than |
| 1461 | // `max_bytes` | ||
| 1462 | const stat_size = size_hint orelse math.cast(usize, try file.getEndPos()) catch | ||
| 1463 | return error.FileTooBig; | ||
| 1458 | 1464 | ||
| 1459 | return file.readAllAllocOptions(allocator, stat_size, max_bytes, alignment, optional_sentinel); | 1465 | return file.readToEndAllocOptions(allocator, max_bytes, stat_size, alignment, optional_sentinel); |
| 1460 | } | 1466 | } |
| 1461 | 1467 | ||
| 1462 | pub const DeleteTreeError = error{ | 1468 | pub const DeleteTreeError = error{ |
lib/std/fs/file.zig+29-11| ... | @@ -363,31 +363,49 @@ pub const File = struct { | ... | @@ -363,31 +363,49 @@ pub const File = struct { |
| 363 | try os.futimens(self.handle, &times); | 363 | try os.futimens(self.handle, &times); |
| 364 | } | 364 | } |
| 365 | 365 | ||
| 366 | /// Reads all the bytes from the current position to the end of the file. | ||
| 366 | /// On success, caller owns returned buffer. | 367 | /// On success, caller owns returned buffer. |
| 367 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. | 368 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. |
| 368 | pub fn readAllAlloc(self: File, allocator: *mem.Allocator, stat_size: u64, max_bytes: usize) ![]u8 { | 369 | pub fn readToEndAlloc(self: File, allocator: *mem.Allocator, max_bytes: usize) ![]u8 { |
| 369 | return self.readAllAllocOptions(allocator, stat_size, max_bytes, @alignOf(u8), null); | 370 | return self.readToEndAllocOptions(allocator, max_bytes, null, @alignOf(u8), null); |
| 370 | } | 371 | } |
| 371 | 372 | ||
| 373 | /// Reads all the bytes from the current position to the end of the file. | ||
| 372 | /// On success, caller owns returned buffer. | 374 | /// On success, caller owns returned buffer. |
| 373 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. | 375 | /// If the file is larger than `max_bytes`, returns `error.FileTooBig`. |
| 376 | /// If `size_hint` is specified the initial buffer size is calculated using | ||
| 377 | /// that value, otherwise an arbitrary value is used instead. | ||
| 374 | /// Allows specifying alignment and a sentinel value. | 378 | /// Allows specifying alignment and a sentinel value. |
| 375 | pub fn readAllAllocOptions( | 379 | pub fn readToEndAllocOptions( |
| 376 | self: File, | 380 | self: File, |
| 377 | allocator: *mem.Allocator, | 381 | allocator: *mem.Allocator, |
| 378 | stat_size: u64, | ||
| 379 | max_bytes: usize, | 382 | max_bytes: usize, |
| 383 | size_hint: ?usize, | ||
| 380 | comptime alignment: u29, | 384 | comptime alignment: u29, |
| 381 | comptime optional_sentinel: ?u8, | 385 | comptime optional_sentinel: ?u8, |
| 382 | ) !(if (optional_sentinel) |s| [:s]align(alignment) u8 else []align(alignment) u8) { | 386 | ) !(if (optional_sentinel) |s| [:s]align(alignment) u8 else []align(alignment) u8) { |
| 383 | const size = math.cast(usize, stat_size) catch math.maxInt(usize); | 387 | // If no size hint is provided fall back to the size=0 code path |
| 384 | if (size > max_bytes) return error.FileTooBig; | 388 | const size = size_hint orelse 0; |
| 385 | 389 | ||
| 386 | const buf = try allocator.allocWithOptions(u8, size, alignment, optional_sentinel); | 390 | // The file size returned by stat is used as hint to set the buffer |
| 387 | errdefer allocator.free(buf); | 391 | // size. If the reported size is zero, as it happens on Linux for files |
| 392 | // in /proc, a small buffer is allocated instead. | ||
| 393 | const initial_cap = (if (size > 0) size else 1024) + @boolToInt(optional_sentinel != null); | ||
| 394 | var array_list = try std.ArrayListAligned(u8, alignment).initCapacity(allocator, initial_cap); | ||
| 395 | defer array_list.deinit(); | ||
| 396 | |||
| 397 | self.reader().readAllArrayList(&array_list, max_bytes) catch |err| switch (err) { | ||
| 398 | error.StreamTooLong => return error.FileTooBig, | ||
| 399 | else => |e| return e, | ||
| 400 | }; | ||
| 388 | 401 | ||
| 389 | try self.reader().readNoEof(buf); | 402 | if (optional_sentinel) |sentinel| { |
| 390 | return buf; | 403 | try array_list.append(sentinel); |
| 404 | const buf = array_list.toOwnedSlice(); | ||
| 405 | return buf[0 .. buf.len - 1 :sentinel]; | ||
| 406 | } else { | ||
| 407 | return array_list.toOwnedSlice(); | ||
| 408 | } | ||
| 391 | } | 409 | } |
| 392 | 410 | ||
| 393 | pub const ReadError = os.ReadError; | 411 | pub const ReadError = os.ReadError; |
lib/std/fs/test.zig+5-5| ... | @@ -188,30 +188,30 @@ test "readAllAlloc" { | ... | @@ -188,30 +188,30 @@ test "readAllAlloc" { |
| 188 | var file = try tmp_dir.dir.createFile("test_file", .{ .read = true }); | 188 | var file = try tmp_dir.dir.createFile("test_file", .{ .read = true }); |
| 189 | defer file.close(); | 189 | defer file.close(); |
| 190 | 190 | ||
| 191 | const buf1 = try file.readAllAlloc(testing.allocator, 0, 1024); | 191 | const buf1 = try file.readToEndAlloc(testing.allocator, 1024); |
| 192 | defer testing.allocator.free(buf1); | 192 | defer testing.allocator.free(buf1); |
| 193 | testing.expect(buf1.len == 0); | 193 | testing.expect(buf1.len == 0); |
| 194 | 194 | ||
| 195 | const write_buf: []const u8 = "this is a test.\nthis is a test.\nthis is a test.\nthis is a test.\n"; | 195 | const write_buf: []const u8 = "this is a test.\nthis is a test.\nthis is a test.\nthis is a test.\n"; |
| 196 | try file.writeAll(write_buf); | 196 | try file.writeAll(write_buf); |
| 197 | try file.seekTo(0); | 197 | try file.seekTo(0); |
| 198 | const file_size = try file.getEndPos(); | ||
| 199 | 198 | ||
| 200 | // max_bytes > file_size | 199 | // max_bytes > file_size |
| 201 | const buf2 = try file.readAllAlloc(testing.allocator, file_size, 1024); | 200 | const buf2 = try file.readToEndAlloc(testing.allocator, 1024); |
| 202 | defer testing.allocator.free(buf2); | 201 | defer testing.allocator.free(buf2); |
| 203 | testing.expectEqual(write_buf.len, buf2.len); | 202 | testing.expectEqual(write_buf.len, buf2.len); |
| 204 | testing.expect(std.mem.eql(u8, write_buf, buf2)); | 203 | testing.expect(std.mem.eql(u8, write_buf, buf2)); |
| 205 | try file.seekTo(0); | 204 | try file.seekTo(0); |
| 206 | 205 | ||
| 207 | // max_bytes == file_size | 206 | // max_bytes == file_size |
| 208 | const buf3 = try file.readAllAlloc(testing.allocator, file_size, write_buf.len); | 207 | const buf3 = try file.readToEndAlloc(testing.allocator, write_buf.len); |
| 209 | defer testing.allocator.free(buf3); | 208 | defer testing.allocator.free(buf3); |
| 210 | testing.expectEqual(write_buf.len, buf3.len); | 209 | testing.expectEqual(write_buf.len, buf3.len); |
| 211 | testing.expect(std.mem.eql(u8, write_buf, buf3)); | 210 | testing.expect(std.mem.eql(u8, write_buf, buf3)); |
| 211 | try file.seekTo(0); | ||
| 212 | 212 | ||
| 213 | // max_bytes < file_size | 213 | // max_bytes < file_size |
| 214 | testing.expectError(error.FileTooBig, file.readAllAlloc(testing.allocator, file_size, write_buf.len - 1)); | 214 | testing.expectError(error.FileTooBig, file.readToEndAlloc(testing.allocator, write_buf.len - 1)); |
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | test "directory operations on files" { | 217 | test "directory operations on files" { |
lib/std/hash/auto_hash.zig+1-1| ... | @@ -113,7 +113,7 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { | ... | @@ -113,7 +113,7 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { |
| 113 | .Array => hashArray(hasher, key, strat), | 113 | .Array => hashArray(hasher, key, strat), |
| 114 | 114 | ||
| 115 | .Vector => |info| { | 115 | .Vector => |info| { |
| 116 | if (info.child.bit_count % 8 == 0) { | 116 | if (std.meta.bitCount(info.child) % 8 == 0) { |
| 117 | // If there's no unused bits in the child type, we can just hash | 117 | // If there's no unused bits in the child type, we can just hash |
| 118 | // this as an array of bytes. | 118 | // this as an array of bytes. |
| 119 | hasher.update(mem.asBytes(&key)); | 119 | hasher.update(mem.asBytes(&key)); |
lib/std/heap.zig+5-1| ... | @@ -915,6 +915,10 @@ pub fn testAllocator(base_allocator: *mem.Allocator) !void { | ... | @@ -915,6 +915,10 @@ pub fn testAllocator(base_allocator: *mem.Allocator) !void { |
| 915 | testing.expect(slice.len == 10); | 915 | testing.expect(slice.len == 10); |
| 916 | 916 | ||
| 917 | allocator.free(slice); | 917 | allocator.free(slice); |
| 918 | |||
| 919 | const zero_bit_ptr = try allocator.create(u0); | ||
| 920 | zero_bit_ptr.* = 0; | ||
| 921 | allocator.destroy(zero_bit_ptr); | ||
| 918 | } | 922 | } |
| 919 | 923 | ||
| 920 | pub fn testAllocatorAligned(base_allocator: *mem.Allocator, comptime alignment: u29) !void { | 924 | pub fn testAllocatorAligned(base_allocator: *mem.Allocator, comptime alignment: u29) !void { |
| ... | @@ -952,7 +956,7 @@ pub fn testAllocatorLargeAlignment(base_allocator: *mem.Allocator) mem.Allocator | ... | @@ -952,7 +956,7 @@ pub fn testAllocatorLargeAlignment(base_allocator: *mem.Allocator) mem.Allocator |
| 952 | // very near usize? | 956 | // very near usize? |
| 953 | if (mem.page_size << 2 > maxInt(usize)) return; | 957 | if (mem.page_size << 2 > maxInt(usize)) return; |
| 954 | 958 | ||
| 955 | const USizeShift = std.meta.Int(false, std.math.log2(usize.bit_count)); | 959 | const USizeShift = std.meta.Int(false, std.math.log2(std.meta.bitCount(usize))); |
| 956 | const large_align = @as(u29, mem.page_size << 2); | 960 | const large_align = @as(u29, mem.page_size << 2); |
| 957 | 961 | ||
| 958 | var align_mask: usize = undefined; | 962 | var align_mask: usize = undefined; |
lib/std/io/reader.zig+5-5| ... | @@ -198,28 +198,28 @@ pub fn Reader( | ... | @@ -198,28 +198,28 @@ pub fn Reader( |
| 198 | 198 | ||
| 199 | /// Reads a native-endian integer | 199 | /// Reads a native-endian integer |
| 200 | pub fn readIntNative(self: Self, comptime T: type) !T { | 200 | pub fn readIntNative(self: Self, comptime T: type) !T { |
| 201 | const bytes = try self.readBytesNoEof((T.bit_count + 7) / 8); | 201 | const bytes = try self.readBytesNoEof((@typeInfo(T).Int.bits + 7) / 8); |
| 202 | return mem.readIntNative(T, &bytes); | 202 | return mem.readIntNative(T, &bytes); |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | /// Reads a foreign-endian integer | 205 | /// Reads a foreign-endian integer |
| 206 | pub fn readIntForeign(self: Self, comptime T: type) !T { | 206 | pub fn readIntForeign(self: Self, comptime T: type) !T { |
| 207 | const bytes = try self.readBytesNoEof((T.bit_count + 7) / 8); | 207 | const bytes = try self.readBytesNoEof((@typeInfo(T).Int.bits + 7) / 8); |
| 208 | return mem.readIntForeign(T, &bytes); | 208 | return mem.readIntForeign(T, &bytes); |
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | pub fn readIntLittle(self: Self, comptime T: type) !T { | 211 | pub fn readIntLittle(self: Self, comptime T: type) !T { |
| 212 | const bytes = try self.readBytesNoEof((T.bit_count + 7) / 8); | 212 | const bytes = try self.readBytesNoEof((@typeInfo(T).Int.bits + 7) / 8); |
| 213 | return mem.readIntLittle(T, &bytes); | 213 | return mem.readIntLittle(T, &bytes); |
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | pub fn readIntBig(self: Self, comptime T: type) !T { | 216 | pub fn readIntBig(self: Self, comptime T: type) !T { |
| 217 | const bytes = try self.readBytesNoEof((T.bit_count + 7) / 8); | 217 | const bytes = try self.readBytesNoEof((@typeInfo(T).Int.bits + 7) / 8); |
| 218 | return mem.readIntBig(T, &bytes); | 218 | return mem.readIntBig(T, &bytes); |
| 219 | } | 219 | } |
| 220 | 220 | ||
| 221 | pub fn readInt(self: Self, comptime T: type, endian: builtin.Endian) !T { | 221 | pub fn readInt(self: Self, comptime T: type, endian: builtin.Endian) !T { |
| 222 | const bytes = try self.readBytesNoEof((T.bit_count + 7) / 8); | 222 | const bytes = try self.readBytesNoEof((@typeInfo(T).Int.bits + 7) / 8); |
| 223 | return mem.readInt(T, &bytes, endian); | 223 | return mem.readInt(T, &bytes, endian); |
| 224 | } | 224 | } |
| 225 | 225 |
lib/std/io/serialization.zig+3-3| ... | @@ -60,7 +60,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, | ... | @@ -60,7 +60,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, |
| 60 | 60 | ||
| 61 | const U = std.meta.Int(false, t_bit_count); | 61 | const U = std.meta.Int(false, t_bit_count); |
| 62 | const Log2U = math.Log2Int(U); | 62 | const Log2U = math.Log2Int(U); |
| 63 | const int_size = (U.bit_count + 7) / 8; | 63 | const int_size = (t_bit_count + 7) / 8; |
| 64 | 64 | ||
| 65 | if (packing == .Bit) { | 65 | if (packing == .Bit) { |
| 66 | const result = try self.in_stream.readBitsNoEof(U, t_bit_count); | 66 | const result = try self.in_stream.readBitsNoEof(U, t_bit_count); |
| ... | @@ -73,7 +73,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, | ... | @@ -73,7 +73,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, |
| 73 | 73 | ||
| 74 | if (int_size == 1) { | 74 | if (int_size == 1) { |
| 75 | if (t_bit_count == 8) return @bitCast(T, buffer[0]); | 75 | if (t_bit_count == 8) return @bitCast(T, buffer[0]); |
| 76 | const PossiblySignedByte = std.meta.Int(T.is_signed, 8); | 76 | const PossiblySignedByte = std.meta.Int(@typeInfo(T).Int.is_signed, 8); |
| 77 | return @truncate(T, @bitCast(PossiblySignedByte, buffer[0])); | 77 | return @truncate(T, @bitCast(PossiblySignedByte, buffer[0])); |
| 78 | } | 78 | } |
| 79 | 79 | ||
| ... | @@ -247,7 +247,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co | ... | @@ -247,7 +247,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co |
| 247 | 247 | ||
| 248 | const U = std.meta.Int(false, t_bit_count); | 248 | const U = std.meta.Int(false, t_bit_count); |
| 249 | const Log2U = math.Log2Int(U); | 249 | const Log2U = math.Log2Int(U); |
| 250 | const int_size = (U.bit_count + 7) / 8; | 250 | const int_size = (t_bit_count + 7) / 8; |
| 251 | 251 | ||
| 252 | const u_value = @bitCast(U, value); | 252 | const u_value = @bitCast(U, value); |
| 253 | 253 |
lib/std/io/writer.zig+5-5| ... | @@ -53,7 +53,7 @@ pub fn Writer( | ... | @@ -53,7 +53,7 @@ pub fn Writer( |
| 53 | /// Write a native-endian integer. | 53 | /// Write a native-endian integer. |
| 54 | /// TODO audit non-power-of-two int sizes | 54 | /// TODO audit non-power-of-two int sizes |
| 55 | pub fn writeIntNative(self: Self, comptime T: type, value: T) Error!void { | 55 | pub fn writeIntNative(self: Self, comptime T: type, value: T) Error!void { |
| 56 | var bytes: [(T.bit_count + 7) / 8]u8 = undefined; | 56 | var bytes: [(@typeInfo(T).Int.bits + 7) / 8]u8 = undefined; |
| 57 | mem.writeIntNative(T, &bytes, value); | 57 | mem.writeIntNative(T, &bytes, value); |
| 58 | return self.writeAll(&bytes); | 58 | return self.writeAll(&bytes); |
| 59 | } | 59 | } |
| ... | @@ -61,28 +61,28 @@ pub fn Writer( | ... | @@ -61,28 +61,28 @@ pub fn Writer( |
| 61 | /// Write a foreign-endian integer. | 61 | /// Write a foreign-endian integer. |
| 62 | /// TODO audit non-power-of-two int sizes | 62 | /// TODO audit non-power-of-two int sizes |
| 63 | pub fn writeIntForeign(self: Self, comptime T: type, value: T) Error!void { | 63 | pub fn writeIntForeign(self: Self, comptime T: type, value: T) Error!void { |
| 64 | var bytes: [(T.bit_count + 7) / 8]u8 = undefined; | 64 | var bytes: [(@typeInfo(T).Int.bits + 7) / 8]u8 = undefined; |
| 65 | mem.writeIntForeign(T, &bytes, value); | 65 | mem.writeIntForeign(T, &bytes, value); |
| 66 | return self.writeAll(&bytes); | 66 | return self.writeAll(&bytes); |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | /// TODO audit non-power-of-two int sizes | 69 | /// TODO audit non-power-of-two int sizes |
| 70 | pub fn writeIntLittle(self: Self, comptime T: type, value: T) Error!void { | 70 | pub fn writeIntLittle(self: Self, comptime T: type, value: T) Error!void { |
| 71 | var bytes: [(T.bit_count + 7) / 8]u8 = undefined; | 71 | var bytes: [(@typeInfo(T).Int.bits + 7) / 8]u8 = undefined; |
| 72 | mem.writeIntLittle(T, &bytes, value); | 72 | mem.writeIntLittle(T, &bytes, value); |
| 73 | return self.writeAll(&bytes); | 73 | return self.writeAll(&bytes); |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | /// TODO audit non-power-of-two int sizes | 76 | /// TODO audit non-power-of-two int sizes |
| 77 | pub fn writeIntBig(self: Self, comptime T: type, value: T) Error!void { | 77 | pub fn writeIntBig(self: Self, comptime T: type, value: T) Error!void { |
| 78 | var bytes: [(T.bit_count + 7) / 8]u8 = undefined; | 78 | var bytes: [(@typeInfo(T).Int.bits + 7) / 8]u8 = undefined; |
| 79 | mem.writeIntBig(T, &bytes, value); | 79 | mem.writeIntBig(T, &bytes, value); |
| 80 | return self.writeAll(&bytes); | 80 | return self.writeAll(&bytes); |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | /// TODO audit non-power-of-two int sizes | 83 | /// TODO audit non-power-of-two int sizes |
| 84 | pub fn writeInt(self: Self, comptime T: type, value: T, endian: builtin.Endian) Error!void { | 84 | pub fn writeInt(self: Self, comptime T: type, value: T, endian: builtin.Endian) Error!void { |
| 85 | var bytes: [(T.bit_count + 7) / 8]u8 = undefined; | 85 | var bytes: [(@typeInfo(T).Int.bits + 7) / 8]u8 = undefined; |
| 86 | mem.writeInt(T, &bytes, value, endian); | 86 | mem.writeInt(T, &bytes, value, endian); |
| 87 | return self.writeAll(&bytes); | 87 | return self.writeAll(&bytes); |
| 88 | } | 88 | } |
lib/std/log.zig+4| ... | @@ -127,6 +127,10 @@ fn log( | ... | @@ -127,6 +127,10 @@ fn log( |
| 127 | if (@enumToInt(message_level) <= @enumToInt(level)) { | 127 | if (@enumToInt(message_level) <= @enumToInt(level)) { |
| 128 | if (@hasDecl(root, "log")) { | 128 | if (@hasDecl(root, "log")) { |
| 129 | root.log(message_level, scope, format, args); | 129 | root.log(message_level, scope, format, args); |
| 130 | } else if (std.Target.current.os.tag == .freestanding) { | ||
| 131 | // On freestanding one must provide a log function; we do not have | ||
| 132 | // any I/O configured. | ||
| 133 | return; | ||
| 130 | } else if (builtin.mode != .ReleaseSmall) { | 134 | } else if (builtin.mode != .ReleaseSmall) { |
| 131 | const held = std.debug.getStderrMutex().acquire(); | 135 | const held = std.debug.getStderrMutex().acquire(); |
| 132 | defer held.release(); | 136 | defer held.release(); |
lib/std/math.zig+32-31| ... | @@ -195,7 +195,7 @@ test "" { | ... | @@ -195,7 +195,7 @@ test "" { |
| 195 | pub fn floatMantissaBits(comptime T: type) comptime_int { | 195 | pub fn floatMantissaBits(comptime T: type) comptime_int { |
| 196 | assert(@typeInfo(T) == .Float); | 196 | assert(@typeInfo(T) == .Float); |
| 197 | 197 | ||
| 198 | return switch (T.bit_count) { | 198 | return switch (@typeInfo(T).Float.bits) { |
| 199 | 16 => 10, | 199 | 16 => 10, |
| 200 | 32 => 23, | 200 | 32 => 23, |
| 201 | 64 => 52, | 201 | 64 => 52, |
| ... | @@ -208,7 +208,7 @@ pub fn floatMantissaBits(comptime T: type) comptime_int { | ... | @@ -208,7 +208,7 @@ pub fn floatMantissaBits(comptime T: type) comptime_int { |
| 208 | pub fn floatExponentBits(comptime T: type) comptime_int { | 208 | pub fn floatExponentBits(comptime T: type) comptime_int { |
| 209 | assert(@typeInfo(T) == .Float); | 209 | assert(@typeInfo(T) == .Float); |
| 210 | 210 | ||
| 211 | return switch (T.bit_count) { | 211 | return switch (@typeInfo(T).Float.bits) { |
| 212 | 16 => 5, | 212 | 16 => 5, |
| 213 | 32 => 8, | 213 | 32 => 8, |
| 214 | 64 => 11, | 214 | 64 => 11, |
| ... | @@ -347,9 +347,9 @@ pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T { | ... | @@ -347,9 +347,9 @@ pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T { |
| 347 | /// A negative shift amount results in a right shift. | 347 | /// A negative shift amount results in a right shift. |
| 348 | pub fn shl(comptime T: type, a: T, shift_amt: anytype) T { | 348 | pub fn shl(comptime T: type, a: T, shift_amt: anytype) T { |
| 349 | const abs_shift_amt = absCast(shift_amt); | 349 | const abs_shift_amt = absCast(shift_amt); |
| 350 | const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt); | 350 | const casted_shift_amt = if (abs_shift_amt >= @typeInfo(T).Int.bits) return 0 else @intCast(Log2Int(T), abs_shift_amt); |
| 351 | 351 | ||
| 352 | if (@TypeOf(shift_amt) == comptime_int or @TypeOf(shift_amt).is_signed) { | 352 | if (@TypeOf(shift_amt) == comptime_int or @typeInfo(@TypeOf(shift_amt)).Int.is_signed) { |
| 353 | if (shift_amt < 0) { | 353 | if (shift_amt < 0) { |
| 354 | return a >> casted_shift_amt; | 354 | return a >> casted_shift_amt; |
| 355 | } | 355 | } |
| ... | @@ -373,9 +373,9 @@ test "math.shl" { | ... | @@ -373,9 +373,9 @@ test "math.shl" { |
| 373 | /// A negative shift amount results in a left shift. | 373 | /// A negative shift amount results in a left shift. |
| 374 | pub fn shr(comptime T: type, a: T, shift_amt: anytype) T { | 374 | pub fn shr(comptime T: type, a: T, shift_amt: anytype) T { |
| 375 | const abs_shift_amt = absCast(shift_amt); | 375 | const abs_shift_amt = absCast(shift_amt); |
| 376 | const casted_shift_amt = if (abs_shift_amt >= T.bit_count) return 0 else @intCast(Log2Int(T), abs_shift_amt); | 376 | const casted_shift_amt = if (abs_shift_amt >= @typeInfo(T).Int.bits) return 0 else @intCast(Log2Int(T), abs_shift_amt); |
| 377 | 377 | ||
| 378 | if (@TypeOf(shift_amt) == comptime_int or @TypeOf(shift_amt).is_signed) { | 378 | if (@TypeOf(shift_amt) == comptime_int or @typeInfo(@TypeOf(shift_amt)).Int.is_signed) { |
| 379 | if (shift_amt >= 0) { | 379 | if (shift_amt >= 0) { |
| 380 | return a >> casted_shift_amt; | 380 | return a >> casted_shift_amt; |
| 381 | } else { | 381 | } else { |
| ... | @@ -400,11 +400,11 @@ test "math.shr" { | ... | @@ -400,11 +400,11 @@ test "math.shr" { |
| 400 | /// Rotates right. Only unsigned values can be rotated. | 400 | /// Rotates right. Only unsigned values can be rotated. |
| 401 | /// Negative shift values results in shift modulo the bit count. | 401 | /// Negative shift values results in shift modulo the bit count. |
| 402 | pub fn rotr(comptime T: type, x: T, r: anytype) T { | 402 | pub fn rotr(comptime T: type, x: T, r: anytype) T { |
| 403 | if (T.is_signed) { | 403 | if (@typeInfo(T).Int.is_signed) { |
| 404 | @compileError("cannot rotate signed integer"); | 404 | @compileError("cannot rotate signed integer"); |
| 405 | } else { | 405 | } else { |
| 406 | const ar = @mod(r, T.bit_count); | 406 | const ar = @mod(r, @typeInfo(T).Int.bits); |
| 407 | return shr(T, x, ar) | shl(T, x, T.bit_count - ar); | 407 | return shr(T, x, ar) | shl(T, x, @typeInfo(T).Int.bits - ar); |
| 408 | } | 408 | } |
| 409 | } | 409 | } |
| 410 | 410 | ||
| ... | @@ -419,11 +419,11 @@ test "math.rotr" { | ... | @@ -419,11 +419,11 @@ test "math.rotr" { |
| 419 | /// Rotates left. Only unsigned values can be rotated. | 419 | /// Rotates left. Only unsigned values can be rotated. |
| 420 | /// Negative shift values results in shift modulo the bit count. | 420 | /// Negative shift values results in shift modulo the bit count. |
| 421 | pub fn rotl(comptime T: type, x: T, r: anytype) T { | 421 | pub fn rotl(comptime T: type, x: T, r: anytype) T { |
| 422 | if (T.is_signed) { | 422 | if (@typeInfo(T).Int.is_signed) { |
| 423 | @compileError("cannot rotate signed integer"); | 423 | @compileError("cannot rotate signed integer"); |
| 424 | } else { | 424 | } else { |
| 425 | const ar = @mod(r, T.bit_count); | 425 | const ar = @mod(r, @typeInfo(T).Int.bits); |
| 426 | return shl(T, x, ar) | shr(T, x, T.bit_count - ar); | 426 | return shl(T, x, ar) | shr(T, x, @typeInfo(T).Int.bits - ar); |
| 427 | } | 427 | } |
| 428 | } | 428 | } |
| 429 | 429 | ||
| ... | @@ -438,7 +438,7 @@ test "math.rotl" { | ... | @@ -438,7 +438,7 @@ test "math.rotl" { |
| 438 | pub fn Log2Int(comptime T: type) type { | 438 | pub fn Log2Int(comptime T: type) type { |
| 439 | // comptime ceil log2 | 439 | // comptime ceil log2 |
| 440 | comptime var count = 0; | 440 | comptime var count = 0; |
| 441 | comptime var s = T.bit_count - 1; | 441 | comptime var s = @typeInfo(T).Int.bits - 1; |
| 442 | inline while (s != 0) : (s >>= 1) { | 442 | inline while (s != 0) : (s >>= 1) { |
| 443 | count += 1; | 443 | count += 1; |
| 444 | } | 444 | } |
| ... | @@ -524,7 +524,7 @@ fn testOverflow() void { | ... | @@ -524,7 +524,7 @@ fn testOverflow() void { |
| 524 | pub fn absInt(x: anytype) !@TypeOf(x) { | 524 | pub fn absInt(x: anytype) !@TypeOf(x) { |
| 525 | const T = @TypeOf(x); | 525 | const T = @TypeOf(x); |
| 526 | comptime assert(@typeInfo(T) == .Int); // must pass an integer to absInt | 526 | comptime assert(@typeInfo(T) == .Int); // must pass an integer to absInt |
| 527 | comptime assert(T.is_signed); // must pass a signed integer to absInt | 527 | comptime assert(@typeInfo(T).Int.is_signed); // must pass a signed integer to absInt |
| 528 | 528 | ||
| 529 | if (x == minInt(@TypeOf(x))) { | 529 | if (x == minInt(@TypeOf(x))) { |
| 530 | return error.Overflow; | 530 | return error.Overflow; |
| ... | @@ -557,7 +557,7 @@ fn testAbsFloat() void { | ... | @@ -557,7 +557,7 @@ fn testAbsFloat() void { |
| 557 | pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T { | 557 | pub fn divTrunc(comptime T: type, numerator: T, denominator: T) !T { |
| 558 | @setRuntimeSafety(false); | 558 | @setRuntimeSafety(false); |
| 559 | if (denominator == 0) return error.DivisionByZero; | 559 | if (denominator == 0) return error.DivisionByZero; |
| 560 | if (@typeInfo(T) == .Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow; | 560 | if (@typeInfo(T) == .Int and @typeInfo(T).Int.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow; |
| 561 | return @divTrunc(numerator, denominator); | 561 | return @divTrunc(numerator, denominator); |
| 562 | } | 562 | } |
| 563 | 563 | ||
| ... | @@ -578,7 +578,7 @@ fn testDivTrunc() void { | ... | @@ -578,7 +578,7 @@ fn testDivTrunc() void { |
| 578 | pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T { | 578 | pub fn divFloor(comptime T: type, numerator: T, denominator: T) !T { |
| 579 | @setRuntimeSafety(false); | 579 | @setRuntimeSafety(false); |
| 580 | if (denominator == 0) return error.DivisionByZero; | 580 | if (denominator == 0) return error.DivisionByZero; |
| 581 | if (@typeInfo(T) == .Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow; | 581 | if (@typeInfo(T) == .Int and @typeInfo(T).Int.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow; |
| 582 | return @divFloor(numerator, denominator); | 582 | return @divFloor(numerator, denominator); |
| 583 | } | 583 | } |
| 584 | 584 | ||
| ... | @@ -652,7 +652,7 @@ fn testDivCeil() void { | ... | @@ -652,7 +652,7 @@ fn testDivCeil() void { |
| 652 | pub fn divExact(comptime T: type, numerator: T, denominator: T) !T { | 652 | pub fn divExact(comptime T: type, numerator: T, denominator: T) !T { |
| 653 | @setRuntimeSafety(false); | 653 | @setRuntimeSafety(false); |
| 654 | if (denominator == 0) return error.DivisionByZero; | 654 | if (denominator == 0) return error.DivisionByZero; |
| 655 | if (@typeInfo(T) == .Int and T.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow; | 655 | if (@typeInfo(T) == .Int and @typeInfo(T).Int.is_signed and numerator == minInt(T) and denominator == -1) return error.Overflow; |
| 656 | const result = @divTrunc(numerator, denominator); | 656 | const result = @divTrunc(numerator, denominator); |
| 657 | if (result * denominator != numerator) return error.UnexpectedRemainder; | 657 | if (result * denominator != numerator) return error.UnexpectedRemainder; |
| 658 | return result; | 658 | return result; |
| ... | @@ -757,10 +757,10 @@ test "math.absCast" { | ... | @@ -757,10 +757,10 @@ test "math.absCast" { |
| 757 | 757 | ||
| 758 | /// Returns the negation of the integer parameter. | 758 | /// Returns the negation of the integer parameter. |
| 759 | /// Result is a signed integer. | 759 | /// Result is a signed integer. |
| 760 | pub fn negateCast(x: anytype) !std.meta.Int(true, @TypeOf(x).bit_count) { | 760 | pub fn negateCast(x: anytype) !std.meta.Int(true, std.meta.bitCount(@TypeOf(x))) { |
| 761 | if (@TypeOf(x).is_signed) return negate(x); | 761 | if (@typeInfo(@TypeOf(x)).Int.is_signed) return negate(x); |
| 762 | 762 | ||
| 763 | const int = std.meta.Int(true, @TypeOf(x).bit_count); | 763 | const int = std.meta.Int(true, std.meta.bitCount(@TypeOf(x))); |
| 764 | if (x > -minInt(int)) return error.Overflow; | 764 | if (x > -minInt(int)) return error.Overflow; |
| 765 | 765 | ||
| 766 | if (x == -minInt(int)) return minInt(int); | 766 | if (x == -minInt(int)) return minInt(int); |
| ... | @@ -823,7 +823,7 @@ pub fn floorPowerOfTwo(comptime T: type, value: T) T { | ... | @@ -823,7 +823,7 @@ pub fn floorPowerOfTwo(comptime T: type, value: T) T { |
| 823 | var x = value; | 823 | var x = value; |
| 824 | 824 | ||
| 825 | comptime var i = 1; | 825 | comptime var i = 1; |
| 826 | inline while (T.bit_count > i) : (i *= 2) { | 826 | inline while (@typeInfo(T).Int.bits > i) : (i *= 2) { |
| 827 | x |= (x >> i); | 827 | x |= (x >> i); |
| 828 | } | 828 | } |
| 829 | 829 | ||
| ... | @@ -847,13 +847,13 @@ fn testFloorPowerOfTwo() void { | ... | @@ -847,13 +847,13 @@ fn testFloorPowerOfTwo() void { |
| 847 | /// Returns the next power of two (if the value is not already a power of two). | 847 | /// Returns the next power of two (if the value is not already a power of two). |
| 848 | /// Only unsigned integers can be used. Zero is not an allowed input. | 848 | /// Only unsigned integers can be used. Zero is not an allowed input. |
| 849 | /// Result is a type with 1 more bit than the input type. | 849 | /// Result is a type with 1 more bit than the input type. |
| 850 | pub fn ceilPowerOfTwoPromote(comptime T: type, value: T) std.meta.Int(T.is_signed, T.bit_count + 1) { | 850 | pub fn ceilPowerOfTwoPromote(comptime T: type, value: T) std.meta.Int(@typeInfo(T).Int.is_signed, @typeInfo(T).Int.bits + 1) { |
| 851 | comptime assert(@typeInfo(T) == .Int); | 851 | comptime assert(@typeInfo(T) == .Int); |
| 852 | comptime assert(!T.is_signed); | 852 | comptime assert(!@typeInfo(T).Int.is_signed); |
| 853 | assert(value != 0); | 853 | assert(value != 0); |
| 854 | comptime const PromotedType = std.meta.Int(T.is_signed, T.bit_count + 1); | 854 | comptime const PromotedType = std.meta.Int(@typeInfo(T).Int.is_signed, @typeInfo(T).Int.bits + 1); |
| 855 | comptime const shiftType = std.math.Log2Int(PromotedType); | 855 | comptime const shiftType = std.math.Log2Int(PromotedType); |
| 856 | return @as(PromotedType, 1) << @intCast(shiftType, T.bit_count - @clz(T, value - 1)); | 856 | return @as(PromotedType, 1) << @intCast(shiftType, @typeInfo(T).Int.bits - @clz(T, value - 1)); |
| 857 | } | 857 | } |
| 858 | 858 | ||
| 859 | /// Returns the next power of two (if the value is not already a power of two). | 859 | /// Returns the next power of two (if the value is not already a power of two). |
| ... | @@ -861,9 +861,10 @@ pub fn ceilPowerOfTwoPromote(comptime T: type, value: T) std.meta.Int(T.is_signe | ... | @@ -861,9 +861,10 @@ pub fn ceilPowerOfTwoPromote(comptime T: type, value: T) std.meta.Int(T.is_signe |
| 861 | /// If the value doesn't fit, returns an error. | 861 | /// If the value doesn't fit, returns an error. |
| 862 | pub fn ceilPowerOfTwo(comptime T: type, value: T) (error{Overflow}!T) { | 862 | pub fn ceilPowerOfTwo(comptime T: type, value: T) (error{Overflow}!T) { |
| 863 | comptime assert(@typeInfo(T) == .Int); | 863 | comptime assert(@typeInfo(T) == .Int); |
| 864 | comptime assert(!T.is_signed); | 864 | const info = @typeInfo(T).Int; |
| 865 | comptime const PromotedType = std.meta.Int(T.is_signed, T.bit_count + 1); | 865 | comptime assert(!info.is_signed); |
| 866 | comptime const overflowBit = @as(PromotedType, 1) << T.bit_count; | 866 | comptime const PromotedType = std.meta.Int(info.is_signed, info.bits + 1); |
| 867 | comptime const overflowBit = @as(PromotedType, 1) << info.bits; | ||
| 867 | var x = ceilPowerOfTwoPromote(T, value); | 868 | var x = ceilPowerOfTwoPromote(T, value); |
| 868 | if (overflowBit & x != 0) { | 869 | if (overflowBit & x != 0) { |
| 869 | return error.Overflow; | 870 | return error.Overflow; |
| ... | @@ -911,7 +912,7 @@ fn testCeilPowerOfTwo() !void { | ... | @@ -911,7 +912,7 @@ fn testCeilPowerOfTwo() !void { |
| 911 | 912 | ||
| 912 | pub fn log2_int(comptime T: type, x: T) Log2Int(T) { | 913 | pub fn log2_int(comptime T: type, x: T) Log2Int(T) { |
| 913 | assert(x != 0); | 914 | assert(x != 0); |
| 914 | return @intCast(Log2Int(T), T.bit_count - 1 - @clz(T, x)); | 915 | return @intCast(Log2Int(T), @typeInfo(T).Int.bits - 1 - @clz(T, x)); |
| 915 | } | 916 | } |
| 916 | 917 | ||
| 917 | pub fn log2_int_ceil(comptime T: type, x: T) Log2Int(T) { | 918 | pub fn log2_int_ceil(comptime T: type, x: T) Log2Int(T) { |
| ... | @@ -1008,8 +1009,8 @@ test "max value type" { | ... | @@ -1008,8 +1009,8 @@ test "max value type" { |
| 1008 | testing.expect(x == 2147483647); | 1009 | testing.expect(x == 2147483647); |
| 1009 | } | 1010 | } |
| 1010 | 1011 | ||
| 1011 | pub fn mulWide(comptime T: type, a: T, b: T) std.meta.Int(T.is_signed, T.bit_count * 2) { | 1012 | pub fn mulWide(comptime T: type, a: T, b: T) std.meta.Int(@typeInfo(T).Int.is_signed, @typeInfo(T).Int.bits * 2) { |
| 1012 | const ResultInt = std.meta.Int(T.is_signed, T.bit_count * 2); | 1013 | const ResultInt = std.meta.Int(@typeInfo(T).Int.is_signed, @typeInfo(T).Int.bits * 2); |
| 1013 | return @as(ResultInt, a) * @as(ResultInt, b); | 1014 | return @as(ResultInt, a) * @as(ResultInt, b); |
| 1014 | } | 1015 | } |
| 1015 | 1016 |
lib/std/math/big.zig+6-5| ... | @@ -9,14 +9,15 @@ const assert = std.debug.assert; | ... | @@ -9,14 +9,15 @@ const assert = std.debug.assert; |
| 9 | pub const Rational = @import("big/rational.zig").Rational; | 9 | pub const Rational = @import("big/rational.zig").Rational; |
| 10 | pub const int = @import("big/int.zig"); | 10 | pub const int = @import("big/int.zig"); |
| 11 | pub const Limb = usize; | 11 | pub const Limb = usize; |
| 12 | pub const DoubleLimb = std.meta.IntType(false, 2 * Limb.bit_count); | 12 | const limb_info = @typeInfo(Limb).Int; |
| 13 | pub const SignedDoubleLimb = std.meta.IntType(true, DoubleLimb.bit_count); | 13 | pub const DoubleLimb = std.meta.IntType(false, 2 * limb_info.bits); |
| 14 | pub const SignedDoubleLimb = std.meta.IntType(true, 2 * limb_info.bits); | ||
| 14 | pub const Log2Limb = std.math.Log2Int(Limb); | 15 | pub const Log2Limb = std.math.Log2Int(Limb); |
| 15 | 16 | ||
| 16 | comptime { | 17 | comptime { |
| 17 | assert(std.math.floorPowerOfTwo(usize, Limb.bit_count) == Limb.bit_count); | 18 | assert(std.math.floorPowerOfTwo(usize, limb_info.bits) == limb_info.bits); |
| 18 | assert(Limb.bit_count <= 64); // u128 set is unsupported | 19 | assert(limb_info.bits <= 64); // u128 set is unsupported |
| 19 | assert(Limb.is_signed == false); | 20 | assert(limb_info.is_signed == false); |
| 20 | } | 21 | } |
| 21 | 22 | ||
| 22 | test "" { | 23 | test "" { |
lib/std/math/big/int.zig+44-43| ... | @@ -6,6 +6,7 @@ | ... | @@ -6,6 +6,7 @@ |
| 6 | const std = @import("../../std.zig"); | 6 | const std = @import("../../std.zig"); |
| 7 | const math = std.math; | 7 | const math = std.math; |
| 8 | const Limb = std.math.big.Limb; | 8 | const Limb = std.math.big.Limb; |
| 9 | const limb_bits = @typeInfo(Limb).Int.bits; | ||
| 9 | const DoubleLimb = std.math.big.DoubleLimb; | 10 | const DoubleLimb = std.math.big.DoubleLimb; |
| 10 | const SignedDoubleLimb = std.math.big.SignedDoubleLimb; | 11 | const SignedDoubleLimb = std.math.big.SignedDoubleLimb; |
| 11 | const Log2Limb = std.math.big.Log2Limb; | 12 | const Log2Limb = std.math.big.Log2Limb; |
| ... | @@ -28,7 +29,7 @@ pub fn calcLimbLen(scalar: anytype) usize { | ... | @@ -28,7 +29,7 @@ pub fn calcLimbLen(scalar: anytype) usize { |
| 28 | }, | 29 | }, |
| 29 | .ComptimeInt => { | 30 | .ComptimeInt => { |
| 30 | const w_value = if (scalar < 0) -scalar else scalar; | 31 | const w_value = if (scalar < 0) -scalar else scalar; |
| 31 | return @divFloor(math.log2(w_value), Limb.bit_count) + 1; | 32 | return @divFloor(math.log2(w_value), limb_bits) + 1; |
| 32 | }, | 33 | }, |
| 33 | else => @compileError("parameter must be a primitive integer type"), | 34 | else => @compileError("parameter must be a primitive integer type"), |
| 34 | } | 35 | } |
| ... | @@ -54,7 +55,7 @@ pub fn calcSetStringLimbsBufferLen(base: u8, string_len: usize) usize { | ... | @@ -54,7 +55,7 @@ pub fn calcSetStringLimbsBufferLen(base: u8, string_len: usize) usize { |
| 54 | } | 55 | } |
| 55 | 56 | ||
| 56 | pub fn calcSetStringLimbCount(base: u8, string_len: usize) usize { | 57 | pub fn calcSetStringLimbCount(base: u8, string_len: usize) usize { |
| 57 | return (string_len + (Limb.bit_count / base - 1)) / (Limb.bit_count / base); | 58 | return (string_len + (limb_bits / base - 1)) / (limb_bits / base); |
| 58 | } | 59 | } |
| 59 | 60 | ||
| 60 | /// a + b * c + *carry, sets carry to the overflow bits | 61 | /// a + b * c + *carry, sets carry to the overflow bits |
| ... | @@ -68,7 +69,7 @@ pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb { | ... | @@ -68,7 +69,7 @@ pub fn addMulLimbWithCarry(a: Limb, b: Limb, c: Limb, carry: *Limb) Limb { |
| 68 | // r2 = b * c | 69 | // r2 = b * c |
| 69 | const bc = @as(DoubleLimb, math.mulWide(Limb, b, c)); | 70 | const bc = @as(DoubleLimb, math.mulWide(Limb, b, c)); |
| 70 | const r2 = @truncate(Limb, bc); | 71 | const r2 = @truncate(Limb, bc); |
| 71 | const c2 = @truncate(Limb, bc >> Limb.bit_count); | 72 | const c2 = @truncate(Limb, bc >> limb_bits); |
| 72 | 73 | ||
| 73 | // r1 = r1 + r2 | 74 | // r1 = r1 + r2 |
| 74 | const c3: Limb = @boolToInt(@addWithOverflow(Limb, r1, r2, &r1)); | 75 | const c3: Limb = @boolToInt(@addWithOverflow(Limb, r1, r2, &r1)); |
| ... | @@ -181,7 +182,7 @@ pub const Mutable = struct { | ... | @@ -181,7 +182,7 @@ pub const Mutable = struct { |
| 181 | 182 | ||
| 182 | switch (@typeInfo(T)) { | 183 | switch (@typeInfo(T)) { |
| 183 | .Int => |info| { | 184 | .Int => |info| { |
| 184 | const UT = if (T.is_signed) std.meta.Int(false, T.bit_count - 1) else T; | 185 | const UT = if (info.is_signed) std.meta.Int(false, info.bits - 1) else T; |
| 185 | 186 | ||
| 186 | const needed_limbs = @sizeOf(UT) / @sizeOf(Limb); | 187 | const needed_limbs = @sizeOf(UT) / @sizeOf(Limb); |
| 187 | assert(needed_limbs <= self.limbs.len); // value too big | 188 | assert(needed_limbs <= self.limbs.len); // value too big |
| ... | @@ -190,7 +191,7 @@ pub const Mutable = struct { | ... | @@ -190,7 +191,7 @@ pub const Mutable = struct { |
| 190 | 191 | ||
| 191 | var w_value: UT = if (value < 0) @intCast(UT, -value) else @intCast(UT, value); | 192 | var w_value: UT = if (value < 0) @intCast(UT, -value) else @intCast(UT, value); |
| 192 | 193 | ||
| 193 | if (info.bits <= Limb.bit_count) { | 194 | if (info.bits <= limb_bits) { |
| 194 | self.limbs[0] = @as(Limb, w_value); | 195 | self.limbs[0] = @as(Limb, w_value); |
| 195 | self.len += 1; | 196 | self.len += 1; |
| 196 | } else { | 197 | } else { |
| ... | @@ -200,15 +201,15 @@ pub const Mutable = struct { | ... | @@ -200,15 +201,15 @@ pub const Mutable = struct { |
| 200 | self.len += 1; | 201 | self.len += 1; |
| 201 | 202 | ||
| 202 | // TODO: shift == 64 at compile-time fails. Fails on u128 limbs. | 203 | // TODO: shift == 64 at compile-time fails. Fails on u128 limbs. |
| 203 | w_value >>= Limb.bit_count / 2; | 204 | w_value >>= limb_bits / 2; |
| 204 | w_value >>= Limb.bit_count / 2; | 205 | w_value >>= limb_bits / 2; |
| 205 | } | 206 | } |
| 206 | } | 207 | } |
| 207 | }, | 208 | }, |
| 208 | .ComptimeInt => { | 209 | .ComptimeInt => { |
| 209 | comptime var w_value = if (value < 0) -value else value; | 210 | comptime var w_value = if (value < 0) -value else value; |
| 210 | 211 | ||
| 211 | const req_limbs = @divFloor(math.log2(w_value), Limb.bit_count) + 1; | 212 | const req_limbs = @divFloor(math.log2(w_value), limb_bits) + 1; |
| 212 | assert(req_limbs <= self.limbs.len); // value too big | 213 | assert(req_limbs <= self.limbs.len); // value too big |
| 213 | 214 | ||
| 214 | self.len = req_limbs; | 215 | self.len = req_limbs; |
| ... | @@ -217,14 +218,14 @@ pub const Mutable = struct { | ... | @@ -217,14 +218,14 @@ pub const Mutable = struct { |
| 217 | if (w_value <= maxInt(Limb)) { | 218 | if (w_value <= maxInt(Limb)) { |
| 218 | self.limbs[0] = w_value; | 219 | self.limbs[0] = w_value; |
| 219 | } else { | 220 | } else { |
| 220 | const mask = (1 << Limb.bit_count) - 1; | 221 | const mask = (1 << limb_bits) - 1; |
| 221 | 222 | ||
| 222 | comptime var i = 0; | 223 | comptime var i = 0; |
| 223 | inline while (w_value != 0) : (i += 1) { | 224 | inline while (w_value != 0) : (i += 1) { |
| 224 | self.limbs[i] = w_value & mask; | 225 | self.limbs[i] = w_value & mask; |
| 225 | 226 | ||
| 226 | w_value >>= Limb.bit_count / 2; | 227 | w_value >>= limb_bits / 2; |
| 227 | w_value >>= Limb.bit_count / 2; | 228 | w_value >>= limb_bits / 2; |
| 228 | } | 229 | } |
| 229 | } | 230 | } |
| 230 | }, | 231 | }, |
| ... | @@ -506,7 +507,7 @@ pub const Mutable = struct { | ... | @@ -506,7 +507,7 @@ pub const Mutable = struct { |
| 506 | /// `a.limbs.len + (shift / (@sizeOf(Limb) * 8))`. | 507 | /// `a.limbs.len + (shift / (@sizeOf(Limb) * 8))`. |
| 507 | pub fn shiftLeft(r: *Mutable, a: Const, shift: usize) void { | 508 | pub fn shiftLeft(r: *Mutable, a: Const, shift: usize) void { |
| 508 | llshl(r.limbs[0..], a.limbs[0..a.limbs.len], shift); | 509 | llshl(r.limbs[0..], a.limbs[0..a.limbs.len], shift); |
| 509 | r.normalize(a.limbs.len + (shift / Limb.bit_count) + 1); | 510 | r.normalize(a.limbs.len + (shift / limb_bits) + 1); |
| 510 | r.positive = a.positive; | 511 | r.positive = a.positive; |
| 511 | } | 512 | } |
| 512 | 513 | ||
| ... | @@ -516,7 +517,7 @@ pub const Mutable = struct { | ... | @@ -516,7 +517,7 @@ pub const Mutable = struct { |
| 516 | /// Asserts there is enough memory to fit the result. The upper bound Limb count is | 517 | /// Asserts there is enough memory to fit the result. The upper bound Limb count is |
| 517 | /// `a.limbs.len - (shift / (@sizeOf(Limb) * 8))`. | 518 | /// `a.limbs.len - (shift / (@sizeOf(Limb) * 8))`. |
| 518 | pub fn shiftRight(r: *Mutable, a: Const, shift: usize) void { | 519 | pub fn shiftRight(r: *Mutable, a: Const, shift: usize) void { |
| 519 | if (a.limbs.len <= shift / Limb.bit_count) { | 520 | if (a.limbs.len <= shift / limb_bits) { |
| 520 | r.len = 1; | 521 | r.len = 1; |
| 521 | r.positive = true; | 522 | r.positive = true; |
| 522 | r.limbs[0] = 0; | 523 | r.limbs[0] = 0; |
| ... | @@ -524,7 +525,7 @@ pub const Mutable = struct { | ... | @@ -524,7 +525,7 @@ pub const Mutable = struct { |
| 524 | } | 525 | } |
| 525 | 526 | ||
| 526 | const r_len = llshr(r.limbs[0..], a.limbs[0..a.limbs.len], shift); | 527 | const r_len = llshr(r.limbs[0..], a.limbs[0..a.limbs.len], shift); |
| 527 | r.len = a.limbs.len - (shift / Limb.bit_count); | 528 | r.len = a.limbs.len - (shift / limb_bits); |
| 528 | r.positive = a.positive; | 529 | r.positive = a.positive; |
| 529 | } | 530 | } |
| 530 | 531 | ||
| ... | @@ -772,7 +773,7 @@ pub const Mutable = struct { | ... | @@ -772,7 +773,7 @@ pub const Mutable = struct { |
| 772 | } | 773 | } |
| 773 | 774 | ||
| 774 | if (ab_zero_limb_count != 0) { | 775 | if (ab_zero_limb_count != 0) { |
| 775 | rem.shiftLeft(rem.toConst(), ab_zero_limb_count * Limb.bit_count); | 776 | rem.shiftLeft(rem.toConst(), ab_zero_limb_count * limb_bits); |
| 776 | } | 777 | } |
| 777 | } | 778 | } |
| 778 | 779 | ||
| ... | @@ -803,10 +804,10 @@ pub const Mutable = struct { | ... | @@ -803,10 +804,10 @@ pub const Mutable = struct { |
| 803 | }; | 804 | }; |
| 804 | tmp.limbs[0] = 0; | 805 | tmp.limbs[0] = 0; |
| 805 | 806 | ||
| 806 | // Normalize so y > Limb.bit_count / 2 (i.e. leading bit is set) and even | 807 | // Normalize so y > limb_bits / 2 (i.e. leading bit is set) and even |
| 807 | var norm_shift = @clz(Limb, y.limbs[y.len - 1]); | 808 | var norm_shift = @clz(Limb, y.limbs[y.len - 1]); |
| 808 | if (norm_shift == 0 and y.toConst().isOdd()) { | 809 | if (norm_shift == 0 and y.toConst().isOdd()) { |
| 809 | norm_shift = Limb.bit_count; | 810 | norm_shift = limb_bits; |
| 810 | } | 811 | } |
| 811 | x.shiftLeft(x.toConst(), norm_shift); | 812 | x.shiftLeft(x.toConst(), norm_shift); |
| 812 | y.shiftLeft(y.toConst(), norm_shift); | 813 | y.shiftLeft(y.toConst(), norm_shift); |
| ... | @@ -820,7 +821,7 @@ pub const Mutable = struct { | ... | @@ -820,7 +821,7 @@ pub const Mutable = struct { |
| 820 | mem.set(Limb, q.limbs[0..q.len], 0); | 821 | mem.set(Limb, q.limbs[0..q.len], 0); |
| 821 | 822 | ||
| 822 | // 2. | 823 | // 2. |
| 823 | tmp.shiftLeft(y.toConst(), Limb.bit_count * (n - t)); | 824 | tmp.shiftLeft(y.toConst(), limb_bits * (n - t)); |
| 824 | while (x.toConst().order(tmp.toConst()) != .lt) { | 825 | while (x.toConst().order(tmp.toConst()) != .lt) { |
| 825 | q.limbs[n - t] += 1; | 826 | q.limbs[n - t] += 1; |
| 826 | x.sub(x.toConst(), tmp.toConst()); | 827 | x.sub(x.toConst(), tmp.toConst()); |
| ... | @@ -833,7 +834,7 @@ pub const Mutable = struct { | ... | @@ -833,7 +834,7 @@ pub const Mutable = struct { |
| 833 | if (x.limbs[i] == y.limbs[t]) { | 834 | if (x.limbs[i] == y.limbs[t]) { |
| 834 | q.limbs[i - t - 1] = maxInt(Limb); | 835 | q.limbs[i - t - 1] = maxInt(Limb); |
| 835 | } else { | 836 | } else { |
| 836 | const num = (@as(DoubleLimb, x.limbs[i]) << Limb.bit_count) | @as(DoubleLimb, x.limbs[i - 1]); | 837 | const num = (@as(DoubleLimb, x.limbs[i]) << limb_bits) | @as(DoubleLimb, x.limbs[i - 1]); |
| 837 | const z = @intCast(Limb, num / @as(DoubleLimb, y.limbs[t])); | 838 | const z = @intCast(Limb, num / @as(DoubleLimb, y.limbs[t])); |
| 838 | q.limbs[i - t - 1] = if (z > maxInt(Limb)) maxInt(Limb) else @as(Limb, z); | 839 | q.limbs[i - t - 1] = if (z > maxInt(Limb)) maxInt(Limb) else @as(Limb, z); |
| 839 | } | 840 | } |
| ... | @@ -862,11 +863,11 @@ pub const Mutable = struct { | ... | @@ -862,11 +863,11 @@ pub const Mutable = struct { |
| 862 | // 3.3 | 863 | // 3.3 |
| 863 | tmp.set(q.limbs[i - t - 1]); | 864 | tmp.set(q.limbs[i - t - 1]); |
| 864 | tmp.mul(tmp.toConst(), y.toConst(), mul_limb_buf, allocator); | 865 | tmp.mul(tmp.toConst(), y.toConst(), mul_limb_buf, allocator); |
| 865 | tmp.shiftLeft(tmp.toConst(), Limb.bit_count * (i - t - 1)); | 866 | tmp.shiftLeft(tmp.toConst(), limb_bits * (i - t - 1)); |
| 866 | x.sub(x.toConst(), tmp.toConst()); | 867 | x.sub(x.toConst(), tmp.toConst()); |
| 867 | 868 | ||
| 868 | if (!x.positive) { | 869 | if (!x.positive) { |
| 869 | tmp.shiftLeft(y.toConst(), Limb.bit_count * (i - t - 1)); | 870 | tmp.shiftLeft(y.toConst(), limb_bits * (i - t - 1)); |
| 870 | x.add(x.toConst(), tmp.toConst()); | 871 | x.add(x.toConst(), tmp.toConst()); |
| 871 | q.limbs[i - t - 1] -= 1; | 872 | q.limbs[i - t - 1] -= 1; |
| 872 | } | 873 | } |
| ... | @@ -949,7 +950,7 @@ pub const Const = struct { | ... | @@ -949,7 +950,7 @@ pub const Const = struct { |
| 949 | 950 | ||
| 950 | /// Returns the number of bits required to represent the absolute value of an integer. | 951 | /// Returns the number of bits required to represent the absolute value of an integer. |
| 951 | pub fn bitCountAbs(self: Const) usize { | 952 | pub fn bitCountAbs(self: Const) usize { |
| 952 | return (self.limbs.len - 1) * Limb.bit_count + (Limb.bit_count - @clz(Limb, self.limbs[self.limbs.len - 1])); | 953 | return (self.limbs.len - 1) * limb_bits + (limb_bits - @clz(Limb, self.limbs[self.limbs.len - 1])); |
| 953 | } | 954 | } |
| 954 | 955 | ||
| 955 | /// Returns the number of bits required to represent the integer in twos-complement form. | 956 | /// Returns the number of bits required to represent the integer in twos-complement form. |
| ... | @@ -1019,10 +1020,10 @@ pub const Const = struct { | ... | @@ -1019,10 +1020,10 @@ pub const Const = struct { |
| 1019 | /// Returns an error if self cannot be narrowed into the requested type without truncation. | 1020 | /// Returns an error if self cannot be narrowed into the requested type without truncation. |
| 1020 | pub fn to(self: Const, comptime T: type) ConvertError!T { | 1021 | pub fn to(self: Const, comptime T: type) ConvertError!T { |
| 1021 | switch (@typeInfo(T)) { | 1022 | switch (@typeInfo(T)) { |
| 1022 | .Int => { | 1023 | .Int => |info| { |
| 1023 | const UT = std.meta.Int(false, T.bit_count); | 1024 | const UT = std.meta.Int(false, info.bits); |
| 1024 | 1025 | ||
| 1025 | if (self.bitCountTwosComp() > T.bit_count) { | 1026 | if (self.bitCountTwosComp() > info.bits) { |
| 1026 | return error.TargetTooSmall; | 1027 | return error.TargetTooSmall; |
| 1027 | } | 1028 | } |
| 1028 | 1029 | ||
| ... | @@ -1033,12 +1034,12 @@ pub const Const = struct { | ... | @@ -1033,12 +1034,12 @@ pub const Const = struct { |
| 1033 | } else { | 1034 | } else { |
| 1034 | for (self.limbs[0..self.limbs.len]) |_, ri| { | 1035 | for (self.limbs[0..self.limbs.len]) |_, ri| { |
| 1035 | const limb = self.limbs[self.limbs.len - ri - 1]; | 1036 | const limb = self.limbs[self.limbs.len - ri - 1]; |
| 1036 | r <<= Limb.bit_count; | 1037 | r <<= limb_bits; |
| 1037 | r |= limb; | 1038 | r |= limb; |
| 1038 | } | 1039 | } |
| 1039 | } | 1040 | } |
| 1040 | 1041 | ||
| 1041 | if (!T.is_signed) { | 1042 | if (!info.is_signed) { |
| 1042 | return if (self.positive) @intCast(T, r) else error.NegativeIntoUnsigned; | 1043 | return if (self.positive) @intCast(T, r) else error.NegativeIntoUnsigned; |
| 1043 | } else { | 1044 | } else { |
| 1044 | if (self.positive) { | 1045 | if (self.positive) { |
| ... | @@ -1149,7 +1150,7 @@ pub const Const = struct { | ... | @@ -1149,7 +1150,7 @@ pub const Const = struct { |
| 1149 | 1150 | ||
| 1150 | outer: for (self.limbs[0..self.limbs.len]) |limb| { | 1151 | outer: for (self.limbs[0..self.limbs.len]) |limb| { |
| 1151 | var shift: usize = 0; | 1152 | var shift: usize = 0; |
| 1152 | while (shift < Limb.bit_count) : (shift += base_shift) { | 1153 | while (shift < limb_bits) : (shift += base_shift) { |
| 1153 | const r = @intCast(u8, (limb >> @intCast(Log2Limb, shift)) & @as(Limb, base - 1)); | 1154 | const r = @intCast(u8, (limb >> @intCast(Log2Limb, shift)) & @as(Limb, base - 1)); |
| 1154 | const ch = std.fmt.digitToChar(r, uppercase); | 1155 | const ch = std.fmt.digitToChar(r, uppercase); |
| 1155 | string[digits_len] = ch; | 1156 | string[digits_len] = ch; |
| ... | @@ -1295,7 +1296,7 @@ pub const Const = struct { | ... | @@ -1295,7 +1296,7 @@ pub const Const = struct { |
| 1295 | /// Memory is allocated as needed to ensure operations never overflow. The range | 1296 | /// Memory is allocated as needed to ensure operations never overflow. The range |
| 1296 | /// is bounded only by available memory. | 1297 | /// is bounded only by available memory. |
| 1297 | pub const Managed = struct { | 1298 | pub const Managed = struct { |
| 1298 | pub const sign_bit: usize = 1 << (usize.bit_count - 1); | 1299 | pub const sign_bit: usize = 1 << (@typeInfo(usize).Int.bits - 1); |
| 1299 | 1300 | ||
| 1300 | /// Default number of limbs to allocate on creation of a `Managed`. | 1301 | /// Default number of limbs to allocate on creation of a `Managed`. |
| 1301 | pub const default_capacity = 4; | 1302 | pub const default_capacity = 4; |
| ... | @@ -1448,7 +1449,7 @@ pub const Managed = struct { | ... | @@ -1448,7 +1449,7 @@ pub const Managed = struct { |
| 1448 | for (self.limbs[0..self.len()]) |limb| { | 1449 | for (self.limbs[0..self.len()]) |limb| { |
| 1449 | std.debug.warn("{x} ", .{limb}); | 1450 | std.debug.warn("{x} ", .{limb}); |
| 1450 | } | 1451 | } |
| 1451 | std.debug.warn("capacity={} positive={}\n", .{ self.limbs.len, self.positive }); | 1452 | std.debug.warn("capacity={} positive={}\n", .{ self.limbs.len, self.isPositive() }); |
| 1452 | } | 1453 | } |
| 1453 | 1454 | ||
| 1454 | /// Negate the sign. | 1455 | /// Negate the sign. |
| ... | @@ -1716,7 +1717,7 @@ pub const Managed = struct { | ... | @@ -1716,7 +1717,7 @@ pub const Managed = struct { |
| 1716 | 1717 | ||
| 1717 | /// r = a << shift, in other words, r = a * 2^shift | 1718 | /// r = a << shift, in other words, r = a * 2^shift |
| 1718 | pub fn shiftLeft(r: *Managed, a: Managed, shift: usize) !void { | 1719 | pub fn shiftLeft(r: *Managed, a: Managed, shift: usize) !void { |
| 1719 | try r.ensureCapacity(a.len() + (shift / Limb.bit_count) + 1); | 1720 | try r.ensureCapacity(a.len() + (shift / limb_bits) + 1); |
| 1720 | var m = r.toMutable(); | 1721 | var m = r.toMutable(); |
| 1721 | m.shiftLeft(a.toConst(), shift); | 1722 | m.shiftLeft(a.toConst(), shift); |
| 1722 | r.setMetadata(m.positive, m.len); | 1723 | r.setMetadata(m.positive, m.len); |
| ... | @@ -1724,13 +1725,13 @@ pub const Managed = struct { | ... | @@ -1724,13 +1725,13 @@ pub const Managed = struct { |
| 1724 | 1725 | ||
| 1725 | /// r = a >> shift | 1726 | /// r = a >> shift |
| 1726 | pub fn shiftRight(r: *Managed, a: Managed, shift: usize) !void { | 1727 | pub fn shiftRight(r: *Managed, a: Managed, shift: usize) !void { |
| 1727 | if (a.len() <= shift / Limb.bit_count) { | 1728 | if (a.len() <= shift / limb_bits) { |
| 1728 | r.metadata = 1; | 1729 | r.metadata = 1; |
| 1729 | r.limbs[0] = 0; | 1730 | r.limbs[0] = 0; |
| 1730 | return; | 1731 | return; |
| 1731 | } | 1732 | } |
| 1732 | 1733 | ||
| 1733 | try r.ensureCapacity(a.len() - (shift / Limb.bit_count)); | 1734 | try r.ensureCapacity(a.len() - (shift / limb_bits)); |
| 1734 | var m = r.toMutable(); | 1735 | var m = r.toMutable(); |
| 1735 | m.shiftRight(a.toConst(), shift); | 1736 | m.shiftRight(a.toConst(), shift); |
| 1736 | r.setMetadata(m.positive, m.len); | 1737 | r.setMetadata(m.positive, m.len); |
| ... | @@ -2021,7 +2022,7 @@ fn lldiv1(quo: []Limb, rem: *Limb, a: []const Limb, b: Limb) void { | ... | @@ -2021,7 +2022,7 @@ fn lldiv1(quo: []Limb, rem: *Limb, a: []const Limb, b: Limb) void { |
| 2021 | rem.* = 0; | 2022 | rem.* = 0; |
| 2022 | for (a) |_, ri| { | 2023 | for (a) |_, ri| { |
| 2023 | const i = a.len - ri - 1; | 2024 | const i = a.len - ri - 1; |
| 2024 | const pdiv = ((@as(DoubleLimb, rem.*) << Limb.bit_count) | a[i]); | 2025 | const pdiv = ((@as(DoubleLimb, rem.*) << limb_bits) | a[i]); |
| 2025 | 2026 | ||
| 2026 | if (pdiv == 0) { | 2027 | if (pdiv == 0) { |
| 2027 | quo[i] = 0; | 2028 | quo[i] = 0; |
| ... | @@ -2042,10 +2043,10 @@ fn lldiv1(quo: []Limb, rem: *Limb, a: []const Limb, b: Limb) void { | ... | @@ -2042,10 +2043,10 @@ fn lldiv1(quo: []Limb, rem: *Limb, a: []const Limb, b: Limb) void { |
| 2042 | fn llshl(r: []Limb, a: []const Limb, shift: usize) void { | 2043 | fn llshl(r: []Limb, a: []const Limb, shift: usize) void { |
| 2043 | @setRuntimeSafety(debug_safety); | 2044 | @setRuntimeSafety(debug_safety); |
| 2044 | assert(a.len >= 1); | 2045 | assert(a.len >= 1); |
| 2045 | assert(r.len >= a.len + (shift / Limb.bit_count) + 1); | 2046 | assert(r.len >= a.len + (shift / limb_bits) + 1); |
| 2046 | 2047 | ||
| 2047 | const limb_shift = shift / Limb.bit_count + 1; | 2048 | const limb_shift = shift / limb_bits + 1; |
| 2048 | const interior_limb_shift = @intCast(Log2Limb, shift % Limb.bit_count); | 2049 | const interior_limb_shift = @intCast(Log2Limb, shift % limb_bits); |
| 2049 | 2050 | ||
| 2050 | var carry: Limb = 0; | 2051 | var carry: Limb = 0; |
| 2051 | var i: usize = 0; | 2052 | var i: usize = 0; |
| ... | @@ -2057,7 +2058,7 @@ fn llshl(r: []Limb, a: []const Limb, shift: usize) void { | ... | @@ -2057,7 +2058,7 @@ fn llshl(r: []Limb, a: []const Limb, shift: usize) void { |
| 2057 | r[dst_i] = carry | @call(.{ .modifier = .always_inline }, math.shr, .{ | 2058 | r[dst_i] = carry | @call(.{ .modifier = .always_inline }, math.shr, .{ |
| 2058 | Limb, | 2059 | Limb, |
| 2059 | src_digit, | 2060 | src_digit, |
| 2060 | Limb.bit_count - @intCast(Limb, interior_limb_shift), | 2061 | limb_bits - @intCast(Limb, interior_limb_shift), |
| 2061 | }); | 2062 | }); |
| 2062 | carry = (src_digit << interior_limb_shift); | 2063 | carry = (src_digit << interior_limb_shift); |
| 2063 | } | 2064 | } |
| ... | @@ -2069,10 +2070,10 @@ fn llshl(r: []Limb, a: []const Limb, shift: usize) void { | ... | @@ -2069,10 +2070,10 @@ fn llshl(r: []Limb, a: []const Limb, shift: usize) void { |
| 2069 | fn llshr(r: []Limb, a: []const Limb, shift: usize) void { | 2070 | fn llshr(r: []Limb, a: []const Limb, shift: usize) void { |
| 2070 | @setRuntimeSafety(debug_safety); | 2071 | @setRuntimeSafety(debug_safety); |
| 2071 | assert(a.len >= 1); | 2072 | assert(a.len >= 1); |
| 2072 | assert(r.len >= a.len - (shift / Limb.bit_count)); | 2073 | assert(r.len >= a.len - (shift / limb_bits)); |
| 2073 | 2074 | ||
| 2074 | const limb_shift = shift / Limb.bit_count; | 2075 | const limb_shift = shift / limb_bits; |
| 2075 | const interior_limb_shift = @intCast(Log2Limb, shift % Limb.bit_count); | 2076 | const interior_limb_shift = @intCast(Log2Limb, shift % limb_bits); |
| 2076 | 2077 | ||
| 2077 | var carry: Limb = 0; | 2078 | var carry: Limb = 0; |
| 2078 | var i: usize = 0; | 2079 | var i: usize = 0; |
| ... | @@ -2085,7 +2086,7 @@ fn llshr(r: []Limb, a: []const Limb, shift: usize) void { | ... | @@ -2085,7 +2086,7 @@ fn llshr(r: []Limb, a: []const Limb, shift: usize) void { |
| 2085 | carry = @call(.{ .modifier = .always_inline }, math.shl, .{ | 2086 | carry = @call(.{ .modifier = .always_inline }, math.shl, .{ |
| 2086 | Limb, | 2087 | Limb, |
| 2087 | src_digit, | 2088 | src_digit, |
| 2088 | Limb.bit_count - @intCast(Limb, interior_limb_shift), | 2089 | limb_bits - @intCast(Limb, interior_limb_shift), |
| 2089 | }); | 2090 | }); |
| 2090 | } | 2091 | } |
| 2091 | } | 2092 | } |
| ... | @@ -2135,7 +2136,7 @@ fn fixedIntFromSignedDoubleLimb(A: SignedDoubleLimb, storage: []Limb) Mutable { | ... | @@ -2135,7 +2136,7 @@ fn fixedIntFromSignedDoubleLimb(A: SignedDoubleLimb, storage: []Limb) Mutable { |
| 2135 | const A_is_positive = A >= 0; | 2136 | const A_is_positive = A >= 0; |
| 2136 | const Au = @intCast(DoubleLimb, if (A < 0) -A else A); | 2137 | const Au = @intCast(DoubleLimb, if (A < 0) -A else A); |
| 2137 | storage[0] = @truncate(Limb, Au); | 2138 | storage[0] = @truncate(Limb, Au); |
| 2138 | storage[1] = @truncate(Limb, Au >> Limb.bit_count); | 2139 | storage[1] = @truncate(Limb, Au >> limb_bits); |
| 2139 | return .{ | 2140 | return .{ |
| 2140 | .limbs = storage[0..2], | 2141 | .limbs = storage[0..2], |
| 2141 | .positive = A_is_positive, | 2142 | .positive = A_is_positive, |
lib/std/math/big/int_test.zig+3-3| ... | @@ -23,13 +23,13 @@ test "big.int comptime_int set" { | ... | @@ -23,13 +23,13 @@ test "big.int comptime_int set" { |
| 23 | var a = try Managed.initSet(testing.allocator, s); | 23 | var a = try Managed.initSet(testing.allocator, s); |
| 24 | defer a.deinit(); | 24 | defer a.deinit(); |
| 25 | 25 | ||
| 26 | const s_limb_count = 128 / Limb.bit_count; | 26 | const s_limb_count = 128 / @typeInfo(Limb).Int.bits; |
| 27 | 27 | ||
| 28 | comptime var i: usize = 0; | 28 | comptime var i: usize = 0; |
| 29 | inline while (i < s_limb_count) : (i += 1) { | 29 | inline while (i < s_limb_count) : (i += 1) { |
| 30 | const result = @as(Limb, s & maxInt(Limb)); | 30 | const result = @as(Limb, s & maxInt(Limb)); |
| 31 | s >>= Limb.bit_count / 2; | 31 | s >>= @typeInfo(Limb).Int.bits / 2; |
| 32 | s >>= Limb.bit_count / 2; | 32 | s >>= @typeInfo(Limb).Int.bits / 2; |
| 33 | testing.expect(a.limbs[i] == result); | 33 | testing.expect(a.limbs[i] == result); |
| 34 | } | 34 | } |
| 35 | } | 35 | } |
lib/std/math/big/rational.zig+9-7| ... | @@ -136,7 +136,7 @@ pub const Rational = struct { | ... | @@ -136,7 +136,7 @@ pub const Rational = struct { |
| 136 | // Translated from golang.go/src/math/big/rat.go. | 136 | // Translated from golang.go/src/math/big/rat.go. |
| 137 | debug.assert(@typeInfo(T) == .Float); | 137 | debug.assert(@typeInfo(T) == .Float); |
| 138 | 138 | ||
| 139 | const UnsignedInt = std.meta.Int(false, T.bit_count); | 139 | const UnsignedInt = std.meta.Int(false, @typeInfo(T).Float.bits); |
| 140 | const f_bits = @bitCast(UnsignedInt, f); | 140 | const f_bits = @bitCast(UnsignedInt, f); |
| 141 | 141 | ||
| 142 | const exponent_bits = math.floatExponentBits(T); | 142 | const exponent_bits = math.floatExponentBits(T); |
| ... | @@ -194,8 +194,8 @@ pub const Rational = struct { | ... | @@ -194,8 +194,8 @@ pub const Rational = struct { |
| 194 | // TODO: Indicate whether the result is not exact. | 194 | // TODO: Indicate whether the result is not exact. |
| 195 | debug.assert(@typeInfo(T) == .Float); | 195 | debug.assert(@typeInfo(T) == .Float); |
| 196 | 196 | ||
| 197 | const fsize = T.bit_count; | 197 | const fsize = @typeInfo(T).Float.bits; |
| 198 | const BitReprType = std.meta.Int(false, T.bit_count); | 198 | const BitReprType = std.meta.Int(false, fsize); |
| 199 | 199 | ||
| 200 | const msize = math.floatMantissaBits(T); | 200 | const msize = math.floatMantissaBits(T); |
| 201 | const msize1 = msize + 1; | 201 | const msize1 = msize + 1; |
| ... | @@ -475,16 +475,18 @@ pub const Rational = struct { | ... | @@ -475,16 +475,18 @@ pub const Rational = struct { |
| 475 | fn extractLowBits(a: Int, comptime T: type) T { | 475 | fn extractLowBits(a: Int, comptime T: type) T { |
| 476 | testing.expect(@typeInfo(T) == .Int); | 476 | testing.expect(@typeInfo(T) == .Int); |
| 477 | 477 | ||
| 478 | if (T.bit_count <= Limb.bit_count) { | 478 | const t_bits = @typeInfo(T).Int.bits; |
| 479 | const limb_bits = @typeInfo(Limb).Int.bits; | ||
| 480 | if (t_bits <= limb_bits) { | ||
| 479 | return @truncate(T, a.limbs[0]); | 481 | return @truncate(T, a.limbs[0]); |
| 480 | } else { | 482 | } else { |
| 481 | var r: T = 0; | 483 | var r: T = 0; |
| 482 | comptime var i: usize = 0; | 484 | comptime var i: usize = 0; |
| 483 | 485 | ||
| 484 | // Remainder is always 0 since if T.bit_count >= Limb.bit_count -> Limb | T and both | 486 | // Remainder is always 0 since if t_bits >= limb_bits -> Limb | T and both |
| 485 | // are powers of two. | 487 | // are powers of two. |
| 486 | inline while (i < T.bit_count / Limb.bit_count) : (i += 1) { | 488 | inline while (i < t_bits / limb_bits) : (i += 1) { |
| 487 | r |= math.shl(T, a.limbs[i], i * Limb.bit_count); | 489 | r |= math.shl(T, a.limbs[i], i * limb_bits); |
| 488 | } | 490 | } |
| 489 | 491 | ||
| 490 | return r; | 492 | return r; |
lib/std/math/cos.zig+1-1| ... | @@ -49,7 +49,7 @@ const pi4c = 2.69515142907905952645E-15; | ... | @@ -49,7 +49,7 @@ const pi4c = 2.69515142907905952645E-15; |
| 49 | const m4pi = 1.273239544735162542821171882678754627704620361328125; | 49 | const m4pi = 1.273239544735162542821171882678754627704620361328125; |
| 50 | 50 | ||
| 51 | fn cos_(comptime T: type, x_: T) T { | 51 | fn cos_(comptime T: type, x_: T) T { |
| 52 | const I = std.meta.Int(true, T.bit_count); | 52 | const I = std.meta.Int(true, @typeInfo(T).Float.bits); |
| 53 | 53 | ||
| 54 | var x = x_; | 54 | var x = x_; |
| 55 | if (math.isNan(x) or math.isInf(x)) { | 55 | if (math.isNan(x) or math.isInf(x)) { |
lib/std/math/pow.zig+2-2| ... | @@ -128,7 +128,7 @@ pub fn pow(comptime T: type, x: T, y: T) T { | ... | @@ -128,7 +128,7 @@ pub fn pow(comptime T: type, x: T, y: T) T { |
| 128 | if (yf != 0 and x < 0) { | 128 | if (yf != 0 and x < 0) { |
| 129 | return math.nan(T); | 129 | return math.nan(T); |
| 130 | } | 130 | } |
| 131 | if (yi >= 1 << (T.bit_count - 1)) { | 131 | if (yi >= 1 << (@typeInfo(T).Float.bits - 1)) { |
| 132 | return math.exp(y * math.ln(x)); | 132 | return math.exp(y * math.ln(x)); |
| 133 | } | 133 | } |
| 134 | 134 | ||
| ... | @@ -150,7 +150,7 @@ pub fn pow(comptime T: type, x: T, y: T) T { | ... | @@ -150,7 +150,7 @@ pub fn pow(comptime T: type, x: T, y: T) T { |
| 150 | var xe = r2.exponent; | 150 | var xe = r2.exponent; |
| 151 | var x1 = r2.significand; | 151 | var x1 = r2.significand; |
| 152 | 152 | ||
| 153 | var i = @floatToInt(std.meta.Int(true, T.bit_count), yi); | 153 | var i = @floatToInt(std.meta.Int(true, @typeInfo(T).Float.bits), yi); |
| 154 | while (i != 0) : (i >>= 1) { | 154 | while (i != 0) : (i >>= 1) { |
| 155 | const overflow_shift = math.floatExponentBits(T) + 1; | 155 | const overflow_shift = math.floatExponentBits(T) + 1; |
| 156 | if (xe < -(1 << overflow_shift) or (1 << overflow_shift) < xe) { | 156 | if (xe < -(1 << overflow_shift) or (1 << overflow_shift) < xe) { |
lib/std/math/sin.zig+1-1| ... | @@ -50,7 +50,7 @@ const pi4c = 2.69515142907905952645E-15; | ... | @@ -50,7 +50,7 @@ const pi4c = 2.69515142907905952645E-15; |
| 50 | const m4pi = 1.273239544735162542821171882678754627704620361328125; | 50 | const m4pi = 1.273239544735162542821171882678754627704620361328125; |
| 51 | 51 | ||
| 52 | fn sin_(comptime T: type, x_: T) T { | 52 | fn sin_(comptime T: type, x_: T) T { |
| 53 | const I = std.meta.Int(true, T.bit_count); | 53 | const I = std.meta.Int(true, @typeInfo(T).Float.bits); |
| 54 | 54 | ||
| 55 | var x = x_; | 55 | var x = x_; |
| 56 | if (x == 0 or math.isNan(x)) { | 56 | if (x == 0 or math.isNan(x)) { |
lib/std/math/sqrt.zig+3-3| ... | @@ -36,10 +36,10 @@ pub fn sqrt(x: anytype) Sqrt(@TypeOf(x)) { | ... | @@ -36,10 +36,10 @@ pub fn sqrt(x: anytype) Sqrt(@TypeOf(x)) { |
| 36 | } | 36 | } |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | fn sqrt_int(comptime T: type, value: T) std.meta.Int(false, T.bit_count / 2) { | 39 | fn sqrt_int(comptime T: type, value: T) std.meta.Int(false, @typeInfo(T).Int.bits / 2) { |
| 40 | var op = value; | 40 | var op = value; |
| 41 | var res: T = 0; | 41 | var res: T = 0; |
| 42 | var one: T = 1 << (T.bit_count - 2); | 42 | var one: T = 1 << (@typeInfo(T).Int.bits - 2); |
| 43 | 43 | ||
| 44 | // "one" starts at the highest power of four <= than the argument. | 44 | // "one" starts at the highest power of four <= than the argument. |
| 45 | while (one > op) { | 45 | while (one > op) { |
| ... | @@ -55,7 +55,7 @@ fn sqrt_int(comptime T: type, value: T) std.meta.Int(false, T.bit_count / 2) { | ... | @@ -55,7 +55,7 @@ fn sqrt_int(comptime T: type, value: T) std.meta.Int(false, T.bit_count / 2) { |
| 55 | one >>= 2; | 55 | one >>= 2; |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | const ResultType = std.meta.Int(false, T.bit_count / 2); | 58 | const ResultType = std.meta.Int(false, @typeInfo(T).Int.bits / 2); |
| 59 | return @intCast(ResultType, res); | 59 | return @intCast(ResultType, res); |
| 60 | } | 60 | } |
| 61 | 61 |
lib/std/math/tan.zig+1-1| ... | @@ -43,7 +43,7 @@ const pi4c = 2.69515142907905952645E-15; | ... | @@ -43,7 +43,7 @@ const pi4c = 2.69515142907905952645E-15; |
| 43 | const m4pi = 1.273239544735162542821171882678754627704620361328125; | 43 | const m4pi = 1.273239544735162542821171882678754627704620361328125; |
| 44 | 44 | ||
| 45 | fn tan_(comptime T: type, x_: T) T { | 45 | fn tan_(comptime T: type, x_: T) T { |
| 46 | const I = std.meta.Int(true, T.bit_count); | 46 | const I = std.meta.Int(true, @typeInfo(T).Float.bits); |
| 47 | 47 | ||
| 48 | var x = x_; | 48 | var x = x_; |
| 49 | if (x == 0 or math.isNan(x)) { | 49 | if (x == 0 or math.isNan(x)) { |
lib/std/mem.zig+21-21| ... | @@ -949,7 +949,7 @@ pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: builtin. | ... | @@ -949,7 +949,7 @@ pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: builtin. |
| 949 | /// This function cannot fail and cannot cause undefined behavior. | 949 | /// This function cannot fail and cannot cause undefined behavior. |
| 950 | /// Assumes the endianness of memory is native. This means the function can | 950 | /// Assumes the endianness of memory is native. This means the function can |
| 951 | /// simply pointer cast memory. | 951 | /// simply pointer cast memory. |
| 952 | pub fn readIntNative(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8) T { | 952 | pub fn readIntNative(comptime T: type, bytes: *const [@divExact(@typeInfo(T).Int.bits, 8)]u8) T { |
| 953 | return @ptrCast(*align(1) const T, bytes).*; | 953 | return @ptrCast(*align(1) const T, bytes).*; |
| 954 | } | 954 | } |
| 955 | 955 | ||
| ... | @@ -957,7 +957,7 @@ pub fn readIntNative(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)] | ... | @@ -957,7 +957,7 @@ pub fn readIntNative(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)] |
| 957 | /// The bit count of T must be evenly divisible by 8. | 957 | /// The bit count of T must be evenly divisible by 8. |
| 958 | /// This function cannot fail and cannot cause undefined behavior. | 958 | /// This function cannot fail and cannot cause undefined behavior. |
| 959 | /// Assumes the endianness of memory is foreign, so it must byte-swap. | 959 | /// Assumes the endianness of memory is foreign, so it must byte-swap. |
| 960 | pub fn readIntForeign(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8) T { | 960 | pub fn readIntForeign(comptime T: type, bytes: *const [@divExact(@typeInfo(T).Int.bits, 8)]u8) T { |
| 961 | return @byteSwap(T, readIntNative(T, bytes)); | 961 | return @byteSwap(T, readIntNative(T, bytes)); |
| 962 | } | 962 | } |
| 963 | 963 | ||
| ... | @@ -971,18 +971,18 @@ pub const readIntBig = switch (builtin.endian) { | ... | @@ -971,18 +971,18 @@ pub const readIntBig = switch (builtin.endian) { |
| 971 | .Big => readIntNative, | 971 | .Big => readIntNative, |
| 972 | }; | 972 | }; |
| 973 | 973 | ||
| 974 | /// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0 | 974 | /// Asserts that bytes.len >= @typeInfo(T).Int.bits / 8. Reads the integer starting from index 0 |
| 975 | /// and ignores extra bytes. | 975 | /// and ignores extra bytes. |
| 976 | /// The bit count of T must be evenly divisible by 8. | 976 | /// The bit count of T must be evenly divisible by 8. |
| 977 | /// Assumes the endianness of memory is native. This means the function can | 977 | /// Assumes the endianness of memory is native. This means the function can |
| 978 | /// simply pointer cast memory. | 978 | /// simply pointer cast memory. |
| 979 | pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T { | 979 | pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T { |
| 980 | const n = @divExact(T.bit_count, 8); | 980 | const n = @divExact(@typeInfo(T).Int.bits, 8); |
| 981 | assert(bytes.len >= n); | 981 | assert(bytes.len >= n); |
| 982 | return readIntNative(T, bytes[0..n]); | 982 | return readIntNative(T, bytes[0..n]); |
| 983 | } | 983 | } |
| 984 | 984 | ||
| 985 | /// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0 | 985 | /// Asserts that bytes.len >= @typeInfo(T).Int.bits / 8. Reads the integer starting from index 0 |
| 986 | /// and ignores extra bytes. | 986 | /// and ignores extra bytes. |
| 987 | /// The bit count of T must be evenly divisible by 8. | 987 | /// The bit count of T must be evenly divisible by 8. |
| 988 | /// Assumes the endianness of memory is foreign, so it must byte-swap. | 988 | /// Assumes the endianness of memory is foreign, so it must byte-swap. |
| ... | @@ -1003,7 +1003,7 @@ pub const readIntSliceBig = switch (builtin.endian) { | ... | @@ -1003,7 +1003,7 @@ pub const readIntSliceBig = switch (builtin.endian) { |
| 1003 | /// Reads an integer from memory with bit count specified by T. | 1003 | /// Reads an integer from memory with bit count specified by T. |
| 1004 | /// The bit count of T must be evenly divisible by 8. | 1004 | /// The bit count of T must be evenly divisible by 8. |
| 1005 | /// This function cannot fail and cannot cause undefined behavior. | 1005 | /// This function cannot fail and cannot cause undefined behavior. |
| 1006 | pub fn readInt(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8, endian: builtin.Endian) T { | 1006 | pub fn readInt(comptime T: type, bytes: *const [@divExact(@typeInfo(T).Int.bits, 8)]u8, endian: builtin.Endian) T { |
| 1007 | if (endian == builtin.endian) { | 1007 | if (endian == builtin.endian) { |
| 1008 | return readIntNative(T, bytes); | 1008 | return readIntNative(T, bytes); |
| 1009 | } else { | 1009 | } else { |
| ... | @@ -1011,11 +1011,11 @@ pub fn readInt(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8, en | ... | @@ -1011,11 +1011,11 @@ pub fn readInt(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8, en |
| 1011 | } | 1011 | } |
| 1012 | } | 1012 | } |
| 1013 | 1013 | ||
| 1014 | /// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0 | 1014 | /// Asserts that bytes.len >= @typeInfo(T).Int.bits / 8. Reads the integer starting from index 0 |
| 1015 | /// and ignores extra bytes. | 1015 | /// and ignores extra bytes. |
| 1016 | /// The bit count of T must be evenly divisible by 8. | 1016 | /// The bit count of T must be evenly divisible by 8. |
| 1017 | pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T { | 1017 | pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T { |
| 1018 | const n = @divExact(T.bit_count, 8); | 1018 | const n = @divExact(@typeInfo(T).Int.bits, 8); |
| 1019 | assert(bytes.len >= n); | 1019 | assert(bytes.len >= n); |
| 1020 | return readInt(T, bytes[0..n], endian); | 1020 | return readInt(T, bytes[0..n], endian); |
| 1021 | } | 1021 | } |
| ... | @@ -1060,7 +1060,7 @@ test "readIntBig and readIntLittle" { | ... | @@ -1060,7 +1060,7 @@ test "readIntBig and readIntLittle" { |
| 1060 | /// accepts any integer bit width. | 1060 | /// accepts any integer bit width. |
| 1061 | /// This function stores in native endian, which means it is implemented as a simple | 1061 | /// This function stores in native endian, which means it is implemented as a simple |
| 1062 | /// memory store. | 1062 | /// memory store. |
| 1063 | pub fn writeIntNative(comptime T: type, buf: *[(T.bit_count + 7) / 8]u8, value: T) void { | 1063 | pub fn writeIntNative(comptime T: type, buf: *[(@typeInfo(T).Int.bits + 7) / 8]u8, value: T) void { |
| 1064 | @ptrCast(*align(1) T, buf).* = value; | 1064 | @ptrCast(*align(1) T, buf).* = value; |
| 1065 | } | 1065 | } |
| 1066 | 1066 | ||
| ... | @@ -1068,7 +1068,7 @@ pub fn writeIntNative(comptime T: type, buf: *[(T.bit_count + 7) / 8]u8, value: | ... | @@ -1068,7 +1068,7 @@ pub fn writeIntNative(comptime T: type, buf: *[(T.bit_count + 7) / 8]u8, value: |
| 1068 | /// This function always succeeds, has defined behavior for all inputs, but | 1068 | /// This function always succeeds, has defined behavior for all inputs, but |
| 1069 | /// the integer bit width must be divisible by 8. | 1069 | /// the integer bit width must be divisible by 8. |
| 1070 | /// This function stores in foreign endian, which means it does a @byteSwap first. | 1070 | /// This function stores in foreign endian, which means it does a @byteSwap first. |
| 1071 | pub fn writeIntForeign(comptime T: type, buf: *[@divExact(T.bit_count, 8)]u8, value: T) void { | 1071 | pub fn writeIntForeign(comptime T: type, buf: *[@divExact(@typeInfo(T).Int.bits, 8)]u8, value: T) void { |
| 1072 | writeIntNative(T, buf, @byteSwap(T, value)); | 1072 | writeIntNative(T, buf, @byteSwap(T, value)); |
| 1073 | } | 1073 | } |
| 1074 | 1074 | ||
| ... | @@ -1085,7 +1085,7 @@ pub const writeIntBig = switch (builtin.endian) { | ... | @@ -1085,7 +1085,7 @@ pub const writeIntBig = switch (builtin.endian) { |
| 1085 | /// Writes an integer to memory, storing it in twos-complement. | 1085 | /// Writes an integer to memory, storing it in twos-complement. |
| 1086 | /// This function always succeeds, has defined behavior for all inputs, but | 1086 | /// This function always succeeds, has defined behavior for all inputs, but |
| 1087 | /// the integer bit width must be divisible by 8. | 1087 | /// the integer bit width must be divisible by 8. |
| 1088 | pub fn writeInt(comptime T: type, buffer: *[@divExact(T.bit_count, 8)]u8, value: T, endian: builtin.Endian) void { | 1088 | pub fn writeInt(comptime T: type, buffer: *[@divExact(@typeInfo(T).Int.bits, 8)]u8, value: T, endian: builtin.Endian) void { |
| 1089 | if (endian == builtin.endian) { | 1089 | if (endian == builtin.endian) { |
| 1090 | return writeIntNative(T, buffer, value); | 1090 | return writeIntNative(T, buffer, value); |
| 1091 | } else { | 1091 | } else { |
| ... | @@ -1094,19 +1094,19 @@ pub fn writeInt(comptime T: type, buffer: *[@divExact(T.bit_count, 8)]u8, value: | ... | @@ -1094,19 +1094,19 @@ pub fn writeInt(comptime T: type, buffer: *[@divExact(T.bit_count, 8)]u8, value: |
| 1094 | } | 1094 | } |
| 1095 | 1095 | ||
| 1096 | /// Writes a twos-complement little-endian integer to memory. | 1096 | /// Writes a twos-complement little-endian integer to memory. |
| 1097 | /// Asserts that buf.len >= T.bit_count / 8. | 1097 | /// Asserts that buf.len >= @typeInfo(T).Int.bits / 8. |
| 1098 | /// The bit count of T must be divisible by 8. | 1098 | /// The bit count of T must be divisible by 8. |
| 1099 | /// Any extra bytes in buffer after writing the integer are set to zero. To | 1099 | /// Any extra bytes in buffer after writing the integer are set to zero. To |
| 1100 | /// avoid the branch to check for extra buffer bytes, use writeIntLittle | 1100 | /// avoid the branch to check for extra buffer bytes, use writeIntLittle |
| 1101 | /// instead. | 1101 | /// instead. |
| 1102 | pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void { | 1102 | pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void { |
| 1103 | assert(buffer.len >= @divExact(T.bit_count, 8)); | 1103 | assert(buffer.len >= @divExact(@typeInfo(T).Int.bits, 8)); |
| 1104 | 1104 | ||
| 1105 | if (T.bit_count == 0) | 1105 | if (@typeInfo(T).Int.bits == 0) |
| 1106 | return set(u8, buffer, 0); | 1106 | return set(u8, buffer, 0); |
| 1107 | 1107 | ||
| 1108 | // TODO I want to call writeIntLittle here but comptime eval facilities aren't good enough | 1108 | // TODO I want to call writeIntLittle here but comptime eval facilities aren't good enough |
| 1109 | const uint = std.meta.Int(false, T.bit_count); | 1109 | const uint = std.meta.Int(false, @typeInfo(T).Int.bits); |
| 1110 | var bits = @truncate(uint, value); | 1110 | var bits = @truncate(uint, value); |
| 1111 | for (buffer) |*b| { | 1111 | for (buffer) |*b| { |
| 1112 | b.* = @truncate(u8, bits); | 1112 | b.* = @truncate(u8, bits); |
| ... | @@ -1115,18 +1115,18 @@ pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void { | ... | @@ -1115,18 +1115,18 @@ pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void { |
| 1115 | } | 1115 | } |
| 1116 | 1116 | ||
| 1117 | /// Writes a twos-complement big-endian integer to memory. | 1117 | /// Writes a twos-complement big-endian integer to memory. |
| 1118 | /// Asserts that buffer.len >= T.bit_count / 8. | 1118 | /// Asserts that buffer.len >= @typeInfo(T).Int.bits / 8. |
| 1119 | /// The bit count of T must be divisible by 8. | 1119 | /// The bit count of T must be divisible by 8. |
| 1120 | /// Any extra bytes in buffer before writing the integer are set to zero. To | 1120 | /// Any extra bytes in buffer before writing the integer are set to zero. To |
| 1121 | /// avoid the branch to check for extra buffer bytes, use writeIntBig instead. | 1121 | /// avoid the branch to check for extra buffer bytes, use writeIntBig instead. |
| 1122 | pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void { | 1122 | pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void { |
| 1123 | assert(buffer.len >= @divExact(T.bit_count, 8)); | 1123 | assert(buffer.len >= @divExact(@typeInfo(T).Int.bits, 8)); |
| 1124 | 1124 | ||
| 1125 | if (T.bit_count == 0) | 1125 | if (@typeInfo(T).Int.bits == 0) |
| 1126 | return set(u8, buffer, 0); | 1126 | return set(u8, buffer, 0); |
| 1127 | 1127 | ||
| 1128 | // TODO I want to call writeIntBig here but comptime eval facilities aren't good enough | 1128 | // TODO I want to call writeIntBig here but comptime eval facilities aren't good enough |
| 1129 | const uint = std.meta.Int(false, T.bit_count); | 1129 | const uint = std.meta.Int(false, @typeInfo(T).Int.bits); |
| 1130 | var bits = @truncate(uint, value); | 1130 | var bits = @truncate(uint, value); |
| 1131 | var index: usize = buffer.len; | 1131 | var index: usize = buffer.len; |
| 1132 | while (index != 0) { | 1132 | while (index != 0) { |
| ... | @@ -1147,13 +1147,13 @@ pub const writeIntSliceForeign = switch (builtin.endian) { | ... | @@ -1147,13 +1147,13 @@ pub const writeIntSliceForeign = switch (builtin.endian) { |
| 1147 | }; | 1147 | }; |
| 1148 | 1148 | ||
| 1149 | /// Writes a twos-complement integer to memory, with the specified endianness. | 1149 | /// Writes a twos-complement integer to memory, with the specified endianness. |
| 1150 | /// Asserts that buf.len >= T.bit_count / 8. | 1150 | /// Asserts that buf.len >= @typeInfo(T).Int.bits / 8. |
| 1151 | /// The bit count of T must be evenly divisible by 8. | 1151 | /// The bit count of T must be evenly divisible by 8. |
| 1152 | /// Any extra bytes in buffer not part of the integer are set to zero, with | 1152 | /// Any extra bytes in buffer not part of the integer are set to zero, with |
| 1153 | /// respect to endianness. To avoid the branch to check for extra buffer bytes, | 1153 | /// respect to endianness. To avoid the branch to check for extra buffer bytes, |
| 1154 | /// use writeInt instead. | 1154 | /// use writeInt instead. |
| 1155 | pub fn writeIntSlice(comptime T: type, buffer: []u8, value: T, endian: builtin.Endian) void { | 1155 | pub fn writeIntSlice(comptime T: type, buffer: []u8, value: T, endian: builtin.Endian) void { |
| 1156 | comptime assert(T.bit_count % 8 == 0); | 1156 | comptime assert(@typeInfo(T).Int.bits % 8 == 0); |
| 1157 | return switch (endian) { | 1157 | return switch (endian) { |
| 1158 | .Little => writeIntSliceLittle(T, buffer, value), | 1158 | .Little => writeIntSliceLittle(T, buffer, value), |
| 1159 | .Big => writeIntSliceBig(T, buffer, value), | 1159 | .Big => writeIntSliceBig(T, buffer, value), |
lib/std/mem/Allocator.zig+4-4| ... | @@ -159,7 +159,7 @@ fn moveBytes( | ... | @@ -159,7 +159,7 @@ fn moveBytes( |
| 159 | /// Returns a pointer to undefined memory. | 159 | /// Returns a pointer to undefined memory. |
| 160 | /// Call `destroy` with the result to free the memory. | 160 | /// Call `destroy` with the result to free the memory. |
| 161 | pub fn create(self: *Allocator, comptime T: type) Error!*T { | 161 | pub fn create(self: *Allocator, comptime T: type) Error!*T { |
| 162 | if (@sizeOf(T) == 0) return &(T{}); | 162 | if (@sizeOf(T) == 0) return @as(*T, undefined); |
| 163 | const slice = try self.allocAdvancedWithRetAddr(T, null, 1, .exact, @returnAddress()); | 163 | const slice = try self.allocAdvancedWithRetAddr(T, null, 1, .exact, @returnAddress()); |
| 164 | return &slice[0]; | 164 | return &slice[0]; |
| 165 | } | 165 | } |
| ... | @@ -167,11 +167,11 @@ pub fn create(self: *Allocator, comptime T: type) Error!*T { | ... | @@ -167,11 +167,11 @@ pub fn create(self: *Allocator, comptime T: type) Error!*T { |
| 167 | /// `ptr` should be the return value of `create`, or otherwise | 167 | /// `ptr` should be the return value of `create`, or otherwise |
| 168 | /// have the same address and alignment property. | 168 | /// have the same address and alignment property. |
| 169 | pub fn destroy(self: *Allocator, ptr: anytype) void { | 169 | pub fn destroy(self: *Allocator, ptr: anytype) void { |
| 170 | const T = @TypeOf(ptr).Child; | 170 | const info = @typeInfo(@TypeOf(ptr)).Pointer; |
| 171 | const T = info.child; | ||
| 171 | if (@sizeOf(T) == 0) return; | 172 | if (@sizeOf(T) == 0) return; |
| 172 | const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr)); | 173 | const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr)); |
| 173 | const ptr_align = @typeInfo(@TypeOf(ptr)).Pointer.alignment; | 174 | _ = self.shrinkBytes(non_const_ptr[0..@sizeOf(T)], info.alignment, 0, 0, @returnAddress()); |
| 174 | _ = self.shrinkBytes(non_const_ptr[0..@sizeOf(T)], ptr_align, 0, 0, @returnAddress()); | ||
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | /// Allocates an array of `n` items of type `T` and sets all the | 177 | /// Allocates an array of `n` items of type `T` and sets all the |
lib/std/os.zig+1-1| ... | @@ -4526,7 +4526,7 @@ pub fn res_mkquery( | ... | @@ -4526,7 +4526,7 @@ pub fn res_mkquery( |
| 4526 | // Make a reasonably unpredictable id | 4526 | // Make a reasonably unpredictable id |
| 4527 | var ts: timespec = undefined; | 4527 | var ts: timespec = undefined; |
| 4528 | clock_gettime(CLOCK_REALTIME, &ts) catch {}; | 4528 | clock_gettime(CLOCK_REALTIME, &ts) catch {}; |
| 4529 | const UInt = std.meta.Int(false, @TypeOf(ts.tv_nsec).bit_count); | 4529 | const UInt = std.meta.Int(false, std.meta.bitCount(@TypeOf(ts.tv_nsec))); |
| 4530 | const unsec = @bitCast(UInt, ts.tv_nsec); | 4530 | const unsec = @bitCast(UInt, ts.tv_nsec); |
| 4531 | const id = @truncate(u32, unsec + unsec / 65536); | 4531 | const id = @truncate(u32, unsec + unsec / 65536); |
| 4532 | q[0] = @truncate(u8, id / 256); | 4532 | q[0] = @truncate(u8, id / 256); |
lib/std/os/bits/linux.zig+1-1| ... | @@ -846,7 +846,7 @@ pub const SIG_ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); | ... | @@ -846,7 +846,7 @@ pub const SIG_ERR = @intToPtr(?Sigaction.sigaction_fn, maxInt(usize)); |
| 846 | pub const SIG_DFL = @intToPtr(?Sigaction.sigaction_fn, 0); | 846 | pub const SIG_DFL = @intToPtr(?Sigaction.sigaction_fn, 0); |
| 847 | pub const SIG_IGN = @intToPtr(?Sigaction.sigaction_fn, 1); | 847 | pub const SIG_IGN = @intToPtr(?Sigaction.sigaction_fn, 1); |
| 848 | 848 | ||
| 849 | pub const empty_sigset = [_]u32{0} ** sigset_t.len; | 849 | pub const empty_sigset = [_]u32{0} ** @typeInfo(sigset_t).Array.len; |
| 850 | 850 | ||
| 851 | pub const signalfd_siginfo = extern struct { | 851 | pub const signalfd_siginfo = extern struct { |
| 852 | signo: u32, | 852 | signo: u32, |
lib/std/os/linux.zig+5-3| ... | @@ -829,17 +829,19 @@ pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigacti | ... | @@ -829,17 +829,19 @@ pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigacti |
| 829 | return 0; | 829 | return 0; |
| 830 | } | 830 | } |
| 831 | 831 | ||
| 832 | const usize_bits = @typeInfo(usize).Int.bits; | ||
| 833 | |||
| 832 | pub fn sigaddset(set: *sigset_t, sig: u6) void { | 834 | pub fn sigaddset(set: *sigset_t, sig: u6) void { |
| 833 | const s = sig - 1; | 835 | const s = sig - 1; |
| 834 | // shift in musl: s&8*sizeof *set->__bits-1 | 836 | // shift in musl: s&8*sizeof *set->__bits-1 |
| 835 | const shift = @intCast(u5, s & (usize.bit_count - 1)); | 837 | const shift = @intCast(u5, s & (usize_bits - 1)); |
| 836 | const val = @intCast(u32, 1) << shift; | 838 | const val = @intCast(u32, 1) << shift; |
| 837 | (set.*)[@intCast(usize, s) / usize.bit_count] |= val; | 839 | (set.*)[@intCast(usize, s) / usize_bits] |= val; |
| 838 | } | 840 | } |
| 839 | 841 | ||
| 840 | pub fn sigismember(set: *const sigset_t, sig: u6) bool { | 842 | pub fn sigismember(set: *const sigset_t, sig: u6) bool { |
| 841 | const s = sig - 1; | 843 | const s = sig - 1; |
| 842 | return ((set.*)[@intCast(usize, s) / usize.bit_count] & (@intCast(usize, 1) << (s & (usize.bit_count - 1)))) != 0; | 844 | return ((set.*)[@intCast(usize, s) / usize_bits] & (@intCast(usize, 1) << (s & (usize_bits - 1)))) != 0; |
| 843 | } | 845 | } |
| 844 | 846 | ||
| 845 | pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { | 847 | pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { |
lib/std/os/windows/ws2_32.zig+1-1| ... | @@ -12,7 +12,7 @@ pub const SOCKET_ERROR = -1; | ... | @@ -12,7 +12,7 @@ pub const SOCKET_ERROR = -1; |
| 12 | pub const WSADESCRIPTION_LEN = 256; | 12 | pub const WSADESCRIPTION_LEN = 256; |
| 13 | pub const WSASYS_STATUS_LEN = 128; | 13 | pub const WSASYS_STATUS_LEN = 128; |
| 14 | 14 | ||
| 15 | pub const WSADATA = if (usize.bit_count == u64.bit_count) | 15 | pub const WSADATA = if (@sizeOf(usize) == @sizeOf(u64)) |
| 16 | extern struct { | 16 | extern struct { |
| 17 | wVersion: WORD, | 17 | wVersion: WORD, |
| 18 | wHighVersion: WORD, | 18 | wHighVersion: WORD, |
lib/std/pdb.zig+1-1| ... | @@ -636,7 +636,7 @@ const MsfStream = struct { | ... | @@ -636,7 +636,7 @@ const MsfStream = struct { |
| 636 | blocks: []u32 = undefined, | 636 | blocks: []u32 = undefined, |
| 637 | block_size: u32 = undefined, | 637 | block_size: u32 = undefined, |
| 638 | 638 | ||
| 639 | pub const Error = @TypeOf(read).ReturnType.ErrorSet; | 639 | pub const Error = @typeInfo(@typeInfo(@TypeOf(read)).Fn.return_type.?).ErrorUnion.error_set; |
| 640 | 640 | ||
| 641 | fn init(block_size: u32, file: File, blocks: []u32) MsfStream { | 641 | fn init(block_size: u32, file: File, blocks: []u32) MsfStream { |
| 642 | const stream = MsfStream{ | 642 | const stream = MsfStream{ |
lib/std/rand.zig+33-24| ... | @@ -51,8 +51,9 @@ pub const Random = struct { | ... | @@ -51,8 +51,9 @@ pub const Random = struct { |
| 51 | /// Returns a random int `i` such that `0 <= i <= maxInt(T)`. | 51 | /// Returns a random int `i` such that `0 <= i <= maxInt(T)`. |
| 52 | /// `i` is evenly distributed. | 52 | /// `i` is evenly distributed. |
| 53 | pub fn int(r: *Random, comptime T: type) T { | 53 | pub fn int(r: *Random, comptime T: type) T { |
| 54 | const UnsignedT = std.meta.Int(false, T.bit_count); | 54 | const bits = @typeInfo(T).Int.bits; |
| 55 | const ByteAlignedT = std.meta.Int(false, @divTrunc(T.bit_count + 7, 8) * 8); | 55 | const UnsignedT = std.meta.Int(false, bits); |
| 56 | const ByteAlignedT = std.meta.Int(false, @divTrunc(bits + 7, 8) * 8); | ||
| 56 | 57 | ||
| 57 | var rand_bytes: [@sizeOf(ByteAlignedT)]u8 = undefined; | 58 | var rand_bytes: [@sizeOf(ByteAlignedT)]u8 = undefined; |
| 58 | r.bytes(rand_bytes[0..]); | 59 | r.bytes(rand_bytes[0..]); |
| ... | @@ -68,10 +69,11 @@ pub const Random = struct { | ... | @@ -68,10 +69,11 @@ pub const Random = struct { |
| 68 | /// Constant-time implementation off `uintLessThan`. | 69 | /// Constant-time implementation off `uintLessThan`. |
| 69 | /// The results of this function may be biased. | 70 | /// The results of this function may be biased. |
| 70 | pub fn uintLessThanBiased(r: *Random, comptime T: type, less_than: T) T { | 71 | pub fn uintLessThanBiased(r: *Random, comptime T: type, less_than: T) T { |
| 71 | comptime assert(T.is_signed == false); | 72 | comptime assert(@typeInfo(T).Int.is_signed == false); |
| 72 | comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation! | 73 | const bits = @typeInfo(T).Int.bits; |
| 74 | comptime assert(bits <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation! | ||
| 73 | assert(0 < less_than); | 75 | assert(0 < less_than); |
| 74 | if (T.bit_count <= 32) { | 76 | if (bits <= 32) { |
| 75 | return @intCast(T, limitRangeBiased(u32, r.int(u32), less_than)); | 77 | return @intCast(T, limitRangeBiased(u32, r.int(u32), less_than)); |
| 76 | } else { | 78 | } else { |
| 77 | return @intCast(T, limitRangeBiased(u64, r.int(u64), less_than)); | 79 | return @intCast(T, limitRangeBiased(u64, r.int(u64), less_than)); |
| ... | @@ -87,13 +89,15 @@ pub const Random = struct { | ... | @@ -87,13 +89,15 @@ pub const Random = struct { |
| 87 | /// this function is guaranteed to return. | 89 | /// this function is guaranteed to return. |
| 88 | /// If you need deterministic runtime bounds, use `uintLessThanBiased`. | 90 | /// If you need deterministic runtime bounds, use `uintLessThanBiased`. |
| 89 | pub fn uintLessThan(r: *Random, comptime T: type, less_than: T) T { | 91 | pub fn uintLessThan(r: *Random, comptime T: type, less_than: T) T { |
| 90 | comptime assert(T.is_signed == false); | 92 | comptime assert(@typeInfo(T).Int.is_signed == false); |
| 91 | comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation! | 93 | const bits = @typeInfo(T).Int.bits; |
| 94 | comptime assert(bits <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation! | ||
| 92 | assert(0 < less_than); | 95 | assert(0 < less_than); |
| 93 | // Small is typically u32 | 96 | // Small is typically u32 |
| 94 | const Small = std.meta.Int(false, @divTrunc(T.bit_count + 31, 32) * 32); | 97 | const small_bits = @divTrunc(bits + 31, 32) * 32; |
| 98 | const Small = std.meta.Int(false, small_bits); | ||
| 95 | // Large is typically u64 | 99 | // Large is typically u64 |
| 96 | const Large = std.meta.Int(false, Small.bit_count * 2); | 100 | const Large = std.meta.Int(false, small_bits * 2); |
| 97 | 101 | ||
| 98 | // adapted from: | 102 | // adapted from: |
| 99 | // http://www.pcg-random.org/posts/bounded-rands.html | 103 | // http://www.pcg-random.org/posts/bounded-rands.html |
| ... | @@ -105,7 +109,7 @@ pub const Random = struct { | ... | @@ -105,7 +109,7 @@ pub const Random = struct { |
| 105 | // TODO: workaround for https://github.com/ziglang/zig/issues/1770 | 109 | // TODO: workaround for https://github.com/ziglang/zig/issues/1770 |
| 106 | // should be: | 110 | // should be: |
| 107 | // var t: Small = -%less_than; | 111 | // var t: Small = -%less_than; |
| 108 | var t: Small = @bitCast(Small, -%@bitCast(std.meta.Int(true, Small.bit_count), @as(Small, less_than))); | 112 | var t: Small = @bitCast(Small, -%@bitCast(std.meta.Int(true, small_bits), @as(Small, less_than))); |
| 109 | 113 | ||
| 110 | if (t >= less_than) { | 114 | if (t >= less_than) { |
| 111 | t -= less_than; | 115 | t -= less_than; |
| ... | @@ -119,13 +123,13 @@ pub const Random = struct { | ... | @@ -119,13 +123,13 @@ pub const Random = struct { |
| 119 | l = @truncate(Small, m); | 123 | l = @truncate(Small, m); |
| 120 | } | 124 | } |
| 121 | } | 125 | } |
| 122 | return @intCast(T, m >> Small.bit_count); | 126 | return @intCast(T, m >> small_bits); |
| 123 | } | 127 | } |
| 124 | 128 | ||
| 125 | /// Constant-time implementation off `uintAtMost`. | 129 | /// Constant-time implementation off `uintAtMost`. |
| 126 | /// The results of this function may be biased. | 130 | /// The results of this function may be biased. |
| 127 | pub fn uintAtMostBiased(r: *Random, comptime T: type, at_most: T) T { | 131 | pub fn uintAtMostBiased(r: *Random, comptime T: type, at_most: T) T { |
| 128 | assert(T.is_signed == false); | 132 | assert(@typeInfo(T).Int.is_signed == false); |
| 129 | if (at_most == maxInt(T)) { | 133 | if (at_most == maxInt(T)) { |
| 130 | // have the full range | 134 | // have the full range |
| 131 | return r.int(T); | 135 | return r.int(T); |
| ... | @@ -137,7 +141,7 @@ pub const Random = struct { | ... | @@ -137,7 +141,7 @@ pub const Random = struct { |
| 137 | /// See `uintLessThan`, which this function uses in most cases, | 141 | /// See `uintLessThan`, which this function uses in most cases, |
| 138 | /// for commentary on the runtime of this function. | 142 | /// for commentary on the runtime of this function. |
| 139 | pub fn uintAtMost(r: *Random, comptime T: type, at_most: T) T { | 143 | pub fn uintAtMost(r: *Random, comptime T: type, at_most: T) T { |
| 140 | assert(T.is_signed == false); | 144 | assert(@typeInfo(T).Int.is_signed == false); |
| 141 | if (at_most == maxInt(T)) { | 145 | if (at_most == maxInt(T)) { |
| 142 | // have the full range | 146 | // have the full range |
| 143 | return r.int(T); | 147 | return r.int(T); |
| ... | @@ -149,9 +153,10 @@ pub const Random = struct { | ... | @@ -149,9 +153,10 @@ pub const Random = struct { |
| 149 | /// The results of this function may be biased. | 153 | /// The results of this function may be biased. |
| 150 | pub fn intRangeLessThanBiased(r: *Random, comptime T: type, at_least: T, less_than: T) T { | 154 | pub fn intRangeLessThanBiased(r: *Random, comptime T: type, at_least: T, less_than: T) T { |
| 151 | assert(at_least < less_than); | 155 | assert(at_least < less_than); |
| 152 | if (T.is_signed) { | 156 | const info = @typeInfo(T).Int; |
| 157 | if (info.is_signed) { | ||
| 153 | // Two's complement makes this math pretty easy. | 158 | // Two's complement makes this math pretty easy. |
| 154 | const UnsignedT = std.meta.Int(false, T.bit_count); | 159 | const UnsignedT = std.meta.Int(false, info.bits); |
| 155 | const lo = @bitCast(UnsignedT, at_least); | 160 | const lo = @bitCast(UnsignedT, at_least); |
| 156 | const hi = @bitCast(UnsignedT, less_than); | 161 | const hi = @bitCast(UnsignedT, less_than); |
| 157 | const result = lo +% r.uintLessThanBiased(UnsignedT, hi -% lo); | 162 | const result = lo +% r.uintLessThanBiased(UnsignedT, hi -% lo); |
| ... | @@ -167,9 +172,10 @@ pub const Random = struct { | ... | @@ -167,9 +172,10 @@ pub const Random = struct { |
| 167 | /// for commentary on the runtime of this function. | 172 | /// for commentary on the runtime of this function. |
| 168 | pub fn intRangeLessThan(r: *Random, comptime T: type, at_least: T, less_than: T) T { | 173 | pub fn intRangeLessThan(r: *Random, comptime T: type, at_least: T, less_than: T) T { |
| 169 | assert(at_least < less_than); | 174 | assert(at_least < less_than); |
| 170 | if (T.is_signed) { | 175 | const info = @typeInfo(T).Int; |
| 176 | if (info.is_signed) { | ||
| 171 | // Two's complement makes this math pretty easy. | 177 | // Two's complement makes this math pretty easy. |
| 172 | const UnsignedT = std.meta.Int(false, T.bit_count); | 178 | const UnsignedT = std.meta.Int(false, info.bits); |
| 173 | const lo = @bitCast(UnsignedT, at_least); | 179 | const lo = @bitCast(UnsignedT, at_least); |
| 174 | const hi = @bitCast(UnsignedT, less_than); | 180 | const hi = @bitCast(UnsignedT, less_than); |
| 175 | const result = lo +% r.uintLessThan(UnsignedT, hi -% lo); | 181 | const result = lo +% r.uintLessThan(UnsignedT, hi -% lo); |
| ... | @@ -184,9 +190,10 @@ pub const Random = struct { | ... | @@ -184,9 +190,10 @@ pub const Random = struct { |
| 184 | /// The results of this function may be biased. | 190 | /// The results of this function may be biased. |
| 185 | pub fn intRangeAtMostBiased(r: *Random, comptime T: type, at_least: T, at_most: T) T { | 191 | pub fn intRangeAtMostBiased(r: *Random, comptime T: type, at_least: T, at_most: T) T { |
| 186 | assert(at_least <= at_most); | 192 | assert(at_least <= at_most); |
| 187 | if (T.is_signed) { | 193 | const info = @typeInfo(T).Int; |
| 194 | if (info.is_signed) { | ||
| 188 | // Two's complement makes this math pretty easy. | 195 | // Two's complement makes this math pretty easy. |
| 189 | const UnsignedT = std.meta.Int(false, T.bit_count); | 196 | const UnsignedT = std.meta.Int(false, info.bits); |
| 190 | const lo = @bitCast(UnsignedT, at_least); | 197 | const lo = @bitCast(UnsignedT, at_least); |
| 191 | const hi = @bitCast(UnsignedT, at_most); | 198 | const hi = @bitCast(UnsignedT, at_most); |
| 192 | const result = lo +% r.uintAtMostBiased(UnsignedT, hi -% lo); | 199 | const result = lo +% r.uintAtMostBiased(UnsignedT, hi -% lo); |
| ... | @@ -202,9 +209,10 @@ pub const Random = struct { | ... | @@ -202,9 +209,10 @@ pub const Random = struct { |
| 202 | /// for commentary on the runtime of this function. | 209 | /// for commentary on the runtime of this function. |
| 203 | pub fn intRangeAtMost(r: *Random, comptime T: type, at_least: T, at_most: T) T { | 210 | pub fn intRangeAtMost(r: *Random, comptime T: type, at_least: T, at_most: T) T { |
| 204 | assert(at_least <= at_most); | 211 | assert(at_least <= at_most); |
| 205 | if (T.is_signed) { | 212 | const info = @typeInfo(T).Int; |
| 213 | if (info.is_signed) { | ||
| 206 | // Two's complement makes this math pretty easy. | 214 | // Two's complement makes this math pretty easy. |
| 207 | const UnsignedT = std.meta.Int(false, T.bit_count); | 215 | const UnsignedT = std.meta.Int(false, info.bits); |
| 208 | const lo = @bitCast(UnsignedT, at_least); | 216 | const lo = @bitCast(UnsignedT, at_least); |
| 209 | const hi = @bitCast(UnsignedT, at_most); | 217 | const hi = @bitCast(UnsignedT, at_most); |
| 210 | const result = lo +% r.uintAtMost(UnsignedT, hi -% lo); | 218 | const result = lo +% r.uintAtMost(UnsignedT, hi -% lo); |
| ... | @@ -280,14 +288,15 @@ pub const Random = struct { | ... | @@ -280,14 +288,15 @@ pub const Random = struct { |
| 280 | /// into an integer 0 <= result < less_than. | 288 | /// into an integer 0 <= result < less_than. |
| 281 | /// This function introduces a minor bias. | 289 | /// This function introduces a minor bias. |
| 282 | pub fn limitRangeBiased(comptime T: type, random_int: T, less_than: T) T { | 290 | pub fn limitRangeBiased(comptime T: type, random_int: T, less_than: T) T { |
| 283 | comptime assert(T.is_signed == false); | 291 | comptime assert(@typeInfo(T).Int.is_signed == false); |
| 284 | const T2 = std.meta.Int(false, T.bit_count * 2); | 292 | const bits = @typeInfo(T).Int.bits; |
| 293 | const T2 = std.meta.Int(false, bits * 2); | ||
| 285 | 294 | ||
| 286 | // adapted from: | 295 | // adapted from: |
| 287 | // http://www.pcg-random.org/posts/bounded-rands.html | 296 | // http://www.pcg-random.org/posts/bounded-rands.html |
| 288 | // "Integer Multiplication (Biased)" | 297 | // "Integer Multiplication (Biased)" |
| 289 | var m: T2 = @as(T2, random_int) * @as(T2, less_than); | 298 | var m: T2 = @as(T2, random_int) * @as(T2, less_than); |
| 290 | return @intCast(T, m >> T.bit_count); | 299 | return @intCast(T, m >> bits); |
| 291 | } | 300 | } |
| 292 | 301 | ||
| 293 | const SequentialPrng = struct { | 302 | const SequentialPrng = struct { |
lib/std/special/build_runner.zig+1-1| ... | @@ -133,7 +133,7 @@ pub fn main() !void { | ... | @@ -133,7 +133,7 @@ pub fn main() !void { |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | fn runBuild(builder: *Builder) anyerror!void { | 135 | fn runBuild(builder: *Builder) anyerror!void { |
| 136 | switch (@typeInfo(@TypeOf(root.build).ReturnType)) { | 136 | switch (@typeInfo(@typeInfo(@TypeOf(root.build)).Fn.return_type.?)) { |
| 137 | .Void => root.build(builder), | 137 | .Void => root.build(builder), |
| 138 | .ErrorUnion => try root.build(builder), | 138 | .ErrorUnion => try root.build(builder), |
| 139 | else => @compileError("expected return type of build to be 'void' or '!void'"), | 139 | else => @compileError("expected return type of build to be 'void' or '!void'"), |
lib/std/special/c.zig+3-2| ... | @@ -516,11 +516,12 @@ export fn roundf(a: f32) f32 { | ... | @@ -516,11 +516,12 @@ export fn roundf(a: f32) f32 { |
| 516 | fn generic_fmod(comptime T: type, x: T, y: T) T { | 516 | fn generic_fmod(comptime T: type, x: T, y: T) T { |
| 517 | @setRuntimeSafety(false); | 517 | @setRuntimeSafety(false); |
| 518 | 518 | ||
| 519 | const uint = std.meta.Int(false, T.bit_count); | 519 | const bits = @typeInfo(T).Float.bits; |
| 520 | const uint = std.meta.Int(false, bits); | ||
| 520 | const log2uint = math.Log2Int(uint); | 521 | const log2uint = math.Log2Int(uint); |
| 521 | const digits = if (T == f32) 23 else 52; | 522 | const digits = if (T == f32) 23 else 52; |
| 522 | const exp_bits = if (T == f32) 9 else 12; | 523 | const exp_bits = if (T == f32) 9 else 12; |
| 523 | const bits_minus_1 = T.bit_count - 1; | 524 | const bits_minus_1 = bits - 1; |
| 524 | const mask = if (T == f32) 0xff else 0x7ff; | 525 | const mask = if (T == f32) 0xff else 0x7ff; |
| 525 | var ux = @bitCast(uint, x); | 526 | var ux = @bitCast(uint, x); |
| 526 | var uy = @bitCast(uint, y); | 527 | var uy = @bitCast(uint, y); |
lib/std/special/compiler_rt/addXf3.zig+10-8| ... | @@ -59,23 +59,25 @@ pub fn __aeabi_dsub(a: f64, b: f64) callconv(.AAPCS) f64 { | ... | @@ -59,23 +59,25 @@ pub fn __aeabi_dsub(a: f64, b: f64) callconv(.AAPCS) f64 { |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | // TODO: restore inline keyword, see: https://github.com/ziglang/zig/issues/2154 | 61 | // TODO: restore inline keyword, see: https://github.com/ziglang/zig/issues/2154 |
| 62 | fn normalize(comptime T: type, significand: *std.meta.Int(false, T.bit_count)) i32 { | 62 | fn normalize(comptime T: type, significand: *std.meta.Int(false, @typeInfo(T).Float.bits)) i32 { |
| 63 | const Z = std.meta.Int(false, T.bit_count); | 63 | const bits = @typeInfo(T).Float.bits; |
| 64 | const S = std.meta.Int(false, T.bit_count - @clz(Z, @as(Z, T.bit_count) - 1)); | 64 | const Z = std.meta.Int(false, bits); |
| 65 | const S = std.meta.Int(false, bits - @clz(Z, @as(Z, bits) - 1)); | ||
| 65 | const significandBits = std.math.floatMantissaBits(T); | 66 | const significandBits = std.math.floatMantissaBits(T); |
| 66 | const implicitBit = @as(Z, 1) << significandBits; | 67 | const implicitBit = @as(Z, 1) << significandBits; |
| 67 | 68 | ||
| 68 | const shift = @clz(std.meta.Int(false, T.bit_count), significand.*) - @clz(Z, implicitBit); | 69 | const shift = @clz(std.meta.Int(false, bits), significand.*) - @clz(Z, implicitBit); |
| 69 | significand.* <<= @intCast(S, shift); | 70 | significand.* <<= @intCast(S, shift); |
| 70 | return 1 - shift; | 71 | return 1 - shift; |
| 71 | } | 72 | } |
| 72 | 73 | ||
| 73 | // TODO: restore inline keyword, see: https://github.com/ziglang/zig/issues/2154 | 74 | // TODO: restore inline keyword, see: https://github.com/ziglang/zig/issues/2154 |
| 74 | fn addXf3(comptime T: type, a: T, b: T) T { | 75 | fn addXf3(comptime T: type, a: T, b: T) T { |
| 75 | const Z = std.meta.Int(false, T.bit_count); | 76 | const bits = @typeInfo(T).Float.bits; |
| 76 | const S = std.meta.Int(false, T.bit_count - @clz(Z, @as(Z, T.bit_count) - 1)); | 77 | const Z = std.meta.Int(false, bits); |
| 78 | const S = std.meta.Int(false, bits - @clz(Z, @as(Z, bits) - 1)); | ||
| 77 | 79 | ||
| 78 | const typeWidth = T.bit_count; | 80 | const typeWidth = bits; |
| 79 | const significandBits = std.math.floatMantissaBits(T); | 81 | const significandBits = std.math.floatMantissaBits(T); |
| 80 | const exponentBits = std.math.floatExponentBits(T); | 82 | const exponentBits = std.math.floatExponentBits(T); |
| 81 | 83 | ||
| ... | @@ -187,7 +189,7 @@ fn addXf3(comptime T: type, a: T, b: T) T { | ... | @@ -187,7 +189,7 @@ fn addXf3(comptime T: type, a: T, b: T) T { |
| 187 | // If partial cancellation occured, we need to left-shift the result | 189 | // If partial cancellation occured, we need to left-shift the result |
| 188 | // and adjust the exponent: | 190 | // and adjust the exponent: |
| 189 | if (aSignificand < implicitBit << 3) { | 191 | if (aSignificand < implicitBit << 3) { |
| 190 | const shift = @intCast(i32, @clz(Z, aSignificand)) - @intCast(i32, @clz(std.meta.Int(false, T.bit_count), implicitBit << 3)); | 192 | const shift = @intCast(i32, @clz(Z, aSignificand)) - @intCast(i32, @clz(std.meta.Int(false, bits), implicitBit << 3)); |
| 191 | aSignificand <<= @intCast(S, shift); | 193 | aSignificand <<= @intCast(S, shift); |
| 192 | aExponent -= shift; | 194 | aExponent -= shift; |
| 193 | } | 195 | } |
lib/std/special/compiler_rt/aulldiv.zig+2-2| ... | @@ -7,8 +7,8 @@ const builtin = @import("builtin"); | ... | @@ -7,8 +7,8 @@ const builtin = @import("builtin"); |
| 7 | 7 | ||
| 8 | pub fn _alldiv(a: i64, b: i64) callconv(.Stdcall) i64 { | 8 | pub fn _alldiv(a: i64, b: i64) callconv(.Stdcall) i64 { |
| 9 | @setRuntimeSafety(builtin.is_test); | 9 | @setRuntimeSafety(builtin.is_test); |
| 10 | const s_a = a >> (i64.bit_count - 1); | 10 | const s_a = a >> (64 - 1); |
| 11 | const s_b = b >> (i64.bit_count - 1); | 11 | const s_b = b >> (64 - 1); |
| 12 | 12 | ||
| 13 | const an = (a ^ s_a) -% s_a; | 13 | const an = (a ^ s_a) -% s_a; |
| 14 | const bn = (b ^ s_b) -% s_b; | 14 | const bn = (b ^ s_b) -% s_b; |
lib/std/special/compiler_rt/aullrem.zig+2-2| ... | @@ -7,8 +7,8 @@ const builtin = @import("builtin"); | ... | @@ -7,8 +7,8 @@ const builtin = @import("builtin"); |
| 7 | 7 | ||
| 8 | pub fn _allrem(a: i64, b: i64) callconv(.Stdcall) i64 { | 8 | pub fn _allrem(a: i64, b: i64) callconv(.Stdcall) i64 { |
| 9 | @setRuntimeSafety(builtin.is_test); | 9 | @setRuntimeSafety(builtin.is_test); |
| 10 | const s_a = a >> (i64.bit_count - 1); | 10 | const s_a = a >> (64 - 1); |
| 11 | const s_b = b >> (i64.bit_count - 1); | 11 | const s_b = b >> (64 - 1); |
| 12 | 12 | ||
| 13 | const an = (a ^ s_a) -% s_a; | 13 | const an = (a ^ s_a) -% s_a; |
| 14 | const bn = (b ^ s_b) -% s_b; | 14 | const bn = (b ^ s_b) -% s_b; |
lib/std/special/compiler_rt/compareXf2.zig+4-3| ... | @@ -27,8 +27,9 @@ const GE = extern enum(i32) { | ... | @@ -27,8 +27,9 @@ const GE = extern enum(i32) { |
| 27 | pub fn cmp(comptime T: type, comptime RT: type, a: T, b: T) RT { | 27 | pub fn cmp(comptime T: type, comptime RT: type, a: T, b: T) RT { |
| 28 | @setRuntimeSafety(builtin.is_test); | 28 | @setRuntimeSafety(builtin.is_test); |
| 29 | 29 | ||
| 30 | const srep_t = std.meta.Int(true, T.bit_count); | 30 | const bits = @typeInfo(T).Float.bits; |
| 31 | const rep_t = std.meta.Int(false, T.bit_count); | 31 | const srep_t = std.meta.Int(true, bits); |
| 32 | const rep_t = std.meta.Int(false, bits); | ||
| 32 | 33 | ||
| 33 | const significandBits = std.math.floatMantissaBits(T); | 34 | const significandBits = std.math.floatMantissaBits(T); |
| 34 | const exponentBits = std.math.floatExponentBits(T); | 35 | const exponentBits = std.math.floatExponentBits(T); |
| ... | @@ -73,7 +74,7 @@ pub fn cmp(comptime T: type, comptime RT: type, a: T, b: T) RT { | ... | @@ -73,7 +74,7 @@ pub fn cmp(comptime T: type, comptime RT: type, a: T, b: T) RT { |
| 73 | pub fn unordcmp(comptime T: type, a: T, b: T) i32 { | 74 | pub fn unordcmp(comptime T: type, a: T, b: T) i32 { |
| 74 | @setRuntimeSafety(builtin.is_test); | 75 | @setRuntimeSafety(builtin.is_test); |
| 75 | 76 | ||
| 76 | const rep_t = std.meta.Int(false, T.bit_count); | 77 | const rep_t = std.meta.Int(false, @typeInfo(T).Float.bits); |
| 77 | 78 | ||
| 78 | const significandBits = std.math.floatMantissaBits(T); | 79 | const significandBits = std.math.floatMantissaBits(T); |
| 79 | const exponentBits = std.math.floatExponentBits(T); | 80 | const exponentBits = std.math.floatExponentBits(T); |
lib/std/special/compiler_rt/divdf3.zig+4-5| ... | @@ -12,10 +12,9 @@ const builtin = @import("builtin"); | ... | @@ -12,10 +12,9 @@ const builtin = @import("builtin"); |
| 12 | 12 | ||
| 13 | pub fn __divdf3(a: f64, b: f64) callconv(.C) f64 { | 13 | pub fn __divdf3(a: f64, b: f64) callconv(.C) f64 { |
| 14 | @setRuntimeSafety(builtin.is_test); | 14 | @setRuntimeSafety(builtin.is_test); |
| 15 | const Z = std.meta.Int(false, f64.bit_count); | 15 | const Z = std.meta.Int(false, 64); |
| 16 | const SignedZ = std.meta.Int(true, f64.bit_count); | 16 | const SignedZ = std.meta.Int(true, 64); |
| 17 | 17 | ||
| 18 | const typeWidth = f64.bit_count; | ||
| 19 | const significandBits = std.math.floatMantissaBits(f64); | 18 | const significandBits = std.math.floatMantissaBits(f64); |
| 20 | const exponentBits = std.math.floatExponentBits(f64); | 19 | const exponentBits = std.math.floatExponentBits(f64); |
| 21 | 20 | ||
| ... | @@ -317,9 +316,9 @@ pub fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { | ... | @@ -317,9 +316,9 @@ pub fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { |
| 317 | } | 316 | } |
| 318 | } | 317 | } |
| 319 | 318 | ||
| 320 | pub fn normalize(comptime T: type, significand: *std.meta.Int(false, T.bit_count)) i32 { | 319 | pub fn normalize(comptime T: type, significand: *std.meta.Int(false, @typeInfo(T).Float.bits)) i32 { |
| 321 | @setRuntimeSafety(builtin.is_test); | 320 | @setRuntimeSafety(builtin.is_test); |
| 322 | const Z = std.meta.Int(false, T.bit_count); | 321 | const Z = std.meta.Int(false, @typeInfo(T).Float.bits); |
| 323 | const significandBits = std.math.floatMantissaBits(T); | 322 | const significandBits = std.math.floatMantissaBits(T); |
| 324 | const implicitBit = @as(Z, 1) << significandBits; | 323 | const implicitBit = @as(Z, 1) << significandBits; |
| 325 | 324 |
lib/std/special/compiler_rt/divsf3.zig+3-4| ... | @@ -12,9 +12,8 @@ const builtin = @import("builtin"); | ... | @@ -12,9 +12,8 @@ const builtin = @import("builtin"); |
| 12 | 12 | ||
| 13 | pub fn __divsf3(a: f32, b: f32) callconv(.C) f32 { | 13 | pub fn __divsf3(a: f32, b: f32) callconv(.C) f32 { |
| 14 | @setRuntimeSafety(builtin.is_test); | 14 | @setRuntimeSafety(builtin.is_test); |
| 15 | const Z = std.meta.Int(false, f32.bit_count); | 15 | const Z = std.meta.Int(false, 32); |
| 16 | 16 | ||
| 17 | const typeWidth = f32.bit_count; | ||
| 18 | const significandBits = std.math.floatMantissaBits(f32); | 17 | const significandBits = std.math.floatMantissaBits(f32); |
| 19 | const exponentBits = std.math.floatExponentBits(f32); | 18 | const exponentBits = std.math.floatExponentBits(f32); |
| 20 | 19 | ||
| ... | @@ -190,9 +189,9 @@ pub fn __divsf3(a: f32, b: f32) callconv(.C) f32 { | ... | @@ -190,9 +189,9 @@ pub fn __divsf3(a: f32, b: f32) callconv(.C) f32 { |
| 190 | } | 189 | } |
| 191 | } | 190 | } |
| 192 | 191 | ||
| 193 | fn normalize(comptime T: type, significand: *std.meta.Int(false, T.bit_count)) i32 { | 192 | fn normalize(comptime T: type, significand: *std.meta.Int(false, @typeInfo(T).Float.bits)) i32 { |
| 194 | @setRuntimeSafety(builtin.is_test); | 193 | @setRuntimeSafety(builtin.is_test); |
| 195 | const Z = std.meta.Int(false, T.bit_count); | 194 | const Z = std.meta.Int(false, @typeInfo(T).Float.bits); |
| 196 | const significandBits = std.math.floatMantissaBits(T); | 195 | const significandBits = std.math.floatMantissaBits(T); |
| 197 | const implicitBit = @as(Z, 1) << significandBits; | 196 | const implicitBit = @as(Z, 1) << significandBits; |
| 198 | 197 |
lib/std/special/compiler_rt/divtf3.zig+2-3| ... | @@ -11,10 +11,9 @@ const wideMultiply = @import("divdf3.zig").wideMultiply; | ... | @@ -11,10 +11,9 @@ const wideMultiply = @import("divdf3.zig").wideMultiply; |
| 11 | 11 | ||
| 12 | pub fn __divtf3(a: f128, b: f128) callconv(.C) f128 { | 12 | pub fn __divtf3(a: f128, b: f128) callconv(.C) f128 { |
| 13 | @setRuntimeSafety(builtin.is_test); | 13 | @setRuntimeSafety(builtin.is_test); |
| 14 | const Z = std.meta.Int(false, f128.bit_count); | 14 | const Z = std.meta.Int(false, 128); |
| 15 | const SignedZ = std.meta.Int(true, f128.bit_count); | 15 | const SignedZ = std.meta.Int(true, 128); |
| 16 | 16 | ||
| 17 | const typeWidth = f128.bit_count; | ||
| 18 | const significandBits = std.math.floatMantissaBits(f128); | 17 | const significandBits = std.math.floatMantissaBits(f128); |
| 19 | const exponentBits = std.math.floatExponentBits(f128); | 18 | const exponentBits = std.math.floatExponentBits(f128); |
| 20 | 19 |
lib/std/special/compiler_rt/divti3.zig+2-2| ... | @@ -9,8 +9,8 @@ const builtin = @import("builtin"); | ... | @@ -9,8 +9,8 @@ const builtin = @import("builtin"); |
| 9 | pub fn __divti3(a: i128, b: i128) callconv(.C) i128 { | 9 | pub fn __divti3(a: i128, b: i128) callconv(.C) i128 { |
| 10 | @setRuntimeSafety(builtin.is_test); | 10 | @setRuntimeSafety(builtin.is_test); |
| 11 | 11 | ||
| 12 | const s_a = a >> (i128.bit_count - 1); | 12 | const s_a = a >> (128 - 1); |
| 13 | const s_b = b >> (i128.bit_count - 1); | 13 | const s_b = b >> (128 - 1); |
| 14 | 14 | ||
| 15 | const an = (a ^ s_a) -% s_a; | 15 | const an = (a ^ s_a) -% s_a; |
| 16 | const bn = (b ^ s_b) -% s_b; | 16 | const bn = (b ^ s_b) -% s_b; |
lib/std/special/compiler_rt/fixint.zig+5-4| ... | @@ -28,7 +28,7 @@ pub fn fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t) fixint_t { | ... | @@ -28,7 +28,7 @@ pub fn fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t) fixint_t { |
| 28 | else => unreachable, | 28 | else => unreachable, |
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| 31 | const typeWidth = rep_t.bit_count; | 31 | const typeWidth = @typeInfo(rep_t).Int.bits; |
| 32 | const exponentBits = (typeWidth - significandBits - 1); | 32 | const exponentBits = (typeWidth - significandBits - 1); |
| 33 | const signBit = (@as(rep_t, 1) << (significandBits + exponentBits)); | 33 | const signBit = (@as(rep_t, 1) << (significandBits + exponentBits)); |
| 34 | const maxExponent = ((1 << exponentBits) - 1); | 34 | const maxExponent = ((1 << exponentBits) - 1); |
| ... | @@ -50,12 +50,13 @@ pub fn fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t) fixint_t { | ... | @@ -50,12 +50,13 @@ pub fn fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t) fixint_t { |
| 50 | if (exponent < 0) return 0; | 50 | if (exponent < 0) return 0; |
| 51 | 51 | ||
| 52 | // The unsigned result needs to be large enough to handle an fixint_t or rep_t | 52 | // The unsigned result needs to be large enough to handle an fixint_t or rep_t |
| 53 | const fixuint_t = std.meta.Int(false, fixint_t.bit_count); | 53 | const fixint_bits = @typeInfo(fixint_t).Int.bits; |
| 54 | const UintResultType = if (fixint_t.bit_count > rep_t.bit_count) fixuint_t else rep_t; | 54 | const fixuint_t = std.meta.Int(false, fixint_bits); |
| 55 | const UintResultType = if (fixint_bits > typeWidth) fixuint_t else rep_t; | ||
| 55 | var uint_result: UintResultType = undefined; | 56 | var uint_result: UintResultType = undefined; |
| 56 | 57 | ||
| 57 | // If the value is too large for the integer type, saturate. | 58 | // If the value is too large for the integer type, saturate. |
| 58 | if (@intCast(usize, exponent) >= fixint_t.bit_count) { | 59 | if (@intCast(usize, exponent) >= fixint_bits) { |
| 59 | return if (negative) @as(fixint_t, minInt(fixint_t)) else @as(fixint_t, maxInt(fixint_t)); | 60 | return if (negative) @as(fixint_t, minInt(fixint_t)) else @as(fixint_t, maxInt(fixint_t)); |
| 60 | } | 61 | } |
| 61 | 62 |
lib/std/special/compiler_rt/fixuint.zig+3-3| ... | @@ -15,14 +15,14 @@ pub fn fixuint(comptime fp_t: type, comptime fixuint_t: type, a: fp_t) fixuint_t | ... | @@ -15,14 +15,14 @@ pub fn fixuint(comptime fp_t: type, comptime fixuint_t: type, a: fp_t) fixuint_t |
| 15 | f128 => u128, | 15 | f128 => u128, |
| 16 | else => unreachable, | 16 | else => unreachable, |
| 17 | }; | 17 | }; |
| 18 | const srep_t = @import("std").meta.Int(true, rep_t.bit_count); | 18 | const typeWidth = @typeInfo(rep_t).Int.bits; |
| 19 | const srep_t = @import("std").meta.Int(true, typeWidth); | ||
| 19 | const significandBits = switch (fp_t) { | 20 | const significandBits = switch (fp_t) { |
| 20 | f32 => 23, | 21 | f32 => 23, |
| 21 | f64 => 52, | 22 | f64 => 52, |
| 22 | f128 => 112, | 23 | f128 => 112, |
| 23 | else => unreachable, | 24 | else => unreachable, |
| 24 | }; | 25 | }; |
| 25 | const typeWidth = rep_t.bit_count; | ||
| 26 | const exponentBits = (typeWidth - significandBits - 1); | 26 | const exponentBits = (typeWidth - significandBits - 1); |
| 27 | const signBit = (@as(rep_t, 1) << (significandBits + exponentBits)); | 27 | const signBit = (@as(rep_t, 1) << (significandBits + exponentBits)); |
| 28 | const maxExponent = ((1 << exponentBits) - 1); | 28 | const maxExponent = ((1 << exponentBits) - 1); |
| ... | @@ -44,7 +44,7 @@ pub fn fixuint(comptime fp_t: type, comptime fixuint_t: type, a: fp_t) fixuint_t | ... | @@ -44,7 +44,7 @@ pub fn fixuint(comptime fp_t: type, comptime fixuint_t: type, a: fp_t) fixuint_t |
| 44 | if (sign == -1 or exponent < 0) return 0; | 44 | if (sign == -1 or exponent < 0) return 0; |
| 45 | 45 | ||
| 46 | // If the value is too large for the integer type, saturate. | 46 | // If the value is too large for the integer type, saturate. |
| 47 | if (@intCast(c_uint, exponent) >= fixuint_t.bit_count) return ~@as(fixuint_t, 0); | 47 | if (@intCast(c_uint, exponent) >= @typeInfo(fixuint_t).Int.bits) return ~@as(fixuint_t, 0); |
| 48 | 48 | ||
| 49 | // If 0 <= exponent < significandBits, right shift to get the result. | 49 | // If 0 <= exponent < significandBits, right shift to get the result. |
| 50 | // Otherwise, shift left. | 50 | // Otherwise, shift left. |
lib/std/special/compiler_rt/floatXisf.zig+5-4| ... | @@ -12,15 +12,16 @@ const FLT_MANT_DIG = 24; | ... | @@ -12,15 +12,16 @@ const FLT_MANT_DIG = 24; |
| 12 | fn __floatXisf(comptime T: type, arg: T) f32 { | 12 | fn __floatXisf(comptime T: type, arg: T) f32 { |
| 13 | @setRuntimeSafety(builtin.is_test); | 13 | @setRuntimeSafety(builtin.is_test); |
| 14 | 14 | ||
| 15 | const Z = std.meta.Int(false, T.bit_count); | 15 | const bits = @typeInfo(T).Int.bits; |
| 16 | const S = std.meta.Int(false, T.bit_count - @clz(Z, @as(Z, T.bit_count) - 1)); | 16 | const Z = std.meta.Int(false, bits); |
| 17 | const S = std.meta.Int(false, bits - @clz(Z, @as(Z, bits) - 1)); | ||
| 17 | 18 | ||
| 18 | if (arg == 0) { | 19 | if (arg == 0) { |
| 19 | return @as(f32, 0.0); | 20 | return @as(f32, 0.0); |
| 20 | } | 21 | } |
| 21 | 22 | ||
| 22 | var ai = arg; | 23 | var ai = arg; |
| 23 | const N: u32 = T.bit_count; | 24 | const N: u32 = bits; |
| 24 | const si = ai >> @intCast(S, (N - 1)); | 25 | const si = ai >> @intCast(S, (N - 1)); |
| 25 | ai = ((ai ^ si) -% si); | 26 | ai = ((ai ^ si) -% si); |
| 26 | var a = @bitCast(Z, ai); | 27 | var a = @bitCast(Z, ai); |
| ... | @@ -66,7 +67,7 @@ fn __floatXisf(comptime T: type, arg: T) f32 { | ... | @@ -66,7 +67,7 @@ fn __floatXisf(comptime T: type, arg: T) f32 { |
| 66 | // a is now rounded to FLT_MANT_DIG bits | 67 | // a is now rounded to FLT_MANT_DIG bits |
| 67 | } | 68 | } |
| 68 | 69 | ||
| 69 | const s = @bitCast(Z, arg) >> (T.bit_count - 32); | 70 | const s = @bitCast(Z, arg) >> (@typeInfo(T).Int.bits - 32); |
| 70 | const r = (@intCast(u32, s) & 0x80000000) | // sign | 71 | const r = (@intCast(u32, s) & 0x80000000) | // sign |
| 71 | (@intCast(u32, (e + 127)) << 23) | // exponent | 72 | (@intCast(u32, (e + 127)) << 23) | // exponent |
| 72 | (@truncate(u32, a) & 0x007fffff); // mantissa-high | 73 | (@truncate(u32, a) & 0x007fffff); // mantissa-high |
lib/std/special/compiler_rt/floatsiXf.zig+4-3| ... | @@ -10,8 +10,9 @@ const maxInt = std.math.maxInt; | ... | @@ -10,8 +10,9 @@ const maxInt = std.math.maxInt; |
| 10 | fn floatsiXf(comptime T: type, a: i32) T { | 10 | fn floatsiXf(comptime T: type, a: i32) T { |
| 11 | @setRuntimeSafety(builtin.is_test); | 11 | @setRuntimeSafety(builtin.is_test); |
| 12 | 12 | ||
| 13 | const Z = std.meta.Int(false, T.bit_count); | 13 | const bits = @typeInfo(T).Float.bits; |
| 14 | const S = std.meta.Int(false, T.bit_count - @clz(Z, @as(Z, T.bit_count) - 1)); | 14 | const Z = std.meta.Int(false, bits); |
| 15 | const S = std.meta.Int(false, bits - @clz(Z, @as(Z, bits) - 1)); | ||
| 15 | 16 | ||
| 16 | if (a == 0) { | 17 | if (a == 0) { |
| 17 | return @as(T, 0.0); | 18 | return @as(T, 0.0); |
| ... | @@ -22,7 +23,7 @@ fn floatsiXf(comptime T: type, a: i32) T { | ... | @@ -22,7 +23,7 @@ fn floatsiXf(comptime T: type, a: i32) T { |
| 22 | const exponentBias = ((1 << exponentBits - 1) - 1); | 23 | const exponentBias = ((1 << exponentBits - 1) - 1); |
| 23 | 24 | ||
| 24 | const implicitBit = @as(Z, 1) << significandBits; | 25 | const implicitBit = @as(Z, 1) << significandBits; |
| 25 | const signBit = @as(Z, 1 << Z.bit_count - 1); | 26 | const signBit = @as(Z, 1 << bits - 1); |
| 26 | 27 | ||
| 27 | const sign = a >> 31; | 28 | const sign = a >> 31; |
| 28 | // Take absolute value of a via abs(x) = (x^(x >> 31)) - (x >> 31). | 29 | // Take absolute value of a via abs(x) = (x^(x >> 31)) - (x >> 31). |
lib/std/special/compiler_rt/floatundisf.zig+1-1| ... | @@ -15,7 +15,7 @@ pub fn __floatundisf(arg: u64) callconv(.C) f32 { | ... | @@ -15,7 +15,7 @@ pub fn __floatundisf(arg: u64) callconv(.C) f32 { |
| 15 | if (arg == 0) return 0; | 15 | if (arg == 0) return 0; |
| 16 | 16 | ||
| 17 | var a = arg; | 17 | var a = arg; |
| 18 | const N: usize = @TypeOf(a).bit_count; | 18 | const N: usize = @typeInfo(@TypeOf(a)).Int.bits; |
| 19 | // Number of significant digits | 19 | // Number of significant digits |
| 20 | const sd = N - @clz(u64, a); | 20 | const sd = N - @clz(u64, a); |
| 21 | // 8 exponent | 21 | // 8 exponent |
lib/std/special/compiler_rt/floatunditf.zig+1-1| ... | @@ -19,7 +19,7 @@ pub fn __floatunditf(a: u64) callconv(.C) f128 { | ... | @@ -19,7 +19,7 @@ pub fn __floatunditf(a: u64) callconv(.C) f128 { |
| 19 | const exponent_bias = (1 << (exponent_bits - 1)) - 1; | 19 | const exponent_bias = (1 << (exponent_bits - 1)) - 1; |
| 20 | const implicit_bit = 1 << mantissa_bits; | 20 | const implicit_bit = 1 << mantissa_bits; |
| 21 | 21 | ||
| 22 | const exp: u128 = (u64.bit_count - 1) - @clz(u64, a); | 22 | const exp: u128 = (64 - 1) - @clz(u64, a); |
| 23 | const shift: u7 = mantissa_bits - @intCast(u7, exp); | 23 | const shift: u7 = mantissa_bits - @intCast(u7, exp); |
| 24 | 24 | ||
| 25 | var result: u128 = (@intCast(u128, a) << shift) ^ implicit_bit; | 25 | var result: u128 = (@intCast(u128, a) << shift) ^ implicit_bit; |
lib/std/special/compiler_rt/floatunsitf.zig+1-1| ... | @@ -19,7 +19,7 @@ pub fn __floatunsitf(a: u64) callconv(.C) f128 { | ... | @@ -19,7 +19,7 @@ pub fn __floatunsitf(a: u64) callconv(.C) f128 { |
| 19 | const exponent_bias = (1 << (exponent_bits - 1)) - 1; | 19 | const exponent_bias = (1 << (exponent_bits - 1)) - 1; |
| 20 | const implicit_bit = 1 << mantissa_bits; | 20 | const implicit_bit = 1 << mantissa_bits; |
| 21 | 21 | ||
| 22 | const exp = (u64.bit_count - 1) - @clz(u64, a); | 22 | const exp = (64 - 1) - @clz(u64, a); |
| 23 | const shift = mantissa_bits - @intCast(u7, exp); | 23 | const shift = mantissa_bits - @intCast(u7, exp); |
| 24 | 24 | ||
| 25 | // TODO(#1148): @bitCast alignment error | 25 | // TODO(#1148): @bitCast alignment error |
lib/std/special/compiler_rt/int.zig+1-1| ... | @@ -219,7 +219,7 @@ fn test_one_divsi3(a: i32, b: i32, expected_q: i32) void { | ... | @@ -219,7 +219,7 @@ fn test_one_divsi3(a: i32, b: i32, expected_q: i32) void { |
| 219 | pub fn __udivsi3(n: u32, d: u32) callconv(.C) u32 { | 219 | pub fn __udivsi3(n: u32, d: u32) callconv(.C) u32 { |
| 220 | @setRuntimeSafety(builtin.is_test); | 220 | @setRuntimeSafety(builtin.is_test); |
| 221 | 221 | ||
| 222 | const n_uword_bits: c_uint = u32.bit_count; | 222 | const n_uword_bits: c_uint = 32; |
| 223 | // special cases | 223 | // special cases |
| 224 | if (d == 0) return 0; // ?! | 224 | if (d == 0) return 0; // ?! |
| 225 | if (n == 0) return 0; | 225 | if (n == 0) return 0; |
lib/std/special/compiler_rt/modti3.zig+2-2| ... | @@ -14,8 +14,8 @@ const compiler_rt = @import("../compiler_rt.zig"); | ... | @@ -14,8 +14,8 @@ const compiler_rt = @import("../compiler_rt.zig"); |
| 14 | pub fn __modti3(a: i128, b: i128) callconv(.C) i128 { | 14 | pub fn __modti3(a: i128, b: i128) callconv(.C) i128 { |
| 15 | @setRuntimeSafety(builtin.is_test); | 15 | @setRuntimeSafety(builtin.is_test); |
| 16 | 16 | ||
| 17 | const s_a = a >> (i128.bit_count - 1); // s = a < 0 ? -1 : 0 | 17 | const s_a = a >> (128 - 1); // s = a < 0 ? -1 : 0 |
| 18 | const s_b = b >> (i128.bit_count - 1); // s = b < 0 ? -1 : 0 | 18 | const s_b = b >> (128 - 1); // s = b < 0 ? -1 : 0 |
| 19 | 19 | ||
| 20 | const an = (a ^ s_a) -% s_a; // negate if s == -1 | 20 | const an = (a ^ s_a) -% s_a; // negate if s == -1 |
| 21 | const bn = (b ^ s_b) -% s_b; // negate if s == -1 | 21 | const bn = (b ^ s_b) -% s_b; // negate if s == -1 |
lib/std/special/compiler_rt/mulXf3.zig+5-5| ... | @@ -33,9 +33,9 @@ pub fn __aeabi_dmul(a: f64, b: f64) callconv(.C) f64 { | ... | @@ -33,9 +33,9 @@ pub fn __aeabi_dmul(a: f64, b: f64) callconv(.C) f64 { |
| 33 | 33 | ||
| 34 | fn mulXf3(comptime T: type, a: T, b: T) T { | 34 | fn mulXf3(comptime T: type, a: T, b: T) T { |
| 35 | @setRuntimeSafety(builtin.is_test); | 35 | @setRuntimeSafety(builtin.is_test); |
| 36 | const Z = std.meta.Int(false, T.bit_count); | 36 | const typeWidth = @typeInfo(T).Float.bits; |
| 37 | const Z = std.meta.Int(false, typeWidth); | ||
| 37 | 38 | ||
| 38 | const typeWidth = T.bit_count; | ||
| 39 | const significandBits = std.math.floatMantissaBits(T); | 39 | const significandBits = std.math.floatMantissaBits(T); |
| 40 | const exponentBits = std.math.floatExponentBits(T); | 40 | const exponentBits = std.math.floatExponentBits(T); |
| 41 | 41 | ||
| ... | @@ -269,9 +269,9 @@ fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { | ... | @@ -269,9 +269,9 @@ fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void { |
| 269 | } | 269 | } |
| 270 | } | 270 | } |
| 271 | 271 | ||
| 272 | fn normalize(comptime T: type, significand: *std.meta.Int(false, T.bit_count)) i32 { | 272 | fn normalize(comptime T: type, significand: *std.meta.Int(false, @typeInfo(T).Float.bits)) i32 { |
| 273 | @setRuntimeSafety(builtin.is_test); | 273 | @setRuntimeSafety(builtin.is_test); |
| 274 | const Z = std.meta.Int(false, T.bit_count); | 274 | const Z = std.meta.Int(false, @typeInfo(T).Float.bits); |
| 275 | const significandBits = std.math.floatMantissaBits(T); | 275 | const significandBits = std.math.floatMantissaBits(T); |
| 276 | const implicitBit = @as(Z, 1) << significandBits; | 276 | const implicitBit = @as(Z, 1) << significandBits; |
| 277 | 277 | ||
| ... | @@ -282,7 +282,7 @@ fn normalize(comptime T: type, significand: *std.meta.Int(false, T.bit_count)) i | ... | @@ -282,7 +282,7 @@ fn normalize(comptime T: type, significand: *std.meta.Int(false, T.bit_count)) i |
| 282 | 282 | ||
| 283 | fn wideRightShiftWithSticky(comptime Z: type, hi: *Z, lo: *Z, count: u32) void { | 283 | fn wideRightShiftWithSticky(comptime Z: type, hi: *Z, lo: *Z, count: u32) void { |
| 284 | @setRuntimeSafety(builtin.is_test); | 284 | @setRuntimeSafety(builtin.is_test); |
| 285 | const typeWidth = Z.bit_count; | 285 | const typeWidth = @typeInfo(Z).Int.bits; |
| 286 | const S = std.math.Log2Int(Z); | 286 | const S = std.math.Log2Int(Z); |
| 287 | if (count < typeWidth) { | 287 | if (count < typeWidth) { |
| 288 | const sticky = @truncate(u8, lo.* << @intCast(S, typeWidth -% count)); | 288 | const sticky = @truncate(u8, lo.* << @intCast(S, typeWidth -% count)); |
lib/std/special/compiler_rt/mulodi4.zig+1-1| ... | @@ -11,7 +11,7 @@ const minInt = std.math.minInt; | ... | @@ -11,7 +11,7 @@ const minInt = std.math.minInt; |
| 11 | pub fn __mulodi4(a: i64, b: i64, overflow: *c_int) callconv(.C) i64 { | 11 | pub fn __mulodi4(a: i64, b: i64, overflow: *c_int) callconv(.C) i64 { |
| 12 | @setRuntimeSafety(builtin.is_test); | 12 | @setRuntimeSafety(builtin.is_test); |
| 13 | 13 | ||
| 14 | const min = @bitCast(i64, @as(u64, 1 << (i64.bit_count - 1))); | 14 | const min = @bitCast(i64, @as(u64, 1 << (64 - 1))); |
| 15 | const max = ~min; | 15 | const max = ~min; |
| 16 | 16 | ||
| 17 | overflow.* = 0; | 17 | overflow.* = 0; |
lib/std/special/compiler_rt/muloti4.zig+3-3| ... | @@ -9,7 +9,7 @@ const compiler_rt = @import("../compiler_rt.zig"); | ... | @@ -9,7 +9,7 @@ const compiler_rt = @import("../compiler_rt.zig"); |
| 9 | pub fn __muloti4(a: i128, b: i128, overflow: *c_int) callconv(.C) i128 { | 9 | pub fn __muloti4(a: i128, b: i128, overflow: *c_int) callconv(.C) i128 { |
| 10 | @setRuntimeSafety(builtin.is_test); | 10 | @setRuntimeSafety(builtin.is_test); |
| 11 | 11 | ||
| 12 | const min = @bitCast(i128, @as(u128, 1 << (i128.bit_count - 1))); | 12 | const min = @bitCast(i128, @as(u128, 1 << (128 - 1))); |
| 13 | const max = ~min; | 13 | const max = ~min; |
| 14 | overflow.* = 0; | 14 | overflow.* = 0; |
| 15 | 15 | ||
| ... | @@ -27,9 +27,9 @@ pub fn __muloti4(a: i128, b: i128, overflow: *c_int) callconv(.C) i128 { | ... | @@ -27,9 +27,9 @@ pub fn __muloti4(a: i128, b: i128, overflow: *c_int) callconv(.C) i128 { |
| 27 | return r; | 27 | return r; |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | const sa = a >> (i128.bit_count - 1); | 30 | const sa = a >> (128 - 1); |
| 31 | const abs_a = (a ^ sa) -% sa; | 31 | const abs_a = (a ^ sa) -% sa; |
| 32 | const sb = b >> (i128.bit_count - 1); | 32 | const sb = b >> (128 - 1); |
| 33 | const abs_b = (b ^ sb) -% sb; | 33 | const abs_b = (b ^ sb) -% sb; |
| 34 | 34 | ||
| 35 | if (abs_a < 2 or abs_b < 2) { | 35 | if (abs_a < 2 or abs_b < 2) { |
lib/std/special/compiler_rt/negXf2.zig+1-2| ... | @@ -24,9 +24,8 @@ pub fn __aeabi_dneg(arg: f64) callconv(.AAPCS) f64 { | ... | @@ -24,9 +24,8 @@ pub fn __aeabi_dneg(arg: f64) callconv(.AAPCS) f64 { |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | fn negXf2(comptime T: type, a: T) T { | 26 | fn negXf2(comptime T: type, a: T) T { |
| 27 | const Z = std.meta.Int(false, T.bit_count); | 27 | const Z = std.meta.Int(false, @typeInfo(T).Float.bits); |
| 28 | 28 | ||
| 29 | const typeWidth = T.bit_count; | ||
| 30 | const significandBits = std.math.floatMantissaBits(T); | 29 | const significandBits = std.math.floatMantissaBits(T); |
| 31 | const exponentBits = std.math.floatExponentBits(T); | 30 | const exponentBits = std.math.floatExponentBits(T); |
| 32 | 31 |
lib/std/special/compiler_rt/shift.zig+13-12| ... | @@ -9,8 +9,9 @@ const Log2Int = std.math.Log2Int; | ... | @@ -9,8 +9,9 @@ const Log2Int = std.math.Log2Int; |
| 9 | 9 | ||
| 10 | fn Dwords(comptime T: type, comptime signed_half: bool) type { | 10 | fn Dwords(comptime T: type, comptime signed_half: bool) type { |
| 11 | return extern union { | 11 | return extern union { |
| 12 | pub const HalfTU = std.meta.Int(false, @divExact(T.bit_count, 2)); | 12 | pub const bits = @divExact(@typeInfo(T).Int.bits, 2); |
| 13 | pub const HalfTS = std.meta.Int(true, @divExact(T.bit_count, 2)); | 13 | pub const HalfTU = std.meta.Int(false, bits); |
| 14 | pub const HalfTS = std.meta.Int(true, bits); | ||
| 14 | pub const HalfT = if (signed_half) HalfTS else HalfTU; | 15 | pub const HalfT = if (signed_half) HalfTS else HalfTU; |
| 15 | 16 | ||
| 16 | all: T, | 17 | all: T, |
| ... | @@ -30,15 +31,15 @@ pub fn ashlXi3(comptime T: type, a: T, b: i32) T { | ... | @@ -30,15 +31,15 @@ pub fn ashlXi3(comptime T: type, a: T, b: i32) T { |
| 30 | const input = dwords{ .all = a }; | 31 | const input = dwords{ .all = a }; |
| 31 | var output: dwords = undefined; | 32 | var output: dwords = undefined; |
| 32 | 33 | ||
| 33 | if (b >= dwords.HalfT.bit_count) { | 34 | if (b >= dwords.bits) { |
| 34 | output.s.low = 0; | 35 | output.s.low = 0; |
| 35 | output.s.high = input.s.low << @intCast(S, b - dwords.HalfT.bit_count); | 36 | output.s.high = input.s.low << @intCast(S, b - dwords.bits); |
| 36 | } else if (b == 0) { | 37 | } else if (b == 0) { |
| 37 | return a; | 38 | return a; |
| 38 | } else { | 39 | } else { |
| 39 | output.s.low = input.s.low << @intCast(S, b); | 40 | output.s.low = input.s.low << @intCast(S, b); |
| 40 | output.s.high = input.s.high << @intCast(S, b); | 41 | output.s.high = input.s.high << @intCast(S, b); |
| 41 | output.s.high |= input.s.low >> @intCast(S, dwords.HalfT.bit_count - b); | 42 | output.s.high |= input.s.low >> @intCast(S, dwords.bits - b); |
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | return output.all; | 45 | return output.all; |
| ... | @@ -53,14 +54,14 @@ pub fn ashrXi3(comptime T: type, a: T, b: i32) T { | ... | @@ -53,14 +54,14 @@ pub fn ashrXi3(comptime T: type, a: T, b: i32) T { |
| 53 | const input = dwords{ .all = a }; | 54 | const input = dwords{ .all = a }; |
| 54 | var output: dwords = undefined; | 55 | var output: dwords = undefined; |
| 55 | 56 | ||
| 56 | if (b >= dwords.HalfT.bit_count) { | 57 | if (b >= dwords.bits) { |
| 57 | output.s.high = input.s.high >> (dwords.HalfT.bit_count - 1); | 58 | output.s.high = input.s.high >> (dwords.bits - 1); |
| 58 | output.s.low = input.s.high >> @intCast(S, b - dwords.HalfT.bit_count); | 59 | output.s.low = input.s.high >> @intCast(S, b - dwords.bits); |
| 59 | } else if (b == 0) { | 60 | } else if (b == 0) { |
| 60 | return a; | 61 | return a; |
| 61 | } else { | 62 | } else { |
| 62 | output.s.high = input.s.high >> @intCast(S, b); | 63 | output.s.high = input.s.high >> @intCast(S, b); |
| 63 | output.s.low = input.s.high << @intCast(S, dwords.HalfT.bit_count - b); | 64 | output.s.low = input.s.high << @intCast(S, dwords.bits - b); |
| 64 | // Avoid sign-extension here | 65 | // Avoid sign-extension here |
| 65 | output.s.low |= @bitCast( | 66 | output.s.low |= @bitCast( |
| 66 | dwords.HalfT, | 67 | dwords.HalfT, |
| ... | @@ -80,14 +81,14 @@ pub fn lshrXi3(comptime T: type, a: T, b: i32) T { | ... | @@ -80,14 +81,14 @@ pub fn lshrXi3(comptime T: type, a: T, b: i32) T { |
| 80 | const input = dwords{ .all = a }; | 81 | const input = dwords{ .all = a }; |
| 81 | var output: dwords = undefined; | 82 | var output: dwords = undefined; |
| 82 | 83 | ||
| 83 | if (b >= dwords.HalfT.bit_count) { | 84 | if (b >= dwords.bits) { |
| 84 | output.s.high = 0; | 85 | output.s.high = 0; |
| 85 | output.s.low = input.s.high >> @intCast(S, b - dwords.HalfT.bit_count); | 86 | output.s.low = input.s.high >> @intCast(S, b - dwords.bits); |
| 86 | } else if (b == 0) { | 87 | } else if (b == 0) { |
| 87 | return a; | 88 | return a; |
| 88 | } else { | 89 | } else { |
| 89 | output.s.high = input.s.high >> @intCast(S, b); | 90 | output.s.high = input.s.high >> @intCast(S, b); |
| 90 | output.s.low = input.s.high << @intCast(S, dwords.HalfT.bit_count - b); | 91 | output.s.low = input.s.high << @intCast(S, dwords.bits - b); |
| 91 | output.s.low |= input.s.low >> @intCast(S, b); | 92 | output.s.low |= input.s.low >> @intCast(S, b); |
| 92 | } | 93 | } |
| 93 | 94 |
lib/std/special/compiler_rt/truncXfYf2.zig+2-2| ... | @@ -50,7 +50,7 @@ fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t { | ... | @@ -50,7 +50,7 @@ fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t { |
| 50 | 50 | ||
| 51 | // Various constants whose values follow from the type parameters. | 51 | // Various constants whose values follow from the type parameters. |
| 52 | // Any reasonable optimizer will fold and propagate all of these. | 52 | // Any reasonable optimizer will fold and propagate all of these. |
| 53 | const srcBits = src_t.bit_count; | 53 | const srcBits = @typeInfo(src_t).Float.bits; |
| 54 | const srcExpBits = srcBits - srcSigBits - 1; | 54 | const srcExpBits = srcBits - srcSigBits - 1; |
| 55 | const srcInfExp = (1 << srcExpBits) - 1; | 55 | const srcInfExp = (1 << srcExpBits) - 1; |
| 56 | const srcExpBias = srcInfExp >> 1; | 56 | const srcExpBias = srcInfExp >> 1; |
| ... | @@ -65,7 +65,7 @@ fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t { | ... | @@ -65,7 +65,7 @@ fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t { |
| 65 | const srcQNaN = 1 << (srcSigBits - 1); | 65 | const srcQNaN = 1 << (srcSigBits - 1); |
| 66 | const srcNaNCode = srcQNaN - 1; | 66 | const srcNaNCode = srcQNaN - 1; |
| 67 | 67 | ||
| 68 | const dstBits = dst_t.bit_count; | 68 | const dstBits = @typeInfo(dst_t).Float.bits; |
| 69 | const dstExpBits = dstBits - dstSigBits - 1; | 69 | const dstExpBits = dstBits - dstSigBits - 1; |
| 70 | const dstInfExp = (1 << dstExpBits) - 1; | 70 | const dstInfExp = (1 << dstExpBits) - 1; |
| 71 | const dstExpBias = dstInfExp >> 1; | 71 | const dstExpBias = dstInfExp >> 1; |
lib/std/special/compiler_rt/udivmod.zig+36-34| ... | @@ -15,8 +15,10 @@ const high = 1 - low; | ... | @@ -15,8 +15,10 @@ const high = 1 - low; |
| 15 | pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: ?*DoubleInt) DoubleInt { | 15 | pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: ?*DoubleInt) DoubleInt { |
| 16 | @setRuntimeSafety(is_test); | 16 | @setRuntimeSafety(is_test); |
| 17 | 17 | ||
| 18 | const SingleInt = @import("std").meta.Int(false, @divExact(DoubleInt.bit_count, 2)); | 18 | const double_int_bits = @typeInfo(DoubleInt).Int.bits; |
| 19 | const SignedDoubleInt = @import("std").meta.Int(true, DoubleInt.bit_count); | 19 | const single_int_bits = @divExact(double_int_bits, 2); |
| 20 | const SingleInt = @import("std").meta.Int(false, single_int_bits); | ||
| 21 | const SignedDoubleInt = @import("std").meta.Int(true, double_int_bits); | ||
| 20 | const Log2SingleInt = @import("std").math.Log2Int(SingleInt); | 22 | const Log2SingleInt = @import("std").math.Log2Int(SingleInt); |
| 21 | 23 | ||
| 22 | const n = @ptrCast(*const [2]SingleInt, &a).*; // TODO issue #421 | 24 | const n = @ptrCast(*const [2]SingleInt, &a).*; // TODO issue #421 |
| ... | @@ -82,21 +84,21 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: | ... | @@ -82,21 +84,21 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: |
| 82 | // --- | 84 | // --- |
| 83 | // K 0 | 85 | // K 0 |
| 84 | sr = @bitCast(c_uint, @as(c_int, @clz(SingleInt, d[high])) - @as(c_int, @clz(SingleInt, n[high]))); | 86 | sr = @bitCast(c_uint, @as(c_int, @clz(SingleInt, d[high])) - @as(c_int, @clz(SingleInt, n[high]))); |
| 85 | // 0 <= sr <= SingleInt.bit_count - 2 or sr large | 87 | // 0 <= sr <= single_int_bits - 2 or sr large |
| 86 | if (sr > SingleInt.bit_count - 2) { | 88 | if (sr > single_int_bits - 2) { |
| 87 | if (maybe_rem) |rem| { | 89 | if (maybe_rem) |rem| { |
| 88 | rem.* = a; | 90 | rem.* = a; |
| 89 | } | 91 | } |
| 90 | return 0; | 92 | return 0; |
| 91 | } | 93 | } |
| 92 | sr += 1; | 94 | sr += 1; |
| 93 | // 1 <= sr <= SingleInt.bit_count - 1 | 95 | // 1 <= sr <= single_int_bits - 1 |
| 94 | // q.all = a << (DoubleInt.bit_count - sr); | 96 | // q.all = a << (double_int_bits - sr); |
| 95 | q[low] = 0; | 97 | q[low] = 0; |
| 96 | q[high] = n[low] << @intCast(Log2SingleInt, SingleInt.bit_count - sr); | 98 | q[high] = n[low] << @intCast(Log2SingleInt, single_int_bits - sr); |
| 97 | // r.all = a >> sr; | 99 | // r.all = a >> sr; |
| 98 | r[high] = n[high] >> @intCast(Log2SingleInt, sr); | 100 | r[high] = n[high] >> @intCast(Log2SingleInt, sr); |
| 99 | r[low] = (n[high] << @intCast(Log2SingleInt, SingleInt.bit_count - sr)) | (n[low] >> @intCast(Log2SingleInt, sr)); | 101 | r[low] = (n[high] << @intCast(Log2SingleInt, single_int_bits - sr)) | (n[low] >> @intCast(Log2SingleInt, sr)); |
| 100 | } else { | 102 | } else { |
| 101 | // d[low] != 0 | 103 | // d[low] != 0 |
| 102 | if (d[high] == 0) { | 104 | if (d[high] == 0) { |
| ... | @@ -113,74 +115,74 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: | ... | @@ -113,74 +115,74 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: |
| 113 | } | 115 | } |
| 114 | sr = @ctz(SingleInt, d[low]); | 116 | sr = @ctz(SingleInt, d[low]); |
| 115 | q[high] = n[high] >> @intCast(Log2SingleInt, sr); | 117 | q[high] = n[high] >> @intCast(Log2SingleInt, sr); |
| 116 | q[low] = (n[high] << @intCast(Log2SingleInt, SingleInt.bit_count - sr)) | (n[low] >> @intCast(Log2SingleInt, sr)); | 118 | q[low] = (n[high] << @intCast(Log2SingleInt, single_int_bits - sr)) | (n[low] >> @intCast(Log2SingleInt, sr)); |
| 117 | return @ptrCast(*align(@alignOf(SingleInt)) DoubleInt, &q[0]).*; // TODO issue #421 | 119 | return @ptrCast(*align(@alignOf(SingleInt)) DoubleInt, &q[0]).*; // TODO issue #421 |
| 118 | } | 120 | } |
| 119 | // K X | 121 | // K X |
| 120 | // --- | 122 | // --- |
| 121 | // 0 K | 123 | // 0 K |
| 122 | sr = 1 + SingleInt.bit_count + @as(c_uint, @clz(SingleInt, d[low])) - @as(c_uint, @clz(SingleInt, n[high])); | 124 | sr = 1 + single_int_bits + @as(c_uint, @clz(SingleInt, d[low])) - @as(c_uint, @clz(SingleInt, n[high])); |
| 123 | // 2 <= sr <= DoubleInt.bit_count - 1 | 125 | // 2 <= sr <= double_int_bits - 1 |
| 124 | // q.all = a << (DoubleInt.bit_count - sr); | 126 | // q.all = a << (double_int_bits - sr); |
| 125 | // r.all = a >> sr; | 127 | // r.all = a >> sr; |
| 126 | if (sr == SingleInt.bit_count) { | 128 | if (sr == single_int_bits) { |
| 127 | q[low] = 0; | 129 | q[low] = 0; |
| 128 | q[high] = n[low]; | 130 | q[high] = n[low]; |
| 129 | r[high] = 0; | 131 | r[high] = 0; |
| 130 | r[low] = n[high]; | 132 | r[low] = n[high]; |
| 131 | } else if (sr < SingleInt.bit_count) { | 133 | } else if (sr < single_int_bits) { |
| 132 | // 2 <= sr <= SingleInt.bit_count - 1 | 134 | // 2 <= sr <= single_int_bits - 1 |
| 133 | q[low] = 0; | 135 | q[low] = 0; |
| 134 | q[high] = n[low] << @intCast(Log2SingleInt, SingleInt.bit_count - sr); | 136 | q[high] = n[low] << @intCast(Log2SingleInt, single_int_bits - sr); |
| 135 | r[high] = n[high] >> @intCast(Log2SingleInt, sr); | 137 | r[high] = n[high] >> @intCast(Log2SingleInt, sr); |
| 136 | r[low] = (n[high] << @intCast(Log2SingleInt, SingleInt.bit_count - sr)) | (n[low] >> @intCast(Log2SingleInt, sr)); | 138 | r[low] = (n[high] << @intCast(Log2SingleInt, single_int_bits - sr)) | (n[low] >> @intCast(Log2SingleInt, sr)); |
| 137 | } else { | 139 | } else { |
| 138 | // SingleInt.bit_count + 1 <= sr <= DoubleInt.bit_count - 1 | 140 | // single_int_bits + 1 <= sr <= double_int_bits - 1 |
| 139 | q[low] = n[low] << @intCast(Log2SingleInt, DoubleInt.bit_count - sr); | 141 | q[low] = n[low] << @intCast(Log2SingleInt, double_int_bits - sr); |
| 140 | q[high] = (n[high] << @intCast(Log2SingleInt, DoubleInt.bit_count - sr)) | (n[low] >> @intCast(Log2SingleInt, sr - SingleInt.bit_count)); | 142 | q[high] = (n[high] << @intCast(Log2SingleInt, double_int_bits - sr)) | (n[low] >> @intCast(Log2SingleInt, sr - single_int_bits)); |
| 141 | r[high] = 0; | 143 | r[high] = 0; |
| 142 | r[low] = n[high] >> @intCast(Log2SingleInt, sr - SingleInt.bit_count); | 144 | r[low] = n[high] >> @intCast(Log2SingleInt, sr - single_int_bits); |
| 143 | } | 145 | } |
| 144 | } else { | 146 | } else { |
| 145 | // K X | 147 | // K X |
| 146 | // --- | 148 | // --- |
| 147 | // K K | 149 | // K K |
| 148 | sr = @bitCast(c_uint, @as(c_int, @clz(SingleInt, d[high])) - @as(c_int, @clz(SingleInt, n[high]))); | 150 | sr = @bitCast(c_uint, @as(c_int, @clz(SingleInt, d[high])) - @as(c_int, @clz(SingleInt, n[high]))); |
| 149 | // 0 <= sr <= SingleInt.bit_count - 1 or sr large | 151 | // 0 <= sr <= single_int_bits - 1 or sr large |
| 150 | if (sr > SingleInt.bit_count - 1) { | 152 | if (sr > single_int_bits - 1) { |
| 151 | if (maybe_rem) |rem| { | 153 | if (maybe_rem) |rem| { |
| 152 | rem.* = a; | 154 | rem.* = a; |
| 153 | } | 155 | } |
| 154 | return 0; | 156 | return 0; |
| 155 | } | 157 | } |
| 156 | sr += 1; | 158 | sr += 1; |
| 157 | // 1 <= sr <= SingleInt.bit_count | 159 | // 1 <= sr <= single_int_bits |
| 158 | // q.all = a << (DoubleInt.bit_count - sr); | 160 | // q.all = a << (double_int_bits - sr); |
| 159 | // r.all = a >> sr; | 161 | // r.all = a >> sr; |
| 160 | q[low] = 0; | 162 | q[low] = 0; |
| 161 | if (sr == SingleInt.bit_count) { | 163 | if (sr == single_int_bits) { |
| 162 | q[high] = n[low]; | 164 | q[high] = n[low]; |
| 163 | r[high] = 0; | 165 | r[high] = 0; |
| 164 | r[low] = n[high]; | 166 | r[low] = n[high]; |
| 165 | } else { | 167 | } else { |
| 166 | r[high] = n[high] >> @intCast(Log2SingleInt, sr); | 168 | r[high] = n[high] >> @intCast(Log2SingleInt, sr); |
| 167 | r[low] = (n[high] << @intCast(Log2SingleInt, SingleInt.bit_count - sr)) | (n[low] >> @intCast(Log2SingleInt, sr)); | 169 | r[low] = (n[high] << @intCast(Log2SingleInt, single_int_bits - sr)) | (n[low] >> @intCast(Log2SingleInt, sr)); |
| 168 | q[high] = n[low] << @intCast(Log2SingleInt, SingleInt.bit_count - sr); | 170 | q[high] = n[low] << @intCast(Log2SingleInt, single_int_bits - sr); |
| 169 | } | 171 | } |
| 170 | } | 172 | } |
| 171 | } | 173 | } |
| 172 | // Not a special case | 174 | // Not a special case |
| 173 | // q and r are initialized with: | 175 | // q and r are initialized with: |
| 174 | // q.all = a << (DoubleInt.bit_count - sr); | 176 | // q.all = a << (double_int_bits - sr); |
| 175 | // r.all = a >> sr; | 177 | // r.all = a >> sr; |
| 176 | // 1 <= sr <= DoubleInt.bit_count - 1 | 178 | // 1 <= sr <= double_int_bits - 1 |
| 177 | var carry: u32 = 0; | 179 | var carry: u32 = 0; |
| 178 | var r_all: DoubleInt = undefined; | 180 | var r_all: DoubleInt = undefined; |
| 179 | while (sr > 0) : (sr -= 1) { | 181 | while (sr > 0) : (sr -= 1) { |
| 180 | // r:q = ((r:q) << 1) | carry | 182 | // r:q = ((r:q) << 1) | carry |
| 181 | r[high] = (r[high] << 1) | (r[low] >> (SingleInt.bit_count - 1)); | 183 | r[high] = (r[high] << 1) | (r[low] >> (single_int_bits - 1)); |
| 182 | r[low] = (r[low] << 1) | (q[high] >> (SingleInt.bit_count - 1)); | 184 | r[low] = (r[low] << 1) | (q[high] >> (single_int_bits - 1)); |
| 183 | q[high] = (q[high] << 1) | (q[low] >> (SingleInt.bit_count - 1)); | 185 | q[high] = (q[high] << 1) | (q[low] >> (single_int_bits - 1)); |
| 184 | q[low] = (q[low] << 1) | carry; | 186 | q[low] = (q[low] << 1) | carry; |
| 185 | // carry = 0; | 187 | // carry = 0; |
| 186 | // if (r.all >= b) | 188 | // if (r.all >= b) |
| ... | @@ -189,7 +191,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: | ... | @@ -189,7 +191,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: |
| 189 | // carry = 1; | 191 | // carry = 1; |
| 190 | // } | 192 | // } |
| 191 | r_all = @ptrCast(*align(@alignOf(SingleInt)) DoubleInt, &r[0]).*; // TODO issue #421 | 193 | r_all = @ptrCast(*align(@alignOf(SingleInt)) DoubleInt, &r[0]).*; // TODO issue #421 |
| 192 | const s: SignedDoubleInt = @bitCast(SignedDoubleInt, b -% r_all -% 1) >> (DoubleInt.bit_count - 1); | 194 | const s: SignedDoubleInt = @bitCast(SignedDoubleInt, b -% r_all -% 1) >> (double_int_bits - 1); |
| 193 | carry = @intCast(u32, s & 1); | 195 | carry = @intCast(u32, s & 1); |
| 194 | r_all -= b & @bitCast(DoubleInt, s); | 196 | r_all -= b & @bitCast(DoubleInt, s); |
| 195 | r = @ptrCast(*[2]SingleInt, &r_all).*; // TODO issue #421 | 197 | r = @ptrCast(*[2]SingleInt, &r_all).*; // TODO issue #421 |
lib/std/start.zig+2-2| ... | @@ -67,7 +67,7 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv | ... | @@ -67,7 +67,7 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv |
| 67 | uefi.handle = handle; | 67 | uefi.handle = handle; |
| 68 | uefi.system_table = system_table; | 68 | uefi.system_table = system_table; |
| 69 | 69 | ||
| 70 | switch (@TypeOf(root.main).ReturnType) { | 70 | switch (@typeInfo(@TypeOf(root.main)).Fn.return_type.?) { |
| 71 | noreturn => { | 71 | noreturn => { |
| 72 | root.main(); | 72 | root.main(); |
| 73 | }, | 73 | }, |
| ... | @@ -239,7 +239,7 @@ fn callMainAsync(loop: *std.event.Loop) callconv(.Async) u8 { | ... | @@ -239,7 +239,7 @@ fn callMainAsync(loop: *std.event.Loop) callconv(.Async) u8 { |
| 239 | // This is not marked inline because it is called with @asyncCall when | 239 | // This is not marked inline because it is called with @asyncCall when |
| 240 | // there is an event loop. | 240 | // there is an event loop. |
| 241 | pub fn callMain() u8 { | 241 | pub fn callMain() u8 { |
| 242 | switch (@typeInfo(@TypeOf(root.main).ReturnType)) { | 242 | switch (@typeInfo(@typeInfo(@TypeOf(root.main)).Fn.return_type.?)) { |
| 243 | .NoReturn => { | 243 | .NoReturn => { |
| 244 | root.main(); | 244 | root.main(); |
| 245 | }, | 245 | }, |
lib/std/target.zig+58| ... | @@ -468,6 +468,7 @@ pub const Target = struct { | ... | @@ -468,6 +468,7 @@ pub const Target = struct { |
| 468 | /// TODO Get rid of this one. | 468 | /// TODO Get rid of this one. |
| 469 | unknown, | 469 | unknown, |
| 470 | coff, | 470 | coff, |
| 471 | pe, | ||
| 471 | elf, | 472 | elf, |
| 472 | macho, | 473 | macho, |
| 473 | wasm, | 474 | wasm, |
| ... | @@ -771,6 +772,63 @@ pub const Target = struct { | ... | @@ -771,6 +772,63 @@ pub const Target = struct { |
| 771 | }; | 772 | }; |
| 772 | } | 773 | } |
| 773 | 774 | ||
| 775 | pub fn toCoffMachine(arch: Arch) std.coff.MachineType { | ||
| 776 | return switch (arch) { | ||
| 777 | .avr => .Unknown, | ||
| 778 | .msp430 => .Unknown, | ||
| 779 | .arc => .Unknown, | ||
| 780 | .arm => .ARM, | ||
| 781 | .armeb => .Unknown, | ||
| 782 | .hexagon => .Unknown, | ||
| 783 | .le32 => .Unknown, | ||
| 784 | .mips => .Unknown, | ||
| 785 | .mipsel => .Unknown, | ||
| 786 | .powerpc => .POWERPC, | ||
| 787 | .r600 => .Unknown, | ||
| 788 | .riscv32 => .RISCV32, | ||
| 789 | .sparc => .Unknown, | ||
| 790 | .sparcel => .Unknown, | ||
| 791 | .tce => .Unknown, | ||
| 792 | .tcele => .Unknown, | ||
| 793 | .thumb => .Thumb, | ||
| 794 | .thumbeb => .Thumb, | ||
| 795 | .i386 => .I386, | ||
| 796 | .xcore => .Unknown, | ||
| 797 | .nvptx => .Unknown, | ||
| 798 | .amdil => .Unknown, | ||
| 799 | .hsail => .Unknown, | ||
| 800 | .spir => .Unknown, | ||
| 801 | .kalimba => .Unknown, | ||
| 802 | .shave => .Unknown, | ||
| 803 | .lanai => .Unknown, | ||
| 804 | .wasm32 => .Unknown, | ||
| 805 | .renderscript32 => .Unknown, | ||
| 806 | .aarch64_32 => .ARM64, | ||
| 807 | .aarch64 => .ARM64, | ||
| 808 | .aarch64_be => .Unknown, | ||
| 809 | .mips64 => .Unknown, | ||
| 810 | .mips64el => .Unknown, | ||
| 811 | .powerpc64 => .Unknown, | ||
| 812 | .powerpc64le => .Unknown, | ||
| 813 | .riscv64 => .RISCV64, | ||
| 814 | .x86_64 => .X64, | ||
| 815 | .nvptx64 => .Unknown, | ||
| 816 | .le64 => .Unknown, | ||
| 817 | .amdil64 => .Unknown, | ||
| 818 | .hsail64 => .Unknown, | ||
| 819 | .spir64 => .Unknown, | ||
| 820 | .wasm64 => .Unknown, | ||
| 821 | .renderscript64 => .Unknown, | ||
| 822 | .amdgcn => .Unknown, | ||
| 823 | .bpfel => .Unknown, | ||
| 824 | .bpfeb => .Unknown, | ||
| 825 | .sparcv9 => .Unknown, | ||
| 826 | .s390x => .Unknown, | ||
| 827 | .ve => .Unknown, | ||
| 828 | .spu_2 => .Unknown, | ||
| 829 | }; | ||
| 830 | } | ||
| 831 | |||
| 774 | pub fn endian(arch: Arch) builtin.Endian { | 832 | pub fn endian(arch: Arch) builtin.Endian { |
| 775 | return switch (arch) { | 833 | return switch (arch) { |
| 776 | .avr, | 834 | .avr, |
lib/std/thread.zig+3-3| ... | @@ -166,7 +166,7 @@ pub const Thread = struct { | ... | @@ -166,7 +166,7 @@ pub const Thread = struct { |
| 166 | fn threadMain(raw_arg: windows.LPVOID) callconv(.C) windows.DWORD { | 166 | fn threadMain(raw_arg: windows.LPVOID) callconv(.C) windows.DWORD { |
| 167 | const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*; | 167 | const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*; |
| 168 | 168 | ||
| 169 | switch (@typeInfo(@TypeOf(startFn).ReturnType)) { | 169 | switch (@typeInfo(@typeInfo(@TypeOf(startFn)).Fn.return_type.?)) { |
| 170 | .NoReturn => { | 170 | .NoReturn => { |
| 171 | startFn(arg); | 171 | startFn(arg); |
| 172 | }, | 172 | }, |
| ... | @@ -227,7 +227,7 @@ pub const Thread = struct { | ... | @@ -227,7 +227,7 @@ pub const Thread = struct { |
| 227 | fn linuxThreadMain(ctx_addr: usize) callconv(.C) u8 { | 227 | fn linuxThreadMain(ctx_addr: usize) callconv(.C) u8 { |
| 228 | const arg = if (@sizeOf(Context) == 0) {} else @intToPtr(*const Context, ctx_addr).*; | 228 | const arg = if (@sizeOf(Context) == 0) {} else @intToPtr(*const Context, ctx_addr).*; |
| 229 | 229 | ||
| 230 | switch (@typeInfo(@TypeOf(startFn).ReturnType)) { | 230 | switch (@typeInfo(@typeInfo(@TypeOf(startFn)).Fn.return_type.?)) { |
| 231 | .NoReturn => { | 231 | .NoReturn => { |
| 232 | startFn(arg); | 232 | startFn(arg); |
| 233 | }, | 233 | }, |
| ... | @@ -259,7 +259,7 @@ pub const Thread = struct { | ... | @@ -259,7 +259,7 @@ pub const Thread = struct { |
| 259 | fn posixThreadMain(ctx: ?*c_void) callconv(.C) ?*c_void { | 259 | fn posixThreadMain(ctx: ?*c_void) callconv(.C) ?*c_void { |
| 260 | const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), ctx)).*; | 260 | const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), ctx)).*; |
| 261 | 261 | ||
| 262 | switch (@typeInfo(@TypeOf(startFn).ReturnType)) { | 262 | switch (@typeInfo(@typeInfo(@TypeOf(startFn)).Fn.return_type.?)) { |
| 263 | .NoReturn => { | 263 | .NoReturn => { |
| 264 | startFn(arg); | 264 | startFn(arg); |
| 265 | }, | 265 | }, |
lib/std/zig.zig+1-1| ... | @@ -22,7 +22,7 @@ pub const SrcHash = [16]u8; | ... | @@ -22,7 +22,7 @@ pub const SrcHash = [16]u8; |
| 22 | /// If it is long, blake3 hash is computed. | 22 | /// If it is long, blake3 hash is computed. |
| 23 | pub fn hashSrc(src: []const u8) SrcHash { | 23 | pub fn hashSrc(src: []const u8) SrcHash { |
| 24 | var out: SrcHash = undefined; | 24 | var out: SrcHash = undefined; |
| 25 | if (src.len <= SrcHash.len) { | 25 | if (src.len <= @typeInfo(SrcHash).Array.len) { |
| 26 | std.mem.copy(u8, &out, src); | 26 | std.mem.copy(u8, &out, src); |
| 27 | std.mem.set(u8, out[src.len..], 0); | 27 | std.mem.set(u8, out[src.len..], 0); |
| 28 | } else { | 28 | } else { |
src-self-hosted/Module.zig+7| ... | @@ -626,6 +626,7 @@ pub const Scope = struct { | ... | @@ -626,6 +626,7 @@ pub const Scope = struct { |
| 626 | module.gpa, | 626 | module.gpa, |
| 627 | self.sub_file_path, | 627 | self.sub_file_path, |
| 628 | std.math.maxInt(u32), | 628 | std.math.maxInt(u32), |
| 629 | null, | ||
| 629 | 1, | 630 | 1, |
| 630 | 0, | 631 | 0, |
| 631 | ); | 632 | ); |
| ... | @@ -723,6 +724,7 @@ pub const Scope = struct { | ... | @@ -723,6 +724,7 @@ pub const Scope = struct { |
| 723 | module.gpa, | 724 | module.gpa, |
| 724 | self.sub_file_path, | 725 | self.sub_file_path, |
| 725 | std.math.maxInt(u32), | 726 | std.math.maxInt(u32), |
| 727 | null, | ||
| 726 | 1, | 728 | 1, |
| 727 | 0, | 729 | 0, |
| 728 | ); | 730 | ); |
| ... | @@ -1820,6 +1822,9 @@ fn analyzeContainer(self: *Module, container_scope: *Scope.Container) !void { | ... | @@ -1820,6 +1822,9 @@ fn analyzeContainer(self: *Module, container_scope: *Scope.Container) !void { |
| 1820 | try self.markOutdatedDecl(decl); | 1822 | try self.markOutdatedDecl(decl); |
| 1821 | decl.contents_hash = contents_hash; | 1823 | decl.contents_hash = contents_hash; |
| 1822 | } else switch (self.bin_file.tag) { | 1824 | } else switch (self.bin_file.tag) { |
| 1825 | .coff => { | ||
| 1826 | // TODO Implement for COFF | ||
| 1827 | }, | ||
| 1823 | .elf => if (decl.fn_link.elf.len != 0) { | 1828 | .elf => if (decl.fn_link.elf.len != 0) { |
| 1824 | // TODO Look into detecting when this would be unnecessary by storing enough state | 1829 | // TODO Look into detecting when this would be unnecessary by storing enough state |
| 1825 | // in `Decl` to notice that the line number did not change. | 1830 | // in `Decl` to notice that the line number did not change. |
| ... | @@ -2078,12 +2083,14 @@ fn allocateNewDecl( | ... | @@ -2078,12 +2083,14 @@ fn allocateNewDecl( |
| 2078 | .deletion_flag = false, | 2083 | .deletion_flag = false, |
| 2079 | .contents_hash = contents_hash, | 2084 | .contents_hash = contents_hash, |
| 2080 | .link = switch (self.bin_file.tag) { | 2085 | .link = switch (self.bin_file.tag) { |
| 2086 | .coff => .{ .coff = link.File.Coff.TextBlock.empty }, | ||
| 2081 | .elf => .{ .elf = link.File.Elf.TextBlock.empty }, | 2087 | .elf => .{ .elf = link.File.Elf.TextBlock.empty }, |
| 2082 | .macho => .{ .macho = link.File.MachO.TextBlock.empty }, | 2088 | .macho => .{ .macho = link.File.MachO.TextBlock.empty }, |
| 2083 | .c => .{ .c = {} }, | 2089 | .c => .{ .c = {} }, |
| 2084 | .wasm => .{ .wasm = {} }, | 2090 | .wasm => .{ .wasm = {} }, |
| 2085 | }, | 2091 | }, |
| 2086 | .fn_link = switch (self.bin_file.tag) { | 2092 | .fn_link = switch (self.bin_file.tag) { |
| 2093 | .coff => .{ .coff = {} }, | ||
| 2087 | .elf => .{ .elf = link.File.Elf.SrcFn.empty }, | 2094 | .elf => .{ .elf = link.File.Elf.SrcFn.empty }, |
| 2088 | .macho => .{ .macho = link.File.MachO.SrcFn.empty }, | 2095 | .macho => .{ .macho = link.File.MachO.SrcFn.empty }, |
| 2089 | .c => .{ .c = {} }, | 2096 | .c => .{ .c = {} }, |
src-self-hosted/codegen.zig+166-112| ... | @@ -59,14 +59,21 @@ pub const GenerateSymbolError = error{ | ... | @@ -59,14 +59,21 @@ pub const GenerateSymbolError = error{ |
| 59 | AnalysisFail, | 59 | AnalysisFail, |
| 60 | }; | 60 | }; |
| 61 | 61 | ||
| 62 | pub const DebugInfoOutput = union(enum) { | ||
| 63 | dwarf: struct { | ||
| 64 | dbg_line: *std.ArrayList(u8), | ||
| 65 | dbg_info: *std.ArrayList(u8), | ||
| 66 | dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable, | ||
| 67 | }, | ||
| 68 | none, | ||
| 69 | }; | ||
| 70 | |||
| 62 | pub fn generateSymbol( | 71 | pub fn generateSymbol( |
| 63 | bin_file: *link.File, | 72 | bin_file: *link.File, |
| 64 | src: usize, | 73 | src: usize, |
| 65 | typed_value: TypedValue, | 74 | typed_value: TypedValue, |
| 66 | code: *std.ArrayList(u8), | 75 | code: *std.ArrayList(u8), |
| 67 | dbg_line: *std.ArrayList(u8), | 76 | debug_output: DebugInfoOutput, |
| 68 | dbg_info: *std.ArrayList(u8), | ||
| 69 | dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable, | ||
| 70 | ) GenerateSymbolError!Result { | 77 | ) GenerateSymbolError!Result { |
| 71 | const tracy = trace(@src()); | 78 | const tracy = trace(@src()); |
| 72 | defer tracy.end(); | 79 | defer tracy.end(); |
| ... | @@ -76,56 +83,56 @@ pub fn generateSymbol( | ... | @@ -76,56 +83,56 @@ pub fn generateSymbol( |
| 76 | switch (bin_file.options.target.cpu.arch) { | 83 | switch (bin_file.options.target.cpu.arch) { |
| 77 | .wasm32 => unreachable, // has its own code path | 84 | .wasm32 => unreachable, // has its own code path |
| 78 | .wasm64 => unreachable, // has its own code path | 85 | .wasm64 => unreachable, // has its own code path |
| 79 | .arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 86 | .arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 80 | .armeb => return Function(.armeb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 87 | .armeb => return Function(.armeb).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 81 | //.aarch64 => return Function(.aarch64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 88 | //.aarch64 => return Function(.aarch64).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 82 | //.aarch64_be => return Function(.aarch64_be).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 89 | //.aarch64_be => return Function(.aarch64_be).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 83 | //.aarch64_32 => return Function(.aarch64_32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 90 | //.aarch64_32 => return Function(.aarch64_32).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 84 | //.arc => return Function(.arc).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 91 | //.arc => return Function(.arc).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 85 | //.avr => return Function(.avr).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 92 | //.avr => return Function(.avr).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 86 | //.bpfel => return Function(.bpfel).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 93 | //.bpfel => return Function(.bpfel).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 87 | //.bpfeb => return Function(.bpfeb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 94 | //.bpfeb => return Function(.bpfeb).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 88 | //.hexagon => return Function(.hexagon).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 95 | //.hexagon => return Function(.hexagon).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 89 | //.mips => return Function(.mips).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 96 | //.mips => return Function(.mips).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 90 | //.mipsel => return Function(.mipsel).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 97 | //.mipsel => return Function(.mipsel).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 91 | //.mips64 => return Function(.mips64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 98 | //.mips64 => return Function(.mips64).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 92 | //.mips64el => return Function(.mips64el).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 99 | //.mips64el => return Function(.mips64el).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 93 | //.msp430 => return Function(.msp430).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 100 | //.msp430 => return Function(.msp430).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 94 | //.powerpc => return Function(.powerpc).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 101 | //.powerpc => return Function(.powerpc).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 95 | //.powerpc64 => return Function(.powerpc64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 102 | //.powerpc64 => return Function(.powerpc64).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 96 | //.powerpc64le => return Function(.powerpc64le).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 103 | //.powerpc64le => return Function(.powerpc64le).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 97 | //.r600 => return Function(.r600).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 104 | //.r600 => return Function(.r600).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 98 | //.amdgcn => return Function(.amdgcn).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 105 | //.amdgcn => return Function(.amdgcn).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 99 | //.riscv32 => return Function(.riscv32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 106 | //.riscv32 => return Function(.riscv32).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 100 | .riscv64 => return Function(.riscv64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 107 | .riscv64 => return Function(.riscv64).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 101 | //.sparc => return Function(.sparc).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 108 | //.sparc => return Function(.sparc).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 102 | //.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 109 | //.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 103 | //.sparcel => return Function(.sparcel).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 110 | //.sparcel => return Function(.sparcel).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 104 | //.s390x => return Function(.s390x).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 111 | //.s390x => return Function(.s390x).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 105 | .spu_2 => return Function(.spu_2).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 112 | .spu_2 => return Function(.spu_2).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 106 | //.tce => return Function(.tce).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 113 | //.tce => return Function(.tce).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 107 | //.tcele => return Function(.tcele).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 114 | //.tcele => return Function(.tcele).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 108 | //.thumb => return Function(.thumb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 115 | //.thumb => return Function(.thumb).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 109 | //.thumbeb => return Function(.thumbeb).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 116 | //.thumbeb => return Function(.thumbeb).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 110 | //.i386 => return Function(.i386).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 117 | //.i386 => return Function(.i386).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 111 | .x86_64 => return Function(.x86_64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 118 | .x86_64 => return Function(.x86_64).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 112 | //.xcore => return Function(.xcore).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 119 | //.xcore => return Function(.xcore).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 113 | //.nvptx => return Function(.nvptx).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 120 | //.nvptx => return Function(.nvptx).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 114 | //.nvptx64 => return Function(.nvptx64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 121 | //.nvptx64 => return Function(.nvptx64).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 115 | //.le32 => return Function(.le32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 122 | //.le32 => return Function(.le32).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 116 | //.le64 => return Function(.le64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 123 | //.le64 => return Function(.le64).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 117 | //.amdil => return Function(.amdil).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 124 | //.amdil => return Function(.amdil).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 118 | //.amdil64 => return Function(.amdil64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 125 | //.amdil64 => return Function(.amdil64).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 119 | //.hsail => return Function(.hsail).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 126 | //.hsail => return Function(.hsail).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 120 | //.hsail64 => return Function(.hsail64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 127 | //.hsail64 => return Function(.hsail64).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 121 | //.spir => return Function(.spir).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 128 | //.spir => return Function(.spir).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 122 | //.spir64 => return Function(.spir64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 129 | //.spir64 => return Function(.spir64).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 123 | //.kalimba => return Function(.kalimba).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 130 | //.kalimba => return Function(.kalimba).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 124 | //.shave => return Function(.shave).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 131 | //.shave => return Function(.shave).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 125 | //.lanai => return Function(.lanai).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 132 | //.lanai => return Function(.lanai).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 126 | //.renderscript32 => return Function(.renderscript32).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 133 | //.renderscript32 => return Function(.renderscript32).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 127 | //.renderscript64 => return Function(.renderscript64).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 134 | //.renderscript64 => return Function(.renderscript64).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 128 | //.ve => return Function(.ve).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs), | 135 | //.ve => return Function(.ve).generateSymbol(bin_file, src, typed_value, code, debug_output), |
| 129 | else => @panic("Backend architectures that don't have good support yet are commented out, to improve compilation performance. If you are interested in one of these other backends feel free to uncomment them. Eventually these will be completed, but stage1 is slow and a memory hog."), | 136 | else => @panic("Backend architectures that don't have good support yet are commented out, to improve compilation performance. If you are interested in one of these other backends feel free to uncomment them. Eventually these will be completed, but stage1 is slow and a memory hog."), |
| 130 | } | 137 | } |
| 131 | }, | 138 | }, |
| ... | @@ -139,7 +146,7 @@ pub fn generateSymbol( | ... | @@ -139,7 +146,7 @@ pub fn generateSymbol( |
| 139 | switch (try generateSymbol(bin_file, src, .{ | 146 | switch (try generateSymbol(bin_file, src, .{ |
| 140 | .ty = typed_value.ty.elemType(), | 147 | .ty = typed_value.ty.elemType(), |
| 141 | .val = sentinel, | 148 | .val = sentinel, |
| 142 | }, code, dbg_line, dbg_info, dbg_info_type_relocs)) { | 149 | }, code, debug_output)) { |
| 143 | .appended => return Result{ .appended = {} }, | 150 | .appended => return Result{ .appended = {} }, |
| 144 | .externally_managed => |slice| { | 151 | .externally_managed => |slice| { |
| 145 | code.appendSliceAssumeCapacity(slice); | 152 | code.appendSliceAssumeCapacity(slice); |
| ... | @@ -239,9 +246,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -239,9 +246,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 239 | target: *const std.Target, | 246 | target: *const std.Target, |
| 240 | mod_fn: *const Module.Fn, | 247 | mod_fn: *const Module.Fn, |
| 241 | code: *std.ArrayList(u8), | 248 | code: *std.ArrayList(u8), |
| 242 | dbg_line: *std.ArrayList(u8), | 249 | debug_output: DebugInfoOutput, |
| 243 | dbg_info: *std.ArrayList(u8), | ||
| 244 | dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable, | ||
| 245 | err_msg: ?*ErrorMsg, | 250 | err_msg: ?*ErrorMsg, |
| 246 | args: []MCValue, | 251 | args: []MCValue, |
| 247 | ret_mcv: MCValue, | 252 | ret_mcv: MCValue, |
| ... | @@ -419,9 +424,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -419,9 +424,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 419 | src: usize, | 424 | src: usize, |
| 420 | typed_value: TypedValue, | 425 | typed_value: TypedValue, |
| 421 | code: *std.ArrayList(u8), | 426 | code: *std.ArrayList(u8), |
| 422 | dbg_line: *std.ArrayList(u8), | 427 | debug_output: DebugInfoOutput, |
| 423 | dbg_info: *std.ArrayList(u8), | ||
| 424 | dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable, | ||
| 425 | ) GenerateSymbolError!Result { | 428 | ) GenerateSymbolError!Result { |
| 426 | const module_fn = typed_value.val.cast(Value.Payload.Function).?.func; | 429 | const module_fn = typed_value.val.cast(Value.Payload.Function).?.func; |
| 427 | 430 | ||
| ... | @@ -457,9 +460,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -457,9 +460,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 457 | .bin_file = bin_file, | 460 | .bin_file = bin_file, |
| 458 | .mod_fn = module_fn, | 461 | .mod_fn = module_fn, |
| 459 | .code = code, | 462 | .code = code, |
| 460 | .dbg_line = dbg_line, | 463 | .debug_output = debug_output, |
| 461 | .dbg_info = dbg_info, | ||
| 462 | .dbg_info_type_relocs = dbg_info_type_relocs, | ||
| 463 | .err_msg = null, | 464 | .err_msg = null, |
| 464 | .args = undefined, // populated after `resolveCallingConventionValues` | 465 | .args = undefined, // populated after `resolveCallingConventionValues` |
| 465 | .ret_mcv = undefined, // populated after `resolveCallingConventionValues` | 466 | .ret_mcv = undefined, // populated after `resolveCallingConventionValues` |
| ... | @@ -598,35 +599,50 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -598,35 +599,50 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 598 | } | 599 | } |
| 599 | 600 | ||
| 600 | fn dbgSetPrologueEnd(self: *Self) InnerError!void { | 601 | fn dbgSetPrologueEnd(self: *Self) InnerError!void { |
| 601 | try self.dbg_line.append(DW.LNS_set_prologue_end); | 602 | switch (self.debug_output) { |
| 602 | try self.dbgAdvancePCAndLine(self.prev_di_src); | 603 | .dwarf => |dbg_out| { |
| 604 | try dbg_out.dbg_line.append(DW.LNS_set_prologue_end); | ||
| 605 | try self.dbgAdvancePCAndLine(self.prev_di_src); | ||
| 606 | }, | ||
| 607 | .none => {}, | ||
| 608 | } | ||
| 603 | } | 609 | } |
| 604 | 610 | ||
| 605 | fn dbgSetEpilogueBegin(self: *Self) InnerError!void { | 611 | fn dbgSetEpilogueBegin(self: *Self) InnerError!void { |
| 606 | try self.dbg_line.append(DW.LNS_set_epilogue_begin); | 612 | switch (self.debug_output) { |
| 607 | try self.dbgAdvancePCAndLine(self.prev_di_src); | 613 | .dwarf => |dbg_out| { |
| 614 | try dbg_out.dbg_line.append(DW.LNS_set_epilogue_begin); | ||
| 615 | try self.dbgAdvancePCAndLine(self.prev_di_src); | ||
| 616 | }, | ||
| 617 | .none => {}, | ||
| 618 | } | ||
| 608 | } | 619 | } |
| 609 | 620 | ||
| 610 | fn dbgAdvancePCAndLine(self: *Self, src: usize) InnerError!void { | 621 | fn dbgAdvancePCAndLine(self: *Self, src: usize) InnerError!void { |
| 611 | // TODO Look into improving the performance here by adding a token-index-to-line | ||
| 612 | // lookup table, and changing ir.Inst from storing byte offset to token. Currently | ||
| 613 | // this involves scanning over the source code for newlines | ||
| 614 | // (but only from the previous byte offset to the new one). | ||
| 615 | const delta_line = std.zig.lineDelta(self.source, self.prev_di_src, src); | ||
| 616 | const delta_pc = self.code.items.len - self.prev_di_pc; | ||
| 617 | self.prev_di_src = src; | 622 | self.prev_di_src = src; |
| 618 | self.prev_di_pc = self.code.items.len; | 623 | self.prev_di_pc = self.code.items.len; |
| 619 | // TODO Look into using the DWARF special opcodes to compress this data. It lets you emit | 624 | switch (self.debug_output) { |
| 620 | // single-byte opcodes that add different numbers to both the PC and the line number | 625 | .dwarf => |dbg_out| { |
| 621 | // at the same time. | 626 | // TODO Look into improving the performance here by adding a token-index-to-line |
| 622 | try self.dbg_line.ensureCapacity(self.dbg_line.items.len + 11); | 627 | // lookup table, and changing ir.Inst from storing byte offset to token. Currently |
| 623 | self.dbg_line.appendAssumeCapacity(DW.LNS_advance_pc); | 628 | // this involves scanning over the source code for newlines |
| 624 | leb128.writeULEB128(self.dbg_line.writer(), delta_pc) catch unreachable; | 629 | // (but only from the previous byte offset to the new one). |
| 625 | if (delta_line != 0) { | 630 | const delta_line = std.zig.lineDelta(self.source, self.prev_di_src, src); |
| 626 | self.dbg_line.appendAssumeCapacity(DW.LNS_advance_line); | 631 | const delta_pc = self.code.items.len - self.prev_di_pc; |
| 627 | leb128.writeILEB128(self.dbg_line.writer(), delta_line) catch unreachable; | 632 | // TODO Look into using the DWARF special opcodes to compress this data. It lets you emit |
| 633 | // single-byte opcodes that add different numbers to both the PC and the line number | ||
| 634 | // at the same time. | ||
| 635 | try dbg_out.dbg_line.ensureCapacity(dbg_out.dbg_line.items.len + 11); | ||
| 636 | dbg_out.dbg_line.appendAssumeCapacity(DW.LNS_advance_pc); | ||
| 637 | leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable; | ||
| 638 | if (delta_line != 0) { | ||
| 639 | dbg_out.dbg_line.appendAssumeCapacity(DW.LNS_advance_line); | ||
| 640 | leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable; | ||
| 641 | } | ||
| 642 | dbg_out.dbg_line.appendAssumeCapacity(DW.LNS_copy); | ||
| 643 | }, | ||
| 644 | .none => {}, | ||
| 628 | } | 645 | } |
| 629 | self.dbg_line.appendAssumeCapacity(DW.LNS_copy); | ||
| 630 | } | 646 | } |
| 631 | 647 | ||
| 632 | /// Asserts there is already capacity to insert into top branch inst_table. | 648 | /// Asserts there is already capacity to insert into top branch inst_table. |
| ... | @@ -654,18 +670,23 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -654,18 +670,23 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 654 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, | 670 | /// Adds a Type to the .debug_info at the current position. The bytes will be populated later, |
| 655 | /// after codegen for this symbol is done. | 671 | /// after codegen for this symbol is done. |
| 656 | fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void { | 672 | fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void { |
| 657 | assert(ty.hasCodeGenBits()); | 673 | switch (self.debug_output) { |
| 658 | const index = self.dbg_info.items.len; | 674 | .dwarf => |dbg_out| { |
| 659 | try self.dbg_info.resize(index + 4); // DW.AT_type, DW.FORM_ref4 | 675 | assert(ty.hasCodeGenBits()); |
| 660 | 676 | const index = dbg_out.dbg_info.items.len; | |
| 661 | const gop = try self.dbg_info_type_relocs.getOrPut(self.gpa, ty); | 677 | try dbg_out.dbg_info.resize(index + 4); // DW.AT_type, DW.FORM_ref4 |
| 662 | if (!gop.found_existing) { | 678 | |
| 663 | gop.entry.value = .{ | 679 | const gop = try dbg_out.dbg_info_type_relocs.getOrPut(self.gpa, ty); |
| 664 | .off = undefined, | 680 | if (!gop.found_existing) { |
| 665 | .relocs = .{}, | 681 | gop.entry.value = .{ |
| 666 | }; | 682 | .off = undefined, |
| 683 | .relocs = .{}, | ||
| 684 | }; | ||
| 685 | } | ||
| 686 | try gop.entry.value.relocs.append(self.gpa, @intCast(u32, index)); | ||
| 687 | }, | ||
| 688 | .none => {}, | ||
| 667 | } | 689 | } |
| 668 | try gop.entry.value.relocs.append(self.gpa, @intCast(u32, index)); | ||
| 669 | } | 690 | } |
| 670 | 691 | ||
| 671 | fn genFuncInst(self: *Self, inst: *ir.Inst) !MCValue { | 692 | fn genFuncInst(self: *Self, inst: *ir.Inst) !MCValue { |
| ... | @@ -1258,14 +1279,19 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1258,14 +1279,19 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1258 | self.registers.putAssumeCapacityNoClobber(toCanonicalReg(reg), &inst.base); | 1279 | self.registers.putAssumeCapacityNoClobber(toCanonicalReg(reg), &inst.base); |
| 1259 | self.markRegUsed(reg); | 1280 | self.markRegUsed(reg); |
| 1260 | 1281 | ||
| 1261 | try self.dbg_info.ensureCapacity(self.dbg_info.items.len + 8 + name_with_null.len); | 1282 | switch (self.debug_output) { |
| 1262 | self.dbg_info.appendAssumeCapacity(link.File.Elf.abbrev_parameter); | 1283 | .dwarf => |dbg_out| { |
| 1263 | self.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT_location, DW.FORM_exprloc | 1284 | try dbg_out.dbg_info.ensureCapacity(dbg_out.dbg_info.items.len + 8 + name_with_null.len); |
| 1264 | 1, // ULEB128 dwarf expression length | 1285 | dbg_out.dbg_info.appendAssumeCapacity(link.File.Elf.abbrev_parameter); |
| 1265 | reg.dwarfLocOp(), | 1286 | dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT_location, DW.FORM_exprloc |
| 1266 | }); | 1287 | 1, // ULEB128 dwarf expression length |
| 1267 | try self.addDbgInfoTypeReloc(inst.base.ty); // DW.AT_type, DW.FORM_ref4 | 1288 | reg.dwarfLocOp(), |
| 1268 | self.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT_name, DW.FORM_string | 1289 | }); |
| 1290 | try self.addDbgInfoTypeReloc(inst.base.ty); // DW.AT_type, DW.FORM_ref4 | ||
| 1291 | dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT_name, DW.FORM_string | ||
| 1292 | }, | ||
| 1293 | .none => {}, | ||
| 1294 | } | ||
| 1269 | }, | 1295 | }, |
| 1270 | else => {}, | 1296 | else => {}, |
| 1271 | } | 1297 | } |
| ... | @@ -1302,7 +1328,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1302,7 +1328,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1302 | 1328 | ||
| 1303 | // Due to incremental compilation, how function calls are generated depends | 1329 | // Due to incremental compilation, how function calls are generated depends |
| 1304 | // on linking. | 1330 | // on linking. |
| 1305 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | 1331 | if (self.bin_file.tag == link.File.Elf.base_tag or self.bin_file.tag == link.File.Coff.base_tag) { |
| 1306 | switch (arch) { | 1332 | switch (arch) { |
| 1307 | .x86_64 => { | 1333 | .x86_64 => { |
| 1308 | for (info.args) |mc_arg, arg_i| { | 1334 | for (info.args) |mc_arg, arg_i| { |
| ... | @@ -1341,10 +1367,17 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1341,10 +1367,17 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1341 | if (inst.func.cast(ir.Inst.Constant)) |func_inst| { | 1367 | if (inst.func.cast(ir.Inst.Constant)) |func_inst| { |
| 1342 | if (func_inst.val.cast(Value.Payload.Function)) |func_val| { | 1368 | if (func_inst.val.cast(Value.Payload.Function)) |func_val| { |
| 1343 | const func = func_val.func; | 1369 | const func = func_val.func; |
| 1344 | const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; | 1370 | |
| 1345 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | 1371 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| 1346 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | 1372 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); |
| 1347 | const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes); | 1373 | const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: { |
| 1374 | const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; | ||
| 1375 | break :blk @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes); | ||
| 1376 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| | ||
| 1377 | @intCast(u32, coff_file.offset_table_virtual_address + func.owner_decl.link.coff.offset_table_index * ptr_bytes) | ||
| 1378 | else | ||
| 1379 | unreachable; | ||
| 1380 | |||
| 1348 | // ff 14 25 xx xx xx xx call [addr] | 1381 | // ff 14 25 xx xx xx xx call [addr] |
| 1349 | try self.code.ensureCapacity(self.code.items.len + 7); | 1382 | try self.code.ensureCapacity(self.code.items.len + 7); |
| 1350 | self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 }); | 1383 | self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 }); |
| ... | @@ -1362,10 +1395,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1362,10 +1395,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1362 | if (inst.func.cast(ir.Inst.Constant)) |func_inst| { | 1395 | if (inst.func.cast(ir.Inst.Constant)) |func_inst| { |
| 1363 | if (func_inst.val.cast(Value.Payload.Function)) |func_val| { | 1396 | if (func_inst.val.cast(Value.Payload.Function)) |func_val| { |
| 1364 | const func = func_val.func; | 1397 | const func = func_val.func; |
| 1365 | const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; | 1398 | |
| 1366 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | 1399 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| 1367 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | 1400 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); |
| 1368 | const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes); | 1401 | const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: { |
| 1402 | const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; | ||
| 1403 | break :blk @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes); | ||
| 1404 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| | ||
| 1405 | coff_file.offset_table_virtual_address + func.owner_decl.link.coff.offset_table_index * ptr_bytes | ||
| 1406 | else | ||
| 1407 | unreachable; | ||
| 1369 | 1408 | ||
| 1370 | try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr }); | 1409 | try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr }); |
| 1371 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32()); | 1410 | mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32()); |
| ... | @@ -1383,8 +1422,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1383,8 +1422,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1383 | } | 1422 | } |
| 1384 | if (func_inst.val.cast(Value.Payload.Function)) |func_val| { | 1423 | if (func_inst.val.cast(Value.Payload.Function)) |func_val| { |
| 1385 | const func = func_val.func; | 1424 | const func = func_val.func; |
| 1386 | const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; | 1425 | const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: { |
| 1387 | const got_addr = @intCast(u16, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * 2); | 1426 | const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; |
| 1427 | break :blk @intCast(u16, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * 2); | ||
| 1428 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| | ||
| 1429 | @intCast(u16, coff_file.offset_table_virtual_address + func.owner_decl.link.coff.offset_table_index * 2) | ||
| 1430 | else | ||
| 1431 | unreachable; | ||
| 1432 | |||
| 1388 | const return_type = func.owner_decl.typed_value.most_recent.typed_value.ty.fnReturnType(); | 1433 | const return_type = func.owner_decl.typed_value.most_recent.typed_value.ty.fnReturnType(); |
| 1389 | // First, push the return address, then jump; if noreturn, don't bother with the first step | 1434 | // First, push the return address, then jump; if noreturn, don't bother with the first step |
| 1390 | // TODO: implement packed struct -> u16 at comptime and move the bitcast here | 1435 | // TODO: implement packed struct -> u16 at comptime and move the bitcast here |
| ... | @@ -1420,10 +1465,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1420,10 +1465,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1420 | if (inst.func.cast(ir.Inst.Constant)) |func_inst| { | 1465 | if (inst.func.cast(ir.Inst.Constant)) |func_inst| { |
| 1421 | if (func_inst.val.cast(Value.Payload.Function)) |func_val| { | 1466 | if (func_inst.val.cast(Value.Payload.Function)) |func_val| { |
| 1422 | const func = func_val.func; | 1467 | const func = func_val.func; |
| 1423 | const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; | ||
| 1424 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | 1468 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); |
| 1425 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | 1469 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); |
| 1426 | const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes); | 1470 | const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: { |
| 1471 | const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?]; | ||
| 1472 | break :blk @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes); | ||
| 1473 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| | ||
| 1474 | coff_file.offset_table_virtual_address + func.owner_decl.link.coff.offset_table_index * ptr_bytes | ||
| 1475 | else | ||
| 1476 | unreachable; | ||
| 1427 | 1477 | ||
| 1428 | // TODO only works with leaf functions | 1478 | // TODO only works with leaf functions |
| 1429 | // at the moment, which works fine for | 1479 | // at the moment, which works fine for |
| ... | @@ -1983,7 +2033,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1983,7 +2033,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1983 | 2033 | ||
| 1984 | if (mem.eql(u8, inst.asm_source, "syscall")) { | 2034 | if (mem.eql(u8, inst.asm_source, "syscall")) { |
| 1985 | try self.code.appendSlice(&[_]u8{ 0x0f, 0x05 }); | 2035 | try self.code.appendSlice(&[_]u8{ 0x0f, 0x05 }); |
| 1986 | } else { | 2036 | } else if (inst.asm_source.len != 0) { |
| 1987 | return self.fail(inst.base.src, "TODO implement support for more x86 assembly instructions", .{}); | 2037 | return self.fail(inst.base.src, "TODO implement support for more x86 assembly instructions", .{}); |
| 1988 | } | 2038 | } |
| 1989 | 2039 | ||
| ... | @@ -2541,6 +2591,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2541,6 +2591,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2541 | const got = &macho_file.sections.items[macho_file.got_section_index.?]; | 2591 | const got = &macho_file.sections.items[macho_file.got_section_index.?]; |
| 2542 | const got_addr = got.addr + decl.link.macho.offset_table_index.? * ptr_bytes; | 2592 | const got_addr = got.addr + decl.link.macho.offset_table_index.? * ptr_bytes; |
| 2543 | return MCValue{ .memory = got_addr }; | 2593 | return MCValue{ .memory = got_addr }; |
| 2594 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { | ||
| 2595 | const decl = payload.decl; | ||
| 2596 | const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes; | ||
| 2597 | return MCValue{ .memory = got_addr }; | ||
| 2544 | } else { | 2598 | } else { |
| 2545 | return self.fail(src, "TODO codegen non-ELF const Decl pointer", .{}); | 2599 | return self.fail(src, "TODO codegen non-ELF const Decl pointer", .{}); |
| 2546 | } | 2600 | } |
src-self-hosted/link.zig+20-2| ... | @@ -34,6 +34,7 @@ pub const File = struct { | ... | @@ -34,6 +34,7 @@ pub const File = struct { |
| 34 | 34 | ||
| 35 | pub const LinkBlock = union { | 35 | pub const LinkBlock = union { |
| 36 | elf: Elf.TextBlock, | 36 | elf: Elf.TextBlock, |
| 37 | coff: Coff.TextBlock, | ||
| 37 | macho: MachO.TextBlock, | 38 | macho: MachO.TextBlock, |
| 38 | c: void, | 39 | c: void, |
| 39 | wasm: void, | 40 | wasm: void, |
| ... | @@ -41,6 +42,7 @@ pub const File = struct { | ... | @@ -41,6 +42,7 @@ pub const File = struct { |
| 41 | 42 | ||
| 42 | pub const LinkFn = union { | 43 | pub const LinkFn = union { |
| 43 | elf: Elf.SrcFn, | 44 | elf: Elf.SrcFn, |
| 45 | coff: Coff.SrcFn, | ||
| 44 | macho: MachO.SrcFn, | 46 | macho: MachO.SrcFn, |
| 45 | c: void, | 47 | c: void, |
| 46 | wasm: ?Wasm.FnData, | 48 | wasm: ?Wasm.FnData, |
| ... | @@ -66,7 +68,7 @@ pub const File = struct { | ... | @@ -66,7 +68,7 @@ pub const File = struct { |
| 66 | pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: Options) !*File { | 68 | pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: Options) !*File { |
| 67 | switch (options.object_format) { | 69 | switch (options.object_format) { |
| 68 | .unknown => unreachable, | 70 | .unknown => unreachable, |
| 69 | .coff => return error.TODOImplementCoff, | 71 | .coff, .pe => return Coff.openPath(allocator, dir, sub_path, options), |
| 70 | .elf => return Elf.openPath(allocator, dir, sub_path, options), | 72 | .elf => return Elf.openPath(allocator, dir, sub_path, options), |
| 71 | .macho => return MachO.openPath(allocator, dir, sub_path, options), | 73 | .macho => return MachO.openPath(allocator, dir, sub_path, options), |
| 72 | .wasm => return Wasm.openPath(allocator, dir, sub_path, options), | 74 | .wasm => return Wasm.openPath(allocator, dir, sub_path, options), |
| ... | @@ -85,7 +87,7 @@ pub const File = struct { | ... | @@ -85,7 +87,7 @@ pub const File = struct { |
| 85 | 87 | ||
| 86 | pub fn makeWritable(base: *File, dir: fs.Dir, sub_path: []const u8) !void { | 88 | pub fn makeWritable(base: *File, dir: fs.Dir, sub_path: []const u8) !void { |
| 87 | switch (base.tag) { | 89 | switch (base.tag) { |
| 88 | .elf, .macho => { | 90 | .coff, .elf, .macho => { |
| 89 | if (base.file != null) return; | 91 | if (base.file != null) return; |
| 90 | base.file = try dir.createFile(sub_path, .{ | 92 | base.file = try dir.createFile(sub_path, .{ |
| 91 | .truncate = false, | 93 | .truncate = false, |
| ... | @@ -112,6 +114,7 @@ pub const File = struct { | ... | @@ -112,6 +114,7 @@ pub const File = struct { |
| 112 | /// after allocateDeclIndexes for any given Decl. | 114 | /// after allocateDeclIndexes for any given Decl. |
| 113 | pub fn updateDecl(base: *File, module: *Module, decl: *Module.Decl) !void { | 115 | pub fn updateDecl(base: *File, module: *Module, decl: *Module.Decl) !void { |
| 114 | switch (base.tag) { | 116 | switch (base.tag) { |
| 117 | .coff => return @fieldParentPtr(Coff, "base", base).updateDecl(module, decl), | ||
| 115 | .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl), | 118 | .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl), |
| 116 | .macho => return @fieldParentPtr(MachO, "base", base).updateDecl(module, decl), | 119 | .macho => return @fieldParentPtr(MachO, "base", base).updateDecl(module, decl), |
| 117 | .c => return @fieldParentPtr(C, "base", base).updateDecl(module, decl), | 120 | .c => return @fieldParentPtr(C, "base", base).updateDecl(module, decl), |
| ... | @@ -121,6 +124,7 @@ pub const File = struct { | ... | @@ -121,6 +124,7 @@ pub const File = struct { |
| 121 | 124 | ||
| 122 | pub fn updateDeclLineNumber(base: *File, module: *Module, decl: *Module.Decl) !void { | 125 | pub fn updateDeclLineNumber(base: *File, module: *Module, decl: *Module.Decl) !void { |
| 123 | switch (base.tag) { | 126 | switch (base.tag) { |
| 127 | .coff => return @fieldParentPtr(Coff, "base", base).updateDeclLineNumber(module, decl), | ||
| 124 | .elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl), | 128 | .elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl), |
| 125 | .macho => return @fieldParentPtr(MachO, "base", base).updateDeclLineNumber(module, decl), | 129 | .macho => return @fieldParentPtr(MachO, "base", base).updateDeclLineNumber(module, decl), |
| 126 | .c, .wasm => {}, | 130 | .c, .wasm => {}, |
| ... | @@ -131,6 +135,7 @@ pub const File = struct { | ... | @@ -131,6 +135,7 @@ pub const File = struct { |
| 131 | /// any given Decl. | 135 | /// any given Decl. |
| 132 | pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void { | 136 | pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void { |
| 133 | switch (base.tag) { | 137 | switch (base.tag) { |
| 138 | .coff => return @fieldParentPtr(Coff, "base", base).allocateDeclIndexes(decl), | ||
| 134 | .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl), | 139 | .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl), |
| 135 | .macho => return @fieldParentPtr(MachO, "base", base).allocateDeclIndexes(decl), | 140 | .macho => return @fieldParentPtr(MachO, "base", base).allocateDeclIndexes(decl), |
| 136 | .c, .wasm => {}, | 141 | .c, .wasm => {}, |
| ... | @@ -140,6 +145,7 @@ pub const File = struct { | ... | @@ -140,6 +145,7 @@ pub const File = struct { |
| 140 | pub fn deinit(base: *File) void { | 145 | pub fn deinit(base: *File) void { |
| 141 | if (base.file) |f| f.close(); | 146 | if (base.file) |f| f.close(); |
| 142 | switch (base.tag) { | 147 | switch (base.tag) { |
| 148 | .coff => @fieldParentPtr(Coff, "base", base).deinit(), | ||
| 143 | .elf => @fieldParentPtr(Elf, "base", base).deinit(), | 149 | .elf => @fieldParentPtr(Elf, "base", base).deinit(), |
| 144 | .macho => @fieldParentPtr(MachO, "base", base).deinit(), | 150 | .macho => @fieldParentPtr(MachO, "base", base).deinit(), |
| 145 | .c => @fieldParentPtr(C, "base", base).deinit(), | 151 | .c => @fieldParentPtr(C, "base", base).deinit(), |
| ... | @@ -149,6 +155,11 @@ pub const File = struct { | ... | @@ -149,6 +155,11 @@ pub const File = struct { |
| 149 | 155 | ||
| 150 | pub fn destroy(base: *File) void { | 156 | pub fn destroy(base: *File) void { |
| 151 | switch (base.tag) { | 157 | switch (base.tag) { |
| 158 | .coff => { | ||
| 159 | const parent = @fieldParentPtr(Coff, "base", base); | ||
| 160 | parent.deinit(); | ||
| 161 | base.allocator.destroy(parent); | ||
| 162 | }, | ||
| 152 | .elf => { | 163 | .elf => { |
| 153 | const parent = @fieldParentPtr(Elf, "base", base); | 164 | const parent = @fieldParentPtr(Elf, "base", base); |
| 154 | parent.deinit(); | 165 | parent.deinit(); |
| ... | @@ -177,6 +188,7 @@ pub const File = struct { | ... | @@ -177,6 +188,7 @@ pub const File = struct { |
| 177 | defer tracy.end(); | 188 | defer tracy.end(); |
| 178 | 189 | ||
| 179 | try switch (base.tag) { | 190 | try switch (base.tag) { |
| 191 | .coff => @fieldParentPtr(Coff, "base", base).flush(module), | ||
| 180 | .elf => @fieldParentPtr(Elf, "base", base).flush(module), | 192 | .elf => @fieldParentPtr(Elf, "base", base).flush(module), |
| 181 | .macho => @fieldParentPtr(MachO, "base", base).flush(module), | 193 | .macho => @fieldParentPtr(MachO, "base", base).flush(module), |
| 182 | .c => @fieldParentPtr(C, "base", base).flush(module), | 194 | .c => @fieldParentPtr(C, "base", base).flush(module), |
| ... | @@ -186,6 +198,7 @@ pub const File = struct { | ... | @@ -186,6 +198,7 @@ pub const File = struct { |
| 186 | 198 | ||
| 187 | pub fn freeDecl(base: *File, decl: *Module.Decl) void { | 199 | pub fn freeDecl(base: *File, decl: *Module.Decl) void { |
| 188 | switch (base.tag) { | 200 | switch (base.tag) { |
| 201 | .coff => @fieldParentPtr(Coff, "base", base).freeDecl(decl), | ||
| 189 | .elf => @fieldParentPtr(Elf, "base", base).freeDecl(decl), | 202 | .elf => @fieldParentPtr(Elf, "base", base).freeDecl(decl), |
| 190 | .macho => @fieldParentPtr(MachO, "base", base).freeDecl(decl), | 203 | .macho => @fieldParentPtr(MachO, "base", base).freeDecl(decl), |
| 191 | .c => unreachable, | 204 | .c => unreachable, |
| ... | @@ -195,6 +208,7 @@ pub const File = struct { | ... | @@ -195,6 +208,7 @@ pub const File = struct { |
| 195 | 208 | ||
| 196 | pub fn errorFlags(base: *File) ErrorFlags { | 209 | pub fn errorFlags(base: *File) ErrorFlags { |
| 197 | return switch (base.tag) { | 210 | return switch (base.tag) { |
| 211 | .coff => @fieldParentPtr(Coff, "base", base).error_flags, | ||
| 198 | .elf => @fieldParentPtr(Elf, "base", base).error_flags, | 212 | .elf => @fieldParentPtr(Elf, "base", base).error_flags, |
| 199 | .macho => @fieldParentPtr(MachO, "base", base).error_flags, | 213 | .macho => @fieldParentPtr(MachO, "base", base).error_flags, |
| 200 | .c => return .{ .no_entry_point_found = false }, | 214 | .c => return .{ .no_entry_point_found = false }, |
| ... | @@ -211,6 +225,7 @@ pub const File = struct { | ... | @@ -211,6 +225,7 @@ pub const File = struct { |
| 211 | exports: []const *Module.Export, | 225 | exports: []const *Module.Export, |
| 212 | ) !void { | 226 | ) !void { |
| 213 | switch (base.tag) { | 227 | switch (base.tag) { |
| 228 | .coff => return @fieldParentPtr(Coff, "base", base).updateDeclExports(module, decl, exports), | ||
| 214 | .elf => return @fieldParentPtr(Elf, "base", base).updateDeclExports(module, decl, exports), | 229 | .elf => return @fieldParentPtr(Elf, "base", base).updateDeclExports(module, decl, exports), |
| 215 | .macho => return @fieldParentPtr(MachO, "base", base).updateDeclExports(module, decl, exports), | 230 | .macho => return @fieldParentPtr(MachO, "base", base).updateDeclExports(module, decl, exports), |
| 216 | .c => return {}, | 231 | .c => return {}, |
| ... | @@ -220,6 +235,7 @@ pub const File = struct { | ... | @@ -220,6 +235,7 @@ pub const File = struct { |
| 220 | 235 | ||
| 221 | pub fn getDeclVAddr(base: *File, decl: *const Module.Decl) u64 { | 236 | pub fn getDeclVAddr(base: *File, decl: *const Module.Decl) u64 { |
| 222 | switch (base.tag) { | 237 | switch (base.tag) { |
| 238 | .coff => return @fieldParentPtr(Coff, "base", base).getDeclVAddr(decl), | ||
| 223 | .elf => return @fieldParentPtr(Elf, "base", base).getDeclVAddr(decl), | 239 | .elf => return @fieldParentPtr(Elf, "base", base).getDeclVAddr(decl), |
| 224 | .macho => return @fieldParentPtr(MachO, "base", base).getDeclVAddr(decl), | 240 | .macho => return @fieldParentPtr(MachO, "base", base).getDeclVAddr(decl), |
| 225 | .c => unreachable, | 241 | .c => unreachable, |
| ... | @@ -228,6 +244,7 @@ pub const File = struct { | ... | @@ -228,6 +244,7 @@ pub const File = struct { |
| 228 | } | 244 | } |
| 229 | 245 | ||
| 230 | pub const Tag = enum { | 246 | pub const Tag = enum { |
| 247 | coff, | ||
| 231 | elf, | 248 | elf, |
| 232 | macho, | 249 | macho, |
| 233 | c, | 250 | c, |
| ... | @@ -239,6 +256,7 @@ pub const File = struct { | ... | @@ -239,6 +256,7 @@ pub const File = struct { |
| 239 | }; | 256 | }; |
| 240 | 257 | ||
| 241 | pub const C = @import("link/C.zig"); | 258 | pub const C = @import("link/C.zig"); |
| 259 | pub const Coff = @import("link/Coff.zig"); | ||
| 242 | pub const Elf = @import("link/Elf.zig"); | 260 | pub const Elf = @import("link/Elf.zig"); |
| 243 | pub const MachO = @import("link/MachO.zig"); | 261 | pub const MachO = @import("link/MachO.zig"); |
| 244 | pub const Wasm = @import("link/Wasm.zig"); | 262 | pub const Wasm = @import("link/Wasm.zig"); |
src-self-hosted/link/Coff.zig created+792| ... | @@ -0,0 +1,792 @@ | ||
| 1 | const Coff = @This(); | ||
| 2 | |||
| 3 | const std = @import("std"); | ||
| 4 | const log = std.log.scoped(.link); | ||
| 5 | const Allocator = std.mem.Allocator; | ||
| 6 | const assert = std.debug.assert; | ||
| 7 | const fs = std.fs; | ||
| 8 | |||
| 9 | const trace = @import("../tracy.zig").trace; | ||
| 10 | const Module = @import("../Module.zig"); | ||
| 11 | const codegen = @import("../codegen.zig"); | ||
| 12 | const link = @import("../link.zig"); | ||
| 13 | |||
| 14 | const allocation_padding = 4 / 3; | ||
| 15 | const minimum_text_block_size = 64 * allocation_padding; | ||
| 16 | |||
| 17 | const section_alignment = 4096; | ||
| 18 | const file_alignment = 512; | ||
| 19 | const image_base = 0x400_000; | ||
| 20 | const section_table_size = 2 * 40; | ||
| 21 | comptime { | ||
| 22 | std.debug.assert(std.mem.isAligned(image_base, section_alignment)); | ||
| 23 | } | ||
| 24 | |||
| 25 | pub const base_tag: link.File.Tag = .coff; | ||
| 26 | |||
| 27 | const msdos_stub = @embedFile("msdos-stub.bin"); | ||
| 28 | |||
| 29 | base: link.File, | ||
| 30 | ptr_width: enum { p32, p64 }, | ||
| 31 | error_flags: link.File.ErrorFlags = .{}, | ||
| 32 | |||
| 33 | text_block_free_list: std.ArrayListUnmanaged(*TextBlock) = .{}, | ||
| 34 | last_text_block: ?*TextBlock = null, | ||
| 35 | |||
| 36 | /// Section table file pointer. | ||
| 37 | section_table_offset: u32 = 0, | ||
| 38 | /// Section data file pointer. | ||
| 39 | section_data_offset: u32 = 0, | ||
| 40 | /// Optiona header file pointer. | ||
| 41 | optional_header_offset: u32 = 0, | ||
| 42 | |||
| 43 | /// Absolute virtual address of the offset table when the executable is loaded in memory. | ||
| 44 | offset_table_virtual_address: u32 = 0, | ||
| 45 | /// Current size of the offset table on disk, must be a multiple of `file_alignment` | ||
| 46 | offset_table_size: u32 = 0, | ||
| 47 | /// Contains absolute virtual addresses | ||
| 48 | offset_table: std.ArrayListUnmanaged(u64) = .{}, | ||
| 49 | /// Free list of offset table indices | ||
| 50 | offset_table_free_list: std.ArrayListUnmanaged(u32) = .{}, | ||
| 51 | |||
| 52 | /// Virtual address of the entry point procedure relative to `image_base` | ||
| 53 | entry_addr: ?u32 = null, | ||
| 54 | |||
| 55 | /// Absolute virtual address of the text section when the executable is loaded in memory. | ||
| 56 | text_section_virtual_address: u32 = 0, | ||
| 57 | /// Current size of the `.text` section on disk, must be a multiple of `file_alignment` | ||
| 58 | text_section_size: u32 = 0, | ||
| 59 | |||
| 60 | offset_table_size_dirty: bool = false, | ||
| 61 | text_section_size_dirty: bool = false, | ||
| 62 | /// This flag is set when the virtual size of the whole image file when loaded in memory has changed | ||
| 63 | /// and needs to be updated in the optional header. | ||
| 64 | size_of_image_dirty: bool = false, | ||
| 65 | |||
| 66 | pub const TextBlock = struct { | ||
| 67 | /// Offset of the code relative to the start of the text section | ||
| 68 | text_offset: u32, | ||
| 69 | /// Used size of the text block | ||
| 70 | size: u32, | ||
| 71 | /// This field is undefined for symbols with size = 0. | ||
| 72 | offset_table_index: u32, | ||
| 73 | /// Points to the previous and next neighbors, based on the `text_offset`. | ||
| 74 | /// This can be used to find, for example, the capacity of this `TextBlock`. | ||
| 75 | prev: ?*TextBlock, | ||
| 76 | next: ?*TextBlock, | ||
| 77 | |||
| 78 | pub const empty = TextBlock{ | ||
| 79 | .text_offset = 0, | ||
| 80 | .size = 0, | ||
| 81 | .offset_table_index = undefined, | ||
| 82 | .prev = null, | ||
| 83 | .next = null, | ||
| 84 | }; | ||
| 85 | |||
| 86 | /// Returns how much room there is to grow in virtual address space. | ||
| 87 | fn capacity(self: TextBlock) u64 { | ||
| 88 | if (self.next) |next| { | ||
| 89 | return next.text_offset - self.text_offset; | ||
| 90 | } | ||
| 91 | // This is the last block, the capacity is only limited by the address space. | ||
| 92 | return std.math.maxInt(u32) - self.text_offset; | ||
| 93 | } | ||
| 94 | |||
| 95 | fn freeListEligible(self: TextBlock) bool { | ||
| 96 | // No need to keep a free list node for the last block. | ||
| 97 | const next = self.next orelse return false; | ||
| 98 | const cap = next.text_offset - self.text_offset; | ||
| 99 | const ideal_cap = self.size * allocation_padding; | ||
| 100 | if (cap <= ideal_cap) return false; | ||
| 101 | const surplus = cap - ideal_cap; | ||
| 102 | return surplus >= minimum_text_block_size; | ||
| 103 | } | ||
| 104 | |||
| 105 | /// Absolute virtual address of the text block when the file is loaded in memory. | ||
| 106 | fn getVAddr(self: TextBlock, coff: Coff) u32 { | ||
| 107 | return coff.text_section_virtual_address + self.text_offset; | ||
| 108 | } | ||
| 109 | }; | ||
| 110 | |||
| 111 | pub const SrcFn = void; | ||
| 112 | |||
| 113 | pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: link.Options) !*link.File { | ||
| 114 | assert(options.object_format == .coff); | ||
| 115 | |||
| 116 | const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = link.determineMode(options) }); | ||
| 117 | errdefer file.close(); | ||
| 118 | |||
| 119 | var coff_file = try allocator.create(Coff); | ||
| 120 | errdefer allocator.destroy(coff_file); | ||
| 121 | |||
| 122 | coff_file.* = openFile(allocator, file, options) catch |err| switch (err) { | ||
| 123 | error.IncrFailed => try createFile(allocator, file, options), | ||
| 124 | else => |e| return e, | ||
| 125 | }; | ||
| 126 | |||
| 127 | return &coff_file.base; | ||
| 128 | } | ||
| 129 | |||
| 130 | /// Returns error.IncrFailed if incremental update could not be performed. | ||
| 131 | fn openFile(allocator: *Allocator, file: fs.File, options: link.Options) !Coff { | ||
| 132 | switch (options.output_mode) { | ||
| 133 | .Exe => {}, | ||
| 134 | .Obj => return error.IncrFailed, | ||
| 135 | .Lib => return error.IncrFailed, | ||
| 136 | } | ||
| 137 | var self: Coff = .{ | ||
| 138 | .base = .{ | ||
| 139 | .file = file, | ||
| 140 | .tag = .coff, | ||
| 141 | .options = options, | ||
| 142 | .allocator = allocator, | ||
| 143 | }, | ||
| 144 | .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) { | ||
| 145 | 32 => .p32, | ||
| 146 | 64 => .p64, | ||
| 147 | else => return error.UnsupportedELFArchitecture, | ||
| 148 | }, | ||
| 149 | }; | ||
| 150 | errdefer self.deinit(); | ||
| 151 | |||
| 152 | // TODO implement reading the PE/COFF file | ||
| 153 | return error.IncrFailed; | ||
| 154 | } | ||
| 155 | |||
| 156 | /// Truncates the existing file contents and overwrites the contents. | ||
| 157 | /// Returns an error if `file` is not already open with +read +write +seek abilities. | ||
| 158 | fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !Coff { | ||
| 159 | // TODO Write object specific relocations, COFF symbol table, then enable object file output. | ||
| 160 | switch (options.output_mode) { | ||
| 161 | .Exe => {}, | ||
| 162 | .Obj => return error.TODOImplementWritingObjFiles, | ||
| 163 | .Lib => return error.TODOImplementWritingLibFiles, | ||
| 164 | } | ||
| 165 | var self: Coff = .{ | ||
| 166 | .base = .{ | ||
| 167 | .tag = .coff, | ||
| 168 | .options = options, | ||
| 169 | .allocator = allocator, | ||
| 170 | .file = file, | ||
| 171 | }, | ||
| 172 | .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) { | ||
| 173 | 32 => .p32, | ||
| 174 | 64 => .p64, | ||
| 175 | else => return error.UnsupportedCOFFArchitecture, | ||
| 176 | }, | ||
| 177 | }; | ||
| 178 | errdefer self.deinit(); | ||
| 179 | |||
| 180 | var coff_file_header_offset: u32 = 0; | ||
| 181 | if (options.output_mode == .Exe) { | ||
| 182 | // Write the MS-DOS stub and the PE signature | ||
| 183 | try self.base.file.?.pwriteAll(msdos_stub ++ "PE\x00\x00", 0); | ||
| 184 | coff_file_header_offset = msdos_stub.len + 4; | ||
| 185 | } | ||
| 186 | |||
| 187 | // COFF file header | ||
| 188 | const data_directory_count = 0; | ||
| 189 | var hdr_data: [112 + data_directory_count * 8 + section_table_size]u8 = undefined; | ||
| 190 | var index: usize = 0; | ||
| 191 | |||
| 192 | const machine = self.base.options.target.cpu.arch.toCoffMachine(); | ||
| 193 | if (machine == .Unknown) { | ||
| 194 | return error.UnsupportedCOFFArchitecture; | ||
| 195 | } | ||
| 196 | std.mem.writeIntLittle(u16, hdr_data[0..2], @enumToInt(machine)); | ||
| 197 | index += 2; | ||
| 198 | |||
| 199 | // Number of sections (we only use .got, .text) | ||
| 200 | std.mem.writeIntLittle(u16, hdr_data[index..][0..2], 2); | ||
| 201 | index += 2; | ||
| 202 | // TimeDateStamp (u32), PointerToSymbolTable (u32), NumberOfSymbols (u32) | ||
| 203 | std.mem.set(u8, hdr_data[index..][0..12], 0); | ||
| 204 | index += 12; | ||
| 205 | |||
| 206 | const optional_header_size = switch (options.output_mode) { | ||
| 207 | .Exe => data_directory_count * 8 + switch (self.ptr_width) { | ||
| 208 | .p32 => @as(u16, 96), | ||
| 209 | .p64 => 112, | ||
| 210 | }, | ||
| 211 | else => 0, | ||
| 212 | }; | ||
| 213 | |||
| 214 | const section_table_offset = coff_file_header_offset + 20 + optional_header_size; | ||
| 215 | const default_offset_table_size = file_alignment; | ||
| 216 | const default_size_of_code = 0; | ||
| 217 | |||
| 218 | self.section_data_offset = std.mem.alignForwardGeneric(u32, self.section_table_offset + section_table_size, file_alignment); | ||
| 219 | const section_data_relative_virtual_address = std.mem.alignForwardGeneric(u32, self.section_table_offset + section_table_size, section_alignment); | ||
| 220 | self.offset_table_virtual_address = image_base + section_data_relative_virtual_address; | ||
| 221 | self.offset_table_size = default_offset_table_size; | ||
| 222 | self.section_table_offset = section_table_offset; | ||
| 223 | self.text_section_virtual_address = image_base + section_data_relative_virtual_address + section_alignment; | ||
| 224 | self.text_section_size = default_size_of_code; | ||
| 225 | |||
| 226 | // Size of file when loaded in memory | ||
| 227 | const size_of_image = std.mem.alignForwardGeneric(u32, self.text_section_virtual_address - image_base + default_size_of_code, section_alignment); | ||
| 228 | |||
| 229 | std.mem.writeIntLittle(u16, hdr_data[index..][0..2], optional_header_size); | ||
| 230 | index += 2; | ||
| 231 | |||
| 232 | // Characteristics | ||
| 233 | var characteristics: u16 = std.coff.IMAGE_FILE_DEBUG_STRIPPED | std.coff.IMAGE_FILE_RELOCS_STRIPPED; // TODO Remove debug info stripped flag when necessary | ||
| 234 | if (options.output_mode == .Exe) { | ||
| 235 | characteristics |= std.coff.IMAGE_FILE_EXECUTABLE_IMAGE; | ||
| 236 | } | ||
| 237 | switch (self.ptr_width) { | ||
| 238 | .p32 => characteristics |= std.coff.IMAGE_FILE_32BIT_MACHINE, | ||
| 239 | .p64 => characteristics |= std.coff.IMAGE_FILE_LARGE_ADDRESS_AWARE, | ||
| 240 | } | ||
| 241 | std.mem.writeIntLittle(u16, hdr_data[index..][0..2], characteristics); | ||
| 242 | index += 2; | ||
| 243 | |||
| 244 | assert(index == 20); | ||
| 245 | try self.base.file.?.pwriteAll(hdr_data[0..index], coff_file_header_offset); | ||
| 246 | |||
| 247 | if (options.output_mode == .Exe) { | ||
| 248 | self.optional_header_offset = coff_file_header_offset + 20; | ||
| 249 | // Optional header | ||
| 250 | index = 0; | ||
| 251 | std.mem.writeIntLittle(u16, hdr_data[0..2], switch (self.ptr_width) { | ||
| 252 | .p32 => @as(u16, 0x10b), | ||
| 253 | .p64 => 0x20b, | ||
| 254 | }); | ||
| 255 | index += 2; | ||
| 256 | |||
| 257 | // Linker version (u8 + u8) | ||
| 258 | std.mem.set(u8, hdr_data[index..][0..2], 0); | ||
| 259 | index += 2; | ||
| 260 | |||
| 261 | // SizeOfCode (UNUSED, u32), SizeOfInitializedData (u32), SizeOfUninitializedData (u32), AddressOfEntryPoint (u32), BaseOfCode (UNUSED, u32) | ||
| 262 | std.mem.set(u8, hdr_data[index..][0..20], 0); | ||
| 263 | index += 20; | ||
| 264 | |||
| 265 | if (self.ptr_width == .p32) { | ||
| 266 | // Base of data relative to the image base (UNUSED) | ||
| 267 | std.mem.set(u8, hdr_data[index..][0..4], 0); | ||
| 268 | index += 4; | ||
| 269 | |||
| 270 | // Image base address | ||
| 271 | std.mem.writeIntLittle(u32, hdr_data[index..][0..4], image_base); | ||
| 272 | index += 4; | ||
| 273 | } else { | ||
| 274 | // Image base address | ||
| 275 | std.mem.writeIntLittle(u64, hdr_data[index..][0..8], image_base); | ||
| 276 | index += 8; | ||
| 277 | } | ||
| 278 | |||
| 279 | // Section alignment | ||
| 280 | std.mem.writeIntLittle(u32, hdr_data[index..][0..4], section_alignment); | ||
| 281 | index += 4; | ||
| 282 | // File alignment | ||
| 283 | std.mem.writeIntLittle(u32, hdr_data[index..][0..4], file_alignment); | ||
| 284 | index += 4; | ||
| 285 | // Required OS version, 6.0 is vista | ||
| 286 | std.mem.writeIntLittle(u16, hdr_data[index..][0..2], 6); | ||
| 287 | index += 2; | ||
| 288 | std.mem.writeIntLittle(u16, hdr_data[index..][0..2], 0); | ||
| 289 | index += 2; | ||
| 290 | // Image version | ||
| 291 | std.mem.set(u8, hdr_data[index..][0..4], 0); | ||
| 292 | index += 4; | ||
| 293 | // Required subsystem version, same as OS version | ||
| 294 | std.mem.writeIntLittle(u16, hdr_data[index..][0..2], 6); | ||
| 295 | index += 2; | ||
| 296 | std.mem.writeIntLittle(u16, hdr_data[index..][0..2], 0); | ||
| 297 | index += 2; | ||
| 298 | // Reserved zeroes (u32) | ||
| 299 | std.mem.set(u8, hdr_data[index..][0..4], 0); | ||
| 300 | index += 4; | ||
| 301 | std.mem.writeIntLittle(u32, hdr_data[index..][0..4], size_of_image); | ||
| 302 | index += 4; | ||
| 303 | std.mem.writeIntLittle(u32, hdr_data[index..][0..4], self.section_data_offset); | ||
| 304 | index += 4; | ||
| 305 | // CheckSum (u32) | ||
| 306 | std.mem.set(u8, hdr_data[index..][0..4], 0); | ||
| 307 | index += 4; | ||
| 308 | // Subsystem, TODO: Let users specify the subsystem, always CUI for now | ||
| 309 | std.mem.writeIntLittle(u16, hdr_data[index..][0..2], 3); | ||
| 310 | index += 2; | ||
| 311 | // DLL characteristics | ||
| 312 | std.mem.writeIntLittle(u16, hdr_data[index..][0..2], 0x0); | ||
| 313 | index += 2; | ||
| 314 | |||
| 315 | switch (self.ptr_width) { | ||
| 316 | .p32 => { | ||
| 317 | // Size of stack reserve + commit | ||
| 318 | std.mem.writeIntLittle(u32, hdr_data[index..][0..4], 0x1_000_000); | ||
| 319 | index += 4; | ||
| 320 | std.mem.writeIntLittle(u32, hdr_data[index..][0..4], 0x1_000); | ||
| 321 | index += 4; | ||
| 322 | // Size of heap reserve + commit | ||
| 323 | std.mem.writeIntLittle(u32, hdr_data[index..][0..4], 0x100_000); | ||
| 324 | index += 4; | ||
| 325 | std.mem.writeIntLittle(u32, hdr_data[index..][0..4], 0x1_000); | ||
| 326 | index += 4; | ||
| 327 | }, | ||
| 328 | .p64 => { | ||
| 329 | // Size of stack reserve + commit | ||
| 330 | std.mem.writeIntLittle(u64, hdr_data[index..][0..8], 0x1_000_000); | ||
| 331 | index += 8; | ||
| 332 | std.mem.writeIntLittle(u64, hdr_data[index..][0..8], 0x1_000); | ||
| 333 | index += 8; | ||
| 334 | // Size of heap reserve + commit | ||
| 335 | std.mem.writeIntLittle(u64, hdr_data[index..][0..8], 0x100_000); | ||
| 336 | index += 8; | ||
| 337 | std.mem.writeIntLittle(u64, hdr_data[index..][0..8], 0x1_000); | ||
| 338 | index += 8; | ||
| 339 | }, | ||
| 340 | } | ||
| 341 | |||
| 342 | // Reserved zeroes | ||
| 343 | std.mem.set(u8, hdr_data[index..][0..4], 0); | ||
| 344 | index += 4; | ||
| 345 | |||
| 346 | // Number of data directories | ||
| 347 | std.mem.writeIntLittle(u32, hdr_data[index..][0..4], data_directory_count); | ||
| 348 | index += 4; | ||
| 349 | // Initialize data directories to zero | ||
| 350 | std.mem.set(u8, hdr_data[index..][0 .. data_directory_count * 8], 0); | ||
| 351 | index += data_directory_count * 8; | ||
| 352 | |||
| 353 | assert(index == optional_header_size); | ||
| 354 | } | ||
| 355 | |||
| 356 | // Write section table. | ||
| 357 | // First, the .got section | ||
| 358 | hdr_data[index..][0..8].* = ".got\x00\x00\x00\x00".*; | ||
| 359 | index += 8; | ||
| 360 | if (options.output_mode == .Exe) { | ||
| 361 | // Virtual size (u32) | ||
| 362 | std.mem.writeIntLittle(u32, hdr_data[index..][0..4], default_offset_table_size); | ||
| 363 | index += 4; | ||
| 364 | // Virtual address (u32) | ||
| 365 | std.mem.writeIntLittle(u32, hdr_data[index..][0..4], self.offset_table_virtual_address - image_base); | ||
| 366 | index += 4; | ||
| 367 | } else { | ||
| 368 | std.mem.set(u8, hdr_data[index..][0..8], 0); | ||
| 369 | index += 8; | ||
| 370 | } | ||
| 371 | // Size of raw data (u32) | ||
| 372 | std.mem.writeIntLittle(u32, hdr_data[index..][0..4], default_offset_table_size); | ||
| 373 | index += 4; | ||
| 374 | // File pointer to the start of the section | ||
| 375 | std.mem.writeIntLittle(u32, hdr_data[index..][0..4], self.section_data_offset); | ||
| 376 | index += 4; | ||
| 377 | // Pointer to relocations (u32), PointerToLinenumbers (u32), NumberOfRelocations (u16), NumberOfLinenumbers (u16) | ||
| 378 | std.mem.set(u8, hdr_data[index..][0..12], 0); | ||
| 379 | index += 12; | ||
| 380 | // Section flags | ||
| 381 | std.mem.writeIntLittle(u32, hdr_data[index..][0..4], std.coff.IMAGE_SCN_CNT_INITIALIZED_DATA | std.coff.IMAGE_SCN_MEM_READ); | ||
| 382 | index += 4; | ||
| 383 | // Then, the .text section | ||
| 384 | hdr_data[index..][0..8].* = ".text\x00\x00\x00".*; | ||
| 385 | index += 8; | ||
| 386 | if (options.output_mode == .Exe) { | ||
| 387 | // Virtual size (u32) | ||
| 388 | std.mem.writeIntLittle(u32, hdr_data[index..][0..4], default_size_of_code); | ||
| 389 | index += 4; | ||
| 390 | // Virtual address (u32) | ||
| 391 | std.mem.writeIntLittle(u32, hdr_data[index..][0..4], self.text_section_virtual_address - image_base); | ||
| 392 | index += 4; | ||
| 393 | } else { | ||
| 394 | std.mem.set(u8, hdr_data[index..][0..8], 0); | ||
| 395 | index += 8; | ||
| 396 | } | ||
| 397 | // Size of raw data (u32) | ||
| 398 | std.mem.writeIntLittle(u32, hdr_data[index..][0..4], default_size_of_code); | ||
| 399 | index += 4; | ||
| 400 | // File pointer to the start of the section | ||
| 401 | std.mem.writeIntLittle(u32, hdr_data[index..][0..4], self.section_data_offset + default_offset_table_size); | ||
| 402 | index += 4; | ||
| 403 | // Pointer to relocations (u32), PointerToLinenumbers (u32), NumberOfRelocations (u16), NumberOfLinenumbers (u16) | ||
| 404 | std.mem.set(u8, hdr_data[index..][0..12], 0); | ||
| 405 | index += 12; | ||
| 406 | // Section flags | ||
| 407 | std.mem.writeIntLittle( | ||
| 408 | u32, | ||
| 409 | hdr_data[index..][0..4], | ||
| 410 | std.coff.IMAGE_SCN_CNT_CODE | std.coff.IMAGE_SCN_MEM_EXECUTE | std.coff.IMAGE_SCN_MEM_READ | std.coff.IMAGE_SCN_MEM_WRITE, | ||
| 411 | ); | ||
| 412 | index += 4; | ||
| 413 | |||
| 414 | assert(index == optional_header_size + section_table_size); | ||
| 415 | try self.base.file.?.pwriteAll(hdr_data[0..index], self.optional_header_offset); | ||
| 416 | try self.base.file.?.setEndPos(self.section_data_offset + default_offset_table_size + default_size_of_code); | ||
| 417 | |||
| 418 | return self; | ||
| 419 | } | ||
| 420 | |||
| 421 | pub fn allocateDeclIndexes(self: *Coff, decl: *Module.Decl) !void { | ||
| 422 | try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1); | ||
| 423 | |||
| 424 | if (self.offset_table_free_list.popOrNull()) |i| { | ||
| 425 | decl.link.coff.offset_table_index = i; | ||
| 426 | } else { | ||
| 427 | decl.link.coff.offset_table_index = @intCast(u32, self.offset_table.items.len); | ||
| 428 | _ = self.offset_table.addOneAssumeCapacity(); | ||
| 429 | |||
| 430 | const entry_size = self.base.options.target.cpu.arch.ptrBitWidth() / 8; | ||
| 431 | if (self.offset_table.items.len > self.offset_table_size / entry_size) { | ||
| 432 | self.offset_table_size_dirty = true; | ||
| 433 | } | ||
| 434 | } | ||
| 435 | |||
| 436 | self.offset_table.items[decl.link.coff.offset_table_index] = 0; | ||
| 437 | } | ||
| 438 | |||
| 439 | fn allocateTextBlock(self: *Coff, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { | ||
| 440 | const new_block_min_capacity = new_block_size * allocation_padding; | ||
| 441 | |||
| 442 | // We use these to indicate our intention to update metadata, placing the new block, | ||
| 443 | // and possibly removing a free list node. | ||
| 444 | // It would be simpler to do it inside the for loop below, but that would cause a | ||
| 445 | // problem if an error was returned later in the function. So this action | ||
| 446 | // is actually carried out at the end of the function, when errors are no longer possible. | ||
| 447 | var block_placement: ?*TextBlock = null; | ||
| 448 | var free_list_removal: ?usize = null; | ||
| 449 | |||
| 450 | const vaddr = blk: { | ||
| 451 | var i: usize = 0; | ||
| 452 | while (i < self.text_block_free_list.items.len) { | ||
| 453 | const free_block = self.text_block_free_list.items[i]; | ||
| 454 | |||
| 455 | const next_block_text_offset = free_block.text_offset + free_block.capacity(); | ||
| 456 | const new_block_text_offset = std.mem.alignForwardGeneric(u64, free_block.getVAddr(self.*) + free_block.size, alignment) - self.text_section_virtual_address; | ||
| 457 | if (new_block_text_offset < next_block_text_offset and next_block_text_offset - new_block_text_offset >= new_block_min_capacity) { | ||
| 458 | block_placement = free_block; | ||
| 459 | |||
| 460 | const remaining_capacity = next_block_text_offset - new_block_text_offset - new_block_min_capacity; | ||
| 461 | if (remaining_capacity < minimum_text_block_size) { | ||
| 462 | free_list_removal = i; | ||
| 463 | } | ||
| 464 | |||
| 465 | break :blk new_block_text_offset + self.text_section_virtual_address; | ||
| 466 | } else { | ||
| 467 | if (!free_block.freeListEligible()) { | ||
| 468 | _ = self.text_block_free_list.swapRemove(i); | ||
| 469 | } else { | ||
| 470 | i += 1; | ||
| 471 | } | ||
| 472 | continue; | ||
| 473 | } | ||
| 474 | } else if (self.last_text_block) |last| { | ||
| 475 | const new_block_vaddr = std.mem.alignForwardGeneric(u64, last.getVAddr(self.*) + last.size, alignment); | ||
| 476 | block_placement = last; | ||
| 477 | break :blk new_block_vaddr; | ||
| 478 | } else { | ||
| 479 | break :blk self.text_section_virtual_address; | ||
| 480 | } | ||
| 481 | }; | ||
| 482 | |||
| 483 | const expand_text_section = block_placement == null or block_placement.?.next == null; | ||
| 484 | if (expand_text_section) { | ||
| 485 | const needed_size = @intCast(u32, std.mem.alignForwardGeneric(u64, vaddr + new_block_size - self.text_section_virtual_address, file_alignment)); | ||
| 486 | if (needed_size > self.text_section_size) { | ||
| 487 | const current_text_section_virtual_size = std.mem.alignForwardGeneric(u32, self.text_section_size, section_alignment); | ||
| 488 | const new_text_section_virtual_size = std.mem.alignForwardGeneric(u32, needed_size, section_alignment); | ||
| 489 | if (current_text_section_virtual_size != new_text_section_virtual_size) { | ||
| 490 | self.size_of_image_dirty = true; | ||
| 491 | // Write new virtual size | ||
| 492 | var buf: [4]u8 = undefined; | ||
| 493 | std.mem.writeIntLittle(u32, &buf, new_text_section_virtual_size); | ||
| 494 | try self.base.file.?.pwriteAll(&buf, self.section_table_offset + 40 + 8); | ||
| 495 | } | ||
| 496 | |||
| 497 | self.text_section_size = needed_size; | ||
| 498 | self.text_section_size_dirty = true; | ||
| 499 | } | ||
| 500 | self.last_text_block = text_block; | ||
| 501 | } | ||
| 502 | text_block.text_offset = @intCast(u32, vaddr - self.text_section_virtual_address); | ||
| 503 | text_block.size = @intCast(u32, new_block_size); | ||
| 504 | |||
| 505 | // This function can also reallocate a text block. | ||
| 506 | // In this case we need to "unplug" it from its previous location before | ||
| 507 | // plugging it in to its new location. | ||
| 508 | if (text_block.prev) |prev| { | ||
| 509 | prev.next = text_block.next; | ||
| 510 | } | ||
| 511 | if (text_block.next) |next| { | ||
| 512 | next.prev = text_block.prev; | ||
| 513 | } | ||
| 514 | |||
| 515 | if (block_placement) |big_block| { | ||
| 516 | text_block.prev = big_block; | ||
| 517 | text_block.next = big_block.next; | ||
| 518 | big_block.next = text_block; | ||
| 519 | } else { | ||
| 520 | text_block.prev = null; | ||
| 521 | text_block.next = null; | ||
| 522 | } | ||
| 523 | if (free_list_removal) |i| { | ||
| 524 | _ = self.text_block_free_list.swapRemove(i); | ||
| 525 | } | ||
| 526 | return vaddr; | ||
| 527 | } | ||
| 528 | |||
| 529 | fn growTextBlock(self: *Coff, text_block: *TextBlock, new_block_size: u64, alignment: u64) !u64 { | ||
| 530 | const block_vaddr = text_block.getVAddr(self.*); | ||
| 531 | const align_ok = std.mem.alignBackwardGeneric(u64, block_vaddr, alignment) == block_vaddr; | ||
| 532 | const need_realloc = !align_ok or new_block_size > text_block.capacity(); | ||
| 533 | if (!need_realloc) return @as(u64, block_vaddr); | ||
| 534 | return self.allocateTextBlock(text_block, new_block_size, alignment); | ||
| 535 | } | ||
| 536 | |||
| 537 | fn shrinkTextBlock(self: *Coff, text_block: *TextBlock, new_block_size: u64) void { | ||
| 538 | text_block.size = @intCast(u32, new_block_size); | ||
| 539 | if (text_block.capacity() - text_block.size >= minimum_text_block_size) { | ||
| 540 | self.text_block_free_list.append(self.base.allocator, text_block) catch {}; | ||
| 541 | } | ||
| 542 | } | ||
| 543 | |||
| 544 | fn freeTextBlock(self: *Coff, text_block: *TextBlock) void { | ||
| 545 | var already_have_free_list_node = false; | ||
| 546 | { | ||
| 547 | var i: usize = 0; | ||
| 548 | // TODO turn text_block_free_list into a hash map | ||
| 549 | while (i < self.text_block_free_list.items.len) { | ||
| 550 | if (self.text_block_free_list.items[i] == text_block) { | ||
| 551 | _ = self.text_block_free_list.swapRemove(i); | ||
| 552 | continue; | ||
| 553 | } | ||
| 554 | if (self.text_block_free_list.items[i] == text_block.prev) { | ||
| 555 | already_have_free_list_node = true; | ||
| 556 | } | ||
| 557 | i += 1; | ||
| 558 | } | ||
| 559 | } | ||
| 560 | if (self.last_text_block == text_block) { | ||
| 561 | self.last_text_block = text_block.prev; | ||
| 562 | } | ||
| 563 | if (text_block.prev) |prev| { | ||
| 564 | prev.next = text_block.next; | ||
| 565 | |||
| 566 | if (!already_have_free_list_node and prev.freeListEligible()) { | ||
| 567 | // The free list is heuristics, it doesn't have to be perfect, so we can | ||
| 568 | // ignore the OOM here. | ||
| 569 | self.text_block_free_list.append(self.base.allocator, prev) catch {}; | ||
| 570 | } | ||
| 571 | } | ||
| 572 | |||
| 573 | if (text_block.next) |next| { | ||
| 574 | next.prev = text_block.prev; | ||
| 575 | } | ||
| 576 | } | ||
| 577 | |||
| 578 | fn writeOffsetTableEntry(self: *Coff, index: usize) !void { | ||
| 579 | const entry_size = self.base.options.target.cpu.arch.ptrBitWidth() / 8; | ||
| 580 | const endian = self.base.options.target.cpu.arch.endian(); | ||
| 581 | |||
| 582 | const offset_table_start = self.section_data_offset; | ||
| 583 | if (self.offset_table_size_dirty) { | ||
| 584 | const current_raw_size = self.offset_table_size; | ||
| 585 | const new_raw_size = self.offset_table_size * 2; | ||
| 586 | log.debug("growing offset table from raw size {} to {}\n", .{ current_raw_size, new_raw_size }); | ||
| 587 | |||
| 588 | // Move the text section to a new place in the executable | ||
| 589 | const current_text_section_start = self.section_data_offset + current_raw_size; | ||
| 590 | const new_text_section_start = self.section_data_offset + new_raw_size; | ||
| 591 | |||
| 592 | const amt = try self.base.file.?.copyRangeAll(current_text_section_start, self.base.file.?, new_text_section_start, self.text_section_size); | ||
| 593 | if (amt != self.text_section_size) return error.InputOutput; | ||
| 594 | |||
| 595 | // Write the new raw size in the .got header | ||
| 596 | var buf: [8]u8 = undefined; | ||
| 597 | std.mem.writeIntLittle(u32, buf[0..4], new_raw_size); | ||
| 598 | try self.base.file.?.pwriteAll(buf[0..4], self.section_table_offset + 16); | ||
| 599 | // Write the new .text section file offset in the .text section header | ||
| 600 | std.mem.writeIntLittle(u32, buf[0..4], new_text_section_start); | ||
| 601 | try self.base.file.?.pwriteAll(buf[0..4], self.section_table_offset + 40 + 20); | ||
| 602 | |||
| 603 | const current_virtual_size = std.mem.alignForwardGeneric(u32, self.offset_table_size, section_alignment); | ||
| 604 | const new_virtual_size = std.mem.alignForwardGeneric(u32, new_raw_size, section_alignment); | ||
| 605 | // If we had to move in the virtual address space, we need to fix the VAs in the offset table, as well as the virtual address of the `.text` section | ||
| 606 | // and the virutal size of the `.got` section | ||
| 607 | |||
| 608 | if (new_virtual_size != current_virtual_size) { | ||
| 609 | log.debug("growing offset table from virtual size {} to {}\n", .{ current_virtual_size, new_virtual_size }); | ||
| 610 | self.size_of_image_dirty = true; | ||
| 611 | const va_offset = new_virtual_size - current_virtual_size; | ||
| 612 | |||
| 613 | // Write .got virtual size | ||
| 614 | std.mem.writeIntLittle(u32, buf[0..4], new_virtual_size); | ||
| 615 | try self.base.file.?.pwriteAll(buf[0..4], self.section_table_offset + 8); | ||
| 616 | |||
| 617 | // Write .text new virtual address | ||
| 618 | self.text_section_virtual_address = self.text_section_virtual_address + va_offset; | ||
| 619 | std.mem.writeIntLittle(u32, buf[0..4], self.text_section_virtual_address - image_base); | ||
| 620 | try self.base.file.?.pwriteAll(buf[0..4], self.section_table_offset + 40 + 12); | ||
| 621 | |||
| 622 | // Fix the VAs in the offset table | ||
| 623 | for (self.offset_table.items) |*va, idx| { | ||
| 624 | if (va.* != 0) { | ||
| 625 | va.* += va_offset; | ||
| 626 | |||
| 627 | switch (entry_size) { | ||
| 628 | 4 => { | ||
| 629 | std.mem.writeInt(u32, buf[0..4], @intCast(u32, va.*), endian); | ||
| 630 | try self.base.file.?.pwriteAll(buf[0..4], offset_table_start + idx * entry_size); | ||
| 631 | }, | ||
| 632 | 8 => { | ||
| 633 | std.mem.writeInt(u64, &buf, va.*, endian); | ||
| 634 | try self.base.file.?.pwriteAll(&buf, offset_table_start + idx * entry_size); | ||
| 635 | }, | ||
| 636 | else => unreachable, | ||
| 637 | } | ||
| 638 | } | ||
| 639 | } | ||
| 640 | } | ||
| 641 | self.offset_table_size = new_raw_size; | ||
| 642 | self.offset_table_size_dirty = false; | ||
| 643 | } | ||
| 644 | // Write the new entry | ||
| 645 | switch (entry_size) { | ||
| 646 | 4 => { | ||
| 647 | var buf: [4]u8 = undefined; | ||
| 648 | std.mem.writeInt(u32, &buf, @intCast(u32, self.offset_table.items[index]), endian); | ||
| 649 | try self.base.file.?.pwriteAll(&buf, offset_table_start + index * entry_size); | ||
| 650 | }, | ||
| 651 | 8 => { | ||
| 652 | var buf: [8]u8 = undefined; | ||
| 653 | std.mem.writeInt(u64, &buf, self.offset_table.items[index], endian); | ||
| 654 | try self.base.file.?.pwriteAll(&buf, offset_table_start + index * entry_size); | ||
| 655 | }, | ||
| 656 | else => unreachable, | ||
| 657 | } | ||
| 658 | } | ||
| 659 | |||
| 660 | pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void { | ||
| 661 | // TODO COFF/PE debug information | ||
| 662 | // TODO Implement exports | ||
| 663 | const tracy = trace(@src()); | ||
| 664 | defer tracy.end(); | ||
| 665 | |||
| 666 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | ||
| 667 | defer code_buffer.deinit(); | ||
| 668 | |||
| 669 | const typed_value = decl.typed_value.most_recent.typed_value; | ||
| 670 | const res = try codegen.generateSymbol(&self.base, decl.src(), typed_value, &code_buffer, .none); | ||
| 671 | const code = switch (res) { | ||
| 672 | .externally_managed => |x| x, | ||
| 673 | .appended => code_buffer.items, | ||
| 674 | .fail => |em| { | ||
| 675 | decl.analysis = .codegen_failure; | ||
| 676 | try module.failed_decls.put(module.gpa, decl, em); | ||
| 677 | return; | ||
| 678 | }, | ||
| 679 | }; | ||
| 680 | |||
| 681 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); | ||
| 682 | const curr_size = decl.link.coff.size; | ||
| 683 | if (curr_size != 0) { | ||
| 684 | const capacity = decl.link.coff.capacity(); | ||
| 685 | const need_realloc = code.len > capacity or | ||
| 686 | !std.mem.isAlignedGeneric(u32, decl.link.coff.text_offset, required_alignment); | ||
| 687 | if (need_realloc) { | ||
| 688 | const curr_vaddr = self.getDeclVAddr(decl); | ||
| 689 | const vaddr = try self.growTextBlock(&decl.link.coff, code.len, required_alignment); | ||
| 690 | log.debug("growing {} from 0x{x} to 0x{x}\n", .{ decl.name, curr_vaddr, vaddr }); | ||
| 691 | if (vaddr != curr_vaddr) { | ||
| 692 | log.debug(" (writing new offset table entry)\n", .{}); | ||
| 693 | self.offset_table.items[decl.link.coff.offset_table_index] = vaddr; | ||
| 694 | try self.writeOffsetTableEntry(decl.link.coff.offset_table_index); | ||
| 695 | } | ||
| 696 | } else if (code.len < curr_size) { | ||
| 697 | self.shrinkTextBlock(&decl.link.coff, code.len); | ||
| 698 | } | ||
| 699 | } else { | ||
| 700 | const vaddr = try self.allocateTextBlock(&decl.link.coff, code.len, required_alignment); | ||
| 701 | log.debug("allocated text block for {} at 0x{x} (size: {Bi})\n", .{ std.mem.spanZ(decl.name), vaddr, code.len }); | ||
| 702 | errdefer self.freeTextBlock(&decl.link.coff); | ||
| 703 | self.offset_table.items[decl.link.coff.offset_table_index] = vaddr; | ||
| 704 | try self.writeOffsetTableEntry(decl.link.coff.offset_table_index); | ||
| 705 | } | ||
| 706 | |||
| 707 | // Write the code into the file | ||
| 708 | try self.base.file.?.pwriteAll(code, self.section_data_offset + self.offset_table_size + decl.link.coff.text_offset); | ||
| 709 | |||
| 710 | // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated. | ||
| 711 | const decl_exports = module.decl_exports.get(decl) orelse &[0]*Module.Export{}; | ||
| 712 | return self.updateDeclExports(module, decl, decl_exports); | ||
| 713 | } | ||
| 714 | |||
| 715 | pub fn freeDecl(self: *Coff, decl: *Module.Decl) void { | ||
| 716 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. | ||
| 717 | self.freeTextBlock(&decl.link.coff); | ||
| 718 | self.offset_table_free_list.append(self.base.allocator, decl.link.coff.offset_table_index) catch {}; | ||
| 719 | } | ||
| 720 | |||
| 721 | pub fn updateDeclExports(self: *Coff, module: *Module, decl: *const Module.Decl, exports: []const *Module.Export) !void { | ||
| 722 | for (exports) |exp| { | ||
| 723 | if (exp.options.section) |section_name| { | ||
| 724 | if (!std.mem.eql(u8, section_name, ".text")) { | ||
| 725 | try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1); | ||
| 726 | module.failed_exports.putAssumeCapacityNoClobber( | ||
| 727 | exp, | ||
| 728 | try Module.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: ExportOptions.section", .{}), | ||
| 729 | ); | ||
| 730 | continue; | ||
| 731 | } | ||
| 732 | } | ||
| 733 | if (std.mem.eql(u8, exp.options.name, "_start")) { | ||
| 734 | self.entry_addr = decl.link.coff.getVAddr(self.*) - image_base; | ||
| 735 | } else { | ||
| 736 | try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1); | ||
| 737 | module.failed_exports.putAssumeCapacityNoClobber( | ||
| 738 | exp, | ||
| 739 | try Module.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: Exports other than '_start'", .{}), | ||
| 740 | ); | ||
| 741 | continue; | ||
| 742 | } | ||
| 743 | } | ||
| 744 | } | ||
| 745 | |||
| 746 | pub fn flush(self: *Coff, module: *Module) !void { | ||
| 747 | if (self.text_section_size_dirty) { | ||
| 748 | // Write the new raw size in the .text header | ||
| 749 | var buf: [4]u8 = undefined; | ||
| 750 | std.mem.writeIntLittle(u32, &buf, self.text_section_size); | ||
| 751 | try self.base.file.?.pwriteAll(&buf, self.section_table_offset + 40 + 16); | ||
| 752 | try self.base.file.?.setEndPos(self.section_data_offset + self.offset_table_size + self.text_section_size); | ||
| 753 | self.text_section_size_dirty = false; | ||
| 754 | } | ||
| 755 | |||
| 756 | if (self.base.options.output_mode == .Exe and self.size_of_image_dirty) { | ||
| 757 | const new_size_of_image = std.mem.alignForwardGeneric(u32, self.text_section_virtual_address - image_base + self.text_section_size, section_alignment); | ||
| 758 | var buf: [4]u8 = undefined; | ||
| 759 | std.mem.writeIntLittle(u32, &buf, new_size_of_image); | ||
| 760 | try self.base.file.?.pwriteAll(&buf, self.optional_header_offset + 56); | ||
| 761 | self.size_of_image_dirty = false; | ||
| 762 | } | ||
| 763 | |||
| 764 | if (self.entry_addr == null and self.base.options.output_mode == .Exe) { | ||
| 765 | log.debug("flushing. no_entry_point_found = true\n", .{}); | ||
| 766 | self.error_flags.no_entry_point_found = true; | ||
| 767 | } else { | ||
| 768 | log.debug("flushing. no_entry_point_found = false\n", .{}); | ||
| 769 | self.error_flags.no_entry_point_found = false; | ||
| 770 | |||
| 771 | if (self.base.options.output_mode == .Exe) { | ||
| 772 | // Write AddressOfEntryPoint | ||
| 773 | var buf: [4]u8 = undefined; | ||
| 774 | std.mem.writeIntLittle(u32, &buf, self.entry_addr.?); | ||
| 775 | try self.base.file.?.pwriteAll(&buf, self.optional_header_offset + 16); | ||
| 776 | } | ||
| 777 | } | ||
| 778 | } | ||
| 779 | |||
| 780 | pub fn getDeclVAddr(self: *Coff, decl: *const Module.Decl) u64 { | ||
| 781 | return self.text_section_virtual_address + decl.link.coff.text_offset; | ||
| 782 | } | ||
| 783 | |||
| 784 | pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !void { | ||
| 785 | // TODO Implement this | ||
| 786 | } | ||
| 787 | |||
| 788 | pub fn deinit(self: *Coff) void { | ||
| 789 | self.text_block_free_list.deinit(self.base.allocator); | ||
| 790 | self.offset_table.deinit(self.base.allocator); | ||
| 791 | self.offset_table_free_list.deinit(self.base.allocator); | ||
| 792 | } | ||
src-self-hosted/link/Elf.zig+7-1| ... | @@ -1735,7 +1735,13 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1735,7 +1735,13 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { |
| 1735 | } else { | 1735 | } else { |
| 1736 | // TODO implement .debug_info for global variables | 1736 | // TODO implement .debug_info for global variables |
| 1737 | } | 1737 | } |
| 1738 | const res = try codegen.generateSymbol(&self.base, decl.src(), typed_value, &code_buffer, &dbg_line_buffer, &dbg_info_buffer, &dbg_info_type_relocs); | 1738 | const res = try codegen.generateSymbol(&self.base, decl.src(), typed_value, &code_buffer, .{ |
| 1739 | .dwarf = .{ | ||
| 1740 | .dbg_line = &dbg_line_buffer, | ||
| 1741 | .dbg_info = &dbg_info_buffer, | ||
| 1742 | .dbg_info_type_relocs = &dbg_info_type_relocs, | ||
| 1743 | }, | ||
| 1744 | }); | ||
| 1739 | const code = switch (res) { | 1745 | const code = switch (res) { |
| 1740 | .externally_managed => |x| x, | 1746 | .externally_managed => |x| x, |
| 1741 | .appended => code_buffer.items, | 1747 | .appended => code_buffer.items, |
src-self-hosted/link/MachO.zig+1-24| ... | @@ -316,31 +316,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -316,31 +316,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 316 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | 316 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 317 | defer code_buffer.deinit(); | 317 | defer code_buffer.deinit(); |
| 318 | 318 | ||
| 319 | var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator); | ||
| 320 | defer dbg_line_buffer.deinit(); | ||
| 321 | |||
| 322 | var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator); | ||
| 323 | defer dbg_info_buffer.deinit(); | ||
| 324 | |||
| 325 | var dbg_info_type_relocs: File.DbgInfoTypeRelocsTable = .{}; | ||
| 326 | defer { | ||
| 327 | var it = dbg_info_type_relocs.iterator(); | ||
| 328 | while (it.next()) |entry| { | ||
| 329 | entry.value.relocs.deinit(self.base.allocator); | ||
| 330 | } | ||
| 331 | dbg_info_type_relocs.deinit(self.base.allocator); | ||
| 332 | } | ||
| 333 | |||
| 334 | const typed_value = decl.typed_value.most_recent.typed_value; | 319 | const typed_value = decl.typed_value.most_recent.typed_value; |
| 335 | const res = try codegen.generateSymbol( | 320 | const res = try codegen.generateSymbol(&self.base, decl.src(), typed_value, &code_buffer, .none); |
| 336 | &self.base, | ||
| 337 | decl.src(), | ||
| 338 | typed_value, | ||
| 339 | &code_buffer, | ||
| 340 | &dbg_line_buffer, | ||
| 341 | &dbg_info_buffer, | ||
| 342 | &dbg_info_type_relocs, | ||
| 343 | ); | ||
| 344 | 321 | ||
| 345 | const code = switch (res) { | 322 | const code = switch (res) { |
| 346 | .externally_managed => |x| x, | 323 | .externally_managed => |x| x, |
src-self-hosted/link/msdos-stub.bin created| Binary files /dev/null and b/src-self-hosted/link/msdos-stub.bin differ | |||
src-self-hosted/main.zig+16-7| ... | @@ -153,8 +153,8 @@ const usage_build_generic = | ... | @@ -153,8 +153,8 @@ const usage_build_generic = |
| 153 | \\ elf Executable and Linking Format | 153 | \\ elf Executable and Linking Format |
| 154 | \\ c Compile to C source code | 154 | \\ c Compile to C source code |
| 155 | \\ wasm WebAssembly | 155 | \\ wasm WebAssembly |
| 156 | \\ pe Portable Executable (Windows) | ||
| 156 | \\ coff (planned) Common Object File Format (Windows) | 157 | \\ coff (planned) Common Object File Format (Windows) |
| 157 | \\ pe (planned) Portable Executable (Windows) | ||
| 158 | \\ macho (planned) macOS relocatables | 158 | \\ macho (planned) macOS relocatables |
| 159 | \\ hex (planned) Intel IHEX | 159 | \\ hex (planned) Intel IHEX |
| 160 | \\ raw (planned) Dump machine code directly | 160 | \\ raw (planned) Dump machine code directly |
| ... | @@ -451,7 +451,7 @@ fn buildOutputType( | ... | @@ -451,7 +451,7 @@ fn buildOutputType( |
| 451 | } else if (mem.eql(u8, ofmt, "coff")) { | 451 | } else if (mem.eql(u8, ofmt, "coff")) { |
| 452 | break :blk .coff; | 452 | break :blk .coff; |
| 453 | } else if (mem.eql(u8, ofmt, "pe")) { | 453 | } else if (mem.eql(u8, ofmt, "pe")) { |
| 454 | break :blk .coff; | 454 | break :blk .pe; |
| 455 | } else if (mem.eql(u8, ofmt, "macho")) { | 455 | } else if (mem.eql(u8, ofmt, "macho")) { |
| 456 | break :blk .macho; | 456 | break :blk .macho; |
| 457 | } else if (mem.eql(u8, ofmt, "wasm")) { | 457 | } else if (mem.eql(u8, ofmt, "wasm")) { |
| ... | @@ -524,17 +524,19 @@ fn buildOutputType( | ... | @@ -524,17 +524,19 @@ fn buildOutputType( |
| 524 | try stderr.print("\nUnable to parse command: {}\n", .{@errorName(err)}); | 524 | try stderr.print("\nUnable to parse command: {}\n", .{@errorName(err)}); |
| 525 | continue; | 525 | continue; |
| 526 | }) |line| { | 526 | }) |line| { |
| 527 | if (mem.eql(u8, line, "update")) { | 527 | const actual_line = mem.trimRight(u8, line, "\r\n "); |
| 528 | |||
| 529 | if (mem.eql(u8, actual_line, "update")) { | ||
| 528 | if (output_mode == .Exe) { | 530 | if (output_mode == .Exe) { |
| 529 | try module.makeBinFileWritable(); | 531 | try module.makeBinFileWritable(); |
| 530 | } | 532 | } |
| 531 | try updateModule(gpa, &module, zir_out_path); | 533 | try updateModule(gpa, &module, zir_out_path); |
| 532 | } else if (mem.eql(u8, line, "exit")) { | 534 | } else if (mem.eql(u8, actual_line, "exit")) { |
| 533 | break; | 535 | break; |
| 534 | } else if (mem.eql(u8, line, "help")) { | 536 | } else if (mem.eql(u8, actual_line, "help")) { |
| 535 | try stderr.writeAll(repl_help); | 537 | try stderr.writeAll(repl_help); |
| 536 | } else { | 538 | } else { |
| 537 | try stderr.print("unknown command: {}\n", .{line}); | 539 | try stderr.print("unknown command: {}\n", .{actual_line}); |
| 538 | } | 540 | } |
| 539 | } else { | 541 | } else { |
| 540 | break; | 542 | break; |
| ... | @@ -742,6 +744,7 @@ const FmtError = error{ | ... | @@ -742,6 +744,7 @@ const FmtError = error{ |
| 742 | LinkQuotaExceeded, | 744 | LinkQuotaExceeded, |
| 743 | FileBusy, | 745 | FileBusy, |
| 744 | EndOfStream, | 746 | EndOfStream, |
| 747 | Unseekable, | ||
| 745 | NotOpenForWriting, | 748 | NotOpenForWriting, |
| 746 | } || fs.File.OpenError; | 749 | } || fs.File.OpenError; |
| 747 | 750 | ||
| ... | @@ -805,7 +808,13 @@ fn fmtPathFile( | ... | @@ -805,7 +808,13 @@ fn fmtPathFile( |
| 805 | if (stat.kind == .Directory) | 808 | if (stat.kind == .Directory) |
| 806 | return error.IsDir; | 809 | return error.IsDir; |
| 807 | 810 | ||
| 808 | const source_code = source_file.readAllAlloc(fmt.gpa, stat.size, max_src_size) catch |err| switch (err) { | 811 | const source_code = source_file.readToEndAllocOptions( |
| 812 | fmt.gpa, | ||
| 813 | max_src_size, | ||
| 814 | stat.size, | ||
| 815 | @alignOf(u8), | ||
| 816 | null, | ||
| 817 | ) catch |err| switch (err) { | ||
| 809 | error.ConnectionResetByPeer => unreachable, | 818 | error.ConnectionResetByPeer => unreachable, |
| 810 | error.ConnectionTimedOut => unreachable, | 819 | error.ConnectionTimedOut => unreachable, |
| 811 | error.NotOpenForReading => unreachable, | 820 | error.NotOpenForReading => unreachable, |
src-self-hosted/stage2.zig-1| ... | @@ -615,7 +615,6 @@ export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [ | ... | @@ -615,7 +615,6 @@ export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [ |
| 615 | error.NotOpenForWriting => unreachable, | 615 | error.NotOpenForWriting => unreachable, |
| 616 | error.NotOpenForReading => unreachable, | 616 | error.NotOpenForReading => unreachable, |
| 617 | error.Unexpected => return .Unexpected, | 617 | error.Unexpected => return .Unexpected, |
| 618 | error.EndOfStream => return .EndOfFile, | ||
| 619 | error.IsDir => return .IsDir, | 618 | error.IsDir => return .IsDir, |
| 620 | error.ConnectionResetByPeer => unreachable, | 619 | error.ConnectionResetByPeer => unreachable, |
| 621 | error.ConnectionTimedOut => unreachable, | 620 | error.ConnectionTimedOut => unreachable, |
src/analyze.cpp+1-1| ... | @@ -1810,7 +1810,7 @@ Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result) { | ... | @@ -1810,7 +1810,7 @@ Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result) { |
| 1810 | ZigType *get_auto_err_set_type(CodeGen *g, ZigFn *fn_entry) { | 1810 | ZigType *get_auto_err_set_type(CodeGen *g, ZigFn *fn_entry) { |
| 1811 | ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); | 1811 | ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); |
| 1812 | buf_resize(&err_set_type->name, 0); | 1812 | buf_resize(&err_set_type->name, 0); |
| 1813 | buf_appendf(&err_set_type->name, "@TypeOf(%s).ReturnType.ErrorSet", buf_ptr(&fn_entry->symbol_name)); | 1813 | buf_appendf(&err_set_type->name, "@typeInfo(@typeInfo(@TypeOf(%s)).Fn.return_type.?).ErrorUnion.error_set", buf_ptr(&fn_entry->symbol_name)); |
| 1814 | err_set_type->data.error_set.err_count = 0; | 1814 | err_set_type->data.error_set.err_count = 0; |
| 1815 | err_set_type->data.error_set.errors = nullptr; | 1815 | err_set_type->data.error_set.errors = nullptr; |
| 1816 | err_set_type->data.error_set.infer_fn = fn_entry; | 1816 | err_set_type->data.error_set.infer_fn = fn_entry; |
src/ir.cpp+3-161| ... | @@ -22836,167 +22836,9 @@ static IrInstGen *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstSrcFiel | ... | @@ -22836,167 +22836,9 @@ static IrInstGen *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstSrcFiel |
| 22836 | bool ptr_is_volatile = false; | 22836 | bool ptr_is_volatile = false; |
| 22837 | return ir_get_const_ptr(ira, &field_ptr_instruction->base.base, const_val, | 22837 | return ir_get_const_ptr(ira, &field_ptr_instruction->base.base, const_val, |
| 22838 | err_set_type, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); | 22838 | err_set_type, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); |
| 22839 | } else if (child_type->id == ZigTypeIdInt) { | ||
| 22840 | if (buf_eql_str(field_name, "bit_count")) { | ||
| 22841 | bool ptr_is_const = true; | ||
| 22842 | bool ptr_is_volatile = false; | ||
| 22843 | return ir_get_const_ptr(ira, &field_ptr_instruction->base.base, | ||
| 22844 | create_const_unsigned_negative(ira->codegen, ira->codegen->builtin_types.entry_num_lit_int, | ||
| 22845 | child_type->data.integral.bit_count, false), | ||
| 22846 | ira->codegen->builtin_types.entry_num_lit_int, | ||
| 22847 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); | ||
| 22848 | } else if (buf_eql_str(field_name, "is_signed")) { | ||
| 22849 | bool ptr_is_const = true; | ||
| 22850 | bool ptr_is_volatile = false; | ||
| 22851 | return ir_get_const_ptr(ira, &field_ptr_instruction->base.base, | ||
| 22852 | create_const_bool(ira->codegen, child_type->data.integral.is_signed), | ||
| 22853 | ira->codegen->builtin_types.entry_bool, | ||
| 22854 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); | ||
| 22855 | } else { | ||
| 22856 | ir_add_error(ira, &field_ptr_instruction->base.base, | ||
| 22857 | buf_sprintf("type '%s' has no member called '%s'", | ||
| 22858 | buf_ptr(&child_type->name), buf_ptr(field_name))); | ||
| 22859 | return ira->codegen->invalid_inst_gen; | ||
| 22860 | } | ||
| 22861 | } else if (child_type->id == ZigTypeIdFloat) { | ||
| 22862 | if (buf_eql_str(field_name, "bit_count")) { | ||
| 22863 | bool ptr_is_const = true; | ||
| 22864 | bool ptr_is_volatile = false; | ||
| 22865 | return ir_get_const_ptr(ira, &field_ptr_instruction->base.base, | ||
| 22866 | create_const_unsigned_negative(ira->codegen, ira->codegen->builtin_types.entry_num_lit_int, | ||
| 22867 | child_type->data.floating.bit_count, false), | ||
| 22868 | ira->codegen->builtin_types.entry_num_lit_int, | ||
| 22869 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); | ||
| 22870 | } else { | ||
| 22871 | ir_add_error(ira, &field_ptr_instruction->base.base, | ||
| 22872 | buf_sprintf("type '%s' has no member called '%s'", | ||
| 22873 | buf_ptr(&child_type->name), buf_ptr(field_name))); | ||
| 22874 | return ira->codegen->invalid_inst_gen; | ||
| 22875 | } | ||
| 22876 | } else if (child_type->id == ZigTypeIdPointer) { | ||
| 22877 | if (buf_eql_str(field_name, "Child")) { | ||
| 22878 | bool ptr_is_const = true; | ||
| 22879 | bool ptr_is_volatile = false; | ||
| 22880 | return ir_get_const_ptr(ira, &field_ptr_instruction->base.base, | ||
| 22881 | create_const_type(ira->codegen, child_type->data.pointer.child_type), | ||
| 22882 | ira->codegen->builtin_types.entry_type, | ||
| 22883 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); | ||
| 22884 | } else if (buf_eql_str(field_name, "alignment")) { | ||
| 22885 | bool ptr_is_const = true; | ||
| 22886 | bool ptr_is_volatile = false; | ||
| 22887 | if ((err = type_resolve(ira->codegen, child_type->data.pointer.child_type, | ||
| 22888 | ResolveStatusAlignmentKnown))) | ||
| 22889 | { | ||
| 22890 | return ira->codegen->invalid_inst_gen; | ||
| 22891 | } | ||
| 22892 | return ir_get_const_ptr(ira, &field_ptr_instruction->base.base, | ||
| 22893 | create_const_unsigned_negative(ira->codegen, ira->codegen->builtin_types.entry_num_lit_int, | ||
| 22894 | get_ptr_align(ira->codegen, child_type), false), | ||
| 22895 | ira->codegen->builtin_types.entry_num_lit_int, | ||
| 22896 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); | ||
| 22897 | } else { | ||
| 22898 | ir_add_error(ira, &field_ptr_instruction->base.base, | ||
| 22899 | buf_sprintf("type '%s' has no member called '%s'", | ||
| 22900 | buf_ptr(&child_type->name), buf_ptr(field_name))); | ||
| 22901 | return ira->codegen->invalid_inst_gen; | ||
| 22902 | } | ||
| 22903 | } else if (child_type->id == ZigTypeIdArray) { | ||
| 22904 | if (buf_eql_str(field_name, "Child")) { | ||
| 22905 | bool ptr_is_const = true; | ||
| 22906 | bool ptr_is_volatile = false; | ||
| 22907 | return ir_get_const_ptr(ira, &field_ptr_instruction->base.base, | ||
| 22908 | create_const_type(ira->codegen, child_type->data.array.child_type), | ||
| 22909 | ira->codegen->builtin_types.entry_type, | ||
| 22910 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); | ||
| 22911 | } else if (buf_eql_str(field_name, "len")) { | ||
| 22912 | bool ptr_is_const = true; | ||
| 22913 | bool ptr_is_volatile = false; | ||
| 22914 | return ir_get_const_ptr(ira, &field_ptr_instruction->base.base, | ||
| 22915 | create_const_unsigned_negative(ira->codegen, ira->codegen->builtin_types.entry_num_lit_int, | ||
| 22916 | child_type->data.array.len, false), | ||
| 22917 | ira->codegen->builtin_types.entry_num_lit_int, | ||
| 22918 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); | ||
| 22919 | } else { | ||
| 22920 | ir_add_error(ira, &field_ptr_instruction->base.base, | ||
| 22921 | buf_sprintf("type '%s' has no member called '%s'", | ||
| 22922 | buf_ptr(&child_type->name), buf_ptr(field_name))); | ||
| 22923 | return ira->codegen->invalid_inst_gen; | ||
| 22924 | } | ||
| 22925 | } else if (child_type->id == ZigTypeIdErrorUnion) { | ||
| 22926 | if (buf_eql_str(field_name, "Payload")) { | ||
| 22927 | bool ptr_is_const = true; | ||
| 22928 | bool ptr_is_volatile = false; | ||
| 22929 | return ir_get_const_ptr(ira, &field_ptr_instruction->base.base, | ||
| 22930 | create_const_type(ira->codegen, child_type->data.error_union.payload_type), | ||
| 22931 | ira->codegen->builtin_types.entry_type, | ||
| 22932 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); | ||
| 22933 | } else if (buf_eql_str(field_name, "ErrorSet")) { | ||
| 22934 | bool ptr_is_const = true; | ||
| 22935 | bool ptr_is_volatile = false; | ||
| 22936 | return ir_get_const_ptr(ira, &field_ptr_instruction->base.base, | ||
| 22937 | create_const_type(ira->codegen, child_type->data.error_union.err_set_type), | ||
| 22938 | ira->codegen->builtin_types.entry_type, | ||
| 22939 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); | ||
| 22940 | } else { | ||
| 22941 | ir_add_error(ira, &field_ptr_instruction->base.base, | ||
| 22942 | buf_sprintf("type '%s' has no member called '%s'", | ||
| 22943 | buf_ptr(&child_type->name), buf_ptr(field_name))); | ||
| 22944 | return ira->codegen->invalid_inst_gen; | ||
| 22945 | } | ||
| 22946 | } else if (child_type->id == ZigTypeIdOptional) { | ||
| 22947 | if (buf_eql_str(field_name, "Child")) { | ||
| 22948 | bool ptr_is_const = true; | ||
| 22949 | bool ptr_is_volatile = false; | ||
| 22950 | return ir_get_const_ptr(ira, &field_ptr_instruction->base.base, | ||
| 22951 | create_const_type(ira->codegen, child_type->data.maybe.child_type), | ||
| 22952 | ira->codegen->builtin_types.entry_type, | ||
| 22953 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); | ||
| 22954 | } else { | ||
| 22955 | ir_add_error(ira, &field_ptr_instruction->base.base, | ||
| 22956 | buf_sprintf("type '%s' has no member called '%s'", | ||
| 22957 | buf_ptr(&child_type->name), buf_ptr(field_name))); | ||
| 22958 | return ira->codegen->invalid_inst_gen; | ||
| 22959 | } | ||
| 22960 | } else if (child_type->id == ZigTypeIdFn) { | ||
| 22961 | if (buf_eql_str(field_name, "ReturnType")) { | ||
| 22962 | if (child_type->data.fn.fn_type_id.return_type == nullptr) { | ||
| 22963 | // Return type can only ever be null, if the function is generic | ||
| 22964 | assert(child_type->data.fn.is_generic); | ||
| 22965 | |||
| 22966 | ir_add_error(ira, &field_ptr_instruction->base.base, | ||
| 22967 | buf_sprintf("ReturnType has not been resolved because '%s' is generic", buf_ptr(&child_type->name))); | ||
| 22968 | return ira->codegen->invalid_inst_gen; | ||
| 22969 | } | ||
| 22970 | |||
| 22971 | bool ptr_is_const = true; | ||
| 22972 | bool ptr_is_volatile = false; | ||
| 22973 | return ir_get_const_ptr(ira, &field_ptr_instruction->base.base, | ||
| 22974 | create_const_type(ira->codegen, child_type->data.fn.fn_type_id.return_type), | ||
| 22975 | ira->codegen->builtin_types.entry_type, | ||
| 22976 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); | ||
| 22977 | } else if (buf_eql_str(field_name, "is_var_args")) { | ||
| 22978 | bool ptr_is_const = true; | ||
| 22979 | bool ptr_is_volatile = false; | ||
| 22980 | return ir_get_const_ptr(ira, &field_ptr_instruction->base.base, | ||
| 22981 | create_const_bool(ira->codegen, child_type->data.fn.fn_type_id.is_var_args), | ||
| 22982 | ira->codegen->builtin_types.entry_bool, | ||
| 22983 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); | ||
| 22984 | } else if (buf_eql_str(field_name, "arg_count")) { | ||
| 22985 | bool ptr_is_const = true; | ||
| 22986 | bool ptr_is_volatile = false; | ||
| 22987 | return ir_get_const_ptr(ira, &field_ptr_instruction->base.base, | ||
| 22988 | create_const_usize(ira->codegen, child_type->data.fn.fn_type_id.param_count), | ||
| 22989 | ira->codegen->builtin_types.entry_usize, | ||
| 22990 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); | ||
| 22991 | } else { | ||
| 22992 | ir_add_error(ira, &field_ptr_instruction->base.base, | ||
| 22993 | buf_sprintf("type '%s' has no member called '%s'", | ||
| 22994 | buf_ptr(&child_type->name), buf_ptr(field_name))); | ||
| 22995 | return ira->codegen->invalid_inst_gen; | ||
| 22996 | } | ||
| 22997 | } else { | 22839 | } else { |
| 22998 | ir_add_error(ira, &field_ptr_instruction->base.base, | 22840 | ir_add_error(ira, &field_ptr_instruction->base.base, |
| 22999 | buf_sprintf("type '%s' does not support field access", buf_ptr(&child_type->name))); | 22841 | buf_sprintf("type '%s' does not support field access", buf_ptr(&container_type->name))); |
| 23000 | return ira->codegen->invalid_inst_gen; | 22842 | return ira->codegen->invalid_inst_gen; |
| 23001 | } | 22843 | } |
| 23002 | } else if (field_ptr_instruction->initializing) { | 22844 | } else if (field_ptr_instruction->initializing) { |
| ... | @@ -26753,7 +26595,7 @@ static IrInstGen *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstSrcCmpxch | ... | @@ -26753,7 +26595,7 @@ static IrInstGen *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstSrcCmpxch |
| 26753 | 26595 | ||
| 26754 | if (operand_type->id == ZigTypeIdFloat) { | 26596 | if (operand_type->id == ZigTypeIdFloat) { |
| 26755 | ir_add_error(ira, &instruction->type_value->child->base, | 26597 | ir_add_error(ira, &instruction->type_value->child->base, |
| 26756 | buf_sprintf("expected integer, enum or pointer type, found '%s'", buf_ptr(&operand_type->name))); | 26598 | buf_sprintf("expected bool, integer, enum or pointer type, found '%s'", buf_ptr(&operand_type->name))); |
| 26757 | return ira->codegen->invalid_inst_gen; | 26599 | return ira->codegen->invalid_inst_gen; |
| 26758 | } | 26600 | } |
| 26759 | 26601 | ||
| ... | @@ -30408,7 +30250,7 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op) { | ... | @@ -30408,7 +30250,7 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op) { |
| 30408 | return ira->codegen->builtin_types.entry_invalid; | 30250 | return ira->codegen->builtin_types.entry_invalid; |
| 30409 | if (operand_ptr_type == nullptr) { | 30251 | if (operand_ptr_type == nullptr) { |
| 30410 | ir_add_error(ira, &op->base, | 30252 | ir_add_error(ira, &op->base, |
| 30411 | buf_sprintf("expected integer, float, enum or pointer type, found '%s'", | 30253 | buf_sprintf("expected bool, integer, float, enum or pointer type, found '%s'", |
| 30412 | buf_ptr(&operand_type->name))); | 30254 | buf_ptr(&operand_type->name))); |
| 30413 | return ira->codegen->builtin_types.entry_invalid; | 30255 | return ira->codegen->builtin_types.entry_invalid; |
| 30414 | } | 30256 | } |
test/compile_errors.zig+8-17| ... | @@ -176,11 +176,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -176,11 +176,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 176 | , &[_][]const u8{ | 176 | , &[_][]const u8{ |
| 177 | "tmp.zig:2:17: error: expected type 'u32', found 'error{Ohno}'", | 177 | "tmp.zig:2:17: error: expected type 'u32', found 'error{Ohno}'", |
| 178 | "tmp.zig:1:17: note: function cannot return an error", | 178 | "tmp.zig:1:17: note: function cannot return an error", |
| 179 | "tmp.zig:8:5: error: expected type 'void', found '@TypeOf(bar).ReturnType.ErrorSet'", | 179 | "tmp.zig:8:5: error: expected type 'void', found '@typeInfo(@typeInfo(@TypeOf(bar)).Fn.return_type.?).ErrorUnion.error_set'", |
| 180 | "tmp.zig:7:17: note: function cannot return an error", | 180 | "tmp.zig:7:17: note: function cannot return an error", |
| 181 | "tmp.zig:11:15: error: expected type 'u32', found '@TypeOf(bar).ReturnType.ErrorSet!u32'", | 181 | "tmp.zig:11:15: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(bar)).Fn.return_type.?).ErrorUnion.error_set!u32'", |
| 182 | "tmp.zig:10:17: note: function cannot return an error", | 182 | "tmp.zig:10:17: note: function cannot return an error", |
| 183 | "tmp.zig:15:14: error: expected type 'u32', found '@TypeOf(bar).ReturnType.ErrorSet!u32'", | 183 | "tmp.zig:15:14: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(bar)).Fn.return_type.?).ErrorUnion.error_set!u32'", |
| 184 | "tmp.zig:14:5: note: cannot store an error in type 'u32'", | 184 | "tmp.zig:14:5: note: cannot store an error in type 'u32'", |
| 185 | }); | 185 | }); |
| 186 | 186 | ||
| ... | @@ -899,7 +899,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -899,7 +899,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 899 | \\ _ = @cmpxchgWeak(f32, &x, 1, 2, .SeqCst, .SeqCst); | 899 | \\ _ = @cmpxchgWeak(f32, &x, 1, 2, .SeqCst, .SeqCst); |
| 900 | \\} | 900 | \\} |
| 901 | , &[_][]const u8{ | 901 | , &[_][]const u8{ |
| 902 | "tmp.zig:3:22: error: expected integer, enum or pointer type, found 'f32'", | 902 | "tmp.zig:3:22: error: expected bool, integer, enum or pointer type, found 'f32'", |
| 903 | }); | 903 | }); |
| 904 | 904 | ||
| 905 | cases.add("atomicrmw with float op not .Xchg, .Add or .Sub", | 905 | cases.add("atomicrmw with float op not .Xchg, .Add or .Sub", |
| ... | @@ -1224,7 +1224,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -1224,7 +1224,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1224 | \\ }; | 1224 | \\ }; |
| 1225 | \\} | 1225 | \\} |
| 1226 | , &[_][]const u8{ | 1226 | , &[_][]const u8{ |
| 1227 | "tmp.zig:11:25: error: expected type 'u32', found '@TypeOf(get_uval).ReturnType.ErrorSet!u32'", | 1227 | "tmp.zig:11:25: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(get_uval)).Fn.return_type.?).ErrorUnion.error_set!u32'", |
| 1228 | }); | 1228 | }); |
| 1229 | 1229 | ||
| 1230 | cases.add("assigning to struct or union fields that are not optionals with a function that returns an optional", | 1230 | cases.add("assigning to struct or union fields that are not optionals with a function that returns an optional", |
| ... | @@ -1929,7 +1929,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -1929,7 +1929,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1929 | \\ const info = @TypeOf(slice).unknown; | 1929 | \\ const info = @TypeOf(slice).unknown; |
| 1930 | \\} | 1930 | \\} |
| 1931 | , &[_][]const u8{ | 1931 | , &[_][]const u8{ |
| 1932 | "tmp.zig:3:32: error: type '[]i32' does not support field access", | 1932 | "tmp.zig:3:32: error: type 'type' does not support field access", |
| 1933 | }); | 1933 | }); |
| 1934 | 1934 | ||
| 1935 | cases.add("peer cast then implicit cast const pointer to mutable C pointer", | 1935 | cases.add("peer cast then implicit cast const pointer to mutable C pointer", |
| ... | @@ -3542,7 +3542,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -3542,7 +3542,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 3542 | \\ } | 3542 | \\ } |
| 3543 | \\} | 3543 | \\} |
| 3544 | , &[_][]const u8{ | 3544 | , &[_][]const u8{ |
| 3545 | "tmp.zig:5:14: error: duplicate switch value: '@TypeOf(foo).ReturnType.ErrorSet.Foo'", | 3545 | "tmp.zig:5:14: error: duplicate switch value: '@typeInfo(@typeInfo(@TypeOf(foo)).Fn.return_type.?).ErrorUnion.error_set.Foo'", |
| 3546 | "tmp.zig:3:14: note: other value is here", | 3546 | "tmp.zig:3:14: note: other value is here", |
| 3547 | }); | 3547 | }); |
| 3548 | 3548 | ||
| ... | @@ -3674,7 +3674,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -3674,7 +3674,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 3674 | \\ try foo(); | 3674 | \\ try foo(); |
| 3675 | \\} | 3675 | \\} |
| 3676 | , &[_][]const u8{ | 3676 | , &[_][]const u8{ |
| 3677 | "tmp.zig:5:5: error: cannot resolve inferred error set '@TypeOf(foo).ReturnType.ErrorSet': function 'foo' not fully analyzed yet", | 3677 | "tmp.zig:5:5: error: cannot resolve inferred error set '@typeInfo(@typeInfo(@TypeOf(foo)).Fn.return_type.?).ErrorUnion.error_set': function 'foo' not fully analyzed yet", |
| 3678 | }); | 3678 | }); |
| 3679 | 3679 | ||
| 3680 | cases.add("implicit cast of error set not a subset", | 3680 | cases.add("implicit cast of error set not a subset", |
| ... | @@ -7206,15 +7206,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -7206,15 +7206,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 7206 | "tmp.zig:7:24: error: accessing union field 'Bar' while field 'Baz' is set", | 7206 | "tmp.zig:7:24: error: accessing union field 'Bar' while field 'Baz' is set", |
| 7207 | }); | 7207 | }); |
| 7208 | 7208 | ||
| 7209 | cases.add("getting return type of generic function", | ||
| 7210 | \\fn generic(a: anytype) void {} | ||
| 7211 | \\comptime { | ||
| 7212 | \\ _ = @TypeOf(generic).ReturnType; | ||
| 7213 | \\} | ||
| 7214 | , &[_][]const u8{ | ||
| 7215 | "tmp.zig:3:25: error: ReturnType has not been resolved because 'fn(anytype) anytype' is generic", | ||
| 7216 | }); | ||
| 7217 | |||
| 7218 | cases.add("unsupported modifier at start of asm output constraint", | 7209 | cases.add("unsupported modifier at start of asm output constraint", |
| 7219 | \\export fn foo() void { | 7210 | \\export fn foo() void { |
| 7220 | \\ var bar: u32 = 3; | 7211 | \\ var bar: u32 = 3; |
test/stage1/behavior/align.zig+1-1| ... | @@ -5,7 +5,7 @@ const builtin = @import("builtin"); | ... | @@ -5,7 +5,7 @@ const builtin = @import("builtin"); |
| 5 | var foo: u8 align(4) = 100; | 5 | var foo: u8 align(4) = 100; |
| 6 | 6 | ||
| 7 | test "global variable alignment" { | 7 | test "global variable alignment" { |
| 8 | comptime expect(@TypeOf(&foo).alignment == 4); | 8 | comptime expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4); |
| 9 | comptime expect(@TypeOf(&foo) == *align(4) u8); | 9 | comptime expect(@TypeOf(&foo) == *align(4) u8); |
| 10 | { | 10 | { |
| 11 | const slice = @as(*[1]u8, &foo)[0..]; | 11 | const slice = @as(*[1]u8, &foo)[0..]; |
test/stage1/behavior/array.zig-10| ... | @@ -136,16 +136,6 @@ test "array literal with specified size" { | ... | @@ -136,16 +136,6 @@ test "array literal with specified size" { |
| 136 | expect(array[1] == 2); | 136 | expect(array[1] == 2); |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | test "array child property" { | ||
| 140 | var x: [5]i32 = undefined; | ||
| 141 | expect(@TypeOf(x).Child == i32); | ||
| 142 | } | ||
| 143 | |||
| 144 | test "array len property" { | ||
| 145 | var x: [5]i32 = undefined; | ||
| 146 | expect(@TypeOf(x).len == 5); | ||
| 147 | } | ||
| 148 | |||
| 149 | test "array len field" { | 139 | test "array len field" { |
| 150 | var arr = [4]u8{ 0, 0, 0, 0 }; | 140 | var arr = [4]u8{ 0, 0, 0, 0 }; |
| 151 | var ptr = &arr; | 141 | var ptr = &arr; |
test/stage1/behavior/async_fn.zig+3-3| ... | @@ -331,7 +331,7 @@ test "async fn with inferred error set" { | ... | @@ -331,7 +331,7 @@ test "async fn with inferred error set" { |
| 331 | fn doTheTest() void { | 331 | fn doTheTest() void { |
| 332 | var frame: [1]@Frame(middle) = undefined; | 332 | var frame: [1]@Frame(middle) = undefined; |
| 333 | var fn_ptr = middle; | 333 | var fn_ptr = middle; |
| 334 | var result: @TypeOf(fn_ptr).ReturnType.ErrorSet!void = undefined; | 334 | var result: @typeInfo(@typeInfo(@TypeOf(fn_ptr)).Fn.return_type.?).ErrorUnion.error_set!void = undefined; |
| 335 | _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, fn_ptr, .{}); | 335 | _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, fn_ptr, .{}); |
| 336 | resume global_frame; | 336 | resume global_frame; |
| 337 | std.testing.expectError(error.Fail, result); | 337 | std.testing.expectError(error.Fail, result); |
| ... | @@ -950,7 +950,7 @@ test "@asyncCall with comptime-known function, but not awaited directly" { | ... | @@ -950,7 +950,7 @@ test "@asyncCall with comptime-known function, but not awaited directly" { |
| 950 | 950 | ||
| 951 | fn doTheTest() void { | 951 | fn doTheTest() void { |
| 952 | var frame: [1]@Frame(middle) = undefined; | 952 | var frame: [1]@Frame(middle) = undefined; |
| 953 | var result: @TypeOf(middle).ReturnType.ErrorSet!void = undefined; | 953 | var result: @typeInfo(@typeInfo(@TypeOf(middle)).Fn.return_type.?).ErrorUnion.error_set!void = undefined; |
| 954 | _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, middle, .{}); | 954 | _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, middle, .{}); |
| 955 | resume global_frame; | 955 | resume global_frame; |
| 956 | std.testing.expectError(error.Fail, result); | 956 | std.testing.expectError(error.Fail, result); |
| ... | @@ -1018,7 +1018,7 @@ test "@TypeOf an async function call of generic fn with error union type" { | ... | @@ -1018,7 +1018,7 @@ test "@TypeOf an async function call of generic fn with error union type" { |
| 1018 | const S = struct { | 1018 | const S = struct { |
| 1019 | fn func(comptime x: anytype) anyerror!i32 { | 1019 | fn func(comptime x: anytype) anyerror!i32 { |
| 1020 | const T = @TypeOf(async func(x)); | 1020 | const T = @TypeOf(async func(x)); |
| 1021 | comptime expect(T == @TypeOf(@frame()).Child); | 1021 | comptime expect(T == @typeInfo(@TypeOf(@frame())).Pointer.child); |
| 1022 | return undefined; | 1022 | return undefined; |
| 1023 | } | 1023 | } |
| 1024 | }; | 1024 | }; |
test/stage1/behavior/bit_shifting.zig+7-5| ... | @@ -2,16 +2,18 @@ const std = @import("std"); | ... | @@ -2,16 +2,18 @@ const std = @import("std"); |
| 2 | const expect = std.testing.expect; | 2 | const expect = std.testing.expect; |
| 3 | 3 | ||
| 4 | fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime V: type) type { | 4 | fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime V: type) type { |
| 5 | expect(Key == std.meta.Int(false, Key.bit_count)); | 5 | const key_bits = @typeInfo(Key).Int.bits; |
| 6 | expect(Key.bit_count >= mask_bit_count); | 6 | expect(Key == std.meta.Int(false, key_bits)); |
| 7 | expect(key_bits >= mask_bit_count); | ||
| 8 | const shard_key_bits = mask_bit_count; | ||
| 7 | const ShardKey = std.meta.Int(false, mask_bit_count); | 9 | const ShardKey = std.meta.Int(false, mask_bit_count); |
| 8 | const shift_amount = Key.bit_count - ShardKey.bit_count; | 10 | const shift_amount = key_bits - shard_key_bits; |
| 9 | return struct { | 11 | return struct { |
| 10 | const Self = @This(); | 12 | const Self = @This(); |
| 11 | shards: [1 << ShardKey.bit_count]?*Node, | 13 | shards: [1 << shard_key_bits]?*Node, |
| 12 | 14 | ||
| 13 | pub fn create() Self { | 15 | pub fn create() Self { |
| 14 | return Self{ .shards = [_]?*Node{null} ** (1 << ShardKey.bit_count) }; | 16 | return Self{ .shards = [_]?*Node{null} ** (1 << shard_key_bits) }; |
| 15 | } | 17 | } |
| 16 | 18 | ||
| 17 | fn getShardKey(key: Key) ShardKey { | 19 | fn getShardKey(key: Key) ShardKey { |
test/stage1/behavior/bugs/5487.zig+2-2| ... | @@ -3,8 +3,8 @@ const io = @import("std").io; | ... | @@ -3,8 +3,8 @@ const io = @import("std").io; |
| 3 | pub fn write(_: void, bytes: []const u8) !usize { | 3 | pub fn write(_: void, bytes: []const u8) !usize { |
| 4 | return 0; | 4 | return 0; |
| 5 | } | 5 | } |
| 6 | pub fn outStream() io.OutStream(void, @TypeOf(write).ReturnType.ErrorSet, write) { | 6 | pub fn outStream() io.OutStream(void, @typeInfo(@typeInfo(@TypeOf(write)).Fn.return_type.?).ErrorUnion.error_set, write) { |
| 7 | return io.OutStream(void, @TypeOf(write).ReturnType.ErrorSet, write){ .context = {} }; | 7 | return io.OutStream(void, @typeInfo(@typeInfo(@TypeOf(write)).Fn.return_type.?).ErrorUnion.error_set, write){ .context = {} }; |
| 8 | } | 8 | } |
| 9 | 9 | ||
| 10 | test "crash" { | 10 | test "crash" { |
test/stage1/behavior/error.zig+2-2| ... | @@ -84,8 +84,8 @@ fn testErrorUnionType() void { | ... | @@ -84,8 +84,8 @@ fn testErrorUnionType() void { |
| 84 | const x: anyerror!i32 = 1234; | 84 | const x: anyerror!i32 = 1234; |
| 85 | if (x) |value| expect(value == 1234) else |_| unreachable; | 85 | if (x) |value| expect(value == 1234) else |_| unreachable; |
| 86 | expect(@typeInfo(@TypeOf(x)) == .ErrorUnion); | 86 | expect(@typeInfo(@TypeOf(x)) == .ErrorUnion); |
| 87 | expect(@typeInfo(@TypeOf(x).ErrorSet) == .ErrorSet); | 87 | expect(@typeInfo(@typeInfo(@TypeOf(x)).ErrorUnion.error_set) == .ErrorSet); |
| 88 | expect(@TypeOf(x).ErrorSet == anyerror); | 88 | expect(@typeInfo(@TypeOf(x)).ErrorUnion.error_set == anyerror); |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | test "error set type" { | 91 | test "error set type" { |
test/stage1/behavior/misc.zig-10| ... | @@ -24,12 +24,6 @@ test "call disabled extern fn" { | ... | @@ -24,12 +24,6 @@ test "call disabled extern fn" { |
| 24 | disabledExternFn(); | 24 | disabledExternFn(); |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | test "floating point primitive bit counts" { | ||
| 28 | expect(f16.bit_count == 16); | ||
| 29 | expect(f32.bit_count == 32); | ||
| 30 | expect(f64.bit_count == 64); | ||
| 31 | } | ||
| 32 | |||
| 33 | test "short circuit" { | 27 | test "short circuit" { |
| 34 | testShortCircuit(false, true); | 28 | testShortCircuit(false, true); |
| 35 | comptime testShortCircuit(false, true); | 29 | comptime testShortCircuit(false, true); |
| ... | @@ -577,10 +571,6 @@ test "slice string literal has correct type" { | ... | @@ -577,10 +571,6 @@ test "slice string literal has correct type" { |
| 577 | comptime expect(@TypeOf(array[runtime_zero..]) == []const i32); | 571 | comptime expect(@TypeOf(array[runtime_zero..]) == []const i32); |
| 578 | } | 572 | } |
| 579 | 573 | ||
| 580 | test "pointer child field" { | ||
| 581 | expect((*u32).Child == u32); | ||
| 582 | } | ||
| 583 | |||
| 584 | test "struct inside function" { | 574 | test "struct inside function" { |
| 585 | testStructInFn(); | 575 | testStructInFn(); |
| 586 | comptime testStructInFn(); | 576 | comptime testStructInFn(); |
test/stage1/behavior/reflection.zig+7-15| ... | @@ -2,23 +2,15 @@ const expect = @import("std").testing.expect; | ... | @@ -2,23 +2,15 @@ const expect = @import("std").testing.expect; |
| 2 | const mem = @import("std").mem; | 2 | const mem = @import("std").mem; |
| 3 | const reflection = @This(); | 3 | const reflection = @This(); |
| 4 | 4 | ||
| 5 | test "reflection: array, pointer, optional, error union type child" { | ||
| 6 | comptime { | ||
| 7 | expect(([10]u8).Child == u8); | ||
| 8 | expect((*u8).Child == u8); | ||
| 9 | expect((anyerror!u8).Payload == u8); | ||
| 10 | expect((?u8).Child == u8); | ||
| 11 | } | ||
| 12 | } | ||
| 13 | |||
| 14 | test "reflection: function return type, var args, and param types" { | 5 | test "reflection: function return type, var args, and param types" { |
| 15 | comptime { | 6 | comptime { |
| 16 | expect(@TypeOf(dummy).ReturnType == i32); | 7 | const info = @typeInfo(@TypeOf(dummy)).Fn; |
| 17 | expect(!@TypeOf(dummy).is_var_args); | 8 | expect(info.return_type.? == i32); |
| 18 | expect(@TypeOf(dummy).arg_count == 3); | 9 | expect(!info.is_var_args); |
| 19 | expect(@typeInfo(@TypeOf(dummy)).Fn.args[0].arg_type.? == bool); | 10 | expect(info.args.len == 3); |
| 20 | expect(@typeInfo(@TypeOf(dummy)).Fn.args[1].arg_type.? == i32); | 11 | expect(info.args[0].arg_type.? == bool); |
| 21 | expect(@typeInfo(@TypeOf(dummy)).Fn.args[2].arg_type.? == f32); | 12 | expect(info.args[1].arg_type.? == i32); |
| 13 | expect(info.args[2].arg_type.? == f32); | ||
| 22 | } | 14 | } |
| 23 | } | 15 | } |
| 24 | 16 |