| author | |
| committer | |
| log | 091d693c5381a17d1de01ab372481f629b560c7c |
| tree | 2977e9fa1fcbbc58057684adf86ceb0291e16ef2 |
| parent | 3abf9e1457ed9332474ab211eb8d996d594a33c3 |
| parent | ad18078d53b448fc18a100dcebca88fe05a1e3ac |
| signature |
Improve crypto benchmarks17 files changed, 150 insertions(+), 114 deletions(-)
lib/std/crypto/benchmark.zig+59-13| ... | @@ -7,6 +7,7 @@ | ... | @@ -7,6 +7,7 @@ |
| 7 | 7 | ||
| 8 | const builtin = @import("builtin"); | 8 | const builtin = @import("builtin"); |
| 9 | const std = @import("std"); | 9 | const std = @import("std"); |
| 10 | const mem = std.mem; | ||
| 10 | const time = std.time; | 11 | const time = std.time; |
| 11 | const Timer = time.Timer; | 12 | const Timer = time.Timer; |
| 12 | const crypto = std.crypto; | 13 | const crypto = std.crypto; |
| ... | @@ -46,6 +47,7 @@ pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 | ... | @@ -46,6 +47,7 @@ pub fn benchmarkHash(comptime Hash: anytype, comptime bytes: comptime_int) !u64 |
| 46 | while (offset < bytes) : (offset += block.len) { | 47 | while (offset < bytes) : (offset += block.len) { |
| 47 | h.update(block[0..]); | 48 | h.update(block[0..]); |
| 48 | } | 49 | } |
| 50 | mem.doNotOptimizeAway(&h); | ||
| 49 | const end = timer.read(); | 51 | const end = timer.read(); |
| 50 | 52 | ||
| 51 | const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s; | 53 | const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s; |
| ... | @@ -67,19 +69,20 @@ const macs = [_]Crypto{ | ... | @@ -67,19 +69,20 @@ const macs = [_]Crypto{ |
| 67 | }; | 69 | }; |
| 68 | 70 | ||
| 69 | pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 { | 71 | pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 { |
| 70 | std.debug.assert(64 >= Mac.mac_length and 32 >= Mac.minimum_key_length); | 72 | var in: [512 * KiB]u8 = undefined; |
| 71 | |||
| 72 | var in: [1 * MiB]u8 = undefined; | ||
| 73 | prng.random.bytes(in[0..]); | 73 | prng.random.bytes(in[0..]); |
| 74 | 74 | ||
| 75 | var key: [64]u8 = undefined; | 75 | const key_length = if (Mac.minimum_key_length == 0) 32 else Mac.minimum_key_length; |
| 76 | var key: [key_length]u8 = undefined; | ||
| 76 | prng.random.bytes(key[0..]); | 77 | prng.random.bytes(key[0..]); |
| 77 | 78 | ||
| 79 | var mac: [Mac.mac_length]u8 = undefined; | ||
| 78 | var offset: usize = 0; | 80 | var offset: usize = 0; |
| 79 | var timer = try Timer.start(); | 81 | var timer = try Timer.start(); |
| 80 | const start = timer.lap(); | 82 | const start = timer.lap(); |
| 81 | while (offset < bytes) : (offset += in.len) { | 83 | while (offset < bytes) : (offset += in.len) { |
| 82 | Mac.create(key[0..], in[0..], key[0..]); | 84 | Mac.create(mac[0..], in[0..], key[0..]); |
| 85 | mem.doNotOptimizeAway(&mac); | ||
| 83 | } | 86 | } |
| 84 | const end = timer.read(); | 87 | const end = timer.read(); |
| 85 | 88 | ||
| ... | @@ -106,6 +109,7 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c | ... | @@ -106,6 +109,7 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c |
| 106 | var i: usize = 0; | 109 | var i: usize = 0; |
| 107 | while (i < exchange_count) : (i += 1) { | 110 | while (i < exchange_count) : (i += 1) { |
| 108 | _ = DhKeyExchange.create(out[0..], out[0..], in[0..]); | 111 | _ = DhKeyExchange.create(out[0..], out[0..], in[0..]); |
| 112 | mem.doNotOptimizeAway(&out); | ||
| 109 | } | 113 | } |
| 110 | } | 114 | } |
| 111 | const end = timer.read(); | 115 | const end = timer.read(); |
| ... | @@ -118,7 +122,7 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c | ... | @@ -118,7 +122,7 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c |
| 118 | 122 | ||
| 119 | const signatures = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" }}; | 123 | const signatures = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" }}; |
| 120 | 124 | ||
| 121 | pub fn benchmarkSignatures(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 { | 125 | pub fn benchmarkSignature(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 { |
| 122 | var seed: [Signature.seed_length]u8 = undefined; | 126 | var seed: [Signature.seed_length]u8 = undefined; |
| 123 | prng.random.bytes(seed[0..]); | 127 | prng.random.bytes(seed[0..]); |
| 124 | const msg = [_]u8{0} ** 64; | 128 | const msg = [_]u8{0} ** 64; |
| ... | @@ -129,7 +133,8 @@ pub fn benchmarkSignatures(comptime Signature: anytype, comptime signatures_coun | ... | @@ -129,7 +133,8 @@ pub fn benchmarkSignatures(comptime Signature: anytype, comptime signatures_coun |
| 129 | { | 133 | { |
| 130 | var i: usize = 0; | 134 | var i: usize = 0; |
| 131 | while (i < signatures_count) : (i += 1) { | 135 | while (i < signatures_count) : (i += 1) { |
| 132 | _ = try Signature.sign(&msg, key_pair, null); | 136 | const s = try Signature.sign(&msg, key_pair, null); |
| 137 | mem.doNotOptimizeAway(&s); | ||
| 133 | } | 138 | } |
| 134 | } | 139 | } |
| 135 | const end = timer.read(); | 140 | const end = timer.read(); |
| ... | @@ -140,6 +145,40 @@ pub fn benchmarkSignatures(comptime Signature: anytype, comptime signatures_coun | ... | @@ -140,6 +145,40 @@ pub fn benchmarkSignatures(comptime Signature: anytype, comptime signatures_coun |
| 140 | return throughput; | 145 | return throughput; |
| 141 | } | 146 | } |
| 142 | 147 | ||
| 148 | const aeads = [_]Crypto{ | ||
| 149 | Crypto{ .ty = crypto.aead.ChaCha20Poly1305, .name = "chacha20Poly1305" }, | ||
| 150 | Crypto{ .ty = crypto.aead.XChaCha20Poly1305, .name = "xchacha20Poly1305" }, | ||
| 151 | Crypto{ .ty = crypto.aead.Gimli, .name = "gimli-aead" }, | ||
| 152 | }; | ||
| 153 | |||
| 154 | pub fn benchmarkAead(comptime Aead: anytype, comptime bytes: comptime_int) !u64 { | ||
| 155 | var in: [512 * KiB]u8 = undefined; | ||
| 156 | prng.random.bytes(in[0..]); | ||
| 157 | |||
| 158 | var tag: [Aead.tag_length]u8 = undefined; | ||
| 159 | |||
| 160 | var key: [Aead.key_length]u8 = undefined; | ||
| 161 | prng.random.bytes(key[0..]); | ||
| 162 | |||
| 163 | var nonce: [Aead.nonce_length]u8 = undefined; | ||
| 164 | prng.random.bytes(nonce[0..]); | ||
| 165 | |||
| 166 | var offset: usize = 0; | ||
| 167 | var timer = try Timer.start(); | ||
| 168 | const start = timer.lap(); | ||
| 169 | while (offset < bytes) : (offset += in.len) { | ||
| 170 | Aead.encrypt(in[0..], tag[0..], in[0..], &[_]u8{}, nonce, key); | ||
| 171 | Aead.decrypt(in[0..], in[0..], tag, &[_]u8{}, nonce, key) catch unreachable; | ||
| 172 | } | ||
| 173 | mem.doNotOptimizeAway(&in); | ||
| 174 | const end = timer.read(); | ||
| 175 | |||
| 176 | const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s; | ||
| 177 | const throughput = @floatToInt(u64, 2 * bytes / elapsed_s); | ||
| 178 | |||
| 179 | return throughput; | ||
| 180 | } | ||
| 181 | |||
| 143 | fn usage() void { | 182 | fn usage() void { |
| 144 | std.debug.warn( | 183 | std.debug.warn( |
| 145 | \\throughput_test [options] | 184 | \\throughput_test [options] |
| ... | @@ -198,29 +237,36 @@ pub fn main() !void { | ... | @@ -198,29 +237,36 @@ pub fn main() !void { |
| 198 | 237 | ||
| 199 | inline for (hashes) |H| { | 238 | inline for (hashes) |H| { |
| 200 | if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) { | 239 | if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) { |
| 201 | const throughput = try benchmarkHash(H.ty, mode(32 * MiB)); | 240 | const throughput = try benchmarkHash(H.ty, mode(128 * MiB)); |
| 202 | try stdout.print("{:>11}: {:5} MiB/s\n", .{ H.name, throughput / (1 * MiB) }); | 241 | try stdout.print("{:>17}: {:7} MiB/s\n", .{ H.name, throughput / (1 * MiB) }); |
| 203 | } | 242 | } |
| 204 | } | 243 | } |
| 205 | 244 | ||
| 206 | inline for (macs) |M| { | 245 | inline for (macs) |M| { |
| 207 | if (filter == null or std.mem.indexOf(u8, M.name, filter.?) != null) { | 246 | if (filter == null or std.mem.indexOf(u8, M.name, filter.?) != null) { |
| 208 | const throughput = try benchmarkMac(M.ty, mode(128 * MiB)); | 247 | const throughput = try benchmarkMac(M.ty, mode(128 * MiB)); |
| 209 | try stdout.print("{:>11}: {:5} MiB/s\n", .{ M.name, throughput / (1 * MiB) }); | 248 | try stdout.print("{:>17}: {:7} MiB/s\n", .{ M.name, throughput / (1 * MiB) }); |
| 210 | } | 249 | } |
| 211 | } | 250 | } |
| 212 | 251 | ||
| 213 | inline for (exchanges) |E| { | 252 | inline for (exchanges) |E| { |
| 214 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { | 253 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { |
| 215 | const throughput = try benchmarkKeyExchange(E.ty, mode(1000)); | 254 | const throughput = try benchmarkKeyExchange(E.ty, mode(1000)); |
| 216 | try stdout.print("{:>11}: {:5} exchanges/s\n", .{ E.name, throughput }); | 255 | try stdout.print("{:>17}: {:7} exchanges/s\n", .{ E.name, throughput }); |
| 217 | } | 256 | } |
| 218 | } | 257 | } |
| 219 | 258 | ||
| 220 | inline for (signatures) |E| { | 259 | inline for (signatures) |E| { |
| 221 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { | 260 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { |
| 222 | const throughput = try benchmarkSignatures(E.ty, mode(1000)); | 261 | const throughput = try benchmarkSignature(E.ty, mode(1000)); |
| 223 | try stdout.print("{:>11}: {:5} signatures/s\n", .{ E.name, throughput }); | 262 | try stdout.print("{:>17}: {:7} signatures/s\n", .{ E.name, throughput }); |
| 263 | } | ||
| 264 | } | ||
| 265 | |||
| 266 | inline for (aeads) |E| { | ||
| 267 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { | ||
| 268 | const throughput = try benchmarkAead(E.ty, mode(128 * MiB)); | ||
| 269 | try stdout.print("{:>17}: {:7} MiB/s\n", .{ E.name, throughput / (1 * MiB) }); | ||
| 224 | } | 270 | } |
| 225 | } | 271 | } |
| 226 | } | 272 | } |
lib/std/crypto/chacha20.zig+13-13| ... | @@ -47,7 +47,7 @@ fn initContext(key: [8]u32, d: [4]u32) [16]u32 { | ... | @@ -47,7 +47,7 @@ fn initContext(key: [8]u32, d: [4]u32) [16]u32 { |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | // The chacha family of ciphers are based on the salsa family. | 49 | // The chacha family of ciphers are based on the salsa family. |
| 50 | fn chacha20Core(x: []u32, input: [16]u32) void { | 50 | inline fn chacha20Core(x: []u32, input: [16]u32) void { |
| 51 | for (x) |_, i| | 51 | for (x) |_, i| |
| 52 | x[i] = input[i]; | 52 | x[i] = input[i]; |
| 53 | 53 | ||
| ... | @@ -744,26 +744,26 @@ pub const Chacha20Poly1305 = struct { | ... | @@ -744,26 +744,26 @@ pub const Chacha20Poly1305 = struct { |
| 744 | pub const key_length = 32; | 744 | pub const key_length = 32; |
| 745 | 745 | ||
| 746 | /// c: ciphertext: output buffer should be of size m.len | 746 | /// c: ciphertext: output buffer should be of size m.len |
| 747 | /// at: authentication tag: output MAC | 747 | /// tag: authentication tag: output MAC |
| 748 | /// m: message | 748 | /// m: message |
| 749 | /// ad: Associated Data | 749 | /// ad: Associated Data |
| 750 | /// npub: public nonce | 750 | /// npub: public nonce |
| 751 | /// k: private key | 751 | /// k: private key |
| 752 | pub fn encrypt(c: []u8, at: *[tag_length]u8, m: []const u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) void { | 752 | pub fn encrypt(c: []u8, tag: *[tag_length]u8, m: []const u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) void { |
| 753 | assert(c.len == m.len); | 753 | assert(c.len == m.len); |
| 754 | return chacha20poly1305SealDetached(c, at, m, ad, k, npub); | 754 | return chacha20poly1305SealDetached(c, tag, m, ad, k, npub); |
| 755 | } | 755 | } |
| 756 | 756 | ||
| 757 | /// m: message: output buffer should be of size c.len | 757 | /// m: message: output buffer should be of size c.len |
| 758 | /// c: ciphertext | 758 | /// c: ciphertext |
| 759 | /// at: authentication tag | 759 | /// tag: authentication tag |
| 760 | /// ad: Associated Data | 760 | /// ad: Associated Data |
| 761 | /// npub: public nonce | 761 | /// npub: public nonce |
| 762 | /// k: private key | 762 | /// k: private key |
| 763 | /// NOTE: the check of the authentication tag is currently not done in constant time | 763 | /// NOTE: the check of the authentication tag is currently not done in constant time |
| 764 | pub fn decrypt(m: []u8, c: []const u8, at: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) !void { | 764 | pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) !void { |
| 765 | assert(c.len == m.len); | 765 | assert(c.len == m.len); |
| 766 | return try chacha20poly1305OpenDetached(m, c, at[0..], ad, k, npub); | 766 | return try chacha20poly1305OpenDetached(m, c, tag[0..], ad, k, npub); |
| 767 | } | 767 | } |
| 768 | }; | 768 | }; |
| 769 | 769 | ||
| ... | @@ -773,26 +773,26 @@ pub const XChacha20Poly1305 = struct { | ... | @@ -773,26 +773,26 @@ pub const XChacha20Poly1305 = struct { |
| 773 | pub const key_length = 32; | 773 | pub const key_length = 32; |
| 774 | 774 | ||
| 775 | /// c: ciphertext: output buffer should be of size m.len | 775 | /// c: ciphertext: output buffer should be of size m.len |
| 776 | /// at: authentication tag: output MAC | 776 | /// tag: authentication tag: output MAC |
| 777 | /// m: message | 777 | /// m: message |
| 778 | /// ad: Associated Data | 778 | /// ad: Associated Data |
| 779 | /// npub: public nonce | 779 | /// npub: public nonce |
| 780 | /// k: private key | 780 | /// k: private key |
| 781 | pub fn encrypt(c: []u8, at: *[tag_length]u8, m: []const u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) void { | 781 | pub fn encrypt(c: []u8, tag: *[tag_length]u8, m: []const u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) void { |
| 782 | assert(c.len == m.len); | 782 | assert(c.len == m.len); |
| 783 | return xchacha20poly1305SealDetached(c, at, m, ad, k, npub); | 783 | return xchacha20poly1305SealDetached(c, tag, m, ad, k, npub); |
| 784 | } | 784 | } |
| 785 | 785 | ||
| 786 | /// m: message: output buffer should be of size c.len | 786 | /// m: message: output buffer should be of size c.len |
| 787 | /// c: ciphertext | 787 | /// c: ciphertext |
| 788 | /// at: authentication tag | 788 | /// tag: authentication tag |
| 789 | /// ad: Associated Data | 789 | /// ad: Associated Data |
| 790 | /// npub: public nonce | 790 | /// npub: public nonce |
| 791 | /// k: private key | 791 | /// k: private key |
| 792 | /// NOTE: the check of the authentication tag is currently not done in constant time | 792 | /// NOTE: the check of the authentication tag is currently not done in constant time |
| 793 | pub fn decrypt(m: []u8, c: []const u8, at: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) !void { | 793 | pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) !void { |
| 794 | assert(c.len == m.len); | 794 | assert(c.len == m.len); |
| 795 | return try xchacha20poly1305OpenDetached(m, c, at[0..], ad, k, npub); | 795 | return try xchacha20poly1305OpenDetached(m, c, tag[0..], ad, k, npub); |
| 796 | } | 796 | } |
| 797 | }; | 797 | }; |
| 798 | 798 |
lib/std/crypto/gimli.zig+31-27| ... | @@ -180,10 +180,14 @@ test "hash" { | ... | @@ -180,10 +180,14 @@ test "hash" { |
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | pub const Aead = struct { | 182 | pub const Aead = struct { |
| 183 | pub const tag_length = State.RATE; | ||
| 184 | pub const nonce_length = 16; | ||
| 185 | pub const key_length = 32; | ||
| 186 | |||
| 183 | /// ad: Associated Data | 187 | /// ad: Associated Data |
| 184 | /// npub: public nonce | 188 | /// npub: public nonce |
| 185 | /// k: private key | 189 | /// k: private key |
| 186 | fn init(ad: []const u8, npub: [16]u8, k: [32]u8) State { | 190 | fn init(ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) State { |
| 187 | var state = State{ | 191 | var state = State{ |
| 188 | .data = undefined, | 192 | .data = undefined, |
| 189 | }; | 193 | }; |
| ... | @@ -224,12 +228,12 @@ pub const Aead = struct { | ... | @@ -224,12 +228,12 @@ pub const Aead = struct { |
| 224 | } | 228 | } |
| 225 | 229 | ||
| 226 | /// c: ciphertext: output buffer should be of size m.len | 230 | /// c: ciphertext: output buffer should be of size m.len |
| 227 | /// at: authentication tag: output MAC | 231 | /// tag: authentication tag: output MAC |
| 228 | /// m: message | 232 | /// m: message |
| 229 | /// ad: Associated Data | 233 | /// ad: Associated Data |
| 230 | /// npub: public nonce | 234 | /// npub: public nonce |
| 231 | /// k: private key | 235 | /// k: private key |
| 232 | pub fn encrypt(c: []u8, at: *[State.RATE]u8, m: []const u8, ad: []const u8, npub: [16]u8, k: [32]u8) void { | 236 | pub fn encrypt(c: []u8, tag: *[tag_length]u8, m: []const u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) void { |
| 233 | assert(c.len == m.len); | 237 | assert(c.len == m.len); |
| 234 | 238 | ||
| 235 | var state = Aead.init(ad, npub, k); | 239 | var state = Aead.init(ad, npub, k); |
| ... | @@ -265,17 +269,17 @@ pub const Aead = struct { | ... | @@ -265,17 +269,17 @@ pub const Aead = struct { |
| 265 | 269 | ||
| 266 | // After the final non-full block of plaintext, the first 16 bytes | 270 | // After the final non-full block of plaintext, the first 16 bytes |
| 267 | // of the state are output as an authentication tag. | 271 | // of the state are output as an authentication tag. |
| 268 | std.mem.copy(u8, at, buf[0..State.RATE]); | 272 | std.mem.copy(u8, tag, buf[0..State.RATE]); |
| 269 | } | 273 | } |
| 270 | 274 | ||
| 271 | /// m: message: output buffer should be of size c.len | 275 | /// m: message: output buffer should be of size c.len |
| 272 | /// c: ciphertext | 276 | /// c: ciphertext |
| 273 | /// at: authentication tag | 277 | /// tag: authentication tag |
| 274 | /// ad: Associated Data | 278 | /// ad: Associated Data |
| 275 | /// npub: public nonce | 279 | /// npub: public nonce |
| 276 | /// k: private key | 280 | /// k: private key |
| 277 | /// NOTE: the check of the authentication tag is currently not done in constant time | 281 | /// NOTE: the check of the authentication tag is currently not done in constant time |
| 278 | pub fn decrypt(m: []u8, c: []const u8, at: [State.RATE]u8, ad: []const u8, npub: [16]u8, k: [32]u8) !void { | 282 | pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) !void { |
| 279 | assert(c.len == m.len); | 283 | assert(c.len == m.len); |
| 280 | 284 | ||
| 281 | var state = Aead.init(ad, npub, k); | 285 | var state = Aead.init(ad, npub, k); |
| ... | @@ -308,7 +312,7 @@ pub const Aead = struct { | ... | @@ -308,7 +312,7 @@ pub const Aead = struct { |
| 308 | // After the final non-full block of plaintext, the first 16 bytes | 312 | // After the final non-full block of plaintext, the first 16 bytes |
| 309 | // of the state are the authentication tag. | 313 | // of the state are the authentication tag. |
| 310 | // TODO: use a constant-time equality check here, see https://github.com/ziglang/zig/issues/1776 | 314 | // TODO: use a constant-time equality check here, see https://github.com/ziglang/zig/issues/1776 |
| 311 | if (!mem.eql(u8, buf[0..State.RATE], &at)) { | 315 | if (!mem.eql(u8, buf[0..State.RATE], &tag)) { |
| 312 | @memset(m.ptr, undefined, m.len); | 316 | @memset(m.ptr, undefined, m.len); |
| 313 | return error.InvalidMessage; | 317 | return error.InvalidMessage; |
| 314 | } | 318 | } |
| ... | @@ -328,13 +332,13 @@ test "cipher" { | ... | @@ -328,13 +332,13 @@ test "cipher" { |
| 328 | const pt: [0]u8 = undefined; | 332 | const pt: [0]u8 = undefined; |
| 329 | 333 | ||
| 330 | var ct: [pt.len]u8 = undefined; | 334 | var ct: [pt.len]u8 = undefined; |
| 331 | var at: [16]u8 = undefined; | 335 | var tag: [16]u8 = undefined; |
| 332 | Aead.encrypt(&ct, &at, &pt, &ad, nonce, key); | 336 | Aead.encrypt(&ct, &tag, &pt, &ad, nonce, key); |
| 333 | htest.assertEqual("", &ct); | 337 | htest.assertEqual("", &ct); |
| 334 | htest.assertEqual("14DA9BB7120BF58B985A8E00FDEBA15B", &at); | 338 | htest.assertEqual("14DA9BB7120BF58B985A8E00FDEBA15B", &tag); |
| 335 | 339 | ||
| 336 | var pt2: [pt.len]u8 = undefined; | 340 | var pt2: [pt.len]u8 = undefined; |
| 337 | try Aead.decrypt(&pt2, &ct, at, &ad, nonce, key); | 341 | try Aead.decrypt(&pt2, &ct, tag, &ad, nonce, key); |
| 338 | testing.expectEqualSlices(u8, &pt, &pt2); | 342 | testing.expectEqualSlices(u8, &pt, &pt2); |
| 339 | } | 343 | } |
| 340 | { // test vector (34) from NIST KAT submission. | 344 | { // test vector (34) from NIST KAT submission. |
| ... | @@ -343,13 +347,13 @@ test "cipher" { | ... | @@ -343,13 +347,13 @@ test "cipher" { |
| 343 | try std.fmt.hexToBytes(&pt, "00"); | 347 | try std.fmt.hexToBytes(&pt, "00"); |
| 344 | 348 | ||
| 345 | var ct: [pt.len]u8 = undefined; | 349 | var ct: [pt.len]u8 = undefined; |
| 346 | var at: [16]u8 = undefined; | 350 | var tag: [16]u8 = undefined; |
| 347 | Aead.encrypt(&ct, &at, &pt, &ad, nonce, key); | 351 | Aead.encrypt(&ct, &tag, &pt, &ad, nonce, key); |
| 348 | htest.assertEqual("7F", &ct); | 352 | htest.assertEqual("7F", &ct); |
| 349 | htest.assertEqual("80492C317B1CD58A1EDC3A0D3E9876FC", &at); | 353 | htest.assertEqual("80492C317B1CD58A1EDC3A0D3E9876FC", &tag); |
| 350 | 354 | ||
| 351 | var pt2: [pt.len]u8 = undefined; | 355 | var pt2: [pt.len]u8 = undefined; |
| 352 | try Aead.decrypt(&pt2, &ct, at, &ad, nonce, key); | 356 | try Aead.decrypt(&pt2, &ct, tag, &ad, nonce, key); |
| 353 | testing.expectEqualSlices(u8, &pt, &pt2); | 357 | testing.expectEqualSlices(u8, &pt, &pt2); |
| 354 | } | 358 | } |
| 355 | { // test vector (106) from NIST KAT submission. | 359 | { // test vector (106) from NIST KAT submission. |
| ... | @@ -359,13 +363,13 @@ test "cipher" { | ... | @@ -359,13 +363,13 @@ test "cipher" { |
| 359 | try std.fmt.hexToBytes(&pt, "000102"); | 363 | try std.fmt.hexToBytes(&pt, "000102"); |
| 360 | 364 | ||
| 361 | var ct: [pt.len]u8 = undefined; | 365 | var ct: [pt.len]u8 = undefined; |
| 362 | var at: [16]u8 = undefined; | 366 | var tag: [16]u8 = undefined; |
| 363 | Aead.encrypt(&ct, &at, &pt, &ad, nonce, key); | 367 | Aead.encrypt(&ct, &tag, &pt, &ad, nonce, key); |
| 364 | htest.assertEqual("484D35", &ct); | 368 | htest.assertEqual("484D35", &ct); |
| 365 | htest.assertEqual("030BBEA23B61C00CED60A923BDCF9147", &at); | 369 | htest.assertEqual("030BBEA23B61C00CED60A923BDCF9147", &tag); |
| 366 | 370 | ||
| 367 | var pt2: [pt.len]u8 = undefined; | 371 | var pt2: [pt.len]u8 = undefined; |
| 368 | try Aead.decrypt(&pt2, &ct, at, &ad, nonce, key); | 372 | try Aead.decrypt(&pt2, &ct, tag, &ad, nonce, key); |
| 369 | testing.expectEqualSlices(u8, &pt, &pt2); | 373 | testing.expectEqualSlices(u8, &pt, &pt2); |
| 370 | } | 374 | } |
| 371 | { // test vector (790) from NIST KAT submission. | 375 | { // test vector (790) from NIST KAT submission. |
| ... | @@ -375,13 +379,13 @@ test "cipher" { | ... | @@ -375,13 +379,13 @@ test "cipher" { |
| 375 | try std.fmt.hexToBytes(&pt, "000102030405060708090A0B0C0D0E0F10111213141516"); | 379 | try std.fmt.hexToBytes(&pt, "000102030405060708090A0B0C0D0E0F10111213141516"); |
| 376 | 380 | ||
| 377 | var ct: [pt.len]u8 = undefined; | 381 | var ct: [pt.len]u8 = undefined; |
| 378 | var at: [16]u8 = undefined; | 382 | var tag: [16]u8 = undefined; |
| 379 | Aead.encrypt(&ct, &at, &pt, &ad, nonce, key); | 383 | Aead.encrypt(&ct, &tag, &pt, &ad, nonce, key); |
| 380 | htest.assertEqual("6815B4A0ECDAD01596EAD87D9E690697475D234C6A13D1", &ct); | 384 | htest.assertEqual("6815B4A0ECDAD01596EAD87D9E690697475D234C6A13D1", &ct); |
| 381 | htest.assertEqual("DFE23F1642508290D68245279558B2FB", &at); | 385 | htest.assertEqual("DFE23F1642508290D68245279558B2FB", &tag); |
| 382 | 386 | ||
| 383 | var pt2: [pt.len]u8 = undefined; | 387 | var pt2: [pt.len]u8 = undefined; |
| 384 | try Aead.decrypt(&pt2, &ct, at, &ad, nonce, key); | 388 | try Aead.decrypt(&pt2, &ct, tag, &ad, nonce, key); |
| 385 | testing.expectEqualSlices(u8, &pt, &pt2); | 389 | testing.expectEqualSlices(u8, &pt, &pt2); |
| 386 | } | 390 | } |
| 387 | { // test vector (1057) from NIST KAT submission. | 391 | { // test vector (1057) from NIST KAT submission. |
| ... | @@ -390,13 +394,13 @@ test "cipher" { | ... | @@ -390,13 +394,13 @@ test "cipher" { |
| 390 | try std.fmt.hexToBytes(&pt, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); | 394 | try std.fmt.hexToBytes(&pt, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); |
| 391 | 395 | ||
| 392 | var ct: [pt.len]u8 = undefined; | 396 | var ct: [pt.len]u8 = undefined; |
| 393 | var at: [16]u8 = undefined; | 397 | var tag: [16]u8 = undefined; |
| 394 | Aead.encrypt(&ct, &at, &pt, &ad, nonce, key); | 398 | Aead.encrypt(&ct, &tag, &pt, &ad, nonce, key); |
| 395 | htest.assertEqual("7F8A2CF4F52AA4D6B2E74105C30A2777B9D0C8AEFDD555DE35861BD3011F652F", &ct); | 399 | htest.assertEqual("7F8A2CF4F52AA4D6B2E74105C30A2777B9D0C8AEFDD555DE35861BD3011F652F", &ct); |
| 396 | htest.assertEqual("7256456FA935AC34BBF55AE135F33257", &at); | 400 | htest.assertEqual("7256456FA935AC34BBF55AE135F33257", &tag); |
| 397 | 401 | ||
| 398 | var pt2: [pt.len]u8 = undefined; | 402 | var pt2: [pt.len]u8 = undefined; |
| 399 | try Aead.decrypt(&pt2, &ct, at, &ad, nonce, key); | 403 | try Aead.decrypt(&pt2, &ct, tag, &ad, nonce, key); |
| 400 | testing.expectEqualSlices(u8, &pt, &pt2); | 404 | testing.expectEqualSlices(u8, &pt, &pt2); |
| 401 | } | 405 | } |
| 402 | } | 406 | } |
lib/std/math.zig+3-28| ... | @@ -5,6 +5,7 @@ | ... | @@ -5,6 +5,7 @@ |
| 5 | // and substantial portions of the software. | 5 | // and substantial portions of the software. |
| 6 | const std = @import("std.zig"); | 6 | const std = @import("std.zig"); |
| 7 | const assert = std.debug.assert; | 7 | const assert = std.debug.assert; |
| 8 | const mem = std.mem; | ||
| 8 | const testing = std.testing; | 9 | const testing = std.testing; |
| 9 | 10 | ||
| 10 | /// Euler's number (e) | 11 | /// Euler's number (e) |
| ... | @@ -108,34 +109,8 @@ pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) bool { | ... | @@ -108,34 +109,8 @@ pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) bool { |
| 108 | return fabs(x - y) < epsilon; | 109 | return fabs(x - y) < epsilon; |
| 109 | } | 110 | } |
| 110 | 111 | ||
| 111 | // TODO: Hide the following in an internal module. | 112 | pub fn doNotOptimizeAway(value: anytype) void { |
| 112 | pub fn forceEval(value: anytype) void { | 113 | mem.doNotOptimizeAway(value); |
| 113 | const T = @TypeOf(value); | ||
| 114 | switch (T) { | ||
| 115 | f16 => { | ||
| 116 | var x: f16 = undefined; | ||
| 117 | const p = @ptrCast(*volatile f16, &x); | ||
| 118 | p.* = x; | ||
| 119 | }, | ||
| 120 | f32 => { | ||
| 121 | var x: f32 = undefined; | ||
| 122 | const p = @ptrCast(*volatile f32, &x); | ||
| 123 | p.* = x; | ||
| 124 | }, | ||
| 125 | f64 => { | ||
| 126 | var x: f64 = undefined; | ||
| 127 | const p = @ptrCast(*volatile f64, &x); | ||
| 128 | p.* = x; | ||
| 129 | }, | ||
| 130 | f128 => { | ||
| 131 | var x: f128 = undefined; | ||
| 132 | const p = @ptrCast(*volatile f128, &x); | ||
| 133 | p.* = x; | ||
| 134 | }, | ||
| 135 | else => { | ||
| 136 | @compileError("forceEval not implemented for " ++ @typeName(T)); | ||
| 137 | }, | ||
| 138 | } | ||
| 139 | } | 114 | } |
| 140 | 115 | ||
| 141 | pub fn raiseInvalid() void { | 116 | pub fn raiseInvalid() void { |
lib/std/math/asinh.zig+2-2| ... | @@ -56,7 +56,7 @@ fn asinh32(x: f32) f32 { | ... | @@ -56,7 +56,7 @@ fn asinh32(x: f32) f32 { |
| 56 | } | 56 | } |
| 57 | // |x| < 0x1p-12, inexact if x != 0 | 57 | // |x| < 0x1p-12, inexact if x != 0 |
| 58 | else { | 58 | else { |
| 59 | math.forceEval(x + 0x1.0p120); | 59 | math.doNotOptimizeAway(x + 0x1.0p120); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | return if (s != 0) -rx else rx; | 62 | return if (s != 0) -rx else rx; |
| ... | @@ -87,7 +87,7 @@ fn asinh64(x: f64) f64 { | ... | @@ -87,7 +87,7 @@ fn asinh64(x: f64) f64 { |
| 87 | } | 87 | } |
| 88 | // |x| < 0x1p-12, inexact if x != 0 | 88 | // |x| < 0x1p-12, inexact if x != 0 |
| 89 | else { | 89 | else { |
| 90 | math.forceEval(x + 0x1.0p120); | 90 | math.doNotOptimizeAway(x + 0x1.0p120); |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | return if (s != 0) -rx else rx; | 93 | return if (s != 0) -rx else rx; |
lib/std/math/atan.zig+2-2| ... | @@ -72,7 +72,7 @@ fn atan32(x_: f32) f32 { | ... | @@ -72,7 +72,7 @@ fn atan32(x_: f32) f32 { |
| 72 | // |x| < 2^(-12) | 72 | // |x| < 2^(-12) |
| 73 | if (ix < 0x39800000) { | 73 | if (ix < 0x39800000) { |
| 74 | if (ix < 0x00800000) { | 74 | if (ix < 0x00800000) { |
| 75 | math.forceEval(x * x); | 75 | math.doNotOptimizeAway(x * x); |
| 76 | } | 76 | } |
| 77 | return x; | 77 | return x; |
| 78 | } | 78 | } |
| ... | @@ -170,7 +170,7 @@ fn atan64(x_: f64) f64 { | ... | @@ -170,7 +170,7 @@ fn atan64(x_: f64) f64 { |
| 170 | // |x| < 2^(-27) | 170 | // |x| < 2^(-27) |
| 171 | if (ix < 0x3E400000) { | 171 | if (ix < 0x3E400000) { |
| 172 | if (ix < 0x00100000) { | 172 | if (ix < 0x00100000) { |
| 173 | math.forceEval(@floatCast(f32, x)); | 173 | math.doNotOptimizeAway(@floatCast(f32, x)); |
| 174 | } | 174 | } |
| 175 | return x; | 175 | return x; |
| 176 | } | 176 | } |
lib/std/math/atanh.zig+2-2| ... | @@ -45,7 +45,7 @@ fn atanh_32(x: f32) f32 { | ... | @@ -45,7 +45,7 @@ fn atanh_32(x: f32) f32 { |
| 45 | if (u < 0x3F800000 - (32 << 23)) { | 45 | if (u < 0x3F800000 - (32 << 23)) { |
| 46 | // underflow | 46 | // underflow |
| 47 | if (u < (1 << 23)) { | 47 | if (u < (1 << 23)) { |
| 48 | math.forceEval(y * y); | 48 | math.doNotOptimizeAway(y * y); |
| 49 | } | 49 | } |
| 50 | } | 50 | } |
| 51 | // |x| < 0.5 | 51 | // |x| < 0.5 |
| ... | @@ -74,7 +74,7 @@ fn atanh_64(x: f64) f64 { | ... | @@ -74,7 +74,7 @@ fn atanh_64(x: f64) f64 { |
| 74 | if (e < 0x3FF - 32) { | 74 | if (e < 0x3FF - 32) { |
| 75 | // underflow | 75 | // underflow |
| 76 | if (e == 0) { | 76 | if (e == 0) { |
| 77 | math.forceEval(@floatCast(f32, y)); | 77 | math.doNotOptimizeAway(@floatCast(f32, y)); |
| 78 | } | 78 | } |
| 79 | } | 79 | } |
| 80 | // |x| < 0.5 | 80 | // |x| < 0.5 |
lib/std/math/ceil.zig+4-4| ... | @@ -47,14 +47,14 @@ fn ceil32(x: f32) f32 { | ... | @@ -47,14 +47,14 @@ fn ceil32(x: f32) f32 { |
| 47 | if (u & m == 0) { | 47 | if (u & m == 0) { |
| 48 | return x; | 48 | return x; |
| 49 | } | 49 | } |
| 50 | math.forceEval(x + 0x1.0p120); | 50 | math.doNotOptimizeAway(x + 0x1.0p120); |
| 51 | if (u >> 31 == 0) { | 51 | if (u >> 31 == 0) { |
| 52 | u += m; | 52 | u += m; |
| 53 | } | 53 | } |
| 54 | u &= ~m; | 54 | u &= ~m; |
| 55 | return @bitCast(f32, u); | 55 | return @bitCast(f32, u); |
| 56 | } else { | 56 | } else { |
| 57 | math.forceEval(x + 0x1.0p120); | 57 | math.doNotOptimizeAway(x + 0x1.0p120); |
| 58 | if (u >> 31 != 0) { | 58 | if (u >> 31 != 0) { |
| 59 | return -0.0; | 59 | return -0.0; |
| 60 | } else { | 60 | } else { |
| ... | @@ -79,7 +79,7 @@ fn ceil64(x: f64) f64 { | ... | @@ -79,7 +79,7 @@ fn ceil64(x: f64) f64 { |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | if (e <= 0x3FF - 1) { | 81 | if (e <= 0x3FF - 1) { |
| 82 | math.forceEval(y); | 82 | math.doNotOptimizeAway(y); |
| 83 | if (u >> 63 != 0) { | 83 | if (u >> 63 != 0) { |
| 84 | return -0.0; | 84 | return -0.0; |
| 85 | } else { | 85 | } else { |
| ... | @@ -106,7 +106,7 @@ fn ceil128(x: f128) f128 { | ... | @@ -106,7 +106,7 @@ fn ceil128(x: f128) f128 { |
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | if (e <= 0x3FFF - 1) { | 108 | if (e <= 0x3FFF - 1) { |
| 109 | math.forceEval(y); | 109 | math.doNotOptimizeAway(y); |
| 110 | if (u >> 127 != 0) { | 110 | if (u >> 127 != 0) { |
| 111 | return -0.0; | 111 | return -0.0; |
| 112 | } else { | 112 | } else { |
lib/std/math/exp.zig+4-4| ... | @@ -56,7 +56,7 @@ fn exp32(x_: f32) f32 { | ... | @@ -56,7 +56,7 @@ fn exp32(x_: f32) f32 { |
| 56 | return x * 0x1.0p127; | 56 | return x * 0x1.0p127; |
| 57 | } | 57 | } |
| 58 | if (sign != 0) { | 58 | if (sign != 0) { |
| 59 | math.forceEval(-0x1.0p-149 / x); // overflow | 59 | math.doNotOptimizeAway(-0x1.0p-149 / x); // overflow |
| 60 | // x <= -103.972084 | 60 | // x <= -103.972084 |
| 61 | if (hx >= 0x42CFF1B5) { | 61 | if (hx >= 0x42CFF1B5) { |
| 62 | return 0; | 62 | return 0; |
| ... | @@ -88,7 +88,7 @@ fn exp32(x_: f32) f32 { | ... | @@ -88,7 +88,7 @@ fn exp32(x_: f32) f32 { |
| 88 | hi = x; | 88 | hi = x; |
| 89 | lo = 0; | 89 | lo = 0; |
| 90 | } else { | 90 | } else { |
| 91 | math.forceEval(0x1.0p127 + x); // inexact | 91 | math.doNotOptimizeAway(0x1.0p127 + x); // inexact |
| 92 | return 1 + x; | 92 | return 1 + x; |
| 93 | } | 93 | } |
| 94 | 94 | ||
| ... | @@ -139,7 +139,7 @@ fn exp64(x_: f64) f64 { | ... | @@ -139,7 +139,7 @@ fn exp64(x_: f64) f64 { |
| 139 | } | 139 | } |
| 140 | if (x < -708.39641853226410622) { | 140 | if (x < -708.39641853226410622) { |
| 141 | // underflow if x != -inf | 141 | // underflow if x != -inf |
| 142 | // math.forceEval(@as(f32, -0x1.0p-149 / x)); | 142 | // math.doNotOptimizeAway(@as(f32, -0x1.0p-149 / x)); |
| 143 | if (x < -745.13321910194110842) { | 143 | if (x < -745.13321910194110842) { |
| 144 | return 0; | 144 | return 0; |
| 145 | } | 145 | } |
| ... | @@ -172,7 +172,7 @@ fn exp64(x_: f64) f64 { | ... | @@ -172,7 +172,7 @@ fn exp64(x_: f64) f64 { |
| 172 | lo = 0; | 172 | lo = 0; |
| 173 | } else { | 173 | } else { |
| 174 | // inexact if x != 0 | 174 | // inexact if x != 0 |
| 175 | // math.forceEval(0x1.0p1023 + x); | 175 | // math.doNotOptimizeAway(0x1.0p1023 + x); |
| 176 | return 1 + x; | 176 | return 1 + x; |
| 177 | } | 177 | } |
| 178 | 178 |
lib/std/math/exp2.zig+2-2| ... | @@ -70,7 +70,7 @@ fn exp2_32(x: f32) f32 { | ... | @@ -70,7 +70,7 @@ fn exp2_32(x: f32) f32 { |
| 70 | // x < -126 | 70 | // x < -126 |
| 71 | if (u >= 0x80000000) { | 71 | if (u >= 0x80000000) { |
| 72 | if (u >= 0xC3160000 or u & 0x000FFFF != 0) { | 72 | if (u >= 0xC3160000 or u & 0x000FFFF != 0) { |
| 73 | math.forceEval(-0x1.0p-149 / x); | 73 | math.doNotOptimizeAway(-0x1.0p-149 / x); |
| 74 | } | 74 | } |
| 75 | // x <= -150 | 75 | // x <= -150 |
| 76 | if (u >= 0x3160000) { | 76 | if (u >= 0x3160000) { |
| ... | @@ -393,7 +393,7 @@ fn exp2_64(x: f64) f64 { | ... | @@ -393,7 +393,7 @@ fn exp2_64(x: f64) f64 { |
| 393 | if (ux >> 63 != 0) { | 393 | if (ux >> 63 != 0) { |
| 394 | // underflow | 394 | // underflow |
| 395 | if (x <= -1075 or x - 0x1.0p52 + 0x1.0p52 != x) { | 395 | if (x <= -1075 or x - 0x1.0p52 + 0x1.0p52 != x) { |
| 396 | math.forceEval(@floatCast(f32, -0x1.0p-149 / x)); | 396 | math.doNotOptimizeAway(@floatCast(f32, -0x1.0p-149 / x)); |
| 397 | } | 397 | } |
| 398 | if (x <= -1075) { | 398 | if (x <= -1075) { |
| 399 | return 0; | 399 | return 0; |
lib/std/math/expm1.zig+2-2| ... | @@ -106,7 +106,7 @@ fn expm1_32(x_: f32) f32 { | ... | @@ -106,7 +106,7 @@ fn expm1_32(x_: f32) f32 { |
| 106 | // |x| < 2^(-25) | 106 | // |x| < 2^(-25) |
| 107 | else if (hx < 0x33000000) { | 107 | else if (hx < 0x33000000) { |
| 108 | if (hx < 0x00800000) { | 108 | if (hx < 0x00800000) { |
| 109 | math.forceEval(x * x); | 109 | math.doNotOptimizeAway(x * x); |
| 110 | } | 110 | } |
| 111 | return x; | 111 | return x; |
| 112 | } else { | 112 | } else { |
| ... | @@ -237,7 +237,7 @@ fn expm1_64(x_: f64) f64 { | ... | @@ -237,7 +237,7 @@ fn expm1_64(x_: f64) f64 { |
| 237 | // |x| < 2^(-54) | 237 | // |x| < 2^(-54) |
| 238 | else if (hx < 0x3C900000) { | 238 | else if (hx < 0x3C900000) { |
| 239 | if (hx < 0x00100000) { | 239 | if (hx < 0x00100000) { |
| 240 | math.forceEval(@floatCast(f32, x)); | 240 | math.doNotOptimizeAway(@floatCast(f32, x)); |
| 241 | } | 241 | } |
| 242 | return x; | 242 | return x; |
| 243 | } else { | 243 | } else { |
lib/std/math/floor.zig+6-6| ... | @@ -50,13 +50,13 @@ fn floor16(x: f16) f16 { | ... | @@ -50,13 +50,13 @@ fn floor16(x: f16) f16 { |
| 50 | if (u & m == 0) { | 50 | if (u & m == 0) { |
| 51 | return x; | 51 | return x; |
| 52 | } | 52 | } |
| 53 | math.forceEval(x + 0x1.0p120); | 53 | math.doNotOptimizeAway(x + 0x1.0p120); |
| 54 | if (u >> 15 != 0) { | 54 | if (u >> 15 != 0) { |
| 55 | u += m; | 55 | u += m; |
| 56 | } | 56 | } |
| 57 | return @bitCast(f16, u & ~m); | 57 | return @bitCast(f16, u & ~m); |
| 58 | } else { | 58 | } else { |
| 59 | math.forceEval(x + 0x1.0p120); | 59 | math.doNotOptimizeAway(x + 0x1.0p120); |
| 60 | if (u >> 15 == 0) { | 60 | if (u >> 15 == 0) { |
| 61 | return 0.0; | 61 | return 0.0; |
| 62 | } else { | 62 | } else { |
| ... | @@ -84,13 +84,13 @@ fn floor32(x: f32) f32 { | ... | @@ -84,13 +84,13 @@ fn floor32(x: f32) f32 { |
| 84 | if (u & m == 0) { | 84 | if (u & m == 0) { |
| 85 | return x; | 85 | return x; |
| 86 | } | 86 | } |
| 87 | math.forceEval(x + 0x1.0p120); | 87 | math.doNotOptimizeAway(x + 0x1.0p120); |
| 88 | if (u >> 31 != 0) { | 88 | if (u >> 31 != 0) { |
| 89 | u += m; | 89 | u += m; |
| 90 | } | 90 | } |
| 91 | return @bitCast(f32, u & ~m); | 91 | return @bitCast(f32, u & ~m); |
| 92 | } else { | 92 | } else { |
| 93 | math.forceEval(x + 0x1.0p120); | 93 | math.doNotOptimizeAway(x + 0x1.0p120); |
| 94 | if (u >> 31 == 0) { | 94 | if (u >> 31 == 0) { |
| 95 | return 0.0; | 95 | return 0.0; |
| 96 | } else { | 96 | } else { |
| ... | @@ -115,7 +115,7 @@ fn floor64(x: f64) f64 { | ... | @@ -115,7 +115,7 @@ fn floor64(x: f64) f64 { |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | if (e <= 0x3FF - 1) { | 117 | if (e <= 0x3FF - 1) { |
| 118 | math.forceEval(y); | 118 | math.doNotOptimizeAway(y); |
| 119 | if (u >> 63 != 0) { | 119 | if (u >> 63 != 0) { |
| 120 | return -1.0; | 120 | return -1.0; |
| 121 | } else { | 121 | } else { |
| ... | @@ -142,7 +142,7 @@ fn floor128(x: f128) f128 { | ... | @@ -142,7 +142,7 @@ fn floor128(x: f128) f128 { |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | if (e <= 0x3FFF - 1) { | 144 | if (e <= 0x3FFF - 1) { |
| 145 | math.forceEval(y); | 145 | math.doNotOptimizeAway(y); |
| 146 | if (u >> 127 != 0) { | 146 | if (u >> 127 != 0) { |
| 147 | return -1.0; | 147 | return -1.0; |
| 148 | } else { | 148 | } else { |
lib/std/math/log1p.zig+1-1| ... | @@ -62,7 +62,7 @@ fn log1p_32(x: f32) f32 { | ... | @@ -62,7 +62,7 @@ fn log1p_32(x: f32) f32 { |
| 62 | if ((ix << 1) < (0x33800000 << 1)) { | 62 | if ((ix << 1) < (0x33800000 << 1)) { |
| 63 | // underflow if subnormal | 63 | // underflow if subnormal |
| 64 | if (ix & 0x7F800000 == 0) { | 64 | if (ix & 0x7F800000 == 0) { |
| 65 | math.forceEval(x * x); | 65 | math.doNotOptimizeAway(x * x); |
| 66 | } | 66 | } |
| 67 | return x; | 67 | return x; |
| 68 | } | 68 | } |
lib/std/math/round.zig+3-3| ... | @@ -43,7 +43,7 @@ fn round32(x_: f32) f32 { | ... | @@ -43,7 +43,7 @@ fn round32(x_: f32) f32 { |
| 43 | x = -x; | 43 | x = -x; |
| 44 | } | 44 | } |
| 45 | if (e < 0x7F - 1) { | 45 | if (e < 0x7F - 1) { |
| 46 | math.forceEval(x + math.f32_toint); | 46 | math.doNotOptimizeAway(x + math.f32_toint); |
| 47 | return 0 * @bitCast(f32, u); | 47 | return 0 * @bitCast(f32, u); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| ... | @@ -76,7 +76,7 @@ fn round64(x_: f64) f64 { | ... | @@ -76,7 +76,7 @@ fn round64(x_: f64) f64 { |
| 76 | x = -x; | 76 | x = -x; |
| 77 | } | 77 | } |
| 78 | if (e < 0x3ff - 1) { | 78 | if (e < 0x3ff - 1) { |
| 79 | math.forceEval(x + math.f64_toint); | 79 | math.doNotOptimizeAway(x + math.f64_toint); |
| 80 | return 0 * @bitCast(f64, u); | 80 | return 0 * @bitCast(f64, u); |
| 81 | } | 81 | } |
| 82 | 82 | ||
| ... | @@ -109,7 +109,7 @@ fn round128(x_: f128) f128 { | ... | @@ -109,7 +109,7 @@ fn round128(x_: f128) f128 { |
| 109 | x = -x; | 109 | x = -x; |
| 110 | } | 110 | } |
| 111 | if (e < 0x3FFF - 1) { | 111 | if (e < 0x3FFF - 1) { |
| 112 | math.forceEval(x + math.f64_toint); | 112 | math.doNotOptimizeAway(x + math.f64_toint); |
| 113 | return 0 * @bitCast(f128, u); | 113 | return 0 * @bitCast(f128, u); |
| 114 | } | 114 | } |
| 115 | 115 |
lib/std/math/tanh.zig+2-2| ... | @@ -67,7 +67,7 @@ fn tanh32(x: f32) f32 { | ... | @@ -67,7 +67,7 @@ fn tanh32(x: f32) f32 { |
| 67 | } | 67 | } |
| 68 | // |x| is subnormal | 68 | // |x| is subnormal |
| 69 | else { | 69 | else { |
| 70 | math.forceEval(x * x); | 70 | math.doNotOptimizeAway(x * x); |
| 71 | t = x; | 71 | t = x; |
| 72 | } | 72 | } |
| 73 | 73 | ||
| ... | @@ -112,7 +112,7 @@ fn tanh64(x: f64) f64 { | ... | @@ -112,7 +112,7 @@ fn tanh64(x: f64) f64 { |
| 112 | } | 112 | } |
| 113 | // |x| is subnormal | 113 | // |x| is subnormal |
| 114 | else { | 114 | else { |
| 115 | math.forceEval(@floatCast(f32, x)); | 115 | math.doNotOptimizeAway(@floatCast(f32, x)); |
| 116 | t = x; | 116 | t = x; |
| 117 | } | 117 | } |
| 118 | 118 |
lib/std/math/trunc.zig+3-3| ... | @@ -46,7 +46,7 @@ fn trunc32(x: f32) f32 { | ... | @@ -46,7 +46,7 @@ fn trunc32(x: f32) f32 { |
| 46 | if (u & m == 0) { | 46 | if (u & m == 0) { |
| 47 | return x; | 47 | return x; |
| 48 | } else { | 48 | } else { |
| 49 | math.forceEval(x + 0x1p120); | 49 | math.doNotOptimizeAway(x + 0x1p120); |
| 50 | return @bitCast(f32, u & ~m); | 50 | return @bitCast(f32, u & ~m); |
| 51 | } | 51 | } |
| 52 | } | 52 | } |
| ... | @@ -67,7 +67,7 @@ fn trunc64(x: f64) f64 { | ... | @@ -67,7 +67,7 @@ fn trunc64(x: f64) f64 { |
| 67 | if (u & m == 0) { | 67 | if (u & m == 0) { |
| 68 | return x; | 68 | return x; |
| 69 | } else { | 69 | } else { |
| 70 | math.forceEval(x + 0x1p120); | 70 | math.doNotOptimizeAway(x + 0x1p120); |
| 71 | return @bitCast(f64, u & ~m); | 71 | return @bitCast(f64, u & ~m); |
| 72 | } | 72 | } |
| 73 | } | 73 | } |
| ... | @@ -88,7 +88,7 @@ fn trunc128(x: f128) f128 { | ... | @@ -88,7 +88,7 @@ fn trunc128(x: f128) f128 { |
| 88 | if (u & m == 0) { | 88 | if (u & m == 0) { |
| 89 | return x; | 89 | return x; |
| 90 | } else { | 90 | } else { |
| 91 | math.forceEval(x + 0x1p120); | 91 | math.doNotOptimizeAway(x + 0x1p120); |
| 92 | return @bitCast(f128, u & ~m); | 92 | return @bitCast(f128, u & ~m); |
| 93 | } | 93 | } |
| 94 | } | 94 | } |
lib/std/mem.zig+11| ... | @@ -2158,6 +2158,17 @@ pub fn alignForwardGeneric(comptime T: type, addr: T, alignment: T) T { | ... | @@ -2158,6 +2158,17 @@ pub fn alignForwardGeneric(comptime T: type, addr: T, alignment: T) T { |
| 2158 | return alignBackwardGeneric(T, addr + (alignment - 1), alignment); | 2158 | return alignBackwardGeneric(T, addr + (alignment - 1), alignment); |
| 2159 | } | 2159 | } |
| 2160 | 2160 | ||
| 2161 | /// Force an evaluation of the expression; this tries to prevent | ||
| 2162 | /// the compiler from optimizing the computation away even if the | ||
| 2163 | /// result eventually gets discarded. | ||
| 2164 | pub fn doNotOptimizeAway(val: anytype) void { | ||
| 2165 | asm volatile ("" | ||
| 2166 | : | ||
| 2167 | : [val] "rm" (val) | ||
| 2168 | : "memory" | ||
| 2169 | ); | ||
| 2170 | } | ||
| 2171 | |||
| 2161 | test "alignForward" { | 2172 | test "alignForward" { |
| 2162 | testing.expect(alignForward(1, 1) == 1); | 2173 | testing.expect(alignForward(1, 1) == 1); |
| 2163 | testing.expect(alignForward(2, 1) == 2); | 2174 | testing.expect(alignForward(2, 1) == 2); |