| author | |
| committer | |
| log | de7fdfecd81e74c115395256179c64cb480cb860 |
| tree | 6bdf7898cf24cf909be6a96b06a3bb40936333d2 |
| parent | ac7bf53d9486d6c9a079a818dc87891551eaeac1 |
| parent | e42cb3b2369b3034c15be3a6f0bf519db4baac98 |
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36043
Reviewed-by: Andrew Kelley <andrew@ziglang.org>55 files changed, 974 insertions(+), 100 deletions(-)
doc/langref.html.in+20-4| ... | @@ -1370,7 +1370,8 @@ a /= b{#endsyntax#}</pre></td> | ... | @@ -1370,7 +1370,8 @@ a /= b{#endsyntax#}</pre></td> |
| 1370 | <li>Can cause {#link|Division by Zero#} for floats in {#link|FloatMode.optimized Mode|Floating Point Operations#}.</li> | 1370 | <li>Can cause {#link|Division by Zero#} for floats in {#link|FloatMode.optimized Mode|Floating Point Operations#}.</li> |
| 1371 | <li>Signed integer operands must be comptime-known and positive. In other cases, use | 1371 | <li>Signed integer operands must be comptime-known and positive. In other cases, use |
| 1372 | {#link|@divTrunc#}, | 1372 | {#link|@divTrunc#}, |
| 1373 | {#link|@divFloor#}, or | 1373 | {#link|@divFloor#}, |
| 1374 | {#link|@divCeil#}, or | ||
| 1374 | {#link|@divExact#} instead. | 1375 | {#link|@divExact#} instead. |
| 1375 | </li> | 1376 | </li> |
| 1376 | <li>Invokes {#link|Peer Type Resolution#} for the operands.</li> | 1377 | <li>Invokes {#link|Peer Type Resolution#} for the operands.</li> |
| ... | @@ -4735,7 +4736,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val | ... | @@ -4735,7 +4736,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val |
| 4735 | <li>{#syntax#}@divExact(a, b) * b == a{#endsyntax#}</li> | 4736 | <li>{#syntax#}@divExact(a, b) * b == a{#endsyntax#}</li> |
| 4736 | </ul> | 4737 | </ul> |
| 4737 | <p>For a function that returns a possible error code, use {#syntax#}@import("std").math.divExact{#endsyntax#}.</p> | 4738 | <p>For a function that returns a possible error code, use {#syntax#}@import("std").math.divExact{#endsyntax#}.</p> |
| 4738 | {#see_also|@divTrunc|@divFloor#} | 4739 | {#see_also|@divTrunc|@divFloor|@divCeil#} |
| 4739 | {#header_close#} | 4740 | {#header_close#} |
| 4740 | {#header_open|@divFloor#} | 4741 | {#header_open|@divFloor#} |
| 4741 | <pre>{#syntax#}@divFloor(numerator: T, denominator: T) T{#endsyntax#}</pre> | 4742 | <pre>{#syntax#}@divFloor(numerator: T, denominator: T) T{#endsyntax#}</pre> |
| ... | @@ -4749,7 +4750,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val | ... | @@ -4749,7 +4750,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val |
| 4749 | <li>{#syntax#}(@divFloor(a, b) * b) + @mod(a, b) == a{#endsyntax#}</li> | 4750 | <li>{#syntax#}(@divFloor(a, b) * b) + @mod(a, b) == a{#endsyntax#}</li> |
| 4750 | </ul> | 4751 | </ul> |
| 4751 | <p>For a function that returns a possible error code, use {#syntax#}@import("std").math.divFloor{#endsyntax#}.</p> | 4752 | <p>For a function that returns a possible error code, use {#syntax#}@import("std").math.divFloor{#endsyntax#}.</p> |
| 4752 | {#see_also|@divTrunc|@divExact#} | 4753 | {#see_also|@divTrunc|@divCeil|@divExact#} |
| 4753 | {#header_close#} | 4754 | {#header_close#} |
| 4754 | {#header_open|@divTrunc#} | 4755 | {#header_open|@divTrunc#} |
| 4755 | <pre>{#syntax#}@divTrunc(numerator: T, denominator: T) T{#endsyntax#}</pre> | 4756 | <pre>{#syntax#}@divTrunc(numerator: T, denominator: T) T{#endsyntax#}</pre> |
| ... | @@ -4763,7 +4764,20 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val | ... | @@ -4763,7 +4764,20 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val |
| 4763 | <li>{#syntax#}(@divTrunc(a, b) * b) + @rem(a, b) == a{#endsyntax#}</li> | 4764 | <li>{#syntax#}(@divTrunc(a, b) * b) + @rem(a, b) == a{#endsyntax#}</li> |
| 4764 | </ul> | 4765 | </ul> |
| 4765 | <p>For a function that returns a possible error code, use {#syntax#}@import("std").math.divTrunc{#endsyntax#}.</p> | 4766 | <p>For a function that returns a possible error code, use {#syntax#}@import("std").math.divTrunc{#endsyntax#}.</p> |
| 4766 | {#see_also|@divFloor|@divExact#} | 4767 | {#see_also|@divFloor|@divCeil|@divExact#} |
| 4768 | {#header_close#} | ||
| 4769 | {#header_open|@divCeil#} | ||
| 4770 | <pre>{#syntax#}@divCeil(numerator: T, denominator: T) T{#endsyntax#}</pre> | ||
| 4771 | <p> | ||
| 4772 | Ceiled division. Rounds toward positive infinity. Caller guarantees {#syntax#}denominator != 0{#endsyntax#} and | ||
| 4773 | {#syntax#}!(@typeInfo(T) == .int and T.is_signed and numerator == std.math.minInt(T) and denominator == -1){#endsyntax#}. | ||
| 4774 | </p> | ||
| 4775 | <ul> | ||
| 4776 | <li>{#syntax#}@divCeil(5, 3) == 2{#endsyntax#}</li> | ||
| 4777 | <li>{#syntax#}@divCeil(-5, 3) == -1{#endsyntax#}</li> | ||
| 4778 | </ul> | ||
| 4779 | <p>For a function that returns a possible error code, use {#syntax#}@import("std").math.divCeil{#endsyntax#}.</p> | ||
| 4780 | {#see_also|@divFloor|@divTrunc|@divExact#} | ||
| 4767 | {#header_close#} | 4781 | {#header_close#} |
| 4768 | 4782 | ||
| 4769 | {#header_open|@embedFile#} | 4783 | {#header_open|@embedFile#} |
| ... | @@ -6095,6 +6109,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val | ... | @@ -6095,6 +6109,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val |
| 6095 | <li>{#syntax#}/{#endsyntax#} (division)</li> | 6109 | <li>{#syntax#}/{#endsyntax#} (division)</li> |
| 6096 | <li>{#link|@divTrunc#} (division)</li> | 6110 | <li>{#link|@divTrunc#} (division)</li> |
| 6097 | <li>{#link|@divFloor#} (division)</li> | 6111 | <li>{#link|@divFloor#} (division)</li> |
| 6112 | <li>{#link|@divCeil#} (division)</li> | ||
| 6098 | <li>{#link|@divExact#} (division)</li> | 6113 | <li>{#link|@divExact#} (division)</li> |
| 6099 | </ul> | 6114 | </ul> |
| 6100 | <p>Example with addition at compile-time:</p> | 6115 | <p>Example with addition at compile-time:</p> |
| ... | @@ -6112,6 +6127,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val | ... | @@ -6112,6 +6127,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val |
| 6112 | <li>{#syntax#}@import("std").math.mul{#endsyntax#}</li> | 6127 | <li>{#syntax#}@import("std").math.mul{#endsyntax#}</li> |
| 6113 | <li>{#syntax#}@import("std").math.divTrunc{#endsyntax#}</li> | 6128 | <li>{#syntax#}@import("std").math.divTrunc{#endsyntax#}</li> |
| 6114 | <li>{#syntax#}@import("std").math.divFloor{#endsyntax#}</li> | 6129 | <li>{#syntax#}@import("std").math.divFloor{#endsyntax#}</li> |
| 6130 | <li>{#syntax#}@import("std").math.divCeil{#endsyntax#}</li> | ||
| 6115 | <li>{#syntax#}@import("std").math.divExact{#endsyntax#}</li> | 6131 | <li>{#syntax#}@import("std").math.divExact{#endsyntax#}</li> |
| 6116 | <li>{#syntax#}@import("std").math.shl{#endsyntax#}</li> | 6132 | <li>{#syntax#}@import("std").math.shl{#endsyntax#}</li> |
| 6117 | </ul> | 6133 | </ul> |
lib/compiler/Maker/WebServer.zig+1-1| ... | @@ -163,7 +163,7 @@ pub fn updateConfiguration(ws: *WebServer, maker: *Maker) !void { | ... | @@ -163,7 +163,7 @@ pub fn updateConfiguration(ws: *WebServer, maker: *Maker) !void { |
| 163 | assert(idx == step_names_trailing.len); | 163 | assert(idx == step_names_trailing.len); |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | const step_status_bits = try gpa.alloc(u8, std.math.divCeil(usize, all_steps.len, 4) catch unreachable); | 166 | const step_status_bits = try gpa.alloc(u8, @divCeil(all_steps.len, 4)); |
| 167 | errdefer gpa.free(step_status_bits); | 167 | errdefer gpa.free(step_status_bits); |
| 168 | @memset(step_status_bits, 0); | 168 | @memset(step_status_bits, 0); |
| 169 | 169 |
lib/compiler_rt/limb64.zig+1-2| ... | @@ -3,7 +3,6 @@ const testing = std.testing; | ... | @@ -3,7 +3,6 @@ const testing = std.testing; |
| 3 | const assert = std.debug.assert; | 3 | const assert = std.debug.assert; |
| 4 | const maxInt = std.math.maxInt; | 4 | const maxInt = std.math.maxInt; |
| 5 | const minInt = std.math.minInt; | 5 | const minInt = std.math.minInt; |
| 6 | const divCeil = std.math.divCeil; | ||
| 7 | 6 | ||
| 8 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 9 | const compiler_rt = @import("../compiler_rt.zig"); | 8 | const compiler_rt = @import("../compiler_rt.zig"); |
| ... | @@ -26,7 +25,7 @@ inline fn limbSet(limbs: []u64, i: usize, value: u64) void { | ... | @@ -26,7 +25,7 @@ inline fn limbSet(limbs: []u64, i: usize, value: u64) void { |
| 26 | } | 25 | } |
| 27 | 26 | ||
| 28 | fn usedLimbCount(bits: u16) u16 { | 27 | fn usedLimbCount(bits: u16) u16 { |
| 29 | return divCeil(u16, bits, 64) catch unreachable; | 28 | return @divCeil(bits, 64); |
| 30 | } | 29 | } |
| 31 | 30 | ||
| 32 | fn limbCount(bits: u16) u16 { | 31 | fn limbCount(bits: u16) u16 { |
lib/compiler_rt/udivmodei4.zig+1-1| ... | @@ -8,7 +8,7 @@ const shl = std.math.shl; | ... | @@ -8,7 +8,7 @@ const shl = std.math.shl; |
| 8 | const compiler_rt = @import("../compiler_rt.zig"); | 8 | const compiler_rt = @import("../compiler_rt.zig"); |
| 9 | const symbol = @import("../compiler_rt.zig").symbol; | 9 | const symbol = @import("../compiler_rt.zig").symbol; |
| 10 | 10 | ||
| 11 | const max_limbs = std.math.divCeil(usize, 65535, 32) catch unreachable; // max supported type is u65535 | 11 | const max_limbs = @divCeil(65535, 32); // max supported type is u65535 |
| 12 | 12 | ||
| 13 | comptime { | 13 | comptime { |
| 14 | symbol(&__udivei4, "__udivei4"); | 14 | symbol(&__udivei4, "__udivei4"); |
lib/fuzzer.zig+1-1| ... | @@ -52,7 +52,7 @@ var fuzzer: Fuzzer = undefined; | ... | @@ -52,7 +52,7 @@ var fuzzer: Fuzzer = undefined; |
| 52 | var current_test_name: ?[]const u8 = null; | 52 | var current_test_name: ?[]const u8 = null; |
| 53 | 53 | ||
| 54 | fn bitsetUsizes(elems: usize) usize { | 54 | fn bitsetUsizes(elems: usize) usize { |
| 55 | return math.divCeil(usize, elems, @bitSizeOf(usize)) catch unreachable; | 55 | return @divCeil(elems, @bitSizeOf(usize)); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | const Executable = struct { | 58 | const Executable = struct { |
lib/std/Random.zig+1-1| ... | @@ -126,7 +126,7 @@ pub fn enumValueWithIndex(r: Random, comptime EnumType: type, comptime Index: ty | ... | @@ -126,7 +126,7 @@ pub fn enumValueWithIndex(r: Random, comptime EnumType: type, comptime Index: ty |
| 126 | pub fn int(r: Random, comptime T: type) T { | 126 | pub fn int(r: Random, comptime T: type) T { |
| 127 | const bits = @typeInfo(T).int.bits; | 127 | const bits = @typeInfo(T).int.bits; |
| 128 | const UnsignedT = @Int(.unsigned, bits); | 128 | const UnsignedT = @Int(.unsigned, bits); |
| 129 | const ceil_bytes = comptime std.math.divCeil(u16, bits, 8) catch unreachable; | 129 | const ceil_bytes = @divCeil(bits, 8); |
| 130 | const ByteAlignedT = @Int(.unsigned, ceil_bytes * 8); | 130 | const ByteAlignedT = @Int(.unsigned, ceil_bytes * 8); |
| 131 | 131 | ||
| 132 | var rand_bytes: [ceil_bytes]u8 = undefined; | 132 | var rand_bytes: [ceil_bytes]u8 = undefined; |
lib/std/Target.zig+1-1| ... | @@ -1232,7 +1232,7 @@ pub const Cpu = struct { | ... | @@ -1232,7 +1232,7 @@ pub const Cpu = struct { |
| 1232 | ints: [usize_count]usize, | 1232 | ints: [usize_count]usize, |
| 1233 | 1233 | ||
| 1234 | pub const needed_bit_count = 347; | 1234 | pub const needed_bit_count = 347; |
| 1235 | pub const byte_count = (needed_bit_count + 7) / 8; | 1235 | pub const byte_count = @divCeil(needed_bit_count, 8); |
| 1236 | pub const usize_count = (byte_count + (@sizeOf(usize) - 1)) / @sizeOf(usize); | 1236 | pub const usize_count = (byte_count + (@sizeOf(usize) - 1)) / @sizeOf(usize); |
| 1237 | pub const Index = std.math.Log2Int(@Int(.unsigned, usize_count * @bitSizeOf(usize))); | 1237 | pub const Index = std.math.Log2Int(@Int(.unsigned, usize_count * @bitSizeOf(usize))); |
| 1238 | pub const ShiftInt = std.math.Log2Int(usize); | 1238 | pub const ShiftInt = std.math.Log2Int(usize); |
lib/std/crypto/aes_gcm.zig+2-2| ... | @@ -39,7 +39,7 @@ fn AesGcm(comptime Aes: anytype) type { | ... | @@ -39,7 +39,7 @@ fn AesGcm(comptime Aes: anytype) type { |
| 39 | mem.writeInt(u32, j[nonce_length..][0..4], 1, .big); | 39 | mem.writeInt(u32, j[nonce_length..][0..4], 1, .big); |
| 40 | aes.encrypt(&t, &j); | 40 | aes.encrypt(&t, &j); |
| 41 | 41 | ||
| 42 | const block_count = (math.divCeil(usize, ad.len, Ghash.block_length) catch unreachable) + (math.divCeil(usize, c.len, Ghash.block_length) catch unreachable) + 1; | 42 | const block_count = @divCeil(ad.len, Ghash.block_length) + @divCeil(c.len, Ghash.block_length) + 1; |
| 43 | var mac = Ghash.initForBlockCount(&h, block_count); | 43 | var mac = Ghash.initForBlockCount(&h, block_count); |
| 44 | mac.update(ad); | 44 | mac.update(ad); |
| 45 | mac.pad(); | 45 | mac.pad(); |
| ... | @@ -81,7 +81,7 @@ fn AesGcm(comptime Aes: anytype) type { | ... | @@ -81,7 +81,7 @@ fn AesGcm(comptime Aes: anytype) type { |
| 81 | mem.writeInt(u32, j[nonce_length..][0..4], 1, .big); | 81 | mem.writeInt(u32, j[nonce_length..][0..4], 1, .big); |
| 82 | aes.encrypt(&t, &j); | 82 | aes.encrypt(&t, &j); |
| 83 | 83 | ||
| 84 | const block_count = (math.divCeil(usize, ad.len, Ghash.block_length) catch unreachable) + (math.divCeil(usize, c.len, Ghash.block_length) catch unreachable) + 1; | 84 | const block_count = @divCeil(ad.len, Ghash.block_length) + @divCeil(c.len, Ghash.block_length) + 1; |
| 85 | var mac = Ghash.initForBlockCount(&h, block_count); | 85 | var mac = Ghash.initForBlockCount(&h, block_count); |
| 86 | mac.update(ad); | 86 | mac.update(ad); |
| 87 | mac.pad(); | 87 | mac.pad(); |
lib/std/crypto/ascon.zig+1-1| ... | @@ -198,7 +198,7 @@ pub fn State(comptime endian: std.builtin.Endian) type { | ... | @@ -198,7 +198,7 @@ pub fn State(comptime endian: std.builtin.Endian) type { |
| 198 | /// | 198 | /// |
| 199 | /// Note: Clears complete words that contain the specified byte range | 199 | /// Note: Clears complete words that contain the specified byte range |
| 200 | pub fn clear(self: *Self, from: usize, to: usize) void { | 200 | pub fn clear(self: *Self, from: usize, to: usize) void { |
| 201 | @memset(self.st[from / 8 .. (to + 7) / 8], 0); | 201 | @memset(self.st[from / 8 .. @divCeil(to, 8)], 0); |
| 202 | } | 202 | } |
| 203 | 203 | ||
| 204 | /// Clear the entire state, disabling compiler optimizations. | 204 | /// Clear the entire state, disabling compiler optimizations. |
lib/std/crypto/ff.zig+3-3| ... | @@ -61,14 +61,14 @@ pub fn Uint(comptime max_bits: comptime_int) type { | ... | @@ -61,14 +61,14 @@ pub fn Uint(comptime max_bits: comptime_int) type { |
| 61 | 61 | ||
| 62 | return struct { | 62 | return struct { |
| 63 | const Self = @This(); | 63 | const Self = @This(); |
| 64 | const max_limbs_count = math.divCeil(usize, max_bits, t_bits) catch unreachable; | 64 | const max_limbs_count = @divCeil(max_bits, t_bits); |
| 65 | 65 | ||
| 66 | limbs_buffer: [max_limbs_count]Limb, | 66 | limbs_buffer: [max_limbs_count]Limb, |
| 67 | /// The number of active limbs. | 67 | /// The number of active limbs. |
| 68 | limbs_len: usize, | 68 | limbs_len: usize, |
| 69 | 69 | ||
| 70 | /// Number of bytes required to serialize an integer. | 70 | /// Number of bytes required to serialize an integer. |
| 71 | pub const encoded_bytes = math.divCeil(usize, max_bits, 8) catch unreachable; | 71 | pub const encoded_bytes = @divCeil(max_bits, 8); |
| 72 | 72 | ||
| 73 | /// Constant slice of active limbs. | 73 | /// Constant slice of active limbs. |
| 74 | fn limbsConst(self: *const Self) []const Limb { | 74 | fn limbsConst(self: *const Self) []const Limb { |
| ... | @@ -847,7 +847,7 @@ pub fn Modulus(comptime max_bits: comptime_int) type { | ... | @@ -847,7 +847,7 @@ pub fn Modulus(comptime max_bits: comptime_int) type { |
| 847 | } | 847 | } |
| 848 | var e_normalized = Fe{ .v = e.v.normalize() }; | 848 | var e_normalized = Fe{ .v = e.v.normalize() }; |
| 849 | var buf_: [Fe.encoded_bytes]u8 = undefined; | 849 | var buf_: [Fe.encoded_bytes]u8 = undefined; |
| 850 | var buf = buf_[0 .. math.divCeil(usize, e_normalized.v.limbs_len * t_bits, 8) catch unreachable]; | 850 | var buf = buf_[0..@divCeil(e_normalized.v.limbs_len * t_bits, 8)]; |
| 851 | e_normalized.toBytes(buf, .little) catch unreachable; | 851 | e_normalized.toBytes(buf, .little) catch unreachable; |
| 852 | const leading = @clz(e_normalized.v.limbsConst()[e_normalized.v.limbs_len - carry_bits]); | 852 | const leading = @clz(e_normalized.v.limbsConst()[e_normalized.v.limbs_len - carry_bits]); |
| 853 | buf = buf[0 .. buf.len - leading / 8]; | 853 | buf = buf[0 .. buf.len - leading / 8]; |
lib/std/crypto/pbkdf2.zig+1-1| ... | @@ -74,7 +74,7 @@ pub fn pbkdf2(dk: []u8, password: []const u8, salt: []const u8, rounds: u32, com | ... | @@ -74,7 +74,7 @@ pub fn pbkdf2(dk: []u8, password: []const u8, salt: []const u8, rounds: u32, com |
| 74 | // block | 74 | // block |
| 75 | // | 75 | // |
| 76 | 76 | ||
| 77 | const blocks_count = @as(u32, @intCast(std.math.divCeil(usize, dk_len, h_len) catch unreachable)); | 77 | const blocks_count: u32 = @intCast(@divCeil(dk_len, h_len)); |
| 78 | var r = dk_len % h_len; | 78 | var r = dk_len % h_len; |
| 79 | if (r == 0) { | 79 | if (r == 0) { |
| 80 | r = h_len; | 80 | r = h_len; |
lib/std/crypto/sha2.zig+1-1| ... | @@ -474,7 +474,7 @@ fn Sha2x64(comptime iv: Iv64, digest_bits: comptime_int) type { | ... | @@ -474,7 +474,7 @@ fn Sha2x64(comptime iv: Iv64, digest_bits: comptime_int) type { |
| 474 | return struct { | 474 | return struct { |
| 475 | const Self = @This(); | 475 | const Self = @This(); |
| 476 | pub const block_length = 128; | 476 | pub const block_length = 128; |
| 477 | pub const digest_length = std.math.divCeil(comptime_int, digest_bits, 8) catch unreachable; | 477 | pub const digest_length = @divCeil(digest_bits, 8); |
| 478 | pub const Options = struct {}; | 478 | pub const Options = struct {}; |
| 479 | 479 | ||
| 480 | s: Iv64, | 480 | s: Iv64, |
lib/std/crypto/sha3.zig+2-2| ... | @@ -58,7 +58,7 @@ pub fn Keccak(comptime f: u11, comptime output_bits: u11, comptime default_delim | ... | @@ -58,7 +58,7 @@ pub fn Keccak(comptime f: u11, comptime output_bits: u11, comptime default_delim |
| 58 | st: State, | 58 | st: State, |
| 59 | 59 | ||
| 60 | /// The output length, in bytes. | 60 | /// The output length, in bytes. |
| 61 | pub const digest_length = std.math.divCeil(comptime_int, output_bits, 8) catch unreachable; | 61 | pub const digest_length: comptime_int = @divCeil(output_bits, 8); |
| 62 | /// The block length, or rate, in bytes. | 62 | /// The block length, or rate, in bytes. |
| 63 | pub const block_length = State.rate; | 63 | pub const block_length = State.rate; |
| 64 | /// The delimiter can be overwritten in the options. | 64 | /// The delimiter can be overwritten in the options. |
| ... | @@ -464,7 +464,7 @@ pub const NistLengthEncoding = enum { | ... | @@ -464,7 +464,7 @@ pub const NistLengthEncoding = enum { |
| 464 | /// Encode a length according to NIST SP 800-185. | 464 | /// Encode a length according to NIST SP 800-185. |
| 465 | pub fn encode(comptime encoding: NistLengthEncoding, len: usize) Length { | 465 | pub fn encode(comptime encoding: NistLengthEncoding, len: usize) Length { |
| 466 | const len_bits = @bitSizeOf(@TypeOf(len)) - @clz(len) + 3; | 466 | const len_bits = @bitSizeOf(@TypeOf(len)) - @clz(len) + 3; |
| 467 | const len_bytes = std.math.divCeil(usize, len_bits, 8) catch unreachable; | 467 | const len_bytes = @divCeil(len_bits, 8); |
| 468 | 468 | ||
| 469 | var res = Length{ .len = len_bytes + 1 }; | 469 | var res = Length{ .len = len_bytes + 1 }; |
| 470 | if (encoding == .right) { | 470 | if (encoding == .right) { |
lib/std/debug.zig+1-1| ... | @@ -349,7 +349,7 @@ pub fn dumpHexFallible(t: Io.Terminal, bytes: []const u8) !void { | ... | @@ -349,7 +349,7 @@ pub fn dumpHexFallible(t: Io.Terminal, bytes: []const u8) !void { |
| 349 | var chunks = mem.window(u8, bytes, 16, 16); | 349 | var chunks = mem.window(u8, bytes, 16, 16); |
| 350 | while (chunks.next()) |window| { | 350 | while (chunks.next()) |window| { |
| 351 | // 1. Print the address. | 351 | // 1. Print the address. |
| 352 | const address = (@intFromPtr(bytes.ptr) + 0x10 * (std.math.divCeil(usize, chunks.index orelse bytes.len, 16) catch unreachable)) - 0x10; | 352 | const address = (@intFromPtr(bytes.ptr) + 0x10 * @divCeil(chunks.index orelse bytes.len, 16) - 0x10); |
| 353 | try t.setColor(.dim); | 353 | try t.setColor(.dim); |
| 354 | // We print the address in lowercase and the bytes in uppercase hexadecimal to distinguish them more. | 354 | // We print the address in lowercase and the bytes in uppercase hexadecimal to distinguish them more. |
| 355 | // Also, make sure all lines are aligned by padding the address. | 355 | // Also, make sure all lines are aligned by padding the address. |
lib/std/enums.zig+1-1| ... | @@ -1391,7 +1391,7 @@ test "EnumIndexer non-exhaustive" { | ... | @@ -1391,7 +1391,7 @@ test "EnumIndexer non-exhaustive" { |
| 1391 | const max_index: comptime_int = std.math.maxInt(RangedType); | 1391 | const max_index: comptime_int = std.math.maxInt(RangedType); |
| 1392 | const number_zero_tag_index: usize = switch (@typeInfo(BackingInt).int.signedness) { | 1392 | const number_zero_tag_index: usize = switch (@typeInfo(BackingInt).int.signedness) { |
| 1393 | .unsigned => 0, | 1393 | .unsigned => 0, |
| 1394 | .signed => std.math.divCeil(comptime_int, max_index, 2) catch unreachable, | 1394 | .signed => @divCeil(max_index, 2), |
| 1395 | }; | 1395 | }; |
| 1396 | 1396 | ||
| 1397 | try testing.expectEqual(E, Indexer.Key); | 1397 | try testing.expectEqual(E, Indexer.Key); |
lib/std/hash/auto_hash.zig+1-1| ... | @@ -99,7 +99,7 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { | ... | @@ -99,7 +99,7 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { |
| 99 | } else { | 99 | } else { |
| 100 | // Take only the part containing the key value, the remaining | 100 | // Take only the part containing the key value, the remaining |
| 101 | // bytes are undefined and must not be hashed! | 101 | // bytes are undefined and must not be hashed! |
| 102 | const byte_size = comptime std.math.divCeil(comptime_int, @bitSizeOf(Key), 8) catch unreachable; | 102 | const byte_size = @divCeil(@bitSizeOf(Key), 8); |
| 103 | @call(.always_inline, Hasher.update, .{ hasher, std.mem.asBytes(&key)[0..byte_size] }); | 103 | @call(.always_inline, Hasher.update, .{ hasher, std.mem.asBytes(&key)[0..byte_size] }); |
| 104 | } | 104 | } |
| 105 | }, | 105 | }, |
lib/std/math.zig+3-14| ... | @@ -922,21 +922,10 @@ fn testDivFloor() !void { | ... | @@ -922,21 +922,10 @@ fn testDivFloor() !void { |
| 922 | pub fn divCeil(comptime T: type, numerator: T, denominator: T) !T { | 922 | pub fn divCeil(comptime T: type, numerator: T, denominator: T) !T { |
| 923 | @setRuntimeSafety(false); | 923 | @setRuntimeSafety(false); |
| 924 | if (denominator == 0) return error.DivisionByZero; | 924 | if (denominator == 0) return error.DivisionByZero; |
| 925 | const info = @typeInfo(T); | 925 | if (@typeInfo(T) == .int and numerator == minInt(T) and denominator == -1) { |
| 926 | switch (info) { | 926 | return error.Overflow; |
| 927 | .comptime_float, .float => return @ceil(numerator / denominator), | ||
| 928 | .comptime_int, .int => { | ||
| 929 | if (numerator < 0 and denominator < 0) { | ||
| 930 | if (info == .int and numerator == minInt(T) and denominator == -1) | ||
| 931 | return error.Overflow; | ||
| 932 | return @divFloor(numerator + 1, denominator) + 1; | ||
| 933 | } | ||
| 934 | if (numerator > 0 and denominator > 0) | ||
| 935 | return @divFloor(numerator - 1, denominator) + 1; | ||
| 936 | return @divTrunc(numerator, denominator); | ||
| 937 | }, | ||
| 938 | else => @compileError("divCeil unsupported on " ++ @typeName(T)), | ||
| 939 | } | 927 | } |
| 928 | return @divCeil(numerator, denominator); | ||
| 940 | } | 929 | } |
| 941 | 930 | ||
| 942 | test divCeil { | 931 | test divCeil { |
lib/std/math/big/int.zig+76-1| ... | @@ -122,7 +122,7 @@ pub fn calcNonZeroTwosCompLimbCount(bit_count: usize) usize { | ... | @@ -122,7 +122,7 @@ pub fn calcNonZeroTwosCompLimbCount(bit_count: usize) usize { |
| 122 | /// Special cases `bit_count == 0` to return 1. Zero-bit integers can only store the value zero | 122 | /// Special cases `bit_count == 0` to return 1. Zero-bit integers can only store the value zero |
| 123 | /// and this big integer implementation stores zero using one limb. | 123 | /// and this big integer implementation stores zero using one limb. |
| 124 | pub fn calcTwosCompLimbCount(bit_count: usize) usize { | 124 | pub fn calcTwosCompLimbCount(bit_count: usize) usize { |
| 125 | return @max(std.math.divCeil(usize, bit_count, @bitSizeOf(Limb)) catch unreachable, 1); | 125 | return @max(@divCeil(bit_count, @bitSizeOf(Limb)), 1); |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | /// a + b * c + *carry, sets carry to the overflow bits | 128 | /// a + b * c + *carry, sets carry to the overflow bits |
| ... | @@ -1221,6 +1221,62 @@ pub const Mutable = struct { | ... | @@ -1221,6 +1221,62 @@ pub const Mutable = struct { |
| 1221 | } | 1221 | } |
| 1222 | } | 1222 | } |
| 1223 | 1223 | ||
| 1224 | /// q = a / b (rem r) | ||
| 1225 | /// | ||
| 1226 | /// a / b are ceiled (rounded towards +inf). | ||
| 1227 | /// q may alias with a or b. | ||
| 1228 | /// | ||
| 1229 | /// Asserts there is enough memory to store q and r. | ||
| 1230 | /// The upper bound for r limb count is `b.limbs.len`. | ||
| 1231 | /// The upper bound for q limb count is given by `a.limbs`. | ||
| 1232 | /// | ||
| 1233 | /// `limbs_buffer` is used for temporary storage. The amount required is given by `calcDivLimbsBufferLen`. | ||
| 1234 | pub fn divCeil( | ||
| 1235 | q: *Mutable, | ||
| 1236 | r: *Mutable, | ||
| 1237 | a: Const, | ||
| 1238 | b: Const, | ||
| 1239 | limbs_buffer: []Limb, | ||
| 1240 | ) void { | ||
| 1241 | const sep = a.limbs.len + 2; | ||
| 1242 | var x = a.toMutable(limbs_buffer[0..sep]); | ||
| 1243 | var y = b.toMutable(limbs_buffer[sep..]); | ||
| 1244 | |||
| 1245 | // div performs truncating division (@divTrunc) which rounds towards negative | ||
| 1246 | // infinity if the result is positive and towards positive infinity if the result is | ||
| 1247 | // negative. | ||
| 1248 | div(q, r, &x, &y); | ||
| 1249 | |||
| 1250 | // @rem gives the remainder after @divTrunc, and is defined by: | ||
| 1251 | // x * @divTrunc(x, y) + @rem(x, y) = x | ||
| 1252 | // For all integers x, y with y != 0. | ||
| 1253 | // In the following comments, a, b will be integers with a >= 0, b > 0, and we will take | ||
| 1254 | // modCeil to be the remainder after @divCeil, defined by: | ||
| 1255 | // x * @divCeil(x, y) + modCeil(x, y) = x | ||
| 1256 | // For all integers x, y with y != 0. | ||
| 1257 | |||
| 1258 | if (a.positive != b.positive or r.eqlZero()) { | ||
| 1259 | // In this case either the result is negative or the remainder is 0. | ||
| 1260 | // If the result is negative then the default truncating division already rounds | ||
| 1261 | // towards positive infinity, so no adjustment is needed. | ||
| 1262 | // If the remainder is 0 then the division is exact and no adjustment is needed. | ||
| 1263 | } else { | ||
| 1264 | // Same sign. | ||
| 1265 | // We have: | ||
| 1266 | // modCeil(a, b) != 0 | ||
| 1267 | // => @divCeil(a, b) = @divTrunc(a, b) + 1 | ||
| 1268 | // And: | ||
| 1269 | // b * @divTrunc(a, b) + @rem(a, b) = a | ||
| 1270 | // b * @divCeil(a, b) + modCeil(a, b) = a | ||
| 1271 | // => b * @divTrunc(a, b) + b + modCeil(a, b) = a | ||
| 1272 | // => modCeil(a, b) = @rem(a, b) - b | ||
| 1273 | // | ||
| 1274 | // This works for both positive and negative b because b keeps its sign. | ||
| 1275 | q.addScalar(q.toConst(), 1); | ||
| 1276 | r.sub(r.toConst(), y.toConst()); | ||
| 1277 | } | ||
| 1278 | } | ||
| 1279 | |||
| 1224 | /// q = a / b (rem r) | 1280 | /// q = a / b (rem r) |
| 1225 | /// | 1281 | /// |
| 1226 | /// a / b are truncated (rounded towards -inf). | 1282 | /// a / b are truncated (rounded towards -inf). |
| ... | @@ -3314,6 +3370,25 @@ pub const Managed = struct { | ... | @@ -3314,6 +3370,25 @@ pub const Managed = struct { |
| 3314 | r.setMetadata(mr.positive, mr.len); | 3370 | r.setMetadata(mr.positive, mr.len); |
| 3315 | } | 3371 | } |
| 3316 | 3372 | ||
| 3373 | /// q = a / b (rem r) | ||
| 3374 | /// | ||
| 3375 | /// a / b are ceiled (rounded towards positive infinity). | ||
| 3376 | /// | ||
| 3377 | /// Returns an error if memory could not be allocated. | ||
| 3378 | pub fn divCeil(q: *Managed, r: *Managed, a: *const Managed, b: *const Managed) !void { | ||
| 3379 | const q_alias = limbsAliasDistinct(q, a) or limbsAliasDistinct(q, b); | ||
| 3380 | const r_alias = limbsAliasDistinct(r, a) or limbsAliasDistinct(r, b); | ||
| 3381 | try q.ensureAliasAwareCapacity(a.len(), q_alias); | ||
| 3382 | try r.ensureAliasAwareCapacity(b.len(), r_alias); | ||
| 3383 | var mq = q.toMutable(); | ||
| 3384 | var mr = r.toMutable(); | ||
| 3385 | const limbs_buffer = try q.allocator.alloc(Limb, calcDivLimbsBufferLen(a.len(), b.len())); | ||
| 3386 | defer q.allocator.free(limbs_buffer); | ||
| 3387 | mq.divCeil(&mr, a.toConst(), b.toConst(), limbs_buffer); | ||
| 3388 | q.setMetadata(mq.positive, mq.len); | ||
| 3389 | r.setMetadata(mr.positive, mr.len); | ||
| 3390 | } | ||
| 3391 | |||
| 3317 | /// q = a / b (rem r) | 3392 | /// q = a / b (rem r) |
| 3318 | /// | 3393 | /// |
| 3319 | /// a / b are truncated (rounded towards -inf). | 3394 | /// a / b are truncated (rounded towards -inf). |
lib/std/math/big/int_test.zig+38| ... | @@ -2127,6 +2127,44 @@ test "div floor positive close to zero" { | ... | @@ -2127,6 +2127,44 @@ test "div floor positive close to zero" { |
| 2127 | try testing.expectEqual(10, try r.toInt(i32)); | 2127 | try testing.expectEqual(10, try r.toInt(i32)); |
| 2128 | } | 2128 | } |
| 2129 | 2129 | ||
| 2130 | fn testDivCeil(comptime T: type, u: T, v: T, eq: T, er: T) !void { | ||
| 2131 | var a = try Managed.initSet(testing.allocator, u); | ||
| 2132 | defer a.deinit(); | ||
| 2133 | var b = try Managed.initSet(testing.allocator, v); | ||
| 2134 | defer b.deinit(); | ||
| 2135 | |||
| 2136 | var q = try Managed.init(testing.allocator); | ||
| 2137 | defer q.deinit(); | ||
| 2138 | var r = try Managed.init(testing.allocator); | ||
| 2139 | defer r.deinit(); | ||
| 2140 | |||
| 2141 | try Managed.divCeil(&q, &r, &a, &b); | ||
| 2142 | |||
| 2143 | try testing.expectEqual(eq, try q.toInt(T)); | ||
| 2144 | try testing.expectEqual(er, try r.toInt(T)); | ||
| 2145 | } | ||
| 2146 | |||
| 2147 | test "div ceil small" { | ||
| 2148 | try testDivCeil(i32, 5, 3, 2, -1); | ||
| 2149 | try testDivCeil(i32, -5, 3, -1, -2); | ||
| 2150 | try testDivCeil(i32, 5, -3, -1, 2); | ||
| 2151 | try testDivCeil(i32, -5, -3, 2, 1); | ||
| 2152 | try testDivCeil(i32, -0x80000000, 1, -0x80000000, 0); | ||
| 2153 | } | ||
| 2154 | |||
| 2155 | test "div ceil multi-limb" { | ||
| 2156 | { | ||
| 2157 | const a = (@as(i128, 1) << 100) + 3; | ||
| 2158 | const b: i128 = 4; | ||
| 2159 | try testDivCeil(i128, a, b, (1 << 98) + 1, -1); | ||
| 2160 | } | ||
| 2161 | { | ||
| 2162 | const a = -((@as(i128, 1) << 100) + 3); | ||
| 2163 | const b: i128 = 4; | ||
| 2164 | try testDivCeil(i128, a, b, -(1 << 98), -3); | ||
| 2165 | } | ||
| 2166 | } | ||
| 2167 | |||
| 2130 | test "div multi-multi with rem" { | 2168 | test "div multi-multi with rem" { |
| 2131 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | 2169 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 2132 | 2170 |
lib/std/mem.zig+3-3| ... | @@ -1937,7 +1937,7 @@ fn readPackedIntLittle(comptime T: type, bytes: []const u8, bit_offset: usize) T | ... | @@ -1937,7 +1937,7 @@ fn readPackedIntLittle(comptime T: type, bytes: []const u8, bit_offset: usize) T |
| 1937 | const bit_count = @as(usize, @bitSizeOf(T)); | 1937 | const bit_count = @as(usize, @bitSizeOf(T)); |
| 1938 | const bit_shift = @as(u3, @intCast(bit_offset % 8)); | 1938 | const bit_shift = @as(u3, @intCast(bit_offset % 8)); |
| 1939 | 1939 | ||
| 1940 | const load_size = (bit_count + 7) / 8; | 1940 | const load_size = @divCeil(bit_count, 8); |
| 1941 | const load_tail_bits = @as(u3, @intCast((load_size * 8) - bit_count)); | 1941 | const load_tail_bits = @as(u3, @intCast((load_size * 8) - bit_count)); |
| 1942 | const LoadInt = @Int(.unsigned, load_size * 8); | 1942 | const LoadInt = @Int(.unsigned, load_size * 8); |
| 1943 | 1943 | ||
| ... | @@ -1964,9 +1964,9 @@ fn readPackedIntBig(comptime T: type, bytes: []const u8, bit_offset: usize) T { | ... | @@ -1964,9 +1964,9 @@ fn readPackedIntBig(comptime T: type, bytes: []const u8, bit_offset: usize) T { |
| 1964 | 1964 | ||
| 1965 | const bit_count = @as(usize, @bitSizeOf(T)); | 1965 | const bit_count = @as(usize, @bitSizeOf(T)); |
| 1966 | const bit_shift = @as(u3, @intCast(bit_offset % 8)); | 1966 | const bit_shift = @as(u3, @intCast(bit_offset % 8)); |
| 1967 | const byte_count = (@as(usize, bit_shift) + bit_count + 7) / 8; | 1967 | const byte_count = @divCeil(@as(usize, bit_shift) + bit_count, 8); |
| 1968 | 1968 | ||
| 1969 | const load_size = (bit_count + 7) / 8; | 1969 | const load_size = @divCeil(bit_count, 8); |
| 1970 | const load_tail_bits = @as(u3, @intCast((load_size * 8) - bit_count)); | 1970 | const load_tail_bits = @as(u3, @intCast((load_size * 8) - bit_count)); |
| 1971 | const LoadInt = @Int(.unsigned, load_size * 8); | 1971 | const LoadInt = @Int(.unsigned, load_size * 8); |
| 1972 | 1972 |
lib/std/zig/AstGen.zig+3-1| ... | @@ -2845,6 +2845,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As | ... | @@ -2845,6 +2845,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2845 | .bit_reverse, | 2845 | .bit_reverse, |
| 2846 | .div_exact, | 2846 | .div_exact, |
| 2847 | .div_floor, | 2847 | .div_floor, |
| 2848 | .div_ceil, | ||
| 2848 | .div_trunc, | 2849 | .div_trunc, |
| 2849 | .mod, | 2850 | .mod, |
| 2850 | .rem, | 2851 | .rem, |
| ... | @@ -4895,7 +4896,7 @@ fn structDeclInner( | ... | @@ -4895,7 +4896,7 @@ fn structDeclInner( |
| 4895 | const field_default_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, scan_result.fields_len); | 4896 | const field_default_body_lens = try scratch.addOptionalSlice(scan_result.any_field_values, scan_result.fields_len); |
| 4896 | const field_comptime_bits = try scratch.addOptionalSlice( | 4897 | const field_comptime_bits = try scratch.addOptionalSlice( |
| 4897 | scan_result.any_comptime_fields, | 4898 | scan_result.any_comptime_fields, |
| 4898 | std.math.divCeil(u32, scan_result.fields_len, 32) catch unreachable, | 4899 | @divCeil(scan_result.fields_len, 32), |
| 4899 | ); | 4900 | ); |
| 4900 | if (field_comptime_bits) |bits| @memset(bits.get(astgen), 0); | 4901 | if (field_comptime_bits) |bits| @memset(bits.get(astgen), 0); |
| 4901 | 4902 | ||
| ... | @@ -9392,6 +9393,7 @@ fn builtinCall( | ... | @@ -9392,6 +9393,7 @@ fn builtinCall( |
| 9392 | 9393 | ||
| 9393 | .div_exact => return divBuiltin(gz, scope, ri, node, params[0], params[1], .div_exact), | 9394 | .div_exact => return divBuiltin(gz, scope, ri, node, params[0], params[1], .div_exact), |
| 9394 | .div_floor => return divBuiltin(gz, scope, ri, node, params[0], params[1], .div_floor), | 9395 | .div_floor => return divBuiltin(gz, scope, ri, node, params[0], params[1], .div_floor), |
| 9396 | .div_ceil => return divBuiltin(gz, scope, ri, node, params[0], params[1], .div_ceil), | ||
| 9395 | .div_trunc => return divBuiltin(gz, scope, ri, node, params[0], params[1], .div_trunc), | 9397 | .div_trunc => return divBuiltin(gz, scope, ri, node, params[0], params[1], .div_trunc), |
| 9396 | .mod => return divBuiltin(gz, scope, ri, node, params[0], params[1], .mod), | 9398 | .mod => return divBuiltin(gz, scope, ri, node, params[0], params[1], .mod), |
| 9397 | .rem => return divBuiltin(gz, scope, ri, node, params[0], params[1], .rem), | 9399 | .rem => return divBuiltin(gz, scope, ri, node, params[0], params[1], .rem), |
lib/std/zig/AstRlAnnotate.zig+1| ... | @@ -936,6 +936,7 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast. | ... | @@ -936,6 +936,7 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast. |
| 936 | }, | 936 | }, |
| 937 | .div_exact, | 937 | .div_exact, |
| 938 | .div_floor, | 938 | .div_floor, |
| 939 | .div_ceil, | ||
| 939 | .div_trunc, | 940 | .div_trunc, |
| 940 | .mod, | 941 | .mod, |
| 941 | .rem, | 942 | .rem, |
lib/std/zig/BuiltinFn.zig+8| ... | @@ -31,6 +31,7 @@ pub const Tag = enum { | ... | @@ -31,6 +31,7 @@ pub const Tag = enum { |
| 31 | c_va_copy, | 31 | c_va_copy, |
| 32 | c_va_end, | 32 | c_va_end, |
| 33 | c_va_start, | 33 | c_va_start, |
| 34 | div_ceil, | ||
| 34 | div_exact, | 35 | div_exact, |
| 35 | div_floor, | 36 | div_floor, |
| 36 | div_trunc, | 37 | div_trunc, |
| ... | @@ -398,6 +399,13 @@ pub const list = list: { | ... | @@ -398,6 +399,13 @@ pub const list = list: { |
| 398 | .param_count = 2, | 399 | .param_count = 2, |
| 399 | }, | 400 | }, |
| 400 | }, | 401 | }, |
| 402 | .{ | ||
| 403 | "@divCeil", | ||
| 404 | .{ | ||
| 405 | .tag = .div_ceil, | ||
| 406 | .param_count = 2, | ||
| 407 | }, | ||
| 408 | }, | ||
| 401 | .{ | 409 | .{ |
| 402 | "@divTrunc", | 410 | "@divTrunc", |
| 403 | .{ | 411 | .{ |
lib/std/zig/Zir.zig+8-1| ... | @@ -200,6 +200,9 @@ pub const Inst = struct { | ... | @@ -200,6 +200,9 @@ pub const Inst = struct { |
| 200 | /// Implements the `@divFloor` builtin. | 200 | /// Implements the `@divFloor` builtin. |
| 201 | /// Uses the `pl_node` union field with payload `Bin`. | 201 | /// Uses the `pl_node` union field with payload `Bin`. |
| 202 | div_floor, | 202 | div_floor, |
| 203 | /// Implements the `@divCeil` builtin. | ||
| 204 | /// Uses the `pl_node` union field with payload `Bin`. | ||
| 205 | div_ceil, | ||
| 203 | /// Implements the `@divTrunc` builtin. | 206 | /// Implements the `@divTrunc` builtin. |
| 204 | /// Uses the `pl_node` union field with payload `Bin`. | 207 | /// Uses the `pl_node` union field with payload `Bin`. |
| 205 | div_trunc, | 208 | div_trunc, |
| ... | @@ -1267,6 +1270,7 @@ pub const Inst = struct { | ... | @@ -1267,6 +1270,7 @@ pub const Inst = struct { |
| 1267 | .bit_reverse, | 1270 | .bit_reverse, |
| 1268 | .div_exact, | 1271 | .div_exact, |
| 1269 | .div_floor, | 1272 | .div_floor, |
| 1273 | .div_ceil, | ||
| 1270 | .div_trunc, | 1274 | .div_trunc, |
| 1271 | .mod, | 1275 | .mod, |
| 1272 | .rem, | 1276 | .rem, |
| ... | @@ -1547,6 +1551,7 @@ pub const Inst = struct { | ... | @@ -1547,6 +1551,7 @@ pub const Inst = struct { |
| 1547 | .bit_reverse, | 1551 | .bit_reverse, |
| 1548 | .div_exact, | 1552 | .div_exact, |
| 1549 | .div_floor, | 1553 | .div_floor, |
| 1554 | .div_ceil, | ||
| 1550 | .div_trunc, | 1555 | .div_trunc, |
| 1551 | .mod, | 1556 | .mod, |
| 1552 | .rem, | 1557 | .rem, |
| ... | @@ -1815,6 +1820,7 @@ pub const Inst = struct { | ... | @@ -1815,6 +1820,7 @@ pub const Inst = struct { |
| 1815 | 1820 | ||
| 1816 | .div_exact = .pl_node, | 1821 | .div_exact = .pl_node, |
| 1817 | .div_floor = .pl_node, | 1822 | .div_floor = .pl_node, |
| 1823 | .div_ceil = .pl_node, | ||
| 1818 | .div_trunc = .pl_node, | 1824 | .div_trunc = .pl_node, |
| 1819 | .mod = .pl_node, | 1825 | .mod = .pl_node, |
| 1820 | .rem = .pl_node, | 1826 | .rem = .pl_node, |
| ... | @@ -4115,6 +4121,7 @@ fn findTrackableInner( | ... | @@ -4115,6 +4121,7 @@ fn findTrackableInner( |
| 4115 | .mul_sat, | 4121 | .mul_sat, |
| 4116 | .div_exact, | 4122 | .div_exact, |
| 4117 | .div_floor, | 4123 | .div_floor, |
| 4124 | .div_ceil, | ||
| 4118 | .div_trunc, | 4125 | .div_trunc, |
| 4119 | .mod, | 4126 | .mod, |
| 4120 | .rem, | 4127 | .rem, |
| ... | @@ -5272,7 +5279,7 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe | ... | @@ -5272,7 +5279,7 @@ pub fn getStructDecl(zir: *const Zir, struct_decl: Inst.Index) UnwrappedStructDe |
| 5272 | break :lens @ptrCast(lens); | 5279 | break :lens @ptrCast(lens); |
| 5273 | } else null; | 5280 | } else null; |
| 5274 | const field_comptime_bits: ?[]const u32 = if (small.any_comptime_fields) bits: { | 5281 | const field_comptime_bits: ?[]const u32 = if (small.any_comptime_fields) bits: { |
| 5275 | const bits_len = std.math.divCeil(u32, fields_len, 32) catch unreachable; | 5282 | const bits_len = @divCeil(fields_len, 32); |
| 5276 | const bits = zir.extra[extra_index..][0..bits_len]; | 5283 | const bits = zir.extra[extra_index..][0..bits_len]; |
| 5277 | extra_index += bits_len; | 5284 | extra_index += bits_len; |
| 5278 | break :bits bits; | 5285 | break :bits bits; |
lib/zig.h+32| ... | @@ -813,6 +813,15 @@ typedef ptrdiff_t intptr_t; | ... | @@ -813,6 +813,15 @@ typedef ptrdiff_t intptr_t; |
| 813 | static inline int##w##_t zig_div_floor_i##w(int##w##_t lhs, int##w##_t rhs) { \ | 813 | static inline int##w##_t zig_div_floor_i##w(int##w##_t lhs, int##w##_t rhs) { \ |
| 814 | return lhs / rhs + (lhs % rhs != INT##w##_C(0) ? zig_shr_i##w(lhs ^ rhs, UINT8_C(w) - UINT8_C(1)) : INT##w##_C(0)); \ | 814 | return lhs / rhs + (lhs % rhs != INT##w##_C(0) ? zig_shr_i##w(lhs ^ rhs, UINT8_C(w) - UINT8_C(1)) : INT##w##_C(0)); \ |
| 815 | } \ | 815 | } \ |
| 816 | \ | ||
| 817 | static inline uint##w##_t zig_div_ceil_u##w(uint##w##_t lhs, uint##w##_t rhs) { \ | ||
| 818 | return lhs / rhs + (lhs % rhs != UINT##w##_C(0) ? UINT##w##_C(1) : UINT##w##_C(0)); \ | ||
| 819 | } \ | ||
| 820 | \ | ||
| 821 | static inline int##w##_t zig_div_ceil_i##w(int##w##_t lhs, int##w##_t rhs) { \ | ||
| 822 | return lhs / rhs + (lhs % rhs != INT##w##_C(0) \ | ||
| 823 | ? zig_shr_i##w(lhs ^ rhs, UINT8_C(w) - UINT8_C(1)) + INT##w##_C(1) : INT##w##_C(0)); \ | ||
| 824 | } \ | ||
| 816 | \ | 825 | \ |
| 817 | zig_basic_operator(uint##w##_t, mod_u##w, %) \ | 826 | zig_basic_operator(uint##w##_t, mod_u##w, %) \ |
| 818 | \ | 827 | \ |
| ... | @@ -2058,6 +2067,21 @@ static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) { | ... | @@ -2058,6 +2067,21 @@ static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) { |
| 2058 | return zig_add_i128(zig_div_trunc_i128(lhs, rhs), zig_make_i128(mask, (uint64_t)mask)); | 2067 | return zig_add_i128(zig_div_trunc_i128(lhs, rhs), zig_make_i128(mask, (uint64_t)mask)); |
| 2059 | } | 2068 | } |
| 2060 | 2069 | ||
| 2070 | static inline zig_u128 zig_div_ceil_u128(zig_u128 lhs, zig_u128 rhs) { | ||
| 2071 | zig_u128 rem = zig_rem_u128(lhs, rhs); | ||
| 2072 | uint64_t mask = zig_or_u64(zig_hi_u128(rem), zig_lo_u128(rem)) != UINT64_C(0) | ||
| 2073 | ? UINT64_C(1) : UINT64_C(0); | ||
| 2074 | return zig_add_u128(zig_div_trunc_u128(lhs, rhs), zig_make_u128(UINT64_C(0), mask)); | ||
| 2075 | } | ||
| 2076 | |||
| 2077 | static inline zig_i128 zig_div_ceil_i128(zig_i128 lhs, zig_i128 rhs) { | ||
| 2078 | zig_i128 rem = zig_rem_i128(lhs, rhs); | ||
| 2079 | int64_t mask = zig_or_u64((uint64_t)zig_hi_i128(rem), zig_lo_i128(rem)) != UINT64_C(0) | ||
| 2080 | ? zig_shr_i64(zig_xor_i64(zig_hi_i128(lhs), zig_hi_i128(rhs)), UINT8_C(63)) + INT64_C(1) | ||
| 2081 | : INT64_C(0); | ||
| 2082 | return zig_add_i128(zig_div_trunc_i128(lhs, rhs), zig_make_i128(INT64_C(0), (uint64_t)mask)); | ||
| 2083 | } | ||
| 2084 | |||
| 2061 | #define zig_mod_u128 zig_rem_u128 | 2085 | #define zig_mod_u128 zig_rem_u128 |
| 2062 | 2086 | ||
| 2063 | static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) { | 2087 | static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) { |
| ... | @@ -3251,6 +3275,10 @@ static inline void zig_div_floor_big(void *res, const void *lhs, const void *rhs | ... | @@ -3251,6 +3275,10 @@ static inline void zig_div_floor_big(void *res, const void *lhs, const void *rhs |
| 3251 | zig_trap(); | 3275 | zig_trap(); |
| 3252 | } | 3276 | } |
| 3253 | 3277 | ||
| 3278 | static inline void zig_div_ceil_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { | ||
| 3279 | zig_trap(); | ||
| 3280 | } | ||
| 3281 | |||
| 3254 | zig_extern void __umodei4(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uintptr_t bits); | 3282 | zig_extern void __umodei4(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uintptr_t bits); |
| 3255 | static inline void zig_rem_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { | 3283 | static inline void zig_rem_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { |
| 3256 | if (!is_signed) { | 3284 | if (!is_signed) { |
| ... | @@ -4010,6 +4038,10 @@ zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0))) | ... | @@ -4010,6 +4038,10 @@ zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0))) |
| 4010 | static inline zig_f##w zig_div_floor_f##w(zig_f##w lhs, zig_f##w rhs) { \ | 4038 | static inline zig_f##w zig_div_floor_f##w(zig_f##w lhs, zig_f##w rhs) { \ |
| 4011 | return zig_floor_f##w(zig_div_f##w(lhs, rhs)); \ | 4039 | return zig_floor_f##w(zig_div_f##w(lhs, rhs)); \ |
| 4012 | } \ | 4040 | } \ |
| 4041 | \ | ||
| 4042 | static inline zig_f##w zig_div_ceil_f##w(zig_f##w lhs, zig_f##w rhs) { \ | ||
| 4043 | return zig_ceil_f##w(zig_div_f##w(lhs, rhs)); \ | ||
| 4044 | } \ | ||
| 4013 | \ | 4045 | \ |
| 4014 | static inline zig_f##w zig_mod_f##w(zig_f##w lhs, zig_f##w rhs) { \ | 4046 | static inline zig_f##w zig_mod_f##w(zig_f##w lhs, zig_f##w rhs) { \ |
| 4015 | return zig_sub_f##w(lhs, zig_mul_f##w(zig_div_floor_f##w(lhs, rhs), rhs)); \ | 4047 | return zig_sub_f##w(lhs, zig_mul_f##w(zig_div_floor_f##w(lhs, rhs), rhs)); \ |
src/Air.zig+14-3| ... | @@ -143,6 +143,13 @@ pub const Inst = struct { | ... | @@ -143,6 +143,13 @@ pub const Inst = struct { |
| 143 | div_floor, | 143 | div_floor, |
| 144 | /// Same as `div_floor` with optimized float mode. | 144 | /// Same as `div_floor` with optimized float mode. |
| 145 | div_floor_optimized, | 145 | div_floor_optimized, |
| 146 | /// Ceiling integer or float division. For integers, wrapping is illegal behavior. | ||
| 147 | /// Both operands are guaranteed to be the same type, and the result type | ||
| 148 | /// is the same as both operands. | ||
| 149 | /// Uses the `bin_op` field. | ||
| 150 | div_ceil, | ||
| 151 | /// Same as `div_ceil` with optimized float mode. | ||
| 152 | div_ceil_optimized, | ||
| 146 | /// Integer or float division. | 153 | /// Integer or float division. |
| 147 | /// If a remainder would be produced, illegal behavior occurs. | 154 | /// If a remainder would be produced, illegal behavior occurs. |
| 148 | /// For integers, overflow is illegal behavior. | 155 | /// For integers, overflow is illegal behavior. |
| ... | @@ -1510,7 +1517,7 @@ pub const ShuffleTwoMask = enum(u32) { | ... | @@ -1510,7 +1517,7 @@ pub const ShuffleTwoMask = enum(u32) { |
| 1510 | /// Trailing: | 1517 | /// Trailing: |
| 1511 | /// 0. `Inst.Ref` for every outputs_len | 1518 | /// 0. `Inst.Ref` for every outputs_len |
| 1512 | /// 1. `Inst.Ref` for every inputs_len | 1519 | /// 1. `Inst.Ref` for every inputs_len |
| 1513 | /// 2. A number of u32 elements follow according to the equation `(source_len + 3) / 4`. | 1520 | /// 2. A number of u32 elements follow according to the equation `@divCeil(source_len, 4)`. |
| 1514 | /// Memory starting at this position is reinterpreted as the source bytes. | 1521 | /// Memory starting at this position is reinterpreted as the source bytes. |
| 1515 | /// 3. for every outputs_len | 1522 | /// 3. for every outputs_len |
| 1516 | /// - constraint: memory at this position is reinterpreted as a null | 1523 | /// - constraint: memory at this position is reinterpreted as a null |
| ... | @@ -1605,6 +1612,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool) | ... | @@ -1605,6 +1612,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool) |
| 1605 | .div_float, | 1612 | .div_float, |
| 1606 | .div_trunc, | 1613 | .div_trunc, |
| 1607 | .div_floor, | 1614 | .div_floor, |
| 1615 | .div_ceil, | ||
| 1608 | .div_exact, | 1616 | .div_exact, |
| 1609 | .rem, | 1617 | .rem, |
| 1610 | .mod, | 1618 | .mod, |
| ... | @@ -1624,6 +1632,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool) | ... | @@ -1624,6 +1632,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool) |
| 1624 | .div_float_optimized, | 1632 | .div_float_optimized, |
| 1625 | .div_trunc_optimized, | 1633 | .div_trunc_optimized, |
| 1626 | .div_floor_optimized, | 1634 | .div_floor_optimized, |
| 1635 | .div_ceil_optimized, | ||
| 1627 | .div_exact_optimized, | 1636 | .div_exact_optimized, |
| 1628 | .rem_optimized, | 1637 | .rem_optimized, |
| 1629 | .mod_optimized, | 1638 | .mod_optimized, |
| ... | @@ -1985,6 +1994,8 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool { | ... | @@ -1985,6 +1994,8 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool { |
| 1985 | .div_trunc_optimized, | 1994 | .div_trunc_optimized, |
| 1986 | .div_floor, | 1995 | .div_floor, |
| 1987 | .div_floor_optimized, | 1996 | .div_floor_optimized, |
| 1997 | .div_ceil, | ||
| 1998 | .div_ceil_optimized, | ||
| 1988 | .div_exact, | 1999 | .div_exact, |
| 1989 | .div_exact_optimized, | 2000 | .div_exact_optimized, |
| 1990 | .rem, | 2001 | .rem, |
| ... | @@ -2214,7 +2225,7 @@ pub fn unwrapSwitch(air: *const Air, switch_inst: Inst.Index) UnwrappedSwitch { | ... | @@ -2214,7 +2225,7 @@ pub fn unwrapSwitch(air: *const Air, switch_inst: Inst.Index) UnwrappedSwitch { |
| 2214 | } | 2225 | } |
| 2215 | const pl_op = inst.data.pl_op; | 2226 | const pl_op = inst.data.pl_op; |
| 2216 | const extra = air.extraData(SwitchBr, pl_op.payload); | 2227 | const extra = air.extraData(SwitchBr, pl_op.payload); |
| 2217 | const hint_bag_count = std.math.divCeil(usize, extra.data.cases_len + 1, 10) catch unreachable; | 2228 | const hint_bag_count = @divCeil(extra.data.cases_len + 1, 10); |
| 2218 | return .{ | 2229 | return .{ |
| 2219 | .air = air, | 2230 | .air = air, |
| 2220 | .operand = pl_op.operand, | 2231 | .operand = pl_op.operand, |
| ... | @@ -2383,7 +2394,7 @@ pub const UnwrappedAsm = struct { | ... | @@ -2383,7 +2394,7 @@ pub const UnwrappedAsm = struct { |
| 2383 | const name = std.mem.sliceTo(constraint_name[constraint.len + 1 ..], 0); | 2394 | const name = std.mem.sliceTo(constraint_name[constraint.len + 1 ..], 0); |
| 2384 | // This equation accounts for the fact that even if we have exactly 4 bytes | 2395 | // This equation accounts for the fact that even if we have exactly 4 bytes |
| 2385 | // for the string, we still use the next u32 for the null terminator. | 2396 | // for the string, we still use the next u32 for the null terminator. |
| 2386 | const next_offset = std.math.divCeil(usize, constraint.len + 1 + name.len + 1, @sizeOf(u32)) catch unreachable; | 2397 | const next_offset = @divCeil(constraint.len + 1 + name.len + 1, @sizeOf(u32)); |
| 2387 | self.constraint_names = self.constraint_names[next_offset..]; | 2398 | self.constraint_names = self.constraint_names[next_offset..]; |
| 2388 | 2399 | ||
| 2389 | return .{ | 2400 | return .{ |
src/Air/Legalize.zig+194-3| ... | @@ -54,6 +54,8 @@ pub const Feature = enum { | ... | @@ -54,6 +54,8 @@ pub const Feature = enum { |
| 54 | scalarize_div_trunc_optimized, | 54 | scalarize_div_trunc_optimized, |
| 55 | scalarize_div_floor, | 55 | scalarize_div_floor, |
| 56 | scalarize_div_floor_optimized, | 56 | scalarize_div_floor_optimized, |
| 57 | scalarize_div_ceil, | ||
| 58 | scalarize_div_ceil_optimized, | ||
| 57 | scalarize_div_exact, | 59 | scalarize_div_exact, |
| 58 | scalarize_div_exact_optimized, | 60 | scalarize_div_exact_optimized, |
| 59 | scalarize_rem, | 61 | scalarize_rem, |
| ... | @@ -173,6 +175,15 @@ pub const Feature = enum { | ... | @@ -173,6 +175,15 @@ pub const Feature = enum { |
| 173 | /// Not compatible with `scalarize_mul_safe`. | 175 | /// Not compatible with `scalarize_mul_safe`. |
| 174 | expand_mul_safe, | 176 | expand_mul_safe, |
| 175 | 177 | ||
| 178 | /// Replace `div_ceil` with truncating division followed by a remainder based adjustment for integers, | ||
| 179 | /// or division followed by ceil for floats. | ||
| 180 | /// Not compatible with `scalarize_div_ceil`. | ||
| 181 | expand_div_ceil, | ||
| 182 | /// Replace `div_ceil_optimized` with truncating division followed by a remainder based adjustment for integers, | ||
| 183 | /// or division followed by ceil for floats. | ||
| 184 | /// Not compatible with `scalarize_div_ceil_optimized`. | ||
| 185 | expand_div_ceil_optimized, | ||
| 186 | |||
| 176 | /// Replace `load` from a packed pointer with a non-packed `load`, `shr`, `truncate`. | 187 | /// Replace `load` from a packed pointer with a non-packed `load`, `shr`, `truncate`. |
| 177 | /// Currently assumes little endian and a specific integer layout where the lsb of every integer is the lsb of the | 188 | /// Currently assumes little endian and a specific integer layout where the lsb of every integer is the lsb of the |
| 178 | /// first byte of memory until bit pointers know their backing type. | 189 | /// first byte of memory until bit pointers know their backing type. |
| ... | @@ -231,6 +242,8 @@ pub const Feature = enum { | ... | @@ -231,6 +242,8 @@ pub const Feature = enum { |
| 231 | .div_trunc_optimized => .scalarize_div_trunc_optimized, | 242 | .div_trunc_optimized => .scalarize_div_trunc_optimized, |
| 232 | .div_floor => .scalarize_div_floor, | 243 | .div_floor => .scalarize_div_floor, |
| 233 | .div_floor_optimized => .scalarize_div_floor_optimized, | 244 | .div_floor_optimized => .scalarize_div_floor_optimized, |
| 245 | .div_ceil => .scalarize_div_ceil, | ||
| 246 | .div_ceil_optimized => .scalarize_div_ceil_optimized, | ||
| 234 | .div_exact => .scalarize_div_exact, | 247 | .div_exact => .scalarize_div_exact, |
| 235 | .div_exact_optimized => .scalarize_div_exact_optimized, | 248 | .div_exact_optimized => .scalarize_div_exact_optimized, |
| 236 | .rem => .scalarize_rem, | 249 | .rem => .scalarize_rem, |
| ... | @@ -382,7 +395,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { | ... | @@ -382,7 +395,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { |
| 382 | switch (l.wantScalarizeOrSoftFloat(air_tag, l.typeOf(bin_op.lhs))) { | 395 | switch (l.wantScalarizeOrSoftFloat(air_tag, l.typeOf(bin_op.lhs))) { |
| 383 | .none => {}, | 396 | .none => {}, |
| 384 | .scalarize => continue :inst l.replaceInst(inst, .block, try l.scalarizeBlockPayload(inst, .bin_op)), | 397 | .scalarize => continue :inst l.replaceInst(inst, .block, try l.scalarizeBlockPayload(inst, .bin_op)), |
| 385 | .soft_float => continue :inst l.replaceInst(inst, .block, try l.softFloatDivTruncFloorBlockPayload( | 398 | .soft_float => continue :inst l.replaceInst(inst, .block, try l.softFloatDivTruncFloorCeilBlockPayload( |
| 386 | inst, | 399 | inst, |
| 387 | bin_op.lhs, | 400 | bin_op.lhs, |
| 388 | bin_op.rhs, | 401 | bin_op.rhs, |
| ... | @@ -596,6 +609,30 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { | ... | @@ -596,6 +609,30 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { |
| 596 | continue :inst l.replaceInst(inst, .block, try l.scalarizeBlockPayload(inst, .ty_op)); | 609 | continue :inst l.replaceInst(inst, .block, try l.scalarizeBlockPayload(inst, .ty_op)); |
| 597 | } | 610 | } |
| 598 | }, | 611 | }, |
| 612 | inline .div_ceil, .div_ceil_optimized => |air_tag| { | ||
| 613 | const expand_feature: Feature = switch (air_tag) { | ||
| 614 | .div_ceil => .expand_div_ceil, | ||
| 615 | .div_ceil_optimized => .expand_div_ceil_optimized, | ||
| 616 | else => unreachable, | ||
| 617 | }; | ||
| 618 | |||
| 619 | if (l.features.has(expand_feature)) { | ||
| 620 | assert(!l.features.has(.scalarize(air_tag))); // it doesn't make sense to do both | ||
| 621 | continue :inst l.replaceInst(inst, .block, try l.divCeilBlockPayload(inst, air_tag)); | ||
| 622 | } else { | ||
| 623 | const bin_op = l.air_instructions.items(.data)[@intFromEnum(inst)].bin_op; | ||
| 624 | switch (l.wantScalarizeOrSoftFloat(air_tag, l.typeOf(bin_op.lhs))) { | ||
| 625 | .none => {}, | ||
| 626 | .scalarize => continue :inst l.replaceInst(inst, .block, try l.scalarizeBlockPayload(inst, .bin_op)), | ||
| 627 | .soft_float => continue :inst l.replaceInst(inst, .block, try l.softFloatDivTruncFloorCeilBlockPayload( | ||
| 628 | inst, | ||
| 629 | bin_op.lhs, | ||
| 630 | bin_op.rhs, | ||
| 631 | air_tag, | ||
| 632 | )), | ||
| 633 | } | ||
| 634 | } | ||
| 635 | }, | ||
| 599 | inline .int_from_float_safe, | 636 | inline .int_from_float_safe, |
| 600 | .int_from_float_optimized_safe, | 637 | .int_from_float_optimized_safe, |
| 601 | => |air_tag| { | 638 | => |air_tag| { |
| ... | @@ -709,7 +746,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { | ... | @@ -709,7 +746,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { |
| 709 | .switch_br, .loop_switch_br => { | 746 | .switch_br, .loop_switch_br => { |
| 710 | const pl_op = l.air_instructions.items(.data)[@intFromEnum(inst)].pl_op; | 747 | const pl_op = l.air_instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 711 | const extra = l.extraData(Air.SwitchBr, pl_op.payload); | 748 | const extra = l.extraData(Air.SwitchBr, pl_op.payload); |
| 712 | const hint_bag_count = std.math.divCeil(usize, extra.data.cases_len + 1, 10) catch unreachable; | 749 | const hint_bag_count = @divCeil(extra.data.cases_len + 1, 10); |
| 713 | var extra_index = extra.end + hint_bag_count; | 750 | var extra_index = extra.end + hint_bag_count; |
| 714 | for (0..extra.data.cases_len) |_| { | 751 | for (0..extra.data.cases_len) |_| { |
| 715 | const case_extra = l.extraData(Air.SwitchBr.Case, extra_index); | 752 | const case_extra = l.extraData(Air.SwitchBr.Case, extra_index); |
| ... | @@ -2419,6 +2456,159 @@ fn safeArithmeticBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index, overflow_ | ... | @@ -2419,6 +2456,159 @@ fn safeArithmeticBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index, overflow_ |
| 2419 | } }; | 2456 | } }; |
| 2420 | } | 2457 | } |
| 2421 | 2458 | ||
| 2459 | fn divCeilBlockPayload( | ||
| 2460 | l: *Legalize, | ||
| 2461 | orig_inst: Air.Inst.Index, | ||
| 2462 | air_tag: Air.Inst.Tag, | ||
| 2463 | ) Error!Air.Inst.Data { | ||
| 2464 | const pt = l.pt; | ||
| 2465 | const zcu = pt.zcu; | ||
| 2466 | const gpa = zcu.gpa; | ||
| 2467 | |||
| 2468 | const bin_op = l.air_instructions.items(.data)[@intFromEnum(orig_inst)].bin_op; | ||
| 2469 | const operand_ty = l.typeOf(bin_op.lhs); | ||
| 2470 | assert(l.typeOf(bin_op.rhs).toIntern() == operand_ty.toIntern()); | ||
| 2471 | |||
| 2472 | const scalar_ty = operand_ty.scalarType(zcu); | ||
| 2473 | const is_vector = operand_ty.zigTypeTag(zcu) == .vector; | ||
| 2474 | |||
| 2475 | switch (scalar_ty.zigTypeTag(zcu)) { | ||
| 2476 | .float => { | ||
| 2477 | // %result = ceil(lhs / rhs) | ||
| 2478 | |||
| 2479 | var inst_buf: [3]Air.Inst.Index = undefined; | ||
| 2480 | try l.air_instructions.ensureUnusedCapacity(gpa, inst_buf.len); | ||
| 2481 | |||
| 2482 | var main_block: Block = .init(&inst_buf); | ||
| 2483 | |||
| 2484 | const div_tag: Air.Inst.Tag = switch (air_tag) { | ||
| 2485 | .div_ceil => .div_float, | ||
| 2486 | .div_ceil_optimized => .div_float_optimized, | ||
| 2487 | else => unreachable, | ||
| 2488 | }; | ||
| 2489 | |||
| 2490 | const div_inst = main_block.add(l, .{ | ||
| 2491 | .tag = div_tag, | ||
| 2492 | .data = .{ .bin_op = bin_op }, | ||
| 2493 | }); | ||
| 2494 | |||
| 2495 | const ceil_inst = main_block.add(l, .{ | ||
| 2496 | .tag = .ceil, | ||
| 2497 | .data = .{ .un_op = div_inst.toRef() }, | ||
| 2498 | }); | ||
| 2499 | |||
| 2500 | main_block.addBr(l, orig_inst, ceil_inst.toRef()); | ||
| 2501 | |||
| 2502 | _ = main_block.stealRemainingCapacity(); | ||
| 2503 | return .{ .ty_pl = .{ | ||
| 2504 | .ty = .fromType(operand_ty), | ||
| 2505 | .payload = try l.addBlockBody(main_block.body()), | ||
| 2506 | } }; | ||
| 2507 | }, | ||
| 2508 | |||
| 2509 | .int => { | ||
| 2510 | // Integer div_ceil: | ||
| 2511 | // | ||
| 2512 | // q = div_trunc(lhs, rhs) | ||
| 2513 | // r = rem(lhs, rhs) | ||
| 2514 | // | ||
| 2515 | // unsigned: | ||
| 2516 | // q + int(r != 0) | ||
| 2517 | // | ||
| 2518 | // signed: | ||
| 2519 | // q + int(r != 0 and same_sign(lhs, rhs)) | ||
| 2520 | // | ||
| 2521 | // same_sign is `(lhs ^ rhs) >= 0`. | ||
| 2522 | |||
| 2523 | var inst_buf: [10]Air.Inst.Index = undefined; | ||
| 2524 | try l.air_instructions.ensureUnusedCapacity(gpa, inst_buf.len); | ||
| 2525 | |||
| 2526 | var main_block: Block = .init(&inst_buf); | ||
| 2527 | |||
| 2528 | const q_inst = main_block.add(l, .{ | ||
| 2529 | .tag = .div_trunc, | ||
| 2530 | .data = .{ .bin_op = bin_op }, | ||
| 2531 | }); | ||
| 2532 | |||
| 2533 | const r_inst = main_block.add(l, .{ | ||
| 2534 | .tag = .rem, | ||
| 2535 | .data = .{ .bin_op = bin_op }, | ||
| 2536 | }); | ||
| 2537 | |||
| 2538 | const zero_ref: Air.Inst.Ref = if (is_vector) zero: { | ||
| 2539 | const zero_scalar = try pt.intValue(scalar_ty, 0); | ||
| 2540 | const zero_vec = try pt.aggregateSplatValue(operand_ty, zero_scalar); | ||
| 2541 | break :zero Air.internedToRef(zero_vec.toIntern()); | ||
| 2542 | } else Air.internedToRef((try pt.intValue(operand_ty, 0)).toIntern()); | ||
| 2543 | |||
| 2544 | const r_nonzero_inst = try main_block.addCmp( | ||
| 2545 | l, | ||
| 2546 | .neq, | ||
| 2547 | r_inst.toRef(), | ||
| 2548 | zero_ref, | ||
| 2549 | .{ .vector = is_vector }, | ||
| 2550 | ); | ||
| 2551 | |||
| 2552 | const int_info = scalar_ty.intInfo(zcu); | ||
| 2553 | |||
| 2554 | const need_adjust_inst: Air.Inst.Index = if (int_info.signedness == .unsigned) r_nonzero_inst else inst: { | ||
| 2555 | const sign_xor_inst = main_block.add(l, .{ | ||
| 2556 | .tag = .xor, | ||
| 2557 | .data = .{ .bin_op = .{ | ||
| 2558 | .lhs = bin_op.lhs, | ||
| 2559 | .rhs = bin_op.rhs, | ||
| 2560 | } }, | ||
| 2561 | }); | ||
| 2562 | |||
| 2563 | const signs_same_inst = try main_block.addCmp( | ||
| 2564 | l, | ||
| 2565 | .gte, | ||
| 2566 | sign_xor_inst.toRef(), | ||
| 2567 | zero_ref, | ||
| 2568 | .{ .vector = is_vector }, | ||
| 2569 | ); | ||
| 2570 | |||
| 2571 | break :inst main_block.add(l, .{ | ||
| 2572 | .tag = .bit_and, | ||
| 2573 | .data = .{ .bin_op = .{ | ||
| 2574 | .lhs = r_nonzero_inst.toRef(), | ||
| 2575 | .rhs = signs_same_inst.toRef(), | ||
| 2576 | } }, | ||
| 2577 | }); | ||
| 2578 | }; | ||
| 2579 | |||
| 2580 | const adjust_u1_ty = if (is_vector) | ||
| 2581 | try pt.vectorType(.{ | ||
| 2582 | .len = operand_ty.vectorLen(zcu), | ||
| 2583 | .child = Type.u1.toIntern(), | ||
| 2584 | }) | ||
| 2585 | else | ||
| 2586 | Type.u1; | ||
| 2587 | |||
| 2588 | const adjust_u1_ref = main_block.addBitCast(l, adjust_u1_ty, need_adjust_inst.toRef()); | ||
| 2589 | const adjust_inst = main_block.addTyOp(l, .int_cast, operand_ty, adjust_u1_ref); | ||
| 2590 | |||
| 2591 | const result_inst = main_block.add(l, .{ | ||
| 2592 | .tag = .add, | ||
| 2593 | .data = .{ .bin_op = .{ | ||
| 2594 | .lhs = q_inst.toRef(), | ||
| 2595 | .rhs = adjust_inst.toRef(), | ||
| 2596 | } }, | ||
| 2597 | }); | ||
| 2598 | |||
| 2599 | main_block.addBr(l, orig_inst, result_inst.toRef()); | ||
| 2600 | |||
| 2601 | _ = main_block.stealRemainingCapacity(); | ||
| 2602 | return .{ .ty_pl = .{ | ||
| 2603 | .ty = .fromType(operand_ty), | ||
| 2604 | .payload = try l.addBlockBody(main_block.body()), | ||
| 2605 | } }; | ||
| 2606 | }, | ||
| 2607 | |||
| 2608 | else => unreachable, | ||
| 2609 | } | ||
| 2610 | } | ||
| 2611 | |||
| 2422 | fn packedLoadBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Error!Air.Inst.Data { | 2612 | fn packedLoadBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Error!Air.Inst.Data { |
| 2423 | const pt = l.pt; | 2613 | const pt = l.pt; |
| 2424 | const zcu = pt.zcu; | 2614 | const zcu = pt.zcu; |
| ... | @@ -3426,7 +3616,7 @@ fn softFloatNegBlockPayload( | ... | @@ -3426,7 +3616,7 @@ fn softFloatNegBlockPayload( |
| 3426 | } }; | 3616 | } }; |
| 3427 | } | 3617 | } |
| 3428 | 3618 | ||
| 3429 | fn softFloatDivTruncFloorBlockPayload( | 3619 | fn softFloatDivTruncFloorCeilBlockPayload( |
| 3430 | l: *Legalize, | 3620 | l: *Legalize, |
| 3431 | orig_inst: Air.Inst.Index, | 3621 | orig_inst: Air.Inst.Index, |
| 3432 | lhs: Air.Inst.Ref, | 3622 | lhs: Air.Inst.Ref, |
| ... | @@ -3441,6 +3631,7 @@ fn softFloatDivTruncFloorBlockPayload( | ... | @@ -3441,6 +3631,7 @@ fn softFloatDivTruncFloorBlockPayload( |
| 3441 | const floor_tag: Air.Inst.Tag = switch (air_tag) { | 3631 | const floor_tag: Air.Inst.Tag = switch (air_tag) { |
| 3442 | .div_trunc, .div_trunc_optimized => .trunc_float, | 3632 | .div_trunc, .div_trunc_optimized => .trunc_float, |
| 3443 | .div_floor, .div_floor_optimized => .floor, | 3633 | .div_floor, .div_floor_optimized => .floor, |
| 3634 | .div_ceil, .div_ceil_optimized => .ceil, | ||
| 3444 | else => unreachable, | 3635 | else => unreachable, |
| 3445 | }; | 3636 | }; |
| 3446 | 3637 |
src/Air/Liveness.zig+2| ... | @@ -417,6 +417,8 @@ fn analyzeInst( | ... | @@ -417,6 +417,8 @@ fn analyzeInst( |
| 417 | .div_floor_optimized, | 417 | .div_floor_optimized, |
| 418 | .div_exact, | 418 | .div_exact, |
| 419 | .div_exact_optimized, | 419 | .div_exact_optimized, |
| 420 | .div_ceil, | ||
| 421 | .div_ceil_optimized, | ||
| 420 | .rem, | 422 | .rem, |
| 421 | .rem_optimized, | 423 | .rem_optimized, |
| 422 | .mod, | 424 | .mod, |
src/Air/Liveness/Verify.zig+2| ... | @@ -235,6 +235,8 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { | ... | @@ -235,6 +235,8 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 235 | .div_trunc_optimized, | 235 | .div_trunc_optimized, |
| 236 | .div_floor, | 236 | .div_floor, |
| 237 | .div_floor_optimized, | 237 | .div_floor_optimized, |
| 238 | .div_ceil, | ||
| 239 | .div_ceil_optimized, | ||
| 238 | .div_exact, | 240 | .div_exact, |
| 239 | .div_exact_optimized, | 241 | .div_exact_optimized, |
| 240 | .rem, | 242 | .rem, |
src/Air/Verify.zig+2| ... | @@ -253,6 +253,8 @@ fn body(verify: *Verify, body_insts: []const Air.Inst.Index) Error!void { | ... | @@ -253,6 +253,8 @@ fn body(verify: *Verify, body_insts: []const Air.Inst.Index) Error!void { |
| 253 | .div_trunc_optimized, | 253 | .div_trunc_optimized, |
| 254 | .div_floor, | 254 | .div_floor, |
| 255 | .div_floor_optimized, | 255 | .div_floor_optimized, |
| 256 | .div_ceil, | ||
| 257 | .div_ceil_optimized, | ||
| 256 | .div_exact, | 258 | .div_exact, |
| 257 | .div_exact_optimized, | 259 | .div_exact_optimized, |
| 258 | .rem, | 260 | .rem, |
src/Air/print.zig+2| ... | @@ -132,6 +132,7 @@ const Writer = struct { | ... | @@ -132,6 +132,7 @@ const Writer = struct { |
| 132 | .div_float, | 132 | .div_float, |
| 133 | .div_trunc, | 133 | .div_trunc, |
| 134 | .div_floor, | 134 | .div_floor, |
| 135 | .div_ceil, | ||
| 135 | .div_exact, | 136 | .div_exact, |
| 136 | .rem, | 137 | .rem, |
| 137 | .mod, | 138 | .mod, |
| ... | @@ -160,6 +161,7 @@ const Writer = struct { | ... | @@ -160,6 +161,7 @@ const Writer = struct { |
| 160 | .div_float_optimized, | 161 | .div_float_optimized, |
| 161 | .div_trunc_optimized, | 162 | .div_trunc_optimized, |
| 162 | .div_floor_optimized, | 163 | .div_floor_optimized, |
| 164 | .div_ceil_optimized, | ||
| 163 | .div_exact_optimized, | 165 | .div_exact_optimized, |
| 164 | .rem_optimized, | 166 | .rem_optimized, |
| 165 | .mod_optimized, | 167 | .mod_optimized, |
src/InternPool.zig+3-3| ... | @@ -3581,11 +3581,11 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { | ... | @@ -3581,11 +3581,11 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { |
| 3581 | .start = extra_index, | 3581 | .start = extra_index, |
| 3582 | .len = extra.data.fields_len, | 3582 | .len = extra.data.fields_len, |
| 3583 | } else .empty; | 3583 | } else .empty; |
| 3584 | extra_index += std.math.divCeil(u32, field_aligns.len, 4) catch unreachable; | 3584 | extra_index += @divCeil(field_aligns.len, 4); |
| 3585 | const field_is_comptime_bits: LoadedStructType.ComptimeBits = if (extra.data.flags.any_comptime_fields) .{ | 3585 | const field_is_comptime_bits: LoadedStructType.ComptimeBits = if (extra.data.flags.any_comptime_fields) .{ |
| 3586 | .tid = unwrapped_index.tid, | 3586 | .tid = unwrapped_index.tid, |
| 3587 | .start = extra_index, | 3587 | .start = extra_index, |
| 3588 | .len = std.math.divCeil(u32, extra.data.fields_len, 32) catch unreachable, | 3588 | .len = @divCeil(extra.data.fields_len, 32), |
| 3589 | } else .empty; | 3589 | } else .empty; |
| 3590 | extra_index += field_is_comptime_bits.len; | 3590 | extra_index += field_is_comptime_bits.len; |
| 3591 | const field_runtime_order: LoadedStructType.RuntimeOrder.Slice = if (extra.data.flags.layout == .auto) .{ | 3591 | const field_runtime_order: LoadedStructType.RuntimeOrder.Slice = if (extra.data.flags.layout == .auto) .{ |
| ... | @@ -3737,7 +3737,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { | ... | @@ -3737,7 +3737,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { |
| 3737 | .start = extra_index, | 3737 | .start = extra_index, |
| 3738 | .len = extra.data.fields_len, | 3738 | .len = extra.data.fields_len, |
| 3739 | } else .empty; | 3739 | } else .empty; |
| 3740 | extra_index += std.math.divCeil(u32, field_aligns.len, 4) catch unreachable; | 3740 | extra_index += @divCeil(field_aligns.len, 4); |
| 3741 | 3741 | ||
| 3742 | return .{ | 3742 | return .{ |
| 3743 | .zir_index = extra.data.zir_index, | 3743 | .zir_index = extra.data.zir_index, |
src/Sema.zig+73-7| ... | @@ -1335,6 +1335,7 @@ fn analyzeBodyInner( | ... | @@ -1335,6 +1335,7 @@ fn analyzeBodyInner( |
| 1335 | .div => try sema.zirDiv(block, inst), | 1335 | .div => try sema.zirDiv(block, inst), |
| 1336 | .div_exact => try sema.zirDivExact(block, inst), | 1336 | .div_exact => try sema.zirDivExact(block, inst), |
| 1337 | .div_floor => try sema.zirDivFloor(block, inst), | 1337 | .div_floor => try sema.zirDivFloor(block, inst), |
| 1338 | .div_ceil => try sema.zirDivCeil(block, inst), | ||
| 1338 | .div_trunc => try sema.zirDivTrunc(block, inst), | 1339 | .div_trunc => try sema.zirDivTrunc(block, inst), |
| 1339 | 1340 | ||
| 1340 | .mod_rem => try sema.zirModRem(block, inst), | 1341 | .mod_rem => try sema.zirModRem(block, inst), |
| ... | @@ -10304,7 +10305,7 @@ fn finishSwitchBr( | ... | @@ -10304,7 +10305,7 @@ fn finishSwitchBr( |
| 10304 | fn ensureUnusedCapacity(hints: *@This(), gpa_inner: Allocator, additional_count: u32) Allocator.Error!void { | 10305 | fn ensureUnusedCapacity(hints: *@This(), gpa_inner: Allocator, additional_count: u32) Allocator.Error!void { |
| 10305 | const unused_hints = hints.bags.capacity * hints_per_bag - hints.count; | 10306 | const unused_hints = hints.bags.capacity * hints_per_bag - hints.count; |
| 10306 | if (unused_hints >= additional_count) return; | 10307 | if (unused_hints >= additional_count) return; |
| 10307 | const bags_required = std.math.divCeil(u32, hints.count + additional_count, hints_per_bag) catch unreachable; | 10308 | const bags_required = @divCeil(hints.count + additional_count, hints_per_bag); |
| 10308 | return hints.bags.ensureUnusedCapacity(gpa_inner, bags_required); | 10309 | return hints.bags.ensureUnusedCapacity(gpa_inner, bags_required); |
| 10309 | } | 10310 | } |
| 10310 | fn appendAssumeCapacity(hints: *@This(), hint: std.lang.BranchHint) void { | 10311 | fn appendAssumeCapacity(hints: *@This(), hint: std.lang.BranchHint) void { |
| ... | @@ -10320,7 +10321,7 @@ fn finishSwitchBr( | ... | @@ -10320,7 +10321,7 @@ fn finishSwitchBr( |
| 10320 | } | 10321 | } |
| 10321 | }; | 10322 | }; |
| 10322 | var branch_hints: BranchHints = hints: { | 10323 | var branch_hints: BranchHints = hints: { |
| 10323 | const num_bags = std.math.divCeil(u32, estimated_cases_len, BranchHints.hints_per_bag) catch unreachable; | 10324 | const num_bags = @divCeil(estimated_cases_len, BranchHints.hints_per_bag); |
| 10324 | break :hints .{ .bags = try .initCapacity(gpa, num_bags), .count = 0 }; | 10325 | break :hints .{ .bags = try .initCapacity(gpa, num_bags), .count = 0 }; |
| 10325 | }; | 10326 | }; |
| 10326 | defer branch_hints.bags.deinit(gpa); | 10327 | defer branch_hints.bags.deinit(gpa); |
| ... | @@ -12211,7 +12212,7 @@ fn analyzeSwitchPayloadCaptureTaggedUnion( | ... | @@ -12211,7 +12212,7 @@ fn analyzeSwitchPayloadCaptureTaggedUnion( |
| 12211 | { | 12212 | { |
| 12212 | // All branch hints are `.none`, so just add zero elems. | 12213 | // All branch hints are `.none`, so just add zero elems. |
| 12213 | comptime assert(@intFromEnum(std.lang.BranchHint.none) == 0); | 12214 | comptime assert(@intFromEnum(std.lang.BranchHint.none) == 0); |
| 12214 | const need_elems = std.math.divCeil(usize, field_indices.len + 1, 10) catch unreachable; | 12215 | const need_elems = @divCeil(field_indices.len + 1, 10); |
| 12215 | try cases_extra.appendNTimes(gpa, 0, need_elems); | 12216 | try cases_extra.appendNTimes(gpa, 0, need_elems); |
| 12216 | } | 12217 | } |
| 12217 | 12218 | ||
| ... | @@ -13850,7 +13851,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins | ... | @@ -13850,7 +13851,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 13850 | return sema.fail( | 13851 | return sema.fail( |
| 13851 | block, | 13852 | block, |
| 13852 | src, | 13853 | src, |
| 13853 | "division with '{f}' and '{f}': signed integers must use @divTrunc, @divFloor, or @divExact", | 13854 | "division with '{f}' and '{f}': signed integers must use @divTrunc, @divFloor, @divCeil, or @divExact", |
| 13854 | .{ lhs_ty.fmt(pt), rhs_ty.fmt(pt) }, | 13855 | .{ lhs_ty.fmt(pt), rhs_ty.fmt(pt) }, |
| 13855 | ); | 13856 | ); |
| 13856 | } | 13857 | } |
| ... | @@ -14023,6 +14024,71 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -14023,6 +14024,71 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14023 | return block.addBinOp(airTag(block, is_int, .div_floor, .div_floor_optimized), casted_lhs, casted_rhs); | 14024 | return block.addBinOp(airTag(block, is_int, .div_floor, .div_floor_optimized), casted_lhs, casted_rhs); |
| 14024 | } | 14025 | } |
| 14025 | 14026 | ||
| 14027 | fn zirDivCeil(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | ||
| 14028 | const pt = sema.pt; | ||
| 14029 | const zcu = pt.zcu; | ||
| 14030 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; | ||
| 14031 | const src = block.src(.{ .node_offset_bin_op = inst_data.src_node }); | ||
| 14032 | const lhs_src = block.builtinCallArgSrc(inst_data.src_node, 0); | ||
| 14033 | const rhs_src = block.builtinCallArgSrc(inst_data.src_node, 1); | ||
| 14034 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | ||
| 14035 | const lhs = sema.resolveInst(extra.lhs); | ||
| 14036 | const rhs = sema.resolveInst(extra.rhs); | ||
| 14037 | const lhs_ty = sema.typeOf(lhs); | ||
| 14038 | const rhs_ty = sema.typeOf(rhs); | ||
| 14039 | const lhs_zig_ty_tag = lhs_ty.zigTypeTag(zcu); | ||
| 14040 | const rhs_zig_ty_tag = rhs_ty.zigTypeTag(zcu); | ||
| 14041 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); | ||
| 14042 | try sema.checkInvalidPtrIntArithmetic(block, src, lhs_ty); | ||
| 14043 | |||
| 14044 | const resolved_type = try sema.resolvePeerTypes(block, src, &.{ lhs, rhs }, .{ | ||
| 14045 | .override = &.{ lhs_src, rhs_src }, | ||
| 14046 | }); | ||
| 14047 | |||
| 14048 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); | ||
| 14049 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); | ||
| 14050 | |||
| 14051 | const lhs_scalar_ty = lhs_ty.scalarType(zcu); | ||
| 14052 | const scalar_tag = resolved_type.scalarType(zcu).zigTypeTag(zcu); | ||
| 14053 | |||
| 14054 | const is_int = scalar_tag == .int or scalar_tag == .comptime_int; | ||
| 14055 | |||
| 14056 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_ceil); | ||
| 14057 | |||
| 14058 | const maybe_lhs_val = sema.resolveValue(casted_lhs); | ||
| 14059 | const maybe_rhs_val = sema.resolveValue(casted_rhs); | ||
| 14060 | |||
| 14061 | const allow_div_zero = !is_int and | ||
| 14062 | resolved_type.toIntern() != .comptime_float_type and | ||
| 14063 | block.float_mode == .strict; | ||
| 14064 | |||
| 14065 | if (maybe_lhs_val) |lhs_val| { | ||
| 14066 | if (maybe_rhs_val) |rhs_val| { | ||
| 14067 | const result = try arith.div(sema, block, resolved_type, lhs_val, rhs_val, src, lhs_src, rhs_src, .div_ceil); | ||
| 14068 | return Air.internedToRef(result.toIntern()); | ||
| 14069 | } | ||
| 14070 | if (allow_div_zero) { | ||
| 14071 | if (lhs_val.isUndef(zcu)) return pt.undefRef(resolved_type); | ||
| 14072 | } else { | ||
| 14073 | try sema.checkAllScalarsDefined(block, lhs_src, lhs_val); | ||
| 14074 | } | ||
| 14075 | } else if (maybe_rhs_val) |rhs_val| { | ||
| 14076 | if (allow_div_zero) { | ||
| 14077 | if (rhs_val.isUndef(zcu)) return pt.undefRef(resolved_type); | ||
| 14078 | } else { | ||
| 14079 | try sema.checkAllScalarsDefined(block, rhs_src, rhs_val); | ||
| 14080 | if (rhs_val.anyScalarIsZero(zcu)) return sema.failWithDivideByZero(block, rhs_src); | ||
| 14081 | } | ||
| 14082 | } | ||
| 14083 | |||
| 14084 | if (block.wantSafety()) { | ||
| 14085 | try sema.addDivIntOverflowSafety(block, src, resolved_type, lhs_scalar_ty, maybe_lhs_val, maybe_rhs_val, casted_lhs, casted_rhs, is_int); | ||
| 14086 | try sema.addDivByZeroSafety(block, src, resolved_type, maybe_rhs_val, casted_rhs, is_int); | ||
| 14087 | } | ||
| 14088 | |||
| 14089 | return block.addBinOp(airTag(block, is_int, .div_ceil, .div_ceil_optimized), casted_lhs, casted_rhs); | ||
| 14090 | } | ||
| 14091 | |||
| 14026 | fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 14092 | fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 14027 | const pt = sema.pt; | 14093 | const pt = sema.pt; |
| 14028 | const zcu = pt.zcu; | 14094 | const zcu = pt.zcu; |
| ... | @@ -18051,7 +18117,7 @@ fn analyzeRet( | ... | @@ -18051,7 +18117,7 @@ fn analyzeRet( |
| 18051 | fn floatOpAllowed(tag: Zir.Inst.Tag) bool { | 18117 | fn floatOpAllowed(tag: Zir.Inst.Tag) bool { |
| 18052 | // extend this swich as additional operators are implemented | 18118 | // extend this swich as additional operators are implemented |
| 18053 | return switch (tag) { | 18119 | return switch (tag) { |
| 18054 | .add, .sub, .mul, .div, .div_exact, .div_trunc, .div_floor, .mod, .rem, .mod_rem => true, | 18120 | .add, .sub, .mul, .div, .div_exact, .div_trunc, .div_floor, .div_ceil, .mod, .rem, .mod_rem => true, |
| 18055 | else => false, | 18121 | else => false, |
| 18056 | }; | 18122 | }; |
| 18057 | } | 18123 | } |
| ... | @@ -18632,7 +18698,7 @@ fn finishStructInit( | ... | @@ -18632,7 +18698,7 @@ fn finishStructInit( |
| 18632 | return sema.addConstantMaybeRef(sema.resolveValue(final_val_ref).?, is_ref); | 18698 | return sema.addConstantMaybeRef(sema.resolveValue(final_val_ref).?, is_ref); |
| 18633 | }, | 18699 | }, |
| 18634 | .@"packed" => { | 18700 | .@"packed" => { |
| 18635 | const buf = try sema.arena.alloc(u8, @intCast((struct_ty.bitSize(zcu) + 7) / 8)); | 18701 | const buf = try sema.arena.alloc(u8, @intCast(@divCeil(struct_ty.bitSize(zcu), 8))); |
| 18636 | @memset(buf, 0); | 18702 | @memset(buf, 0); |
| 18637 | var bit_offset: u16 = 0; | 18703 | var bit_offset: u16 = 0; |
| 18638 | for (field_inits) |field_init| { | 18704 | for (field_inits) |field_init| { |
| ... | @@ -29679,7 +29745,7 @@ pub fn bitCastVal( | ... | @@ -29679,7 +29745,7 @@ pub fn bitCastVal( |
| 29679 | if (val.isUndef(zcu)) { | 29745 | if (val.isUndef(zcu)) { |
| 29680 | return pt.undefValue(dest_ty); | 29746 | return pt.undefValue(dest_ty); |
| 29681 | } else { | 29747 | } else { |
| 29682 | const buf = try sema.arena.alloc(u8, @intCast((bit_size + 7) / 8)); | 29748 | const buf = try sema.arena.alloc(u8, @intCast(@divCeil(bit_size, 8))); |
| 29683 | @memset(buf, 0); | 29749 | @memset(buf, 0); |
| 29684 | val.writeToPackedMemory(zcu, buf, 0); | 29750 | val.writeToPackedMemory(zcu, buf, 0); |
| 29685 | return .readFromPackedMemory(dest_ty, pt, buf, 0); | 29751 | return .readFromPackedMemory(dest_ty, pt, buf, 0); |
src/Sema/arith.zig+69-3| ... | @@ -768,7 +768,7 @@ fn mulSatScalar( | ... | @@ -768,7 +768,7 @@ fn mulSatScalar( |
| 768 | } | 768 | } |
| 769 | } | 769 | } |
| 770 | 770 | ||
| 771 | pub const DivOp = enum { div, div_trunc, div_floor, div_exact }; | 771 | pub const DivOp = enum { div, div_trunc, div_floor, div_ceil, div_exact }; |
| 772 | 772 | ||
| 773 | /// Applies the `/` operator to comptime-known values. | 773 | /// Applies the `/` operator to comptime-known values. |
| 774 | /// `lhs_val` and `rhs_val` are fully-resolved values of type `ty`. | 774 | /// `lhs_val` and `rhs_val` are fully-resolved values of type `ty`. |
| ... | @@ -843,6 +843,11 @@ fn divScalar( | ... | @@ -843,6 +843,11 @@ fn divScalar( |
| 843 | if (res.overflow) return sema.failWithIntegerOverflow(block, src, ty, res.val, vec_idx); | 843 | if (res.overflow) return sema.failWithIntegerOverflow(block, src, ty, res.val, vec_idx); |
| 844 | return res.val; | 844 | return res.val; |
| 845 | }, | 845 | }, |
| 846 | .div_ceil => { | ||
| 847 | const res = try intDivCeil(sema, lhs_val, rhs_val, ty); | ||
| 848 | if (res.overflow) return sema.failWithIntegerOverflow(block, src, ty, res.val, vec_idx); | ||
| 849 | return res.val; | ||
| 850 | }, | ||
| 846 | .div_exact => switch (try intDivExact(sema, lhs_val, rhs_val, ty)) { | 851 | .div_exact => switch (try intDivExact(sema, lhs_val, rhs_val, ty)) { |
| 847 | .remainder => return sema.fail(block, src, "exact division produced remainder", .{}), | 852 | .remainder => return sema.fail(block, src, "exact division produced remainder", .{}), |
| 848 | .overflow => |val| return sema.failWithIntegerOverflow(block, src, ty, val, vec_idx), | 853 | .overflow => |val| return sema.failWithIntegerOverflow(block, src, ty, val, vec_idx), |
| ... | @@ -851,7 +856,7 @@ fn divScalar( | ... | @@ -851,7 +856,7 @@ fn divScalar( |
| 851 | } | 856 | } |
| 852 | } else { | 857 | } else { |
| 853 | const allow_div_zero = switch (op) { | 858 | const allow_div_zero = switch (op) { |
| 854 | .div, .div_trunc, .div_floor => ty.toIntern() != .comptime_float_type and block.float_mode == .strict, | 859 | .div, .div_trunc, .div_floor, .div_ceil => ty.toIntern() != .comptime_float_type and block.float_mode == .strict, |
| 855 | .div_exact => false, | 860 | .div_exact => false, |
| 856 | }; | 861 | }; |
| 857 | if (!allow_div_zero) { | 862 | if (!allow_div_zero) { |
| ... | @@ -871,6 +876,7 @@ fn divScalar( | ... | @@ -871,6 +876,7 @@ fn divScalar( |
| 871 | .div => return floatDiv(sema, lhs_val, rhs_val, ty), | 876 | .div => return floatDiv(sema, lhs_val, rhs_val, ty), |
| 872 | .div_trunc => return floatDivTrunc(sema, lhs_val, rhs_val, ty), | 877 | .div_trunc => return floatDivTrunc(sema, lhs_val, rhs_val, ty), |
| 873 | .div_floor => return floatDivFloor(sema, lhs_val, rhs_val, ty), | 878 | .div_floor => return floatDivFloor(sema, lhs_val, rhs_val, ty), |
| 879 | .div_ceil => return floatDivCeil(sema, lhs_val, rhs_val, ty), | ||
| 874 | .div_exact => { | 880 | .div_exact => { |
| 875 | if (!floatDivIsExact(sema, lhs_val, rhs_val, ty)) { | 881 | if (!floatDivIsExact(sema, lhs_val, rhs_val, ty)) { |
| 876 | return sema.fail(block, src, "exact division produced remainder", .{}); | 882 | return sema.fail(block, src, "exact division produced remainder", .{}); |
| ... | @@ -1755,6 +1761,49 @@ fn intDivFloorInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value { | ... | @@ -1755,6 +1761,49 @@ fn intDivFloorInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value { |
| 1755 | } | 1761 | } |
| 1756 | return pt.intValue_big(ty, result_q.toConst()); | 1762 | return pt.intValue_big(ty, result_q.toConst()); |
| 1757 | } | 1763 | } |
| 1764 | fn intDivCeil(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !struct { overflow: bool, val: Value } { | ||
| 1765 | const result = intDivCeilInner(sema, lhs, rhs, ty) catch |err| switch (err) { | ||
| 1766 | error.Overflow => { | ||
| 1767 | const result = intDivCeilInner(sema, lhs, rhs, .comptime_int) catch |err1| switch (err1) { | ||
| 1768 | error.Overflow => unreachable, | ||
| 1769 | else => |e| return e, | ||
| 1770 | }; | ||
| 1771 | return .{ .overflow = true, .val = result }; | ||
| 1772 | }, | ||
| 1773 | else => |e| return e, | ||
| 1774 | }; | ||
| 1775 | return .{ .overflow = false, .val = result }; | ||
| 1776 | } | ||
| 1777 | fn intDivCeilInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value { | ||
| 1778 | const pt = sema.pt; | ||
| 1779 | const zcu = pt.zcu; | ||
| 1780 | var lhs_space: Value.BigIntSpace = undefined; | ||
| 1781 | var rhs_space: Value.BigIntSpace = undefined; | ||
| 1782 | const lhs_bigint = lhs.toBigInt(&lhs_space, zcu); | ||
| 1783 | const rhs_bigint = rhs.toBigInt(&rhs_space, zcu); | ||
| 1784 | const limbs_q = try sema.arena.alloc( | ||
| 1785 | std.math.big.Limb, | ||
| 1786 | lhs_bigint.limbs.len, | ||
| 1787 | ); | ||
| 1788 | const limbs_r = try sema.arena.alloc( | ||
| 1789 | std.math.big.Limb, | ||
| 1790 | rhs_bigint.limbs.len, | ||
| 1791 | ); | ||
| 1792 | const limbs_buf = try sema.arena.alloc( | ||
| 1793 | std.math.big.Limb, | ||
| 1794 | std.math.big.int.calcDivLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len), | ||
| 1795 | ); | ||
| 1796 | var result_q: BigIntMutable = .{ .limbs = limbs_q, .positive = undefined, .len = undefined }; | ||
| 1797 | var result_r: BigIntMutable = .{ .limbs = limbs_r, .positive = undefined, .len = undefined }; | ||
| 1798 | result_q.divCeil(&result_r, lhs_bigint, rhs_bigint, limbs_buf); | ||
| 1799 | if (ty.toIntern() != .comptime_int_type) { | ||
| 1800 | const info = ty.intInfo(zcu); | ||
| 1801 | if (!result_q.toConst().fitsInTwosComp(info.signedness, info.bits)) { | ||
| 1802 | return error.Overflow; | ||
| 1803 | } | ||
| 1804 | } | ||
| 1805 | return pt.intValue_big(ty, result_q.toConst()); | ||
| 1806 | } | ||
| 1758 | fn intMod(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value { | 1807 | fn intMod(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value { |
| 1759 | const pt = sema.pt; | 1808 | const pt = sema.pt; |
| 1760 | const zcu = pt.zcu; | 1809 | const zcu = pt.zcu; |
| ... | @@ -2140,6 +2189,23 @@ fn floatDivFloor(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value { | ... | @@ -2140,6 +2189,23 @@ fn floatDivFloor(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value { |
| 2140 | .storage = storage, | 2189 | .storage = storage, |
| 2141 | } })); | 2190 | } })); |
| 2142 | } | 2191 | } |
| 2192 | fn floatDivCeil(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value { | ||
| 2193 | const pt = sema.pt; | ||
| 2194 | const zcu = pt.zcu; | ||
| 2195 | const target = zcu.getTarget(); | ||
| 2196 | const storage: InternPool.Key.Float.Storage = switch (ty.floatBits(target)) { | ||
| 2197 | 16 => .{ .f16 = @divCeil(lhs.toFloat(f16, zcu), rhs.toFloat(f16, zcu)) }, | ||
| 2198 | 32 => .{ .f32 = @divCeil(lhs.toFloat(f32, zcu), rhs.toFloat(f32, zcu)) }, | ||
| 2199 | 64 => .{ .f64 = @divCeil(lhs.toFloat(f64, zcu), rhs.toFloat(f64, zcu)) }, | ||
| 2200 | 80 => .{ .f80 = @divCeil(lhs.toFloat(f80, zcu), rhs.toFloat(f80, zcu)) }, | ||
| 2201 | 128 => .{ .f128 = @divCeil(lhs.toFloat(f128, zcu), rhs.toFloat(f128, zcu)) }, | ||
| 2202 | else => unreachable, | ||
| 2203 | }; | ||
| 2204 | return .fromInterned(try pt.intern(.{ .float = .{ | ||
| 2205 | .ty = ty.toIntern(), | ||
| 2206 | .storage = storage, | ||
| 2207 | } })); | ||
| 2208 | } | ||
| 2143 | fn floatDivIsExact(sema: *Sema, lhs: Value, rhs: Value, ty: Type) bool { | 2209 | fn floatDivIsExact(sema: *Sema, lhs: Value, rhs: Value, ty: Type) bool { |
| 2144 | const zcu = sema.pt.zcu; | 2210 | const zcu = sema.pt.zcu; |
| 2145 | const target = zcu.getTarget(); | 2211 | const target = zcu.getTarget(); |
| ... | @@ -2238,7 +2304,7 @@ fn intValueAa(sema: *Sema, ty: Type) !Value { | ... | @@ -2238,7 +2304,7 @@ fn intValueAa(sema: *Sema, ty: Type) !Value { |
| 2238 | if (ty.toIntern() == .u0_type) return pt.intValue(ty, 0); | 2304 | if (ty.toIntern() == .u0_type) return pt.intValue(ty, 0); |
| 2239 | const info = ty.intInfo(zcu); | 2305 | const info = ty.intInfo(zcu); |
| 2240 | 2306 | ||
| 2241 | const buf = try sema.arena.alloc(u8, (info.bits + 7) / 8); | 2307 | const buf = try sema.arena.alloc(u8, @divCeil(info.bits, 8)); |
| 2242 | @memset(buf, 0xAA); | 2308 | @memset(buf, 0xAA); |
| 2243 | 2309 | ||
| 2244 | const limbs = try sema.arena.alloc( | 2310 | const limbs = try sema.arena.alloc( |
src/Type.zig+3-3| ... | @@ -968,7 +968,7 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { | ... | @@ -968,7 +968,7 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { |
| 968 | if (vector_type.len > 256 and target.cpu.has(.x86, .avx512f)) return .@"64"; | 968 | if (vector_type.len > 256 and target.cpu.has(.x86, .avx512f)) return .@"64"; |
| 969 | if (vector_type.len > 128 and target.cpu.has(.x86, .avx)) return .@"32"; | 969 | if (vector_type.len > 128 and target.cpu.has(.x86, .avx)) return .@"32"; |
| 970 | if (vector_type.len > 64) return .@"16"; | 970 | if (vector_type.len > 64) return .@"16"; |
| 971 | const bytes = std.math.divCeil(u32, vector_type.len, 8) catch unreachable; | 971 | const bytes = @divCeil(vector_type.len, 8); |
| 972 | return .fromByteUnits(std.math.ceilPowerOfTwoAssert(u32, bytes)); | 972 | return .fromByteUnits(std.math.ceilPowerOfTwoAssert(u32, bytes)); |
| 973 | } | 973 | } |
| 974 | const elem_bytes: u32 = @intCast(Type.fromInterned(vector_type.child).abiSize(zcu)); | 974 | const elem_bytes: u32 = @intCast(Type.fromInterned(vector_type.child).abiSize(zcu)); |
| ... | @@ -1111,10 +1111,10 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 { | ... | @@ -1111,10 +1111,10 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 { |
| 1111 | .vector_type => |vec| { | 1111 | .vector_type => |vec| { |
| 1112 | const elem_ty: Type = .fromInterned(vec.child); | 1112 | const elem_ty: Type = .fromInterned(vec.child); |
| 1113 | const bytes = switch (zcu.comp.getZigBackend()) { | 1113 | const bytes = switch (zcu.comp.getZigBackend()) { |
| 1114 | else => std.math.divCeil(u64, vec.len * elem_ty.bitSize(zcu), 8) catch unreachable, | 1114 | else => @divCeil(vec.len * elem_ty.bitSize(zcu), 8), |
| 1115 | .stage2_c, .stage2_wasm => vec.len * elem_ty.abiSize(zcu), | 1115 | .stage2_c, .stage2_wasm => vec.len * elem_ty.abiSize(zcu), |
| 1116 | .stage2_x86_64 => switch (elem_ty.toIntern()) { | 1116 | .stage2_x86_64 => switch (elem_ty.toIntern()) { |
| 1117 | .bool_type => std.math.divCeil(u64, vec.len, 8) catch unreachable, | 1117 | .bool_type => @divCeil(vec.len, 8), |
| 1118 | else => vec.len * elem_ty.abiSize(zcu), | 1118 | else => vec.len * elem_ty.abiSize(zcu), |
| 1119 | }, | 1119 | }, |
| 1120 | }; | 1120 | }; |
src/codegen/aarch64/Select.zig+12-10| ... | @@ -175,6 +175,8 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { | ... | @@ -175,6 +175,8 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { |
| 175 | .div_trunc_optimized, | 175 | .div_trunc_optimized, |
| 176 | .div_floor, | 176 | .div_floor, |
| 177 | .div_floor_optimized, | 177 | .div_floor_optimized, |
| 178 | .div_ceil, | ||
| 179 | .div_ceil_optimized, | ||
| 178 | .div_exact, | 180 | .div_exact, |
| 179 | .div_exact_optimized, | 181 | .div_exact_optimized, |
| 180 | .rem, | 182 | .rem, |
| ... | @@ -403,11 +405,11 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { | ... | @@ -403,11 +405,11 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { |
| 403 | .live_registers = undefined, | 405 | .live_registers = undefined, |
| 404 | .repeat_list = undefined, | 406 | .repeat_list = undefined, |
| 405 | }); | 407 | }); |
| 406 | try isel.dom.appendNTimes(gpa, 0, std.math.divCeil(usize, isel.dom_len, @bitSizeOf(DomInt)) catch unreachable); | 408 | try isel.dom.appendNTimes(gpa, 0, @divCeil(isel.dom_len, @bitSizeOf(DomInt))); |
| 407 | try isel.analyze(air_body_block.body); | 409 | try isel.analyze(air_body_block.body); |
| 408 | for ( | 410 | for ( |
| 409 | isel.dom.items[initial_dom_start..].ptr, | 411 | isel.dom.items[initial_dom_start..].ptr, |
| 410 | isel.dom.items[isel.dom_start..][0 .. std.math.divCeil(usize, initial_dom_len, @bitSizeOf(DomInt)) catch unreachable], | 412 | isel.dom.items[isel.dom_start..][0..@divCeil(initial_dom_len, @bitSizeOf(DomInt))], |
| 411 | ) |*initial_dom, loop_dom| initial_dom.* |= loop_dom; | 413 | ) |*initial_dom, loop_dom| initial_dom.* |= loop_dom; |
| 412 | isel.dom_start = initial_dom_start; | 414 | isel.dom_start = initial_dom_start; |
| 413 | isel.dom_len = initial_dom_len; | 415 | isel.dom_len = initial_dom_len; |
| ... | @@ -589,7 +591,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { | ... | @@ -589,7 +591,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { |
| 589 | .live_registers = undefined, | 591 | .live_registers = undefined, |
| 590 | .repeat_list = undefined, | 592 | .repeat_list = undefined, |
| 591 | }); | 593 | }); |
| 592 | try isel.dom.appendNTimes(gpa, 0, std.math.divCeil(usize, isel.dom_len, @bitSizeOf(DomInt)) catch unreachable); | 594 | try isel.dom.appendNTimes(gpa, 0, @divCeil(isel.dom_len, @bitSizeOf(DomInt))); |
| 593 | 595 | ||
| 594 | var cases_it = switch_br.iterateCases(); | 596 | var cases_it = switch_br.iterateCases(); |
| 595 | while (cases_it.next()) |case| try isel.analyze(case.body); | 597 | while (cases_it.next()) |case| try isel.analyze(case.body); |
| ... | @@ -597,7 +599,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { | ... | @@ -597,7 +599,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { |
| 597 | 599 | ||
| 598 | for ( | 600 | for ( |
| 599 | isel.dom.items[initial_dom_start..].ptr, | 601 | isel.dom.items[initial_dom_start..].ptr, |
| 600 | isel.dom.items[isel.dom_start..][0 .. std.math.divCeil(usize, initial_dom_len, @bitSizeOf(DomInt)) catch unreachable], | 602 | isel.dom.items[isel.dom_start..][0..@divCeil(initial_dom_len, @bitSizeOf(DomInt))], |
| 601 | ) |*initial_dom, loop_dom| initial_dom.* |= loop_dom; | 603 | ) |*initial_dom, loop_dom| initial_dom.* |= loop_dom; |
| 602 | isel.dom_start = initial_dom_start; | 604 | isel.dom_start = initial_dom_start; |
| 603 | isel.dom_len = initial_dom_len; | 605 | isel.dom_len = initial_dom_len; |
| ... | @@ -10194,7 +10196,7 @@ pub const Value = struct { | ... | @@ -10194,7 +10196,7 @@ pub const Value = struct { |
| 10194 | 0 => unreachable, | 10196 | 0 => unreachable, |
| 10195 | 1...64 => unreachable, | 10197 | 1...64 => unreachable, |
| 10196 | 65...256 => |bits| if (offset == 0 and size == ty_size) { | 10198 | 65...256 => |bits| if (offset == 0 and size == ty_size) { |
| 10197 | const parts_len = std.math.divCeil(u16, bits, 64) catch unreachable; | 10199 | const parts_len = @divCeil(bits, 64); |
| 10198 | vi.setParts(isel, @intCast(parts_len)); | 10200 | vi.setParts(isel, @intCast(parts_len)); |
| 10199 | for (0..parts_len) |part_index| _ = vi.addPart(isel, 8 * part_index, 8); | 10201 | for (0..parts_len) |part_index| _ = vi.addPart(isel, 8 * part_index, 8); |
| 10200 | }, | 10202 | }, |
| ... | @@ -10238,7 +10240,7 @@ pub const Value = struct { | ... | @@ -10238,7 +10240,7 @@ pub const Value = struct { |
| 10238 | const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; | 10240 | const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; |
| 10239 | const array_len = array_type.lenIncludingSentinel(); | 10241 | const array_len = array_type.lenIncludingSentinel(); |
| 10240 | if (array_len > Value.max_parts and | 10242 | if (array_len > Value.max_parts and |
| 10241 | (std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts) | 10243 | (@divCeil(size, @as(u64, 1) << min_part_log2_stride)) > Value.max_parts) |
| 10242 | return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); | 10244 | return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); |
| 10243 | const alignment = vi.alignment(isel); | 10245 | const alignment = vi.alignment(isel); |
| 10244 | const Part = struct { offset: u64, size: u64 }; | 10246 | const Part = struct { offset: u64, size: u64 }; |
| ... | @@ -10288,7 +10290,7 @@ pub const Value = struct { | ... | @@ -10288,7 +10290,7 @@ pub const Value = struct { |
| 10288 | .anyframe_type => unreachable, | 10290 | .anyframe_type => unreachable, |
| 10289 | .error_union_type => |error_union_type| { | 10291 | .error_union_type => |error_union_type| { |
| 10290 | const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; | 10292 | const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; |
| 10291 | if ((std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts) | 10293 | if ((@divCeil(size, @as(u64, 1) << min_part_log2_stride)) > Value.max_parts) |
| 10292 | return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); | 10294 | return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); |
| 10293 | const alignment = vi.alignment(isel); | 10295 | const alignment = vi.alignment(isel); |
| 10294 | const payload_ty: ZigType = .fromInterned(error_union_type.payload_type); | 10296 | const payload_ty: ZigType = .fromInterned(error_union_type.payload_type); |
| ... | @@ -10395,7 +10397,7 @@ pub const Value = struct { | ... | @@ -10395,7 +10397,7 @@ pub const Value = struct { |
| 10395 | } | 10397 | } |
| 10396 | const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; | 10398 | const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; |
| 10397 | if (loaded_struct.field_types.len > Value.max_parts and | 10399 | if (loaded_struct.field_types.len > Value.max_parts and |
| 10398 | (std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts) | 10400 | (@divCeil(size, @as(u64, 1) << min_part_log2_stride)) > Value.max_parts) |
| 10399 | return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); | 10401 | return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); |
| 10400 | const alignment = vi.alignment(isel); | 10402 | const alignment = vi.alignment(isel); |
| 10401 | const Part = struct { offset: u64, size: u64, signedness: ?std.lang.Signedness, is_vector: bool }; | 10403 | const Part = struct { offset: u64, size: u64, signedness: ?std.lang.Signedness, is_vector: bool }; |
| ... | @@ -10456,7 +10458,7 @@ pub const Value = struct { | ... | @@ -10456,7 +10458,7 @@ pub const Value = struct { |
| 10456 | .tuple_type => |tuple_type| { | 10458 | .tuple_type => |tuple_type| { |
| 10457 | const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; | 10459 | const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; |
| 10458 | if (tuple_type.types.len > Value.max_parts and | 10460 | if (tuple_type.types.len > Value.max_parts and |
| 10459 | (std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts) | 10461 | (@divCeil(size, @as(u64, 1) << min_part_log2_stride)) > Value.max_parts) |
| 10460 | return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); | 10462 | return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); |
| 10461 | const alignment = vi.alignment(isel); | 10463 | const alignment = vi.alignment(isel); |
| 10462 | const Part = struct { offset: u64, size: u64, is_vector: bool }; | 10464 | const Part = struct { offset: u64, size: u64, is_vector: bool }; |
| ... | @@ -10511,7 +10513,7 @@ pub const Value = struct { | ... | @@ -10511,7 +10513,7 @@ pub const Value = struct { |
| 10511 | } }, | 10513 | } }, |
| 10512 | } | 10514 | } |
| 10513 | const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; | 10515 | const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; |
| 10514 | if ((std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts) | 10516 | if ((@divCeil(size, @as(u64, 1) << min_part_log2_stride)) > Value.max_parts) |
| 10515 | return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); | 10517 | return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); |
| 10516 | const union_layout = ZigType.getUnionLayout(loaded_union, zcu); | 10518 | const union_layout = ZigType.getUnionLayout(loaded_union, zcu); |
| 10517 | const alignment = vi.alignment(isel); | 10519 | const alignment = vi.alignment(isel); |
src/codegen/c.zig+2| ... | @@ -2675,6 +2675,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void { | ... | @@ -2675,6 +2675,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void { |
| 2675 | try airBinBuiltinCall(f, inst, "fmod", .none); | 2675 | try airBinBuiltinCall(f, inst, "fmod", .none); |
| 2676 | }, | 2676 | }, |
| 2677 | .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .none), | 2677 | .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .none), |
| 2678 | .div_ceil => try airBinBuiltinCall(f, inst, "div_ceil", .none), | ||
| 2678 | .mod => try airBinBuiltinCall(f, inst, "mod", .none), | 2679 | .mod => try airBinBuiltinCall(f, inst, "mod", .none), |
| 2679 | .abs => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].ty_op.operand, "abs", .none), | 2680 | .abs => try airUnBuiltinCall(f, inst, air_datas[@intFromEnum(inst)].ty_op.operand, "abs", .none), |
| 2680 | 2681 | ||
| ... | @@ -2856,6 +2857,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void { | ... | @@ -2856,6 +2857,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void { |
| 2856 | .div_float_optimized, | 2857 | .div_float_optimized, |
| 2857 | .div_trunc_optimized, | 2858 | .div_trunc_optimized, |
| 2858 | .div_floor_optimized, | 2859 | .div_floor_optimized, |
| 2860 | .div_ceil_optimized, | ||
| 2859 | .div_exact_optimized, | 2861 | .div_exact_optimized, |
| 2860 | .rem_optimized, | 2862 | .rem_optimized, |
| 2861 | .mod_optimized, | 2863 | .mod_optimized, |
src/codegen/llvm/FuncGen.zig+76-2| ... | @@ -383,6 +383,7 @@ fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air.Cov | ... | @@ -383,6 +383,7 @@ fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air.Cov |
| 383 | .div_float => try self.airDivFloat(inst, .normal), | 383 | .div_float => try self.airDivFloat(inst, .normal), |
| 384 | .div_trunc => try self.airDivTrunc(inst, .normal), | 384 | .div_trunc => try self.airDivTrunc(inst, .normal), |
| 385 | .div_floor => try self.airDivFloor(inst, .normal), | 385 | .div_floor => try self.airDivFloor(inst, .normal), |
| 386 | .div_ceil => try self.airDivCeil(inst, .normal), | ||
| 386 | .div_exact => try self.airDivExact(inst, .normal), | 387 | .div_exact => try self.airDivExact(inst, .normal), |
| 387 | .rem => try self.airRem(inst, .normal), | 388 | .rem => try self.airRem(inst, .normal), |
| 388 | .mod => try self.airMod(inst, .normal), | 389 | .mod => try self.airMod(inst, .normal), |
| ... | @@ -400,6 +401,7 @@ fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air.Cov | ... | @@ -400,6 +401,7 @@ fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air.Cov |
| 400 | .div_float_optimized => try self.airDivFloat(inst, .fast), | 401 | .div_float_optimized => try self.airDivFloat(inst, .fast), |
| 401 | .div_trunc_optimized => try self.airDivTrunc(inst, .fast), | 402 | .div_trunc_optimized => try self.airDivTrunc(inst, .fast), |
| 402 | .div_floor_optimized => try self.airDivFloor(inst, .fast), | 403 | .div_floor_optimized => try self.airDivFloor(inst, .fast), |
| 404 | .div_ceil_optimized => try self.airDivCeil(inst, .fast), | ||
| 403 | .div_exact_optimized => try self.airDivExact(inst, .fast), | 405 | .div_exact_optimized => try self.airDivExact(inst, .fast), |
| 404 | .rem_optimized => try self.airRem(inst, .fast), | 406 | .rem_optimized => try self.airRem(inst, .fast), |
| 405 | .mod_optimized => try self.airMod(inst, .fast), | 407 | .mod_optimized => try self.airMod(inst, .fast), |
| ... | @@ -3578,6 +3580,78 @@ fn airDivFloor(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) | ... | @@ -3578,6 +3580,78 @@ fn airDivFloor(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) |
| 3578 | return self.wip.bin(.udiv, lhs, rhs, ""); | 3580 | return self.wip.bin(.udiv, lhs, rhs, ""); |
| 3579 | } | 3581 | } |
| 3580 | 3582 | ||
| 3583 | fn airDivCeil(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allocator.Error!Builder.Value { | ||
| 3584 | const o = self.object; | ||
| 3585 | const zcu = o.zcu; | ||
| 3586 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | ||
| 3587 | const lhs = try self.resolveInst(bin_op.lhs); | ||
| 3588 | const rhs = try self.resolveInst(bin_op.rhs); | ||
| 3589 | const inst_ty = self.typeOfIndex(inst); | ||
| 3590 | const scalar_ty = inst_ty.scalarType(zcu); | ||
| 3591 | |||
| 3592 | if (scalar_ty.isRuntimeFloat()) { | ||
| 3593 | const result = try self.buildFloatOp(.div, fast, inst_ty, 2, .{ lhs, rhs }); | ||
| 3594 | return self.buildFloatOp(.ceil, fast, inst_ty, 1, .{result}); | ||
| 3595 | } | ||
| 3596 | if (scalar_ty.isSignedInt(zcu)) { | ||
| 3597 | const scalar_llvm_ty = try o.lowerType(scalar_ty, .by_value); | ||
| 3598 | const inst_llvm_ty = try o.lowerType(inst_ty, .by_value); | ||
| 3599 | |||
| 3600 | const ExpectedContents = [std.math.big.int.calcTwosCompLimbCount(256)]std.math.big.Limb; | ||
| 3601 | var bfa_buf: ExpectedContents = undefined; | ||
| 3602 | var bfa: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), self.gpa); | ||
| 3603 | const allocator = bfa.allocator(); | ||
| 3604 | |||
| 3605 | const scalar_bits = scalar_ty.intInfo(zcu).bits; | ||
| 3606 | var smin_big_int: std.math.big.int.Mutable = .{ | ||
| 3607 | .limbs = try allocator.alloc( | ||
| 3608 | std.math.big.Limb, | ||
| 3609 | std.math.big.int.calcTwosCompLimbCount(scalar_bits), | ||
| 3610 | ), | ||
| 3611 | .len = undefined, | ||
| 3612 | .positive = undefined, | ||
| 3613 | }; | ||
| 3614 | defer allocator.free(smin_big_int.limbs); | ||
| 3615 | smin_big_int.setTwosCompIntLimit(.min, .signed, scalar_bits); | ||
| 3616 | const smin = try o.builder.splatValue(inst_llvm_ty, try o.builder.bigIntConst( | ||
| 3617 | scalar_llvm_ty, | ||
| 3618 | smin_big_int.toConst(), | ||
| 3619 | )); | ||
| 3620 | |||
| 3621 | const zero = try o.builder.splatValue( | ||
| 3622 | inst_llvm_ty, | ||
| 3623 | try o.builder.intConst(scalar_llvm_ty, 0), | ||
| 3624 | ); | ||
| 3625 | |||
| 3626 | const div = try self.wip.bin(.sdiv, lhs, rhs, "divCeil.div"); | ||
| 3627 | const rem = try self.wip.bin(.srem, lhs, rhs, "divCeil.rem"); | ||
| 3628 | |||
| 3629 | const rhs_sign = try self.wip.bin(.@"and", rhs, smin, "divCeil.rhs_sign"); | ||
| 3630 | const rem_xor_rhs_sign = try self.wip.bin(.xor, rem, rhs_sign, "divCeil.rem_xor_rhs_sign"); | ||
| 3631 | |||
| 3632 | const need_correction = try self.wip.icmp(.sgt, rem_xor_rhs_sign, zero, "divCeil.need_correction"); | ||
| 3633 | |||
| 3634 | const correction = try self.wip.cast(.zext, need_correction, inst_llvm_ty, "divCeil.correction"); | ||
| 3635 | return self.wip.bin(.@"add nsw", div, correction, "divCeil"); | ||
| 3636 | } else { | ||
| 3637 | const scalar_llvm_ty = try o.lowerType(scalar_ty, .by_value); | ||
| 3638 | const inst_llvm_ty = try o.lowerType(inst_ty, .by_value); | ||
| 3639 | |||
| 3640 | const zero = try o.builder.splatValue( | ||
| 3641 | inst_llvm_ty, | ||
| 3642 | try o.builder.intConst(scalar_llvm_ty, 0), | ||
| 3643 | ); | ||
| 3644 | |||
| 3645 | const div = try self.wip.bin(.udiv, lhs, rhs, "divCeil.div"); | ||
| 3646 | const rem = try self.wip.bin(.urem, lhs, rhs, "divCeil.rem"); | ||
| 3647 | |||
| 3648 | const rem_nonzero = try self.wip.icmp(.ne, rem, zero, "divCeil.rem_nonzero"); | ||
| 3649 | const correction = try self.wip.cast(.zext, rem_nonzero, inst_llvm_ty, "divCeil.correction"); | ||
| 3650 | |||
| 3651 | return self.wip.bin(.@"add nuw", div, correction, "divCeil"); | ||
| 3652 | } | ||
| 3653 | } | ||
| 3654 | |||
| 3581 | fn airDivExact(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allocator.Error!Builder.Value { | 3655 | fn airDivExact(self: *FuncGen, inst: Air.Inst.Index, fast: Builder.FastMathKind) Allocator.Error!Builder.Value { |
| 3582 | const zcu = self.object.zcu; | 3656 | const zcu = self.object.zcu; |
| 3583 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 3657 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| ... | @@ -6874,7 +6948,7 @@ const ParamTypeIterator = struct { | ... | @@ -6874,7 +6948,7 @@ const ParamTypeIterator = struct { |
| 6874 | switch (ip.indexToKey(ty.toIntern())) { | 6948 | switch (ip.indexToKey(ty.toIntern())) { |
| 6875 | .struct_type => { | 6949 | .struct_type => { |
| 6876 | const size = ty.abiSize(zcu); | 6950 | const size = ty.abiSize(zcu); |
| 6877 | assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index); | 6951 | assert(@divCeil(size, 8) == types_index); |
| 6878 | if (size % 8 > 0) { | 6952 | if (size % 8 > 0) { |
| 6879 | it.types_buffer[types_index - 1] = | 6953 | it.types_buffer[types_index - 1] = |
| 6880 | try it.object.builder.intType(@intCast(size % 8 * 8)); | 6954 | try it.object.builder.intType(@intCast(size % 8 * 8)); |
| ... | @@ -7119,7 +7193,7 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.E | ... | @@ -7119,7 +7193,7 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.E |
| 7119 | switch (ip.indexToKey(ret_ty.toIntern())) { | 7193 | switch (ip.indexToKey(ret_ty.toIntern())) { |
| 7120 | .struct_type => { | 7194 | .struct_type => { |
| 7121 | const size = ret_ty.abiSize(zcu); | 7195 | const size = ret_ty.abiSize(zcu); |
| 7122 | assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index); | 7196 | assert(@divCeil(size, 8) == types_index); |
| 7123 | if (size % 8 > 0) { | 7197 | if (size % 8 > 0) { |
| 7124 | types_buffer[types_index - 1] = try o.builder.intType(@intCast(size % 8 * 8)); | 7198 | types_buffer[types_index - 1] = try o.builder.intType(@intCast(size % 8 * 8)); |
| 7125 | } | 7199 | } |
src/codegen/riscv64/CodeGen.zig+3-2| ... | @@ -1422,6 +1422,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1422,6 +1422,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { |
| 1422 | .mod, | 1422 | .mod, |
| 1423 | .div_float, | 1423 | .div_float, |
| 1424 | .div_floor, | 1424 | .div_floor, |
| 1425 | .div_ceil, | ||
| 1425 | => return func.fail("TODO: {s}", .{@tagName(tag)}), | 1426 | => return func.fail("TODO: {s}", .{@tagName(tag)}), |
| 1426 | 1427 | ||
| 1427 | .sqrt, | 1428 | .sqrt, |
| ... | @@ -1621,6 +1622,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1621,6 +1622,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { |
| 1621 | .div_trunc_optimized, | 1622 | .div_trunc_optimized, |
| 1622 | .div_floor_optimized, | 1623 | .div_floor_optimized, |
| 1623 | .div_exact_optimized, | 1624 | .div_exact_optimized, |
| 1625 | .div_ceil_optimized, | ||
| 1624 | .rem_optimized, | 1626 | .rem_optimized, |
| 1625 | .mod_optimized, | 1627 | .mod_optimized, |
| 1626 | .neg_optimized, | 1628 | .neg_optimized, |
| ... | @@ -2215,8 +2217,7 @@ fn airIntCast(func: *Func, inst: Air.Inst.Index) !void { | ... | @@ -2215,8 +2217,7 @@ fn airIntCast(func: *Func, inst: Air.Inst.Index) !void { |
| 2215 | }; | 2217 | }; |
| 2216 | 2218 | ||
| 2217 | const dst_mcv = if (dst_int_info.bits <= src_storage_bits and | 2219 | const dst_mcv = if (dst_int_info.bits <= src_storage_bits and |
| 2218 | math.divCeil(u16, dst_int_info.bits, 64) catch unreachable == | 2220 | @divCeil(dst_int_info.bits, 64) == @divCeil(src_storage_bits, 64) and |
| 2219 | math.divCeil(u32, src_storage_bits, 64) catch unreachable and | ||
| 2220 | func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: { | 2221 | func.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: { |
| 2221 | const dst_mcv = try func.allocRegOrMem(dst_ty, inst, true); | 2222 | const dst_mcv = try func.allocRegOrMem(dst_ty, inst, true); |
| 2222 | try func.genCopy(min_ty, dst_mcv, src_mcv); | 2223 | try func.genCopy(min_ty, dst_mcv, src_mcv); |
src/codegen/sparc64/CodeGen.zig+2-1| ... | @@ -523,7 +523,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -523,7 +523,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 523 | .mul_with_overflow => try self.airMulWithOverflow(inst), | 523 | .mul_with_overflow => try self.airMulWithOverflow(inst), |
| 524 | .shl_with_overflow => try self.airShlWithOverflow(inst), | 524 | .shl_with_overflow => try self.airShlWithOverflow(inst), |
| 525 | 525 | ||
| 526 | .div_float, .div_trunc, .div_floor, .div_exact => try self.airDiv(inst), | 526 | .div_float, .div_trunc, .div_floor, .div_ceil, .div_exact => try self.airDiv(inst), |
| 527 | 527 | ||
| 528 | .cmp_lt => try self.airCmp(inst, .lt), | 528 | .cmp_lt => try self.airCmp(inst, .lt), |
| 529 | .cmp_lte => try self.airCmp(inst, .lte), | 529 | .cmp_lte => try self.airCmp(inst, .lte), |
| ... | @@ -678,6 +678,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -678,6 +678,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 678 | .div_float_optimized, | 678 | .div_float_optimized, |
| 679 | .div_trunc_optimized, | 679 | .div_trunc_optimized, |
| 680 | .div_floor_optimized, | 680 | .div_floor_optimized, |
| 681 | .div_ceil_optimized, | ||
| 681 | .div_exact_optimized, | 682 | .div_exact_optimized, |
| 682 | .rem_optimized, | 683 | .rem_optimized, |
| 683 | .mod_optimized, | 684 | .mod_optimized, |
src/codegen/spirv/Assembler.zig+1-1| ... | @@ -375,7 +375,7 @@ fn processGenericInstruction(ass: *Assembler) !?AsmValue { | ... | @@ -375,7 +375,7 @@ fn processGenericInstruction(ass: *Assembler) !?AsmValue { |
| 375 | }, | 375 | }, |
| 376 | .string => |offset| { | 376 | .string => |offset| { |
| 377 | const text = std.mem.sliceTo(ass.inst.string_bytes.items[offset..], 0); | 377 | const text = std.mem.sliceTo(ass.inst.string_bytes.items[offset..], 0); |
| 378 | const size = std.math.divCeil(usize, text.len + 1, @sizeOf(Word)) catch unreachable; | 378 | const size = @divCeil(text.len + 1, @sizeOf(Word)); |
| 379 | try section.ensureUnusedCapacity(cg.gpa, size); | 379 | try section.ensureUnusedCapacity(cg.gpa, size); |
| 380 | section.writeOperand(spec.LiteralString, text); | 380 | section.writeOperand(spec.LiteralString, text); |
| 381 | }, | 381 | }, |
src/codegen/spirv/Section.zig+1-1| ... | @@ -232,7 +232,7 @@ fn operandSize(comptime Operand: type, operand: Operand) usize { | ... | @@ -232,7 +232,7 @@ fn operandSize(comptime Operand: type, operand: Operand) usize { |
| 232 | return switch (Operand) { | 232 | return switch (Operand) { |
| 233 | spec.LiteralSpecConstantOpInteger => unreachable, | 233 | spec.LiteralSpecConstantOpInteger => unreachable, |
| 234 | spec.Id, spec.LiteralInteger, spec.LiteralExtInstInteger => 1, | 234 | spec.Id, spec.LiteralInteger, spec.LiteralExtInstInteger => 1, |
| 235 | spec.LiteralString => std.math.divCeil(usize, operand.len + 1, @sizeOf(Word)) catch unreachable, | 235 | spec.LiteralString => @divCeil(operand.len + 1, @sizeOf(Word)), |
| 236 | spec.LiteralContextDependentNumber => switch (operand) { | 236 | spec.LiteralContextDependentNumber => switch (operand) { |
| 237 | .int32, .uint32, .float32 => 1, | 237 | .int32, .uint32, .float32 => 1, |
| 238 | .int64, .uint64, .float64 => 2, | 238 | .int64, .uint64, .float64 => 2, |
src/codegen/wasm/CodeGen.zig+106-3| ... | @@ -62,6 +62,8 @@ pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features { | ... | @@ -62,6 +62,8 @@ pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features { |
| 62 | .scalarize_div_trunc_optimized, | 62 | .scalarize_div_trunc_optimized, |
| 63 | .scalarize_div_floor, | 63 | .scalarize_div_floor, |
| 64 | .scalarize_div_floor_optimized, | 64 | .scalarize_div_floor_optimized, |
| 65 | .scalarize_div_ceil, | ||
| 66 | .scalarize_div_ceil_optimized, | ||
| 65 | .scalarize_div_exact, | 67 | .scalarize_div_exact, |
| 66 | .scalarize_div_exact_optimized, | 68 | .scalarize_div_exact_optimized, |
| 67 | .scalarize_rem, | 69 | .scalarize_rem, |
| ... | @@ -1340,6 +1342,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -1340,6 +1342,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1340 | .div_exact, | 1342 | .div_exact, |
| 1341 | .div_trunc, | 1343 | .div_trunc, |
| 1342 | .div_floor, | 1344 | .div_floor, |
| 1345 | .div_ceil, | ||
| 1343 | => |tag| { | 1346 | => |tag| { |
| 1344 | const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 1347 | const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 1345 | const lhs = try cg.resolveInst(bin_op.lhs); | 1348 | const lhs = try cg.resolveInst(bin_op.lhs); |
| ... | @@ -1366,6 +1369,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -1366,6 +1369,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1366 | .div_exact => try cg.floatDiv(float_ty, lhs, rhs), | 1369 | .div_exact => try cg.floatDiv(float_ty, lhs, rhs), |
| 1367 | .div_trunc => try cg.floatDivTrunc(float_ty, lhs, rhs), | 1370 | .div_trunc => try cg.floatDivTrunc(float_ty, lhs, rhs), |
| 1368 | .div_floor => try cg.floatDivFloor(float_ty, lhs, rhs), | 1371 | .div_floor => try cg.floatDivFloor(float_ty, lhs, rhs), |
| 1372 | .div_ceil => try cg.floatDivCeil(float_ty, lhs, rhs), | ||
| 1369 | else => unreachable, | 1373 | else => unreachable, |
| 1370 | }; | 1374 | }; |
| 1371 | 1375 | ||
| ... | @@ -1384,6 +1388,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -1384,6 +1388,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1384 | .div_exact => try cg.intDiv(int_ty, lhs, rhs), | 1388 | .div_exact => try cg.intDiv(int_ty, lhs, rhs), |
| 1385 | .div_trunc => try cg.intDiv(int_ty, lhs, rhs), | 1389 | .div_trunc => try cg.intDiv(int_ty, lhs, rhs), |
| 1386 | .div_floor => try cg.intDivFloor(int_ty, lhs, rhs), | 1390 | .div_floor => try cg.intDivFloor(int_ty, lhs, rhs), |
| 1391 | .div_ceil => try cg.intDivCeil(int_ty, lhs, rhs), | ||
| 1387 | else => unreachable, | 1392 | else => unreachable, |
| 1388 | }; | 1393 | }; |
| 1389 | 1394 | ||
| ... | @@ -1881,6 +1886,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -1881,6 +1886,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1881 | .div_float_optimized, | 1886 | .div_float_optimized, |
| 1882 | .div_trunc_optimized, | 1887 | .div_trunc_optimized, |
| 1883 | .div_floor_optimized, | 1888 | .div_floor_optimized, |
| 1889 | .div_ceil_optimized, | ||
| 1884 | .div_exact_optimized, | 1890 | .div_exact_optimized, |
| 1885 | .rem_optimized, | 1891 | .rem_optimized, |
| 1886 | .mod_optimized, | 1892 | .mod_optimized, |
| ... | @@ -2799,6 +2805,97 @@ fn intDivFloor(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!W | ... | @@ -2799,6 +2805,97 @@ fn intDivFloor(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!W |
| 2799 | } | 2805 | } |
| 2800 | } | 2806 | } |
| 2801 | 2807 | ||
| 2808 | fn intDivCeil(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue { | ||
| 2809 | switch (ty.bits) { | ||
| 2810 | 0 => unreachable, | ||
| 2811 | 1...32 => { | ||
| 2812 | var q = try (try cg.intDiv(ty, lhs, rhs)).toLocal(cg, Type.i32); | ||
| 2813 | defer q.free(cg); | ||
| 2814 | |||
| 2815 | const zero: WValue = .{ .imm32 = 0 }; | ||
| 2816 | |||
| 2817 | const r = try cg.intRem(ty, lhs, rhs); | ||
| 2818 | var r_nonzero = try (try cg.intCmp(ty, .neq, r, zero)).toLocal(cg, Type.i32); | ||
| 2819 | defer r_nonzero.free(cg); | ||
| 2820 | |||
| 2821 | if (!ty.is_signed) { | ||
| 2822 | try cg.emitWValue(q); | ||
| 2823 | try cg.emitWValue(r_nonzero); | ||
| 2824 | try cg.addTag(.i32_add); | ||
| 2825 | return .stack; | ||
| 2826 | } | ||
| 2827 | |||
| 2828 | const sign_xor = try cg.intXor(ty, lhs, rhs); | ||
| 2829 | var same_sign = try (try cg.intCmp(ty, .gte, sign_xor, zero)).toLocal(cg, Type.i32); | ||
| 2830 | defer same_sign.free(cg); | ||
| 2831 | |||
| 2832 | try cg.emitWValue(q); | ||
| 2833 | const need_adjust = try cg.intAnd(.u32, r_nonzero, same_sign); | ||
| 2834 | try cg.emitWValue(need_adjust); | ||
| 2835 | try cg.addTag(.i32_add); | ||
| 2836 | return .stack; | ||
| 2837 | }, | ||
| 2838 | 33...64 => { | ||
| 2839 | var q = try (try cg.intDiv(ty, lhs, rhs)).toLocal(cg, Type.i64); | ||
| 2840 | defer q.free(cg); | ||
| 2841 | |||
| 2842 | const zero: WValue = .{ .imm64 = 0 }; | ||
| 2843 | |||
| 2844 | const r = try cg.intRem(ty, lhs, rhs); | ||
| 2845 | var r_nonzero = try (try cg.intCmp(ty, .neq, r, zero)).toLocal(cg, Type.i32); | ||
| 2846 | defer r_nonzero.free(cg); | ||
| 2847 | |||
| 2848 | if (!ty.is_signed) { | ||
| 2849 | try cg.emitWValue(q); | ||
| 2850 | try cg.emitWValue(r_nonzero); | ||
| 2851 | try cg.addTag(.i64_extend_i32_u); | ||
| 2852 | try cg.addTag(.i64_add); | ||
| 2853 | return .stack; | ||
| 2854 | } | ||
| 2855 | |||
| 2856 | const sign_xor = try cg.intXor(ty, lhs, rhs); | ||
| 2857 | var same_sign = try (try cg.intCmp(ty, .gte, sign_xor, zero)).toLocal(cg, Type.i32); | ||
| 2858 | defer same_sign.free(cg); | ||
| 2859 | |||
| 2860 | try cg.emitWValue(q); | ||
| 2861 | const need_adjust = try cg.intAnd(.u32, r_nonzero, same_sign); | ||
| 2862 | try cg.emitWValue(need_adjust); | ||
| 2863 | try cg.addTag(.i64_extend_i32_u); | ||
| 2864 | try cg.addTag(.i64_add); | ||
| 2865 | return .stack; | ||
| 2866 | }, | ||
| 2867 | else => { | ||
| 2868 | var q = try (try cg.intDiv(ty, lhs, rhs)).toLocal(cg, Type.usize); | ||
| 2869 | defer q.free(cg); | ||
| 2870 | |||
| 2871 | const zero = try cg.intZeroValue(ty); | ||
| 2872 | |||
| 2873 | const r = try cg.intRem(ty, lhs, rhs); | ||
| 2874 | var r_nonzero = try (try cg.intCmp(ty, .neq, r, zero)).toLocal(cg, Type.u32); | ||
| 2875 | defer r_nonzero.free(cg); | ||
| 2876 | |||
| 2877 | if (!ty.is_signed) { | ||
| 2878 | var adjust_bigint = try (try cg.intCast(ty, .u32, r_nonzero)).toLocal(cg, Type.usize); | ||
| 2879 | defer adjust_bigint.free(cg); | ||
| 2880 | |||
| 2881 | return try cg.intAdd(ty, q, adjust_bigint); | ||
| 2882 | } | ||
| 2883 | |||
| 2884 | const sign_xor = try cg.intXor(ty, lhs, rhs); | ||
| 2885 | var same_sign = try (try cg.intCmp(ty, .gte, sign_xor, zero)).toLocal(cg, Type.u32); | ||
| 2886 | defer same_sign.free(cg); | ||
| 2887 | |||
| 2888 | var adjust = try (try cg.intAnd(.u32, r_nonzero, same_sign)).toLocal(cg, Type.u32); | ||
| 2889 | defer adjust.free(cg); | ||
| 2890 | |||
| 2891 | var adjust_bigint = try (try cg.intCast(ty, .u32, adjust)).toLocal(cg, Type.usize); | ||
| 2892 | defer adjust_bigint.free(cg); | ||
| 2893 | |||
| 2894 | return try cg.intAdd(ty, q, adjust_bigint); | ||
| 2895 | }, | ||
| 2896 | } | ||
| 2897 | } | ||
| 2898 | |||
| 2802 | fn intRem(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue { | 2899 | fn intRem(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue { |
| 2803 | switch (ty.bits) { | 2900 | switch (ty.bits) { |
| 2804 | 0 => unreachable, | 2901 | 0 => unreachable, |
| ... | @@ -3581,7 +3678,7 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3581,7 +3678,7 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3581 | 3678 | ||
| 3582 | const result = try cg.allocInt(ty); | 3679 | const result = try cg.allocInt(ty); |
| 3583 | 3680 | ||
| 3584 | const used_len = (math.divCeil(u16, ty.bits, 64) catch unreachable) * 8; | 3681 | const used_len = @divCeil(ty.bits, 64) * 8; |
| 3585 | 3682 | ||
| 3586 | if (ty.bits % 64 != 0) { | 3683 | if (ty.bits % 64 != 0) { |
| 3587 | try cg.memcpy(result, operand, .{ .imm32 = used_len - 8 }); | 3684 | try cg.memcpy(result, operand, .{ .imm32 = used_len - 8 }); |
| ... | @@ -3647,7 +3744,7 @@ fn intMaxValue(cg: *CodeGen, int_ty: IntType) InnerError!WValue { | ... | @@ -3647,7 +3744,7 @@ fn intMaxValue(cg: *CodeGen, int_ty: IntType) InnerError!WValue { |
| 3647 | } else { | 3744 | } else { |
| 3648 | const result = try cg.allocInt(int_ty); | 3745 | const result = try cg.allocInt(int_ty); |
| 3649 | const full_len = @divExact(cg.intBackingBits(int_ty.bits), 8); | 3746 | const full_len = @divExact(cg.intBackingBits(int_ty.bits), 8); |
| 3650 | const used_len = (math.divCeil(u16, int_ty.bits, 64) catch unreachable) * 8; | 3747 | const used_len = @divCeil(int_ty.bits, 64) * 8; |
| 3651 | 3748 | ||
| 3652 | try cg.memset(Type.u8, result, .{ .imm32 = used_len - 8 }, .{ .imm32 = 0xFF }); | 3749 | try cg.memset(Type.u8, result, .{ .imm32 = used_len - 8 }, .{ .imm32 = 0xFF }); |
| 3653 | 3750 | ||
| ... | @@ -3681,7 +3778,7 @@ fn intMinValue(cg: *CodeGen, int_ty: IntType) InnerError!WValue { | ... | @@ -3681,7 +3778,7 @@ fn intMinValue(cg: *CodeGen, int_ty: IntType) InnerError!WValue { |
| 3681 | } else { | 3778 | } else { |
| 3682 | const result = try cg.allocInt(int_ty); | 3779 | const result = try cg.allocInt(int_ty); |
| 3683 | const full_len = @divExact(cg.intBackingBits(int_ty.bits), 8); | 3780 | const full_len = @divExact(cg.intBackingBits(int_ty.bits), 8); |
| 3684 | const used_len = (math.divCeil(u16, int_ty.bits, 64) catch unreachable) * 8; | 3781 | const used_len = @divCeil(int_ty.bits, 64) * 8; |
| 3685 | 3782 | ||
| 3686 | try cg.memset(Type.u8, result, .{ .imm32 = used_len - 8 }, .{ .imm32 = 0 }); | 3783 | try cg.memset(Type.u8, result, .{ .imm32 = used_len - 8 }, .{ .imm32 = 0 }); |
| 3687 | try cg.store(result, .{ .imm64 = ~@as(u64, 0) << @intCast(int_ty.bits - (used_len - 8) * 8 - 1) }, Type.u64, used_len - 8); | 3784 | try cg.store(result, .{ .imm64 = ~@as(u64, 0) << @intCast(int_ty.bits - (used_len - 8) * 8 - 1) }, Type.u64, used_len - 8); |
| ... | @@ -4265,6 +4362,12 @@ fn floatDivFloor(cg: *CodeGen, ty: FloatType, lhs: WValue, rhs: WValue) InnerErr | ... | @@ -4265,6 +4362,12 @@ fn floatDivFloor(cg: *CodeGen, ty: FloatType, lhs: WValue, rhs: WValue) InnerErr |
| 4265 | return cg.floatFloor(ty, div_result); | 4362 | return cg.floatFloor(ty, div_result); |
| 4266 | } | 4363 | } |
| 4267 | 4364 | ||
| 4365 | // div_ceil(a, b) = ceil(a / b) | ||
| 4366 | fn floatDivCeil(cg: *CodeGen, ty: FloatType, lhs: WValue, rhs: WValue) InnerError!WValue { | ||
| 4367 | const div_result = try cg.floatDiv(ty, lhs, rhs); | ||
| 4368 | return cg.floatCeil(ty, div_result); | ||
| 4369 | } | ||
| 4370 | |||
| 4268 | // mod(a, b) = fmod(fmod(a, b) + b, b) | 4371 | // mod(a, b) = fmod(fmod(a, b) + b, b) |
| 4269 | fn floatMod(cg: *CodeGen, ty: FloatType, lhs: WValue, rhs: WValue) InnerError!WValue { | 4372 | fn floatMod(cg: *CodeGen, ty: FloatType, lhs: WValue, rhs: WValue) InnerError!WValue { |
| 4270 | const r = try cg.floatRem(ty, lhs, rhs); | 4373 | const r = try cg.floatRem(ty, lhs, rhs); |
src/codegen/x86_64/CodeGen.zig+11-6| ... | @@ -70,6 +70,9 @@ pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features { | ... | @@ -70,6 +70,9 @@ pub fn legalizeFeatures(_: *const std.Target) *const Air.Legalize.Features { |
| 70 | .expand_sub_safe, | 70 | .expand_sub_safe, |
| 71 | .expand_mul_safe, | 71 | .expand_mul_safe, |
| 72 | 72 | ||
| 73 | .expand_div_ceil, | ||
| 74 | .expand_div_ceil_optimized, | ||
| 75 | |||
| 73 | .expand_packed_load, | 76 | .expand_packed_load, |
| 74 | .expand_packed_store, | 77 | .expand_packed_store, |
| 75 | .expand_packed_agg_field_val, | 78 | .expand_packed_agg_field_val, |
| ... | @@ -173873,6 +173876,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -173873,6 +173876,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 173873 | for (ops) |op| try op.die(cg); | 173876 | for (ops) |op| try op.die(cg); |
| 173874 | }, | 173877 | }, |
| 173875 | 173878 | ||
| 173879 | .div_ceil, .div_ceil_optimized => unreachable, | ||
| 173880 | |||
| 173876 | // No soft-float `Legalize` features are enabled, so this instruction never appears. | 173881 | // No soft-float `Legalize` features are enabled, so this instruction never appears. |
| 173877 | .legalize_compiler_rt_call => unreachable, | 173882 | .legalize_compiler_rt_call => unreachable, |
| 173878 | 173883 | ||
| ... | @@ -174781,7 +174786,7 @@ fn genShiftBinOpMir( | ... | @@ -174781,7 +174786,7 @@ fn genShiftBinOpMir( |
| 174781 | try self.spillEflagsIfOccupied(); | 174786 | try self.spillEflagsIfOccupied(); |
| 174782 | 174787 | ||
| 174783 | if (abi_size > 16) { | 174788 | if (abi_size > 16) { |
| 174784 | const limbs_len = std.math.divCeil(u32, abi_size, 8) catch unreachable; | 174789 | const limbs_len = @divCeil(abi_size, 8); |
| 174785 | assert(shift_abi_size >= 1 and shift_abi_size <= 2); | 174790 | assert(shift_abi_size >= 1 and shift_abi_size <= 2); |
| 174786 | 174791 | ||
| 174787 | const rcx_lock: ?RegisterLock = switch (rhs_mcv) { | 174792 | const rcx_lock: ?RegisterLock = switch (rhs_mcv) { |
| ... | @@ -179593,7 +179598,7 @@ fn genSetReg( | ... | @@ -179593,7 +179598,7 @@ fn genSetReg( |
| 179593 | if (pack_alias != sign_alias) try cg.asmRegisterRegister(.{ ._dqa, .mov }, pack_alias, sign_alias); | 179598 | if (pack_alias != sign_alias) try cg.asmRegisterRegister(.{ ._dqa, .mov }, pack_alias, sign_alias); |
| 179594 | try cg.asmRegisterRegister(.{ .p_b, .ackssw }, pack_alias, pack_alias); | 179599 | try cg.asmRegisterRegister(.{ .p_b, .ackssw }, pack_alias, pack_alias); |
| 179595 | } | 179600 | } |
| 179596 | mask_size = std.math.divCeil(u32, mask_size, 2) catch unreachable; | 179601 | mask_size = @divCeil(mask_size, 2); |
| 179597 | break :pack_reg pack_reg; | 179602 | break :pack_reg pack_reg; |
| 179598 | }, | 179603 | }, |
| 179599 | }; | 179604 | }; |
| ... | @@ -180157,7 +180162,7 @@ fn airBitCast(self: *CodeGen, inst: Air.Inst.Index) !void { | ... | @@ -180157,7 +180162,7 @@ fn airBitCast(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 180157 | const bit_size = dst_ty.bitSize(zcu); | 180162 | const bit_size = dst_ty.bitSize(zcu); |
| 180158 | if (abi_size * 8 <= bit_size) break :result dst_mcv; | 180163 | if (abi_size * 8 <= bit_size) break :result dst_mcv; |
| 180159 | 180164 | ||
| 180160 | const dst_limbs_len = std.math.divCeil(u31, @intCast(bit_size), 64) catch unreachable; | 180165 | const dst_limbs_len: u31 = @intCast(@divCeil(bit_size, 64)); |
| 180161 | const high_mcv: MCValue = switch (dst_mcv) { | 180166 | const high_mcv: MCValue = switch (dst_mcv) { |
| 180162 | .register => |dst_reg| .{ .register = dst_reg }, | 180167 | .register => |dst_reg| .{ .register = dst_reg }, |
| 180163 | .register_pair => |dst_regs| .{ .register = dst_regs[1] }, | 180168 | .register_pair => |dst_regs| .{ .register = dst_regs[1] }, |
| ... | @@ -183550,7 +183555,7 @@ const Temp = struct { | ... | @@ -183550,7 +183555,7 @@ const Temp = struct { |
| 183550 | const part_ty: Type = if (src_regs.len == 1) | 183555 | const part_ty: Type = if (src_regs.len == 1) |
| 183551 | src_ty | 183556 | src_ty |
| 183552 | else if (cg.intInfo(src_ty)) |int_info| part_ty: { | 183557 | else if (cg.intInfo(src_ty)) |int_info| part_ty: { |
| 183553 | assert(src_regs.len == std.math.divCeil(u16, int_info.bits, 64) catch unreachable); | 183558 | assert(src_regs.len == @divCeil(int_info.bits, 64)); |
| 183554 | break :part_ty .u64; | 183559 | break :part_ty .u64; |
| 183555 | } else part_ty: switch (ip.indexToKey(src_ty.toIntern())) { | 183560 | } else part_ty: switch (ip.indexToKey(src_ty.toIntern())) { |
| 183556 | else => std.debug.panic("{s}: {f}\n", .{ @src().fn_name, src_ty.fmt(cg.pt) }), | 183561 | else => std.debug.panic("{s}: {f}\n", .{ @src().fn_name, src_ty.fmt(cg.pt) }), |
| ... | @@ -183560,7 +183565,7 @@ const Temp = struct { | ... | @@ -183560,7 +183565,7 @@ const Temp = struct { |
| 183560 | break :part_ty .usize; | 183565 | break :part_ty .usize; |
| 183561 | }, | 183566 | }, |
| 183562 | .array_type => { | 183567 | .array_type => { |
| 183563 | assert(src_regs.len - part_index == std.math.divCeil(u32, src_size, 8) catch unreachable); | 183568 | assert(src_regs.len - part_index == @divCeil(src_size, 8)); |
| 183564 | break :part_ty try cg.pt.intType(.unsigned, @as(u16, 8) * @min(src_size, 8)); | 183569 | break :part_ty try cg.pt.intType(.unsigned, @as(u16, 8) * @min(src_size, 8)); |
| 183565 | }, | 183570 | }, |
| 183566 | .vector_type => |vector_type| switch (@divExact(vector_type.len, src_regs.len)) { | 183571 | .vector_type => |vector_type| switch (@divExact(vector_type.len, src_regs.len)) { |
| ... | @@ -183580,7 +183585,7 @@ const Temp = struct { | ... | @@ -183580,7 +183585,7 @@ const Temp = struct { |
| 183580 | }, | 183585 | }, |
| 183581 | }, | 183586 | }, |
| 183582 | .struct_type, .union_type => { | 183587 | .struct_type, .union_type => { |
| 183583 | assert(src_regs.len - part_index == std.math.divCeil(u32, src_size, 8) catch unreachable); | 183588 | assert(src_regs.len - part_index == @divCeil(src_size, 8)); |
| 183584 | break :part_ty switch (src_size) { | 183589 | break :part_ty switch (src_size) { |
| 183585 | 0, 3, 5...7 => unreachable, | 183590 | 0, 3, 5...7 => unreachable, |
| 183586 | 1 => .u8, | 183591 | 1 => .u8, |
src/codegen/x86_64/Emit.zig+1-1| ... | @@ -772,7 +772,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI | ... | @@ -772,7 +772,7 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI |
| 772 | const enc_length: u4 = if (is_mem) switch (lowered_inst.ops[op_index].mem.sib.base) { | 772 | const enc_length: u4 = if (is_mem) switch (lowered_inst.ops[op_index].mem.sib.base) { |
| 773 | .rip_inst => 4, | 773 | .rip_inst => 4, |
| 774 | else => unreachable, | 774 | else => unreachable, |
| 775 | } else @intCast(std.math.divCeil(u7, @intCast(op.immBitSize()), 8) catch unreachable); | 775 | } else @intCast(@divCeil(op.immBitSize(), 8)); |
| 776 | reloc_offset -= enc_length; | 776 | reloc_offset -= enc_length; |
| 777 | if (op_index == reloc.op_index) break :reloc_offset_length .{ reloc_offset, enc_length }; | 777 | if (op_index == reloc.op_index) break :reloc_offset_length .{ reloc_offset, enc_length }; |
| 778 | assert(!is_mem); | 778 | assert(!is_mem); |
src/link/Dwarf.zig+3-3| ... | @@ -2137,7 +2137,7 @@ pub const WipNav = struct { | ... | @@ -2137,7 +2137,7 @@ pub const WipNav = struct { |
| 2137 | .signed => DW.FORM.sdata, | 2137 | .signed => DW.FORM.sdata, |
| 2138 | .unsigned => DW.FORM.udata, | 2138 | .unsigned => DW.FORM.udata, |
| 2139 | })); | 2139 | })); |
| 2140 | try wip_nav.debug_info.ensureUnusedCapacity(std.math.divCeil(usize, bits, 7) catch unreachable); | 2140 | try wip_nav.debug_info.ensureUnusedCapacity(@divCeil(bits, 7)); |
| 2141 | var bit: usize = 0; | 2141 | var bit: usize = 0; |
| 2142 | var carry: u1 = 1; | 2142 | var carry: u1 = 1; |
| 2143 | while (bit < bits) { | 2143 | while (bit < bits) { |
| ... | @@ -2158,7 +2158,7 @@ pub const WipNav = struct { | ... | @@ -2158,7 +2158,7 @@ pub const WipNav = struct { |
| 2158 | } | 2158 | } |
| 2159 | } else { | 2159 | } else { |
| 2160 | try diw.writeUleb128(DW.FORM.block); | 2160 | try diw.writeUleb128(DW.FORM.block); |
| 2161 | const bytes = @max(ty.abiSize(zcu), std.math.divCeil(usize, bits, 8) catch unreachable); | 2161 | const bytes = @max(ty.abiSize(zcu), @divCeil(bits, 8)); |
| 2162 | try diw.writeUleb128(bytes); | 2162 | try diw.writeUleb128(bytes); |
| 2163 | try wip_nav.debug_info.ensureUnusedCapacity(@intCast(bytes)); | 2163 | try wip_nav.debug_info.ensureUnusedCapacity(@intCast(bytes)); |
| 2164 | big_int.writeTwosComplement( | 2164 | big_int.writeTwosComplement( |
| ... | @@ -4275,7 +4275,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co | ... | @@ -4275,7 +4275,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co |
| 4275 | try wip_nav.abbrevCode(.aggregate_undefined_comptime_value); | 4275 | try wip_nav.abbrevCode(.aggregate_undefined_comptime_value); |
| 4276 | try wip_nav.refType(.fromInterned(error_union.ty)); | 4276 | try wip_nav.refType(.fromInterned(error_union.ty)); |
| 4277 | var err_buf: [4]u8 = undefined; | 4277 | var err_buf: [4]u8 = undefined; |
| 4278 | const err_bytes = err_buf[0 .. std.math.divCeil(u17, zcu.errorSetBits(), 8) catch unreachable]; | 4278 | const err_bytes = err_buf[0..@divCeil(zcu.errorSetBits(), 8)]; |
| 4279 | dwarf.writeInt(err_bytes, switch (error_union.val) { | 4279 | dwarf.writeInt(err_bytes, switch (error_union.val) { |
| 4280 | .err_name => |err_name| try pt.getErrorValue(err_name), | 4280 | .err_name => |err_name| try pt.getErrorValue(err_name), |
| 4281 | .payload => 0, | 4281 | .payload => 0, |
src/main.zig+1-2| ... | @@ -162,8 +162,7 @@ const use_safe_allocator = build_options.debug_gpa or | ... | @@ -162,8 +162,7 @@ const use_safe_allocator = build_options.debug_gpa or |
| 162 | .ReleaseFast, .ReleaseSmall => false, | 162 | .ReleaseFast, .ReleaseSmall => false, |
| 163 | }); | 163 | }); |
| 164 | 164 | ||
| 165 | // TODO: The `align(@alignOf(std.heap.SafeAllocator))` can be removed the next time zig1.wasm is updated | 165 | var safe_allocator: std.heap.SafeAllocator = .init(std.heap.page_allocator, .{ |
| 166 | var safe_allocator: std.heap.SafeAllocator align(@alignOf(std.heap.SafeAllocator)) = .init(std.heap.page_allocator, .{ | ||
| 167 | .stack_trace_frames = build_options.mem_leak_frames, | 166 | .stack_trace_frames = build_options.mem_leak_frames, |
| 168 | }); | 167 | }); |
| 169 | 168 |
src/print_zir.zig+1| ... | @@ -392,6 +392,7 @@ const Writer = struct { | ... | @@ -392,6 +392,7 @@ const Writer = struct { |
| 392 | .truncate, | 392 | .truncate, |
| 393 | .div_exact, | 393 | .div_exact, |
| 394 | .div_floor, | 394 | .div_floor, |
| 395 | .div_ceil, | ||
| 395 | .div_trunc, | 396 | .div_trunc, |
| 396 | .mod, | 397 | .mod, |
| 397 | .rem, | 398 | .rem, |
stage1/zig.h+32| ... | @@ -813,6 +813,15 @@ typedef ptrdiff_t intptr_t; | ... | @@ -813,6 +813,15 @@ typedef ptrdiff_t intptr_t; |
| 813 | static inline int##w##_t zig_div_floor_i##w(int##w##_t lhs, int##w##_t rhs) { \ | 813 | static inline int##w##_t zig_div_floor_i##w(int##w##_t lhs, int##w##_t rhs) { \ |
| 814 | return lhs / rhs + (lhs % rhs != INT##w##_C(0) ? zig_shr_i##w(lhs ^ rhs, UINT8_C(w) - UINT8_C(1)) : INT##w##_C(0)); \ | 814 | return lhs / rhs + (lhs % rhs != INT##w##_C(0) ? zig_shr_i##w(lhs ^ rhs, UINT8_C(w) - UINT8_C(1)) : INT##w##_C(0)); \ |
| 815 | } \ | 815 | } \ |
| 816 | \ | ||
| 817 | static inline uint##w##_t zig_div_ceil_u##w(uint##w##_t lhs, uint##w##_t rhs) { \ | ||
| 818 | return lhs / rhs + (lhs % rhs != UINT##w##_C(0) ? UINT##w##_C(1) : UINT##w##_C(0)); \ | ||
| 819 | } \ | ||
| 820 | \ | ||
| 821 | static inline int##w##_t zig_div_ceil_i##w(int##w##_t lhs, int##w##_t rhs) { \ | ||
| 822 | return lhs / rhs + (lhs % rhs != INT##w##_C(0) \ | ||
| 823 | ? zig_shr_i##w(lhs ^ rhs, UINT8_C(w) - UINT8_C(1)) + INT##w##_C(1) : INT##w##_C(0)); \ | ||
| 824 | } \ | ||
| 816 | \ | 825 | \ |
| 817 | zig_basic_operator(uint##w##_t, mod_u##w, %) \ | 826 | zig_basic_operator(uint##w##_t, mod_u##w, %) \ |
| 818 | \ | 827 | \ |
| ... | @@ -2058,6 +2067,21 @@ static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) { | ... | @@ -2058,6 +2067,21 @@ static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) { |
| 2058 | return zig_add_i128(zig_div_trunc_i128(lhs, rhs), zig_make_i128(mask, (uint64_t)mask)); | 2067 | return zig_add_i128(zig_div_trunc_i128(lhs, rhs), zig_make_i128(mask, (uint64_t)mask)); |
| 2059 | } | 2068 | } |
| 2060 | 2069 | ||
| 2070 | static inline zig_u128 zig_div_ceil_u128(zig_u128 lhs, zig_u128 rhs) { | ||
| 2071 | zig_u128 rem = zig_rem_u128(lhs, rhs); | ||
| 2072 | uint64_t mask = zig_or_u64(zig_hi_u128(rem), zig_lo_u128(rem)) != UINT64_C(0) | ||
| 2073 | ? UINT64_C(1) : UINT64_C(0); | ||
| 2074 | return zig_add_u128(zig_div_trunc_u128(lhs, rhs), zig_make_u128(UINT64_C(0), mask)); | ||
| 2075 | } | ||
| 2076 | |||
| 2077 | static inline zig_i128 zig_div_ceil_i128(zig_i128 lhs, zig_i128 rhs) { | ||
| 2078 | zig_i128 rem = zig_rem_i128(lhs, rhs); | ||
| 2079 | int64_t mask = zig_or_u64((uint64_t)zig_hi_i128(rem), zig_lo_i128(rem)) != UINT64_C(0) | ||
| 2080 | ? zig_shr_i64(zig_xor_i64(zig_hi_i128(lhs), zig_hi_i128(rhs)), UINT8_C(63)) + INT64_C(1) | ||
| 2081 | : INT64_C(0); | ||
| 2082 | return zig_add_i128(zig_div_trunc_i128(lhs, rhs), zig_make_i128(INT64_C(0), (uint64_t)mask)); | ||
| 2083 | } | ||
| 2084 | |||
| 2061 | #define zig_mod_u128 zig_rem_u128 | 2085 | #define zig_mod_u128 zig_rem_u128 |
| 2062 | 2086 | ||
| 2063 | static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) { | 2087 | static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) { |
| ... | @@ -3251,6 +3275,10 @@ static inline void zig_div_floor_big(void *res, const void *lhs, const void *rhs | ... | @@ -3251,6 +3275,10 @@ static inline void zig_div_floor_big(void *res, const void *lhs, const void *rhs |
| 3251 | zig_trap(); | 3275 | zig_trap(); |
| 3252 | } | 3276 | } |
| 3253 | 3277 | ||
| 3278 | static inline void zig_div_ceil_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { | ||
| 3279 | zig_trap(); | ||
| 3280 | } | ||
| 3281 | |||
| 3254 | zig_extern void __umodei4(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uintptr_t bits); | 3282 | zig_extern void __umodei4(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uintptr_t bits); |
| 3255 | static inline void zig_rem_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { | 3283 | static inline void zig_rem_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { |
| 3256 | if (!is_signed) { | 3284 | if (!is_signed) { |
| ... | @@ -4010,6 +4038,10 @@ zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0))) | ... | @@ -4010,6 +4038,10 @@ zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0))) |
| 4010 | static inline zig_f##w zig_div_floor_f##w(zig_f##w lhs, zig_f##w rhs) { \ | 4038 | static inline zig_f##w zig_div_floor_f##w(zig_f##w lhs, zig_f##w rhs) { \ |
| 4011 | return zig_floor_f##w(zig_div_f##w(lhs, rhs)); \ | 4039 | return zig_floor_f##w(zig_div_f##w(lhs, rhs)); \ |
| 4012 | } \ | 4040 | } \ |
| 4041 | \ | ||
| 4042 | static inline zig_f##w zig_div_ceil_f##w(zig_f##w lhs, zig_f##w rhs) { \ | ||
| 4043 | return zig_ceil_f##w(zig_div_f##w(lhs, rhs)); \ | ||
| 4044 | } \ | ||
| 4013 | \ | 4045 | \ |
| 4014 | static inline zig_f##w zig_mod_f##w(zig_f##w lhs, zig_f##w rhs) { \ | 4046 | static inline zig_f##w zig_mod_f##w(zig_f##w lhs, zig_f##w rhs) { \ |
| 4015 | return zig_sub_f##w(lhs, zig_mul_f##w(zig_div_floor_f##w(lhs, rhs), rhs)); \ | 4047 | return zig_sub_f##w(lhs, zig_mul_f##w(zig_div_floor_f##w(lhs, rhs), rhs)); \ |
stage1/zig1.wasm| Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ | |||
test/behavior/int128.zig+1| ... | @@ -59,6 +59,7 @@ test "int128" { | ... | @@ -59,6 +59,7 @@ test "int128" { |
| 59 | const a: i128 = -170141183460469231731687303715884105728; | 59 | const a: i128 = -170141183460469231731687303715884105728; |
| 60 | const b: i128 = -0x8000_0000_0000_0000_0000_0000_0000_0000; | 60 | const b: i128 = -0x8000_0000_0000_0000_0000_0000_0000_0000; |
| 61 | try expect(@divFloor(b, 1_000_000) == -170141183460469231731687303715885); | 61 | try expect(@divFloor(b, 1_000_000) == -170141183460469231731687303715885); |
| 62 | try expect(@divCeil(b, 1_000_000) == -170141183460469231731687303715884); | ||
| 62 | try expect(a == b); | 63 | try expect(a == b); |
| 63 | } | 64 | } |
| 64 | 65 |
test/behavior/math.zig+89| ... | @@ -488,6 +488,36 @@ fn testIntDivision() !void { | ... | @@ -488,6 +488,36 @@ fn testIntDivision() !void { |
| 488 | try expect(divFloor(i64, -0x80000000, -2) == 0x40000000); | 488 | try expect(divFloor(i64, -0x80000000, -2) == 0x40000000); |
| 489 | try expect(divFloor(i64, -0x40000001, 0x40000000) == -2); | 489 | try expect(divFloor(i64, -0x40000001, 0x40000000) == -2); |
| 490 | 490 | ||
| 491 | try expect(divCeil(i32, 5, 3) == 2); | ||
| 492 | try expect(divCeil(i32, -5, 3) == -1); | ||
| 493 | try expect(divCeil(i32, -0x80000000, -2) == 0x40000000); | ||
| 494 | try expect(divCeil(i32, 0, -0x80000000) == 0); | ||
| 495 | try expect(divCeil(i32, -0x40000001, 0x40000000) == -1); | ||
| 496 | try expect(divCeil(i32, -0x80000000, 1) == -0x80000000); | ||
| 497 | try expect(divCeil(i32, 10, 12) == 1); | ||
| 498 | try expect(divCeil(i32, -14, 12) == -1); | ||
| 499 | try expect(divCeil(i32, -2, 12) == 0); | ||
| 500 | |||
| 501 | try expect(divCeil(u32, 5, 3) == 2); | ||
| 502 | try expect(divCeil(u32, 16, 4) == 4); | ||
| 503 | try expect(divCeil(u32, 0, 100) == 0); | ||
| 504 | try expect(divCeil(u32, maxInt(u32) - 1, 100) == 42949673); | ||
| 505 | |||
| 506 | try expect(divCeil(i64, 5, 3) == 2); | ||
| 507 | try expect(divCeil(i64, -5, 3) == -1); | ||
| 508 | try expect(divCeil(i64, -0x80000000, -2) == 0x40000000); | ||
| 509 | try expect(divCeil(i64, 0, -0x80000000) == 0); | ||
| 510 | try expect(divCeil(i64, -0x40000001, 0x40000000) == -1); | ||
| 511 | try expect(divCeil(i64, -0x80000000, 1) == -0x80000000); | ||
| 512 | try expect(divCeil(i64, 10, 12) == 1); | ||
| 513 | try expect(divCeil(i64, -14, 12) == -1); | ||
| 514 | try expect(divCeil(i64, -2, 12) == 0); | ||
| 515 | |||
| 516 | try expect(divCeil(u64, 5, 3) == 2); | ||
| 517 | try expect(divCeil(u64, 16, 4) == 4); | ||
| 518 | try expect(divCeil(u64, 0, 100) == 0); | ||
| 519 | try expect(divCeil(u64, maxInt(u64) - 1, 10000) == 1844674407370956); | ||
| 520 | |||
| 491 | try expect(divTrunc(i32, 5, 3) == 1); | 521 | try expect(divTrunc(i32, 5, 3) == 1); |
| 492 | try expect(divTrunc(i32, -5, 3) == -1); | 522 | try expect(divTrunc(i32, -5, 3) == -1); |
| 493 | try expect(divTrunc(i32, 9, -10) == 0); | 523 | try expect(divTrunc(i32, 9, -10) == 0); |
| ... | @@ -531,6 +561,24 @@ fn testIntDivision() !void { | ... | @@ -531,6 +561,24 @@ fn testIntDivision() !void { |
| 531 | try expect( | 561 | try expect( |
| 532 | 1194735857077236777412821811143690633098347576 / 508740759824825164163191790951174292733114988 == 2, | 562 | 1194735857077236777412821811143690633098347576 / 508740759824825164163191790951174292733114988 == 2, |
| 533 | ); | 563 | ); |
| 564 | try expect( | ||
| 565 | @divFloor(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -3, | ||
| 566 | ); | ||
| 567 | try expect( | ||
| 568 | @divFloor(1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == -3, | ||
| 569 | ); | ||
| 570 | try expect( | ||
| 571 | @divFloor(-1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == 2, | ||
| 572 | ); | ||
| 573 | try expect( | ||
| 574 | @divCeil(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -2, | ||
| 575 | ); | ||
| 576 | try expect( | ||
| 577 | @divCeil(1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == -2, | ||
| 578 | ); | ||
| 579 | try expect( | ||
| 580 | @divCeil(-1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == 3, | ||
| 581 | ); | ||
| 534 | try expect( | 582 | try expect( |
| 535 | @divTrunc(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -2, | 583 | @divTrunc(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -2, |
| 536 | ); | 584 | ); |
| ... | @@ -559,6 +607,13 @@ fn testFloatDivision() !void { | ... | @@ -559,6 +607,13 @@ fn testFloatDivision() !void { |
| 559 | try expect(divFloor(f16, -43.0, 12.0) == -4.0); | 607 | try expect(divFloor(f16, -43.0, 12.0) == -4.0); |
| 560 | try expect(divFloor(f64, -90.0, -9.0) == 10.0); | 608 | try expect(divFloor(f64, -90.0, -9.0) == 10.0); |
| 561 | 609 | ||
| 610 | try expect(divCeil(f32, 5.0, 3.0) == 2.0); | ||
| 611 | try expect(divCeil(f32, -5.0, 3.0) == -1.0); | ||
| 612 | try expect(divCeil(f32, 56.0, 9.0) == 7.0); | ||
| 613 | try expect(divCeil(f32, 1053.0, -41.0) == -25.0); | ||
| 614 | try expect(divCeil(f16, -43.0, 12.0) == -3.0); | ||
| 615 | try expect(divCeil(f64, -90.0, -9.0) == 10.0); | ||
| 616 | |||
| 562 | try expect(divTrunc(f32, 5.0, 3.0) == 1.0); | 617 | try expect(divTrunc(f32, 5.0, 3.0) == 1.0); |
| 563 | try expect(divTrunc(f32, -5.0, 3.0) == -1.0); | 618 | try expect(divTrunc(f32, -5.0, 3.0) == -1.0); |
| 564 | try expect(divTrunc(f32, 9.0, -10.0) == 0.0); | 619 | try expect(divTrunc(f32, 9.0, -10.0) == 0.0); |
| ... | @@ -607,6 +662,8 @@ fn testDivisionFP16() !void { | ... | @@ -607,6 +662,8 @@ fn testDivisionFP16() !void { |
| 607 | 662 | ||
| 608 | try expect(divFloor(f16, 5.0, 3.0) == 1.0); | 663 | try expect(divFloor(f16, 5.0, 3.0) == 1.0); |
| 609 | try expect(divFloor(f16, -5.0, 3.0) == -2.0); | 664 | try expect(divFloor(f16, -5.0, 3.0) == -2.0); |
| 665 | try expect(divCeil(f16, 5.0, 3.0) == 2.0); | ||
| 666 | try expect(divCeil(f16, -5.0, 3.0) == -1.0); | ||
| 610 | try expect(divTrunc(f16, 5.0, 3.0) == 1.0); | 667 | try expect(divTrunc(f16, 5.0, 3.0) == 1.0); |
| 611 | try expect(divTrunc(f16, -5.0, 3.0) == -1.0); | 668 | try expect(divTrunc(f16, -5.0, 3.0) == -1.0); |
| 612 | try expect(divTrunc(f16, 9.0, -10.0) == 0.0); | 669 | try expect(divTrunc(f16, 9.0, -10.0) == 0.0); |
| ... | @@ -622,6 +679,9 @@ fn divExact(comptime T: type, a: T, b: T) T { | ... | @@ -622,6 +679,9 @@ fn divExact(comptime T: type, a: T, b: T) T { |
| 622 | fn divFloor(comptime T: type, a: T, b: T) T { | 679 | fn divFloor(comptime T: type, a: T, b: T) T { |
| 623 | return @divFloor(a, b); | 680 | return @divFloor(a, b); |
| 624 | } | 681 | } |
| 682 | fn divCeil(comptime T: type, a: T, b: T) T { | ||
| 683 | return @divCeil(a, b); | ||
| 684 | } | ||
| 625 | fn divTrunc(comptime T: type, a: T, b: T) T { | 685 | fn divTrunc(comptime T: type, a: T, b: T) T { |
| 626 | return @divTrunc(a, b); | 686 | return @divTrunc(a, b); |
| 627 | } | 687 | } |
| ... | @@ -1846,6 +1906,35 @@ test "@divFloor > 128 bits" { | ... | @@ -1846,6 +1906,35 @@ test "@divFloor > 128 bits" { |
| 1846 | try testDivFloor(i200, maxInt(i200), 2, (1 << 198) - 1); | 1906 | try testDivFloor(i200, maxInt(i200), 2, (1 << 198) - 1); |
| 1847 | } | 1907 | } |
| 1848 | 1908 | ||
| 1909 | fn testDivCeil(comptime T: type, numerator: T, denominator: T, expected: T) !void { | ||
| 1910 | try expect(@divCeil(numerator, denominator) == expected); | ||
| 1911 | } | ||
| 1912 | |||
| 1913 | test "@divCeil > 128 bits" { | ||
| 1914 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | ||
| 1915 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | ||
| 1916 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | ||
| 1917 | |||
| 1918 | try testDivCeil(u140, 0, maxInt(u140), 0); | ||
| 1919 | try testDivCeil(u140, maxInt(u140), maxInt(u140), 1); | ||
| 1920 | try testDivCeil(u140, maxInt(u140), 2, maxInt(u140) / 2 + 1); | ||
| 1921 | try testDivCeil(u140, (1 << 139) + 5, 1 << 70, (1 << 69) + 1); | ||
| 1922 | try testDivCeil(u140, (1 << 100) + (1 << 50) + 7, 1 << 50, (1 << 50) + 2); | ||
| 1923 | try testDivCeil(u200, 123, 1 << 100, 1); | ||
| 1924 | try testDivCeil(u200, 1 << 120, 1 << 60, 1 << 60); | ||
| 1925 | try testDivCeil(u200, maxInt(u200), 1 << 100, 1 << 100); | ||
| 1926 | |||
| 1927 | try testDivCeil(i140, 0, maxInt(i140), 0); | ||
| 1928 | try testDivCeil(i140, maxInt(i140), maxInt(i140), 1); | ||
| 1929 | try testDivCeil(i140, -((1 << 100) + 1), 1 << 50, -(1 << 50)); | ||
| 1930 | try testDivCeil(i140, (1 << 100) + 1, -(1 << 50), -(1 << 50)); | ||
| 1931 | try testDivCeil(i140, -((1 << 100) + 1), -(1 << 50), (1 << 50) + 1); | ||
| 1932 | try testDivCeil(i200, -3, 2, -1); | ||
| 1933 | try testDivCeil(i200, minInt(i200), 1, minInt(i200)); | ||
| 1934 | try testDivCeil(i200, minInt(i200), -2, 1 << 198); | ||
| 1935 | try testDivCeil(i200, maxInt(i200), 2, 1 << 198); | ||
| 1936 | } | ||
| 1937 | |||
| 1849 | fn testDivTrunc(comptime T: type, numerator: T, denominator: T, expected: T) !void { | 1938 | fn testDivTrunc(comptime T: type, numerator: T, denominator: T, expected: T) !void { |
| 1850 | try expect(@divTrunc(numerator, denominator) == expected); | 1939 | try expect(@divTrunc(numerator, denominator) == expected); |
| 1851 | } | 1940 | } |
test/behavior/vector.zig+35-1| ... | @@ -510,8 +510,37 @@ test "vector division operators" { | ... | @@ -510,8 +510,37 @@ test "vector division operators" { |
| 510 | inline for (@as([4]T, d2), 0..) |v, i| { | 510 | inline for (@as([4]T, d2), 0..) |v, i| { |
| 511 | try expect(@divFloor(x[i], y[i]) == v); | 511 | try expect(@divFloor(x[i], y[i]) == v); |
| 512 | } | 512 | } |
| 513 | const d3 = @divTrunc(x, y); | 513 | const d3 = @divCeil(x, y); |
| 514 | inline for (@as([4]T, d3), 0..) |v, i| { | 514 | inline for (@as([4]T, d3), 0..) |v, i| { |
| 515 | try expect(@divCeil(x[i], y[i]) == v); | ||
| 516 | } | ||
| 517 | const d4 = @divTrunc(x, y); | ||
| 518 | inline for (@as([4]T, d4), 0..) |v, i| { | ||
| 519 | try expect(@divTrunc(x[i], y[i]) == v); | ||
| 520 | } | ||
| 521 | } | ||
| 522 | |||
| 523 | fn doTheTestDivNoExact(comptime T: type, x: @Vector(4, T), y: @Vector(4, T)) !void { | ||
| 524 | const is_signed_int = switch (@typeInfo(T)) { | ||
| 525 | .int => |info| info.signedness == .signed, | ||
| 526 | else => false, | ||
| 527 | }; | ||
| 528 | if (!is_signed_int) { | ||
| 529 | const d0 = x / y; | ||
| 530 | inline for (@as([4]T, d0), 0..) |v, i| { | ||
| 531 | try expect(x[i] / y[i] == v); | ||
| 532 | } | ||
| 533 | } | ||
| 534 | const d2 = @divFloor(x, y); | ||
| 535 | inline for (@as([4]T, d2), 0..) |v, i| { | ||
| 536 | try expect(@divFloor(x[i], y[i]) == v); | ||
| 537 | } | ||
| 538 | const d3 = @divCeil(x, y); | ||
| 539 | inline for (@as([4]T, d3), 0..) |v, i| { | ||
| 540 | try expect(@divCeil(x[i], y[i]) == v); | ||
| 541 | } | ||
| 542 | const d4 = @divTrunc(x, y); | ||
| 543 | inline for (@as([4]T, d4), 0..) |v, i| { | ||
| 515 | try expect(@divTrunc(x[i], y[i]) == v); | 544 | try expect(@divTrunc(x[i], y[i]) == v); |
| 516 | } | 545 | } |
| 517 | } | 546 | } |
| ... | @@ -566,6 +595,9 @@ test "vector division operators" { | ... | @@ -566,6 +595,9 @@ test "vector division operators" { |
| 566 | try doTheTestMod(u16, [4]u16{ 1, 2, 4, 8 }, [4]u16{ 1, 1, 2, 4 }); | 595 | try doTheTestMod(u16, [4]u16{ 1, 2, 4, 8 }, [4]u16{ 1, 1, 2, 4 }); |
| 567 | try doTheTestMod(u32, [4]u32{ 1, 2, 4, 8 }, [4]u32{ 1, 1, 2, 4 }); | 596 | try doTheTestMod(u32, [4]u32{ 1, 2, 4, 8 }, [4]u32{ 1, 1, 2, 4 }); |
| 568 | try doTheTestMod(u64, [4]u64{ 1, 2, 4, 8 }, [4]u64{ 1, 1, 2, 4 }); | 597 | try doTheTestMod(u64, [4]u64{ 1, 2, 4, 8 }, [4]u64{ 1, 1, 2, 4 }); |
| 598 | |||
| 599 | try doTheTestDivNoExact(u64, [4]u64{ 4, 5, 6, 7 }, [4]u64{ 4, 4, 4, 4 }); | ||
| 600 | try doTheTestDivNoExact(i64, [4]i64{ 4, -4, 4, -4 }, [4]i64{ 3, 3, -3, -3 }); | ||
| 569 | } | 601 | } |
| 570 | }; | 602 | }; |
| 571 | 603 | ||
| ... | @@ -1318,11 +1350,13 @@ test "zero divisor" { | ... | @@ -1318,11 +1350,13 @@ test "zero divisor" { |
| 1318 | const v2 = @divExact(zeros, ones); | 1350 | const v2 = @divExact(zeros, ones); |
| 1319 | const v3 = @divTrunc(zeros, ones); | 1351 | const v3 = @divTrunc(zeros, ones); |
| 1320 | const v4 = @divFloor(zeros, ones); | 1352 | const v4 = @divFloor(zeros, ones); |
| 1353 | const v5 = @divCeil(zeros, ones); | ||
| 1321 | 1354 | ||
| 1322 | _ = v1[0]; | 1355 | _ = v1[0]; |
| 1323 | _ = v2[0]; | 1356 | _ = v2[0]; |
| 1324 | _ = v3[0]; | 1357 | _ = v3[0]; |
| 1325 | _ = v4[0]; | 1358 | _ = v4[0]; |
| 1359 | _ = v5[0]; | ||
| 1326 | } | 1360 | } |
| 1327 | 1361 | ||
| 1328 | test "zero multiplicand" { | 1362 | test "zero multiplicand" { |
test/behavior/x86_64/binary.zig+21| ... | @@ -5279,6 +5279,27 @@ test divFloorOptimized { | ... | @@ -5279,6 +5279,27 @@ test divFloorOptimized { |
| 5279 | try test_div_floor_optimized.testFloatVectors(); | 5279 | try test_div_floor_optimized.testFloatVectors(); |
| 5280 | } | 5280 | } |
| 5281 | 5281 | ||
| 5282 | inline fn divCeilUnoptimized(comptime Type: type, lhs: Type, rhs: Type) Type { | ||
| 5283 | return @divCeil(lhs, rhs); | ||
| 5284 | } | ||
| 5285 | test divCeilUnoptimized { | ||
| 5286 | const test_div_ceil_unoptimized = binary(divCeilUnoptimized, .{ .compare = .approx_int }); | ||
| 5287 | try test_div_ceil_unoptimized.testInts(); | ||
| 5288 | try test_div_ceil_unoptimized.testIntVectors(); | ||
| 5289 | try test_div_ceil_unoptimized.testFloats(); | ||
| 5290 | try test_div_ceil_unoptimized.testFloatVectors(); | ||
| 5291 | } | ||
| 5292 | |||
| 5293 | inline fn divCeilOptimized(comptime Type: type, lhs: Type, rhs: Type) Type { | ||
| 5294 | @setFloatMode(.optimized); | ||
| 5295 | return @divCeil(lhs, select(@abs(rhs) > splat(Type, 0.0), rhs, splat(Type, 1.0))); | ||
| 5296 | } | ||
| 5297 | test divCeilOptimized { | ||
| 5298 | const test_div_ceil_optimized = binary(divCeilOptimized, .{ .compare = .approx_int }); | ||
| 5299 | try test_div_ceil_optimized.testFloats(); | ||
| 5300 | try test_div_ceil_optimized.testFloatVectors(); | ||
| 5301 | } | ||
| 5302 | |||
| 5282 | inline fn rem(comptime Type: type, lhs: Type, rhs: Type) Type { | 5303 | inline fn rem(comptime Type: type, lhs: Type, rhs: Type) Type { |
| 5283 | return @rem(lhs, rhs); | 5304 | return @rem(lhs, rhs); |
| 5284 | } | 5305 | } |
test/cases/compile_errors/signed_integer_division.zig+1-1| ... | @@ -4,4 +4,4 @@ export fn foo(a: i32, b: i32) i32 { | ... | @@ -4,4 +4,4 @@ export fn foo(a: i32, b: i32) i32 { |
| 4 | 4 | ||
| 5 | // error | 5 | // error |
| 6 | // | 6 | // |
| 7 | // :2:14: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, or @divExact | 7 | // :2:14: error: division with 'i32' and 'i32': signed integers must use @divTrunc, @divFloor, @divCeil, or @divExact |