aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-10-08 15:47:45 -0700
committerAndrew Kelley <andrew@ziglang.org>2020-10-08 15:47:45 -0700
commit8b7539bd9554d25599ccff6f0e9ea79aa051946b (patch)
tree9157fafcbe37f904346fd73042be1d1d299d4da2 /lib/std
parentb5a36f676b1fd69f195d9f1eb6e35f3eb2f15946 (diff)
parentb02341d6f58e0b8a87fc2ab589dcfd85e5dc96cd (diff)
downloadzig-8b7539bd9554d25599ccff6f0e9ea79aa051946b.tar.gz
zig-8b7539bd9554d25599ccff6f0e9ea79aa051946b.zip
Merge remote-tracking branch 'origin/master' into llvm11
Conflicts: src/clang.zig Master branch renamed an enum; this branch gave it an explicit tag type and explicitly initialized values. This commit combines the changes together.
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/builtin.zig9
-rw-r--r--lib/std/c.zig4
-rw-r--r--lib/std/crypto/aes.zig10
-rw-r--r--lib/std/crypto/aes/aesni.zig1
-rw-r--r--lib/std/crypto/aes/armcrypto.zig490
-rw-r--r--lib/std/crypto/ghash.zig20
-rw-r--r--lib/std/event.zig2
-rw-r--r--lib/std/event/loop.zig2
-rw-r--r--lib/std/event/wait_group.zig120
-rw-r--r--lib/std/fmt.zig7
-rw-r--r--lib/std/math.zig13
-rw-r--r--lib/std/os/linux/bpf/kern.zig50
-rw-r--r--lib/std/os/uefi.zig6
-rw-r--r--lib/std/os/uefi/protocols/hii.zig2
-rw-r--r--lib/std/os/windows/bits.zig30
-rw-r--r--lib/std/os/windows/ws2_32.zig2
-rw-r--r--lib/std/zig/ast.zig2
-rw-r--r--lib/std/zig/parse.zig3
-rw-r--r--lib/std/zig/render.zig14
-rw-r--r--lib/std/zig/tokenizer.zig3
20 files changed, 732 insertions, 58 deletions
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index 68bbbe3b2d..8543461f33 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -151,7 +151,6 @@ pub const Mode = enum {
pub const CallingConvention = enum {
Unspecified,
C,
- Cold,
Naked,
Async,
Interrupt,
@@ -199,7 +198,7 @@ pub const TypeInfo = union(enum) {
Union: Union,
Fn: Fn,
BoundFn: Fn,
- Opaque: void,
+ Opaque: Opaque,
Frame: Frame,
AnyFrame: AnyFrame,
Vector: Vector,
@@ -362,6 +361,12 @@ pub const TypeInfo = union(enum) {
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
+ pub const Opaque = struct {
+ decls: []const Declaration,
+ };
+
+ /// This data structure is used by the Zig language code generation and
+ /// therefore must be kept in sync with the compiler implementation.
pub const Frame = struct {
function: anytype,
};
diff --git a/lib/std/c.zig b/lib/std/c.zig
index 7cfc44714f..a75fcaa84b 100644
--- a/lib/std/c.zig
+++ b/lib/std/c.zig
@@ -329,8 +329,8 @@ pub extern "c" fn pthread_cond_signal(cond: *pthread_cond_t) c_int;
pub extern "c" fn pthread_cond_broadcast(cond: *pthread_cond_t) c_int;
pub extern "c" fn pthread_cond_destroy(cond: *pthread_cond_t) c_int;
-pub const pthread_t = *@Type(.Opaque);
-pub const FILE = @Type(.Opaque);
+pub const pthread_t = *opaque {};
+pub const FILE = opaque {};
pub extern "c" fn dlopen(path: [*:0]const u8, mode: c_int) ?*c_void;
pub extern "c" fn dlclose(handle: *c_void) c_int;
diff --git a/lib/std/crypto/aes.zig b/lib/std/crypto/aes.zig
index 7c509b297f..9040524939 100644
--- a/lib/std/crypto/aes.zig
+++ b/lib/std/crypto/aes.zig
@@ -10,7 +10,15 @@ const builtin = std.builtin;
const has_aesni = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .aes);
const has_avx = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .avx);
-const impl = if (std.Target.current.cpu.arch == .x86_64 and has_aesni and has_avx) @import("aes/aesni.zig") else @import("aes/soft.zig");
+const has_armaes = comptime std.Target.aarch64.featureSetHas(std.Target.current.cpu.features, .aes);
+const impl = if (std.Target.current.cpu.arch == .x86_64 and has_aesni and has_avx) impl: {
+ break :impl @import("aes/aesni.zig");
+} else if (std.Target.current.cpu.arch == .aarch64 and has_armaes)
+impl: {
+ break :impl @import("aes/armcrypto.zig");
+} else impl: {
+ break :impl @import("aes/soft.zig");
+};
pub const Block = impl.Block;
pub const AESEncryptCtx = impl.AESEncryptCtx;
diff --git a/lib/std/crypto/aes/aesni.zig b/lib/std/crypto/aes/aesni.zig
index 47dd029bec..c1c077a988 100644
--- a/lib/std/crypto/aes/aesni.zig
+++ b/lib/std/crypto/aes/aesni.zig
@@ -3,7 +3,6 @@
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
// The MIT license requires this copyright notice to be included in all copies
// and substantial portions of the software.
-// Based on Go stdlib implementation
const std = @import("../../std.zig");
const mem = std.mem;
diff --git a/lib/std/crypto/aes/armcrypto.zig b/lib/std/crypto/aes/armcrypto.zig
new file mode 100644
index 0000000000..b1d8252c94
--- /dev/null
+++ b/lib/std/crypto/aes/armcrypto.zig
@@ -0,0 +1,490 @@
+// SPDX-License-Identifier: MIT
+// Copyright (c) 2015-2020 Zig Contributors
+// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
+// The MIT license requires this copyright notice to be included in all copies
+// and substantial portions of the software.
+
+const std = @import("../../std.zig");
+const mem = std.mem;
+const debug = std.debug;
+const Vector = std.meta.Vector;
+
+const BlockVec = Vector(2, u64);
+
+/// A single AES block.
+pub const Block = struct {
+ pub const block_size: usize = 16;
+
+ /// Internal representation of a block.
+ repr: BlockVec,
+
+ /// Convert a byte sequence into an internal representation.
+ pub inline fn fromBytes(bytes: *const [16]u8) Block {
+ const repr = mem.bytesToValue(BlockVec, bytes);
+ return Block{ .repr = repr };
+ }
+
+ /// Convert the internal representation of a block into a byte sequence.
+ pub inline fn toBytes(block: Block) [16]u8 {
+ return mem.toBytes(block.repr);
+ }
+
+ /// XOR the block with a byte sequence.
+ pub inline fn xorBytes(block: Block, bytes: *const [16]u8) [16]u8 {
+ const x = block.repr ^ fromBytes(bytes).repr;
+ return mem.toBytes(x);
+ }
+
+ const zero = Vector(2, u64){ 0, 0 };
+
+ /// Encrypt a block with a round key.
+ pub inline fn encrypt(block: Block, round_key: Block) Block {
+ return Block{
+ .repr = asm (
+ \\ mov %[out].16b, %[in].16b
+ \\ aese %[out].16b, %[zero].16b
+ \\ aesmc %[out].16b, %[out].16b
+ \\ eor %[out].16b, %[out].16b, %[rk].16b
+ : [out] "=&x" (-> BlockVec)
+ : [in] "x" (block.repr),
+ [rk] "x" (round_key.repr),
+ [zero] "x" (zero)
+ ),
+ };
+ }
+
+ /// Encrypt a block with the last round key.
+ pub inline fn encryptLast(block: Block, round_key: Block) Block {
+ return Block{
+ .repr = asm (
+ \\ mov %[out].16b, %[in].16b
+ \\ aese %[out].16b, %[zero].16b
+ \\ eor %[out].16b, %[out].16b, %[rk].16b
+ : [out] "=&x" (-> BlockVec)
+ : [in] "x" (block.repr),
+ [rk] "x" (round_key.repr),
+ [zero] "x" (zero)
+ ),
+ };
+ }
+
+ /// Decrypt a block with a round key.
+ pub inline fn decrypt(block: Block, inv_round_key: Block) Block {
+ return Block{
+ .repr = asm (
+ \\ mov %[out].16b, %[in].16b
+ \\ aesd %[out].16b, %[zero].16b
+ \\ aesimc %[out].16b, %[out].16b
+ \\ eor %[out].16b, %[out].16b, %[rk].16b
+ : [out] "=&x" (-> BlockVec)
+ : [in] "x" (block.repr),
+ [rk] "x" (inv_round_key.repr),
+ [zero] "x" (zero)
+ ),
+ };
+ }
+
+ /// Decrypt a block with the last round key.
+ pub inline fn decryptLast(block: Block, inv_round_key: Block) Block {
+ return Block{
+ .repr = asm (
+ \\ mov %[out].16b, %[in].16b
+ \\ aesd %[out].16b, %[zero].16b
+ \\ eor %[out].16b, %[out].16b, %[rk].16b
+ : [out] "=&x" (-> BlockVec)
+ : [in] "x" (block.repr),
+ [rk] "x" (inv_round_key.repr),
+ [zero] "x" (zero)
+ ),
+ };
+ }
+
+ /// Apply the bitwise XOR operation to the content of two blocks.
+ pub inline fn xorBlocks(block1: Block, block2: Block) Block {
+ return Block{ .repr = block1.repr ^ block2.repr };
+ }
+
+ /// Apply the bitwise AND operation to the content of two blocks.
+ pub inline fn andBlocks(block1: Block, block2: Block) Block {
+ return Block{ .repr = block1.repr & block2.repr };
+ }
+
+ /// Apply the bitwise OR operation to the content of two blocks.
+ pub inline fn orBlocks(block1: Block, block2: Block) Block {
+ return Block{ .repr = block1.repr | block2.repr };
+ }
+
+ /// Perform operations on multiple blocks in parallel.
+ pub const parallel = struct {
+ /// The recommended number of AES encryption/decryption to perform in parallel for the chosen implementation.
+ pub const optimal_parallel_blocks = 8;
+
+ /// Encrypt multiple blocks in parallel, each their own round key.
+ pub inline fn encryptParallel(comptime count: usize, blocks: [count]Block, round_keys: [count]Block) [count]Block {
+ comptime var i = 0;
+ var out: [count]Block = undefined;
+ inline while (i < count) : (i += 1) {
+ out[i] = blocks[i].encrypt(round_keys[i]);
+ }
+ return out;
+ }
+
+ /// Decrypt multiple blocks in parallel, each their own round key.
+ pub inline fn decryptParallel(comptime count: usize, blocks: [count]Block, round_keys: [count]Block) [count]Block {
+ comptime var i = 0;
+ var out: [count]Block = undefined;
+ inline while (i < count) : (i += 1) {
+ out[i] = blocks[i].decrypt(round_keys[i]);
+ }
+ return out;
+ }
+
+ /// Encrypt multple blocks in parallel with the same round key.
+ pub inline fn encryptWide(comptime count: usize, blocks: [count]Block, round_key: Block) [count]Block {
+ comptime var i = 0;
+ var out: [count]Block = undefined;
+ inline while (i < count) : (i += 1) {
+ out[i] = blocks[i].encrypt(round_key);
+ }
+ return out;
+ }
+
+ /// Decrypt multple blocks in parallel with the same round key.
+ pub inline fn decryptWide(comptime count: usize, blocks: [count]Block, round_key: Block) [count]Block {
+ comptime var i = 0;
+ var out: [count]Block = undefined;
+ inline while (i < count) : (i += 1) {
+ out[i] = blocks[i].decrypt(round_key);
+ }
+ return out;
+ }
+
+ /// Encrypt multple blocks in parallel with the same last round key.
+ pub inline fn encryptLastWide(comptime count: usize, blocks: [count]Block, round_key: Block) [count]Block {
+ comptime var i = 0;
+ var out: [count]Block = undefined;
+ inline while (i < count) : (i += 1) {
+ out[i] = blocks[i].encryptLast(round_key);
+ }
+ return out;
+ }
+
+ /// Decrypt multple blocks in parallel with the same last round key.
+ pub inline fn decryptLastWide(comptime count: usize, blocks: [count]Block, round_key: Block) [count]Block {
+ comptime var i = 0;
+ var out: [count]Block = undefined;
+ inline while (i < count) : (i += 1) {
+ out[i] = blocks[i].decryptLast(round_key);
+ }
+ return out;
+ }
+ };
+};
+
+fn KeySchedule(comptime AES: type) type {
+ std.debug.assert(AES.rounds == 10 or AES.rounds == 14);
+ const rounds = AES.rounds;
+
+ return struct {
+ const Self = @This();
+
+ const zero = Vector(2, u64){ 0, 0 };
+ const mask1 = @Vector(16, u8){ 13, 14, 15, 12, 13, 14, 15, 12, 13, 14, 15, 12, 13, 14, 15, 12 };
+ const mask2 = @Vector(16, u8){ 12, 13, 14, 15, 12, 13, 14, 15, 12, 13, 14, 15, 12, 13, 14, 15 };
+
+ round_keys: [rounds + 1]Block,
+
+ fn drc128(comptime rc: u8, t: BlockVec) BlockVec {
+ var v1: BlockVec = undefined;
+ var v2: BlockVec = undefined;
+ var v3: BlockVec = undefined;
+ var v4: BlockVec = undefined;
+
+ return asm (
+ \\ movi %[v2].4s, %[rc]
+ \\ tbl %[v4].16b, {%[t].16b}, %[mask].16b
+ \\ ext %[r].16b, %[zero].16b, %[t].16b, #12
+ \\ aese %[v4].16b, %[zero].16b
+ \\ eor %[v2].16b, %[r].16b, %[v2].16b
+ \\ ext %[r].16b, %[zero].16b, %[r].16b, #12
+ \\ eor %[v1].16b, %[v2].16b, %[t].16b
+ \\ ext %[v3].16b, %[zero].16b, %[r].16b, #12
+ \\ eor %[v1].16b, %[v1].16b, %[r].16b
+ \\ eor %[r].16b, %[v1].16b, %[v3].16b
+ \\ eor %[r].16b, %[r].16b, %[v4].16b
+ : [r] "=&x" (-> BlockVec),
+ [v1] "=&x" (v1),
+ [v2] "=&x" (v2),
+ [v3] "=&x" (v3),
+ [v4] "=&x" (v4)
+ : [rc] "N" (rc),
+ [t] "x" (t),
+ [zero] "x" (zero),
+ [mask] "x" (mask1)
+ );
+ }
+
+ fn drc256(comptime second: bool, comptime rc: u8, t: BlockVec, tx: BlockVec) BlockVec {
+ var v1: BlockVec = undefined;
+ var v2: BlockVec = undefined;
+ var v3: BlockVec = undefined;
+ var v4: BlockVec = undefined;
+
+ return asm (
+ \\ movi %[v2].4s, %[rc]
+ \\ tbl %[v4].16b, {%[t].16b}, %[mask].16b
+ \\ ext %[r].16b, %[zero].16b, %[tx].16b, #12
+ \\ aese %[v4].16b, %[zero].16b
+ \\ eor %[v1].16b, %[tx].16b, %[r].16b
+ \\ ext %[r].16b, %[zero].16b, %[r].16b, #12
+ \\ eor %[v1].16b, %[v1].16b, %[r].16b
+ \\ ext %[v3].16b, %[zero].16b, %[r].16b, #12
+ \\ eor %[v1].16b, %[v1].16b, %[v2].16b
+ \\ eor %[v1].16b, %[v1].16b, %[v3].16b
+ \\ eor %[r].16b, %[v1].16b, %[v4].16b
+ : [r] "=&x" (-> BlockVec),
+ [v1] "=&x" (v1),
+ [v2] "=&x" (v2),
+ [v3] "=&x" (v3),
+ [v4] "=&x" (v4)
+ : [rc] "N" (if (second) @as(u8, 0) else rc),
+ [t] "x" (t),
+ [tx] "x" (tx),
+ [zero] "x" (zero),
+ [mask] "x" (if (second) mask2 else mask1)
+ );
+ }
+
+ fn expand128(t1: *Block) Self {
+ var round_keys: [11]Block = undefined;
+ const rcs = [_]u8{ 1, 2, 4, 8, 16, 32, 64, 128, 27, 54 };
+ inline for (rcs) |rc, round| {
+ round_keys[round] = t1.*;
+ t1.repr = drc128(rc, t1.repr);
+ }
+ round_keys[rcs.len] = t1.*;
+ return Self{ .round_keys = round_keys };
+ }
+
+ fn expand256(t1: *Block, t2: *Block) Self {
+ var round_keys: [15]Block = undefined;
+ const rcs = [_]u8{ 1, 2, 4, 8, 16, 32 };
+ round_keys[0] = t1.*;
+ inline for (rcs) |rc, round| {
+ round_keys[round * 2 + 1] = t2.*;
+ t1.repr = drc256(false, rc, t2.repr, t1.repr);
+ round_keys[round * 2 + 2] = t1.*;
+ t2.repr = drc256(true, rc, t1.repr, t2.repr);
+ }
+ round_keys[rcs.len * 2 + 1] = t2.*;
+ t1.repr = drc256(false, 64, t2.repr, t1.repr);
+ round_keys[rcs.len * 2 + 2] = t1.*;
+ return Self{ .round_keys = round_keys };
+ }
+
+ /// Invert the key schedule.
+ pub fn invert(key_schedule: Self) Self {
+ const round_keys = &key_schedule.round_keys;
+ var inv_round_keys: [rounds + 1]Block = undefined;
+ inv_round_keys[0] = round_keys[rounds];
+ comptime var i = 1;
+ inline while (i < rounds) : (i += 1) {
+ inv_round_keys[i] = Block{
+ .repr = asm (
+ \\ aesimc %[inv_rk].16b, %[rk].16b
+ : [inv_rk] "=x" (-> BlockVec)
+ : [rk] "x" (round_keys[rounds - i].repr)
+ ),
+ };
+ }
+ inv_round_keys[rounds] = round_keys[0];
+ return Self{ .round_keys = inv_round_keys };
+ }
+ };
+}
+
+/// A context to perform encryption using the standard AES key schedule.
+pub fn AESEncryptCtx(comptime AES: type) type {
+ std.debug.assert(AES.key_bits == 128 or AES.key_bits == 256);
+ const rounds = AES.rounds;
+
+ return struct {
+ const Self = @This();
+ pub const block = AES.block;
+ pub const block_size = block.block_size;
+ key_schedule: KeySchedule(AES),
+
+ /// Create a new encryption context with the given key.
+ pub fn init(key: [AES.key_bits / 8]u8) Self {
+ var t1 = Block.fromBytes(key[0..16]);
+ const key_schedule = if (AES.key_bits == 128) ks: {
+ break :ks KeySchedule(AES).expand128(&t1);
+ } else ks: {
+ var t2 = Block.fromBytes(key[16..32]);
+ break :ks KeySchedule(AES).expand256(&t1, &t2);
+ };
+ return Self{
+ .key_schedule = key_schedule,
+ };
+ }
+
+ /// Encrypt a single block.
+ pub fn encrypt(ctx: Self, dst: *[16]u8, src: *const [16]u8) void {
+ const round_keys = ctx.key_schedule.round_keys;
+ var t = Block.fromBytes(src).xorBlocks(round_keys[0]);
+ comptime var i = 1;
+ inline while (i < rounds) : (i += 1) {
+ t = t.encrypt(round_keys[i]);
+ }
+ t = t.encryptLast(round_keys[rounds]);
+ dst.* = t.toBytes();
+ }
+
+ /// Encrypt+XOR a single block.
+ pub fn xor(ctx: Self, dst: *[16]u8, src: *const [16]u8, counter: [16]u8) void {
+ const round_keys = ctx.key_schedule.round_keys;
+ var t = Block.fromBytes(&counter).xorBlocks(round_keys[0]);
+ comptime var i = 1;
+ inline while (i < rounds) : (i += 1) {
+ t = t.encrypt(round_keys[i]);
+ }
+ t = t.encryptLast(round_keys[rounds]);
+ dst.* = t.xorBytes(src);
+ }
+
+ /// Encrypt multiple blocks, possibly leveraging parallelization.
+ pub fn encryptWide(ctx: Self, comptime count: usize, dst: *[16 * count]u8, src: *const [16 * count]u8) void {
+ const round_keys = ctx.key_schedule.round_keys;
+ var ts: [count]Block = undefined;
+ comptime var j = 0;
+ inline while (j < count) : (j += 1) {
+ ts[j] = Block.fromBytes(src[j * 16 .. j * 16 + 16][0..16]).xorBlocks(round_keys[0]);
+ }
+ comptime var i = 1;
+ inline while (i < rounds) : (i += 1) {
+ ts = Block.parallel.encryptWide(count, ts, round_keys[i]);
+ }
+ i = 1;
+ inline while (i < count) : (i += 1) {
+ ts = Block.parallel.encryptLastWide(count, ts, round_keys[i]);
+ }
+ j = 0;
+ inline while (j < count) : (j += 1) {
+ dst[16 * j .. 16 * j + 16].* = ts[j].toBytes();
+ }
+ }
+
+ /// Encrypt+XOR multiple blocks, possibly leveraging parallelization.
+ pub fn xorWide(ctx: Self, comptime count: usize, dst: *[16 * count]u8, src: *const [16 * count]u8, counters: [16 * count]u8) void {
+ const round_keys = ctx.key_schedule.round_keys;
+ var ts: [count]Block = undefined;
+ comptime var j = 0;
+ inline while (j < count) : (j += 1) {
+ ts[j] = Block.fromBytes(counters[j * 16 .. j * 16 + 16][0..16]).xorBlocks(round_keys[0]);
+ }
+ comptime var i = 1;
+ inline while (i < rounds) : (i += 1) {
+ ts = Block.parallel.encryptWide(count, ts, round_keys[i]);
+ }
+ ts = Block.parallel.encryptLastWide(count, ts, round_keys[i]);
+ j = 0;
+ inline while (j < count) : (j += 1) {
+ dst[16 * j .. 16 * j + 16].* = ts[j].xorBytes(src[16 * j .. 16 * j + 16]);
+ }
+ }
+ };
+}
+
+/// A context to perform decryption using the standard AES key schedule.
+pub fn AESDecryptCtx(comptime AES: type) type {
+ std.debug.assert(AES.key_bits == 128 or AES.key_bits == 256);
+ const rounds = AES.rounds;
+
+ return struct {
+ const Self = @This();
+ pub const block = AES.block;
+ pub const block_size = block.block_size;
+ key_schedule: KeySchedule(AES),
+
+ /// Create a decryption context from an existing encryption context.
+ pub fn initFromEnc(ctx: AESEncryptCtx(AES)) Self {
+ return Self{
+ .key_schedule = ctx.key_schedule.invert(),
+ };
+ }
+
+ /// Create a new decryption context with the given key.
+ pub fn init(key: [AES.key_bits / 8]u8) Self {
+ const enc_ctx = AESEncryptCtx(AES).init(key);
+ return initFromEnc(enc_ctx);
+ }
+
+ /// Decrypt a single block.
+ pub fn decrypt(ctx: Self, dst: *[16]u8, src: *const [16]u8) void {
+ const inv_round_keys = ctx.key_schedule.round_keys;
+ var t = Block.fromBytes(src).xorBlocks(inv_round_keys[0]);
+ comptime var i = 1;
+ inline while (i < rounds) : (i += 1) {
+ t = t.decrypt(inv_round_keys[i]);
+ }
+ t = t.decryptLast(inv_round_keys[rounds]);
+ dst.* = t.toBytes();
+ }
+
+ /// Decrypt multiple blocks, possibly leveraging parallelization.
+ pub fn decryptWide(ctx: Self, comptime count: usize, dst: *[16 * count]u8, src: *const [16 * count]u8) void {
+ const inv_round_keys = ctx.key_schedule.round_keys;
+ var ts: [count]Block = undefined;
+ comptime var j = 0;
+ inline while (j < count) : (j += 1) {
+ ts[j] = Block.fromBytes(src[j * 16 .. j * 16 + 16][0..16]).xorBlocks(inv_round_keys[0]);
+ }
+ comptime var i = 1;
+ inline while (i < rounds) : (i += 1) {
+ ts = Block.parallel.decryptWide(count, ts, inv_round_keys[i]);
+ }
+ i = 1;
+ inline while (i < count) : (i += 1) {
+ ts = Block.parallel.decryptLastWide(count, ts, inv_round_keys[i]);
+ }
+ j = 0;
+ inline while (j < count) : (j += 1) {
+ dst[16 * j .. 16 * j + 16].* = ts[j].toBytes();
+ }
+ }
+ };
+}
+
+/// AES-128 with the standard key schedule.
+pub const AES128 = struct {
+ pub const key_bits: usize = 128;
+ pub const rounds = ((key_bits - 64) / 32 + 8);
+ pub const block = Block;
+
+ /// Create a new context for encryption.
+ pub fn initEnc(key: [key_bits / 8]u8) AESEncryptCtx(AES128) {
+ return AESEncryptCtx(AES128).init(key);
+ }
+
+ /// Create a new context for decryption.
+ pub fn initDec(key: [key_bits / 8]u8) AESDecryptCtx(AES128) {
+ return AESDecryptCtx(AES128).init(key);
+ }
+};
+
+/// AES-256 with the standard key schedule.
+pub const AES256 = struct {
+ pub const key_bits: usize = 256;
+ pub const rounds = ((key_bits - 64) / 32 + 8);
+ pub const block = Block;
+
+ /// Create a new context for encryption.
+ pub fn initEnc(key: [key_bits / 8]u8) AESEncryptCtx(AES256) {
+ return AESEncryptCtx(AES256).init(key);
+ }
+
+ /// Create a new context for decryption.
+ pub fn initDec(key: [key_bits / 8]u8) AESDecryptCtx(AES256) {
+ return AESDecryptCtx(AES256).init(key);
+ }
+};
diff --git a/lib/std/crypto/ghash.zig b/lib/std/crypto/ghash.zig
index 04bc6a8275..83446f280b 100644
--- a/lib/std/crypto/ghash.zig
+++ b/lib/std/crypto/ghash.zig
@@ -105,6 +105,17 @@ pub const Ghash = struct {
return product[0];
}
+ inline fn clmul_pmull(x: u64, y: u64) u64 {
+ const Vector = std.meta.Vector;
+ const product = asm (
+ \\ pmull %[out].1q, %[x].1d, %[y].1d
+ : [out] "=w" (-> Vector(2, u64))
+ : [x] "w" (@bitCast(Vector(2, u64), @as(u128, x))),
+ [y] "w" (@bitCast(Vector(2, u64), @as(u128, y)))
+ );
+ return product[0];
+ }
+
fn clmul_soft(x: u64, y: u64) u64 {
const x0 = x & 0x1111111111111111;
const x1 = x & 0x2222222222222222;
@@ -127,7 +138,14 @@ pub const Ghash = struct {
const has_pclmul = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .pclmul);
const has_avx = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .avx);
- const clmul = if (std.Target.current.cpu.arch == .x86_64 and has_pclmul and has_avx) clmul_pclmul else clmul_soft;
+ const has_armaes = comptime std.Target.aarch64.featureSetHas(std.Target.current.cpu.features, .aes);
+ const clmul = if (std.Target.current.cpu.arch == .x86_64 and has_pclmul and has_avx) impl: {
+ break :impl clmul_pclmul;
+ } else if (std.Target.current.cpu.arch == .aarch64 and has_armaes) impl: {
+ break :impl clmul_pmull;
+ } else impl: {
+ break :impl clmul_soft;
+ };
fn blocks(st: *Ghash, msg: []const u8) void {
assert(msg.len % 16 == 0); // GHASH blocks() expects full blocks
diff --git a/lib/std/event.zig b/lib/std/event.zig
index 42f3176a1b..eeee8be65b 100644
--- a/lib/std/event.zig
+++ b/lib/std/event.zig
@@ -12,6 +12,7 @@ pub const Locked = @import("event/locked.zig").Locked;
pub const RwLock = @import("event/rwlock.zig").RwLock;
pub const RwLocked = @import("event/rwlocked.zig").RwLocked;
pub const Loop = @import("event/loop.zig").Loop;
+pub const WaitGroup = @import("event/WaitGroup.zig").WaitGroup;
test "import event tests" {
_ = @import("event/channel.zig");
@@ -23,4 +24,5 @@ test "import event tests" {
_ = @import("event/rwlock.zig");
_ = @import("event/rwlocked.zig");
_ = @import("event/loop.zig");
+ _ = @import("event/wait_group.zig");
}
diff --git a/lib/std/event/loop.zig b/lib/std/event/loop.zig
index 226d5f1d52..a064f711e2 100644
--- a/lib/std/event/loop.zig
+++ b/lib/std/event/loop.zig
@@ -660,9 +660,11 @@ pub const Loop = struct {
const Wrapper = struct {
const Args = @TypeOf(args);
fn run(func_args: Args, loop: *Loop, allocator: *mem.Allocator) void {
+ loop.beginOneEvent();
loop.yield();
const result = @call(.{}, func, func_args);
suspend {
+ loop.finishOneEvent();
allocator.destroy(@frame());
}
}
diff --git a/lib/std/event/wait_group.zig b/lib/std/event/wait_group.zig
new file mode 100644
index 0000000000..f0222e7644
--- /dev/null
+++ b/lib/std/event/wait_group.zig
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: MIT
+// Copyright (c) 2015-2020 Zig Contributors
+// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
+// The MIT license requires this copyright notice to be included in all copies
+// and substantial portions of the software.
+const std = @import("../std.zig");
+const builtin = @import("builtin");
+const Loop = std.event.Loop;
+
+/// A WaitGroup keeps track and waits for a group of async tasks to finish.
+/// Call `begin` when creating new tasks, and have tasks call `finish` when done.
+/// You can provide a count for both operations to perform them in bulk.
+/// Call `wait` to suspend until all tasks are completed.
+/// Multiple waiters are supported.
+///
+/// WaitGroup is an instance of WaitGroupGeneric, which takes in a bitsize
+/// for the internal counter. WaitGroup defaults to a `usize` counter.
+/// It's also possible to define a max value for the counter so that
+/// `begin` will return error.Overflow when the limit is reached, even
+/// if the integer type has not has not overflowed.
+/// By default `max_value` is set to std.math.maxInt(CounterType).
+pub const WaitGroup = WaitGroupGeneric(std.meta.bitCount(usize));
+
+pub fn WaitGroupGeneric(comptime counter_size: u16) type {
+ const CounterType = std.meta.Int(false, counter_size);
+
+ const global_event_loop = Loop.instance orelse
+ @compileError("std.event.WaitGroup currently only works with event-based I/O");
+
+ return struct {
+ counter: CounterType = 0,
+ max_counter: CounterType = std.math.maxInt(CounterType),
+ mutex: std.Mutex = .{},
+ waiters: ?*Waiter = null,
+ const Waiter = struct {
+ next: ?*Waiter,
+ tail: *Waiter,
+ node: Loop.NextTickNode,
+ };
+
+ const Self = @This();
+ pub fn begin(self: *Self, count: CounterType) error{Overflow}!void {
+ const held = self.mutex.acquire();
+ defer held.release();
+
+ const new_counter = try std.math.add(CounterType, self.counter, count);
+ if (new_counter > self.max_counter) return error.Overflow;
+ self.counter = new_counter;
+ }
+
+ pub fn finish(self: *Self, count: CounterType) void {
+ var waiters = blk: {
+ const held = self.mutex.acquire();
+ defer held.release();
+ self.counter = std.math.sub(CounterType, self.counter, count) catch unreachable;
+ if (self.counter == 0) {
+ const temp = self.waiters;
+ self.waiters = null;
+ break :blk temp;
+ }
+ break :blk null;
+ };
+
+ // We don't need to hold the lock to reschedule any potential waiter.
+ while (waiters) |w| {
+ const temp_w = w;
+ waiters = w.next;
+ global_event_loop.onNextTick(&temp_w.node);
+ }
+ }
+
+ pub fn wait(self: *Self) void {
+ const held = self.mutex.acquire();
+
+ if (self.counter == 0) {
+ held.release();
+ return;
+ }
+
+ var self_waiter: Waiter = undefined;
+ self_waiter.node.data = @frame();
+ if (self.waiters) |head| {
+ head.tail.next = &self_waiter;
+ head.tail = &self_waiter;
+ } else {
+ self.waiters = &self_waiter;
+ self_waiter.tail = &self_waiter;
+ self_waiter.next = null;
+ }
+ suspend {
+ held.release();
+ }
+ }
+ };
+}
+
+test "basic WaitGroup usage" {
+ if (!std.io.is_async) return error.SkipZigTest;
+
+ // TODO https://github.com/ziglang/zig/issues/1908
+ if (builtin.single_threaded) return error.SkipZigTest;
+
+ // TODO https://github.com/ziglang/zig/issues/3251
+ if (builtin.os.tag == .freebsd) return error.SkipZigTest;
+
+ var initial_wg = WaitGroup{};
+ var final_wg = WaitGroup{};
+
+ try initial_wg.begin(1);
+ try final_wg.begin(1);
+ var task_frame = async task(&initial_wg, &final_wg);
+ initial_wg.finish(1);
+ final_wg.wait();
+ await task_frame;
+}
+
+fn task(wg_i: *WaitGroup, wg_f: *WaitGroup) void {
+ wg_i.wait();
+ wg_f.finish(1);
+}
diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig
index ab2cc1577d..ce90f67585 100644
--- a/lib/std/fmt.zig
+++ b/lib/std/fmt.zig
@@ -1181,13 +1181,16 @@ fn bufPrintIntToSlice(buf: []u8, value: anytype, base: u8, uppercase: bool, opti
return buf[0..formatIntBuf(buf, value, base, uppercase, options)];
}
-pub fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [count(fmt, args)]u8 {
- comptime var buf: [count(fmt, args)]u8 = undefined;
+pub fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [count(fmt, args):0]u8 {
+ comptime var buf: [count(fmt, args):0]u8 = undefined;
_ = bufPrint(&buf, fmt, args) catch unreachable;
+ buf[buf.len] = 0;
return &buf;
}
test "comptimePrint" {
+ @setEvalBranchQuota(2000);
+ std.testing.expectEqual(*const [3:0]u8, @TypeOf(comptime comptimePrint("{}", .{100})));
std.testing.expectEqualSlices(u8, "100", comptime comptimePrint("{}", .{100}));
}
diff --git a/lib/std/math.zig b/lib/std/math.zig
index f05c967b2d..a1db1309c9 100644
--- a/lib/std/math.zig
+++ b/lib/std/math.zig
@@ -110,7 +110,12 @@ pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) bool {
}
pub fn doNotOptimizeAway(value: anytype) void {
- mem.doNotOptimizeAway(value);
+ // TODO: use @declareSideEffect() when it is available.
+ // https://github.com/ziglang/zig/issues/6168
+ const T = @TypeOf(value);
+ var x: T = undefined;
+ const p = @ptrCast(*volatile T, &x);
+ p.* = x;
}
pub fn raiseInvalid() void {
@@ -1131,3 +1136,9 @@ test "compare between signed and unsigned" {
testing.expect(!compare(@as(u8, 255), .eq, @as(i8, -1)));
testing.expect(compare(@as(u8, 1), .eq, @as(u8, 1)));
}
+
+test "math.comptime" {
+ comptime const v = sin(@as(f32, 1)) + ln(@as(f32, 5));
+ testing.expect(v == sin(@as(f32, 1)) + ln(@as(f32, 5)));
+}
+
diff --git a/lib/std/os/linux/bpf/kern.zig b/lib/std/os/linux/bpf/kern.zig
index 3bd605301a..a2e9d36aa1 100644
--- a/lib/std/os/linux/bpf/kern.zig
+++ b/lib/std/os/linux/bpf/kern.zig
@@ -12,28 +12,28 @@ const in_bpf_program = switch (std.builtin.arch) {
pub const helpers = if (in_bpf_program) @import("helpers.zig") else struct {};
-pub const BpfSock = @Type(.Opaque);
-pub const BpfSockAddr = @Type(.Opaque);
-pub const FibLookup = @Type(.Opaque);
-pub const MapDef = @Type(.Opaque);
-pub const PerfEventData = @Type(.Opaque);
-pub const PerfEventValue = @Type(.Opaque);
-pub const PidNsInfo = @Type(.Opaque);
-pub const SeqFile = @Type(.Opaque);
-pub const SkBuff = @Type(.Opaque);
-pub const SkMsgMd = @Type(.Opaque);
-pub const SkReusePortMd = @Type(.Opaque);
-pub const Sock = @Type(.Opaque);
-pub const SockAddr = @Type(.Opaque);
-pub const SockOps = @Type(.Opaque);
-pub const SockTuple = @Type(.Opaque);
-pub const SpinLock = @Type(.Opaque);
-pub const SysCtl = @Type(.Opaque);
-pub const Tcp6Sock = @Type(.Opaque);
-pub const TcpRequestSock = @Type(.Opaque);
-pub const TcpSock = @Type(.Opaque);
-pub const TcpTimewaitSock = @Type(.Opaque);
-pub const TunnelKey = @Type(.Opaque);
-pub const Udp6Sock = @Type(.Opaque);
-pub const XdpMd = @Type(.Opaque);
-pub const XfrmState = @Type(.Opaque);
+pub const BpfSock = opaque {};
+pub const BpfSockAddr = opaque {};
+pub const FibLookup = opaque {};
+pub const MapDef = opaque {};
+pub const PerfEventData = opaque {};
+pub const PerfEventValue = opaque {};
+pub const PidNsInfo = opaque {};
+pub const SeqFile = opaque {};
+pub const SkBuff = opaque {};
+pub const SkMsgMd = opaque {};
+pub const SkReusePortMd = opaque {};
+pub const Sock = opaque {};
+pub const SockAddr = opaque {};
+pub const SockOps = opaque {};
+pub const SockTuple = opaque {};
+pub const SpinLock = opaque {};
+pub const SysCtl = opaque {};
+pub const Tcp6Sock = opaque {};
+pub const TcpRequestSock = opaque {};
+pub const TcpSock = opaque {};
+pub const TcpTimewaitSock = opaque {};
+pub const TunnelKey = opaque {};
+pub const Udp6Sock = opaque {};
+pub const XdpMd = opaque {};
+pub const XfrmState = opaque {};
diff --git a/lib/std/os/uefi.zig b/lib/std/os/uefi.zig
index 0127033db2..ba1544105c 100644
--- a/lib/std/os/uefi.zig
+++ b/lib/std/os/uefi.zig
@@ -17,7 +17,7 @@ pub var handle: Handle = undefined;
pub var system_table: *tables.SystemTable = undefined;
/// A handle to an event structure.
-pub const Event = *@Type(.Opaque);
+pub const Event = *opaque {};
/// GUIDs must be align(8)
pub const Guid = extern struct {
@@ -51,7 +51,7 @@ pub const Guid = extern struct {
};
/// An EFI Handle represents a collection of related interfaces.
-pub const Handle = *@Type(.Opaque);
+pub const Handle = *opaque {};
/// This structure represents time information.
pub const Time = extern struct {
@@ -108,4 +108,4 @@ pub const TimeCapabilities = extern struct {
};
/// File Handle as specified in the EFI Shell Spec
-pub const FileHandle = *@Type(.Opaque);
+pub const FileHandle = *opaque {};
diff --git a/lib/std/os/uefi/protocols/hii.zig b/lib/std/os/uefi/protocols/hii.zig
index 960402828e..ed7c40d6ac 100644
--- a/lib/std/os/uefi/protocols/hii.zig
+++ b/lib/std/os/uefi/protocols/hii.zig
@@ -6,7 +6,7 @@
const uefi = @import("std").os.uefi;
const Guid = uefi.Guid;
-pub const HIIHandle = *@Type(.Opaque);
+pub const HIIHandle = *opaque {};
/// The header found at the start of each package.
pub const HIIPackageHeader = packed struct {
diff --git a/lib/std/os/windows/bits.zig b/lib/std/os/windows/bits.zig
index d22f42d6e8..bf786d5c91 100644
--- a/lib/std/os/windows/bits.zig
+++ b/lib/std/os/windows/bits.zig
@@ -32,16 +32,16 @@ pub const UCHAR = u8;
pub const FLOAT = f32;
pub const HANDLE = *c_void;
pub const HCRYPTPROV = ULONG_PTR;
-pub const HBRUSH = *@Type(.Opaque);
-pub const HCURSOR = *@Type(.Opaque);
-pub const HICON = *@Type(.Opaque);
-pub const HINSTANCE = *@Type(.Opaque);
-pub const HMENU = *@Type(.Opaque);
-pub const HMODULE = *@Type(.Opaque);
-pub const HWND = *@Type(.Opaque);
-pub const HDC = *@Type(.Opaque);
-pub const HGLRC = *@Type(.Opaque);
-pub const FARPROC = *@Type(.Opaque);
+pub const HBRUSH = *opaque {};
+pub const HCURSOR = *opaque {};
+pub const HICON = *opaque {};
+pub const HINSTANCE = *opaque {};
+pub const HMENU = *opaque {};
+pub const HMODULE = *opaque {};
+pub const HWND = *opaque {};
+pub const HDC = *opaque {};
+pub const HGLRC = *opaque {};
+pub const FARPROC = *opaque {};
pub const INT = c_int;
pub const LPBYTE = *BYTE;
pub const LPCH = *CHAR;
@@ -81,7 +81,7 @@ pub const WPARAM = usize;
pub const LPARAM = ?*c_void;
pub const LRESULT = ?*c_void;
-pub const va_list = *@Type(.Opaque);
+pub const va_list = *opaque {};
pub const TRUE = 1;
pub const FALSE = 0;
@@ -1175,10 +1175,10 @@ pub const UNICODE_STRING = extern struct {
Buffer: [*]WCHAR,
};
-const ACTIVATION_CONTEXT_DATA = @Type(.Opaque);
-const ASSEMBLY_STORAGE_MAP = @Type(.Opaque);
-const FLS_CALLBACK_INFO = @Type(.Opaque);
-const RTL_BITMAP = @Type(.Opaque);
+const ACTIVATION_CONTEXT_DATA = opaque {};
+const ASSEMBLY_STORAGE_MAP = opaque {};
+const FLS_CALLBACK_INFO = opaque {};
+const RTL_BITMAP = opaque {};
pub const PRTL_BITMAP = *RTL_BITMAP;
const KAFFINITY = usize;
diff --git a/lib/std/os/windows/ws2_32.zig b/lib/std/os/windows/ws2_32.zig
index ac21b6ffc9..19bfc0d83e 100644
--- a/lib/std/os/windows/ws2_32.zig
+++ b/lib/std/os/windows/ws2_32.zig
@@ -5,7 +5,7 @@
// and substantial portions of the software.
usingnamespace @import("bits.zig");
-pub const SOCKET = *@Type(.Opaque);
+pub const SOCKET = *opaque {};
pub const INVALID_SOCKET = @intToPtr(SOCKET, ~@as(usize, 0));
pub const SOCKET_ERROR = -1;
diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig
index d8943adde0..0973877aa8 100644
--- a/lib/std/zig/ast.zig
+++ b/lib/std/zig/ast.zig
@@ -288,7 +288,7 @@ pub const Error = union(enum) {
pub const ExpectedVarDecl = SingleTokenError("Expected variable declaration, found '{}'");
pub const ExpectedFn = SingleTokenError("Expected function, found '{}'");
pub const ExpectedReturnType = SingleTokenError("Expected 'var' or return type expression, found '{}'");
- pub const ExpectedAggregateKw = SingleTokenError("Expected '" ++ Token.Id.Keyword_struct.symbol() ++ "', '" ++ Token.Id.Keyword_union.symbol() ++ "', or '" ++ Token.Id.Keyword_enum.symbol() ++ "', found '{}'");
+ pub const ExpectedAggregateKw = SingleTokenError("Expected '" ++ Token.Id.Keyword_struct.symbol() ++ "', '" ++ Token.Id.Keyword_union.symbol() ++ "', '" ++ Token.Id.Keyword_enum.symbol() ++ "', or '" ++ Token.Id.Keyword_opaque.symbol() ++ "', found '{}'");
pub const ExpectedEqOrSemi = SingleTokenError("Expected '=' or ';', found '{}'");
pub const ExpectedSemiOrLBrace = SingleTokenError("Expected ';' or '{{', found '{}'");
pub const ExpectedSemiOrElse = SingleTokenError("Expected ';' or 'else', found '{}'");
diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig
index 2af2ee4a45..467b06a5ca 100644
--- a/lib/std/zig/parse.zig
+++ b/lib/std/zig/parse.zig
@@ -2896,11 +2896,12 @@ const Parser = struct {
/// <- KEYWORD_struct
/// / KEYWORD_enum (LPAREN Expr RPAREN)?
/// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
+ /// / KEYWORD_opaque
fn parseContainerDeclType(p: *Parser) !?ContainerDeclType {
const kind_token = p.nextToken();
const init_arg_expr = switch (p.token_ids[kind_token]) {
- .Keyword_struct => Node.ContainerDecl.InitArg{ .None = {} },
+ .Keyword_struct, .Keyword_opaque => Node.ContainerDecl.InitArg{ .None = {} },
.Keyword_enum => blk: {
if (p.eatToken(.LParen) != null) {
const expr = try p.expectNode(parseExpr, .{
diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig
index 67afbb77d9..8c8a2fc50b 100644
--- a/lib/std/zig/render.zig
+++ b/lib/std/zig/render.zig
@@ -1492,7 +1492,19 @@ fn renderExpression(
// TODO remove after 0.7.0 release
if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@OpaqueType"))
- return ais.writer().writeAll("@Type(.Opaque)");
+ return ais.writer().writeAll("opaque {}");
+
+ // TODO remove after 0.7.0 release
+ {
+ const params = builtin_call.paramsConst();
+ if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@Type") and
+ params.len == 1)
+ {
+ if (params[0].castTag(.EnumLiteral)) |enum_literal|
+ if (mem.eql(u8, tree.tokenSlice(enum_literal.name), "Opaque"))
+ return ais.writer().writeAll("opaque {}");
+ }
+ }
try renderToken(tree, ais, builtin_call.builtin_token, Space.None); // @name
diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig
index e40483c022..c8f33dbfaa 100644
--- a/lib/std/zig/tokenizer.zig
+++ b/lib/std/zig/tokenizer.zig
@@ -47,6 +47,7 @@ pub const Token = struct {
.{ "noinline", .Keyword_noinline },
.{ "nosuspend", .Keyword_nosuspend },
.{ "null", .Keyword_null },
+ .{ "opaque", .Keyword_opaque },
.{ "or", .Keyword_or },
.{ "orelse", .Keyword_orelse },
.{ "packed", .Keyword_packed },
@@ -173,6 +174,7 @@ pub const Token = struct {
Keyword_noinline,
Keyword_nosuspend,
Keyword_null,
+ Keyword_opaque,
Keyword_or,
Keyword_orelse,
Keyword_packed,
@@ -296,6 +298,7 @@ pub const Token = struct {
.Keyword_noinline => "noinline",
.Keyword_nosuspend => "nosuspend",
.Keyword_null => "null",
+ .Keyword_opaque => "opaque",
.Keyword_or => "or",
.Keyword_orelse => "orelse",
.Keyword_packed => "packed",