Skip to content

Commit

Permalink
Merge pull request #7934 from Vexu/stage2-cbe
Browse files Browse the repository at this point in the history
Stage2 cbe: optionals and errors
  • Loading branch information
andrewrk committed Mar 12, 2021
2 parents a5cb4ab + fc62ff7 commit e9a038c
Show file tree
Hide file tree
Showing 9 changed files with 447 additions and 31 deletions.
45 changes: 24 additions & 21 deletions lib/std/hash_map.zig
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,20 @@ pub fn getAutoEqlFn(comptime K: type) (fn (K, K) bool) {
}

pub fn AutoHashMap(comptime K: type, comptime V: type) type {
return HashMap(K, V, getAutoHashFn(K), getAutoEqlFn(K), DefaultMaxLoadPercentage);
return HashMap(K, V, getAutoHashFn(K), getAutoEqlFn(K), default_max_load_percentage);
}

pub fn AutoHashMapUnmanaged(comptime K: type, comptime V: type) type {
return HashMapUnmanaged(K, V, getAutoHashFn(K), getAutoEqlFn(K), DefaultMaxLoadPercentage);
return HashMapUnmanaged(K, V, getAutoHashFn(K), getAutoEqlFn(K), default_max_load_percentage);
}

/// Builtin hashmap for strings as keys.
pub fn StringHashMap(comptime V: type) type {
return HashMap([]const u8, V, hashString, eqlString, DefaultMaxLoadPercentage);
return HashMap([]const u8, V, hashString, eqlString, default_max_load_percentage);
}

pub fn StringHashMapUnmanaged(comptime V: type) type {
return HashMapUnmanaged([]const u8, V, hashString, eqlString, DefaultMaxLoadPercentage);
return HashMapUnmanaged([]const u8, V, hashString, eqlString, default_max_load_percentage);
}

pub fn eqlString(a: []const u8, b: []const u8) bool {
Expand All @@ -74,7 +74,10 @@ pub fn hashString(s: []const u8) u64 {
return std.hash.Wyhash.hash(0, s);
}

pub const DefaultMaxLoadPercentage = 80;
/// Deprecated use `default_max_load_percentage`
pub const DefaultMaxLoadPercentage = default_max_load_percentage;

pub const default_max_load_percentage = 80;

/// General purpose hash table.
/// No order is guaranteed and any modification invalidates live iterators.
Expand All @@ -89,13 +92,13 @@ pub fn HashMap(
comptime V: type,
comptime hashFn: fn (key: K) u64,
comptime eqlFn: fn (a: K, b: K) bool,
comptime MaxLoadPercentage: u64,
comptime max_load_percentage: u64,
) type {
return struct {
unmanaged: Unmanaged,
allocator: *Allocator,

pub const Unmanaged = HashMapUnmanaged(K, V, hashFn, eqlFn, MaxLoadPercentage);
pub const Unmanaged = HashMapUnmanaged(K, V, hashFn, eqlFn, max_load_percentage);
pub const Entry = Unmanaged.Entry;
pub const Hash = Unmanaged.Hash;
pub const Iterator = Unmanaged.Iterator;
Expand Down Expand Up @@ -251,9 +254,9 @@ pub fn HashMapUnmanaged(
comptime V: type,
hashFn: fn (key: K) u64,
eqlFn: fn (a: K, b: K) bool,
comptime MaxLoadPercentage: u64,
comptime max_load_percentage: u64,
) type {
comptime assert(MaxLoadPercentage > 0 and MaxLoadPercentage < 100);
comptime assert(max_load_percentage > 0 and max_load_percentage < 100);

return struct {
const Self = @This();
Expand All @@ -274,12 +277,12 @@ pub fn HashMapUnmanaged(
// Having a countdown to grow reduces the number of instructions to
// execute when determining if the hashmap has enough capacity already.
/// Number of available slots before a grow is needed to satisfy the
/// `MaxLoadPercentage`.
/// `max_load_percentage`.
available: Size = 0,

// This is purely empirical and not a /very smart magic constant™/.
/// Capacity of the first grow when bootstrapping the hashmap.
const MinimalCapacity = 8;
const minimal_capacity = 8;

// This hashmap is specially designed for sizes that fit in a u32.
const Size = u32;
Expand Down Expand Up @@ -382,7 +385,7 @@ pub fn HashMapUnmanaged(
found_existing: bool,
};

pub const Managed = HashMap(K, V, hashFn, eqlFn, MaxLoadPercentage);
pub const Managed = HashMap(K, V, hashFn, eqlFn, max_load_percentage);

pub fn promote(self: Self, allocator: *Allocator) Managed {
return .{
Expand All @@ -392,7 +395,7 @@ pub fn HashMapUnmanaged(
}

fn isUnderMaxLoadPercentage(size: Size, cap: Size) bool {
return size * 100 < MaxLoadPercentage * cap;
return size * 100 < max_load_percentage * cap;
}

pub fn init(allocator: *Allocator) Self {
Expand Down Expand Up @@ -425,7 +428,7 @@ pub fn HashMapUnmanaged(
}

fn capacityForSize(size: Size) Size {
var new_cap = @truncate(u32, (@as(u64, size) * 100) / MaxLoadPercentage + 1);
var new_cap = @truncate(u32, (@as(u64, size) * 100) / max_load_percentage + 1);
new_cap = math.ceilPowerOfTwo(u32, new_cap) catch unreachable;
return new_cap;
}
Expand All @@ -439,7 +442,7 @@ pub fn HashMapUnmanaged(
if (self.metadata) |_| {
self.initMetadatas();
self.size = 0;
self.available = @truncate(u32, (self.capacity() * MaxLoadPercentage) / 100);
self.available = @truncate(u32, (self.capacity() * max_load_percentage) / 100);
}
}

Expand Down Expand Up @@ -712,9 +715,9 @@ pub fn HashMapUnmanaged(
}

// This counts the number of occupied slots, used + tombstones, which is
// what has to stay under the MaxLoadPercentage of capacity.
// what has to stay under the max_load_percentage of capacity.
fn load(self: *const Self) Size {
const max_load = (self.capacity() * MaxLoadPercentage) / 100;
const max_load = (self.capacity() * max_load_percentage) / 100;
assert(max_load >= self.available);
return @truncate(Size, max_load - self.available);
}
Expand All @@ -733,7 +736,7 @@ pub fn HashMapUnmanaged(
const new_cap = capacityForSize(self.size);
try other.allocate(allocator, new_cap);
other.initMetadatas();
other.available = @truncate(u32, (new_cap * MaxLoadPercentage) / 100);
other.available = @truncate(u32, (new_cap * max_load_percentage) / 100);

var i: Size = 0;
var metadata = self.metadata.?;
Expand All @@ -751,15 +754,15 @@ pub fn HashMapUnmanaged(
}

fn grow(self: *Self, allocator: *Allocator, new_capacity: Size) !void {
const new_cap = std.math.max(new_capacity, MinimalCapacity);
const new_cap = std.math.max(new_capacity, minimal_capacity);
assert(new_cap > self.capacity());
assert(std.math.isPowerOfTwo(new_cap));

var map = Self{};
defer map.deinit(allocator);
try map.allocate(allocator, new_cap);
map.initMetadatas();
map.available = @truncate(u32, (new_cap * MaxLoadPercentage) / 100);
map.available = @truncate(u32, (new_cap * max_load_percentage) / 100);

if (self.size != 0) {
const old_capacity = self.capacity();
Expand Down Expand Up @@ -943,7 +946,7 @@ test "std.hash_map ensureCapacity with existing elements" {

try map.put(0, 0);
expectEqual(map.count(), 1);
expectEqual(map.capacity(), @TypeOf(map).Unmanaged.MinimalCapacity);
expectEqual(map.capacity(), @TypeOf(map).Unmanaged.minimal_capacity);

try map.ensureCapacity(65);
expectEqual(map.count(), 1);
Expand Down
2 changes: 2 additions & 0 deletions src/Compilation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1653,6 +1653,8 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
.error_msg = null,
.decl = decl,
.fwd_decl = fwd_decl.toManaged(module.gpa),
// we don't want to emit optionals and error unions to headers since they have no ABI
.typedefs = undefined,
};
defer dg.fwd_decl.deinit();

Expand Down
2 changes: 2 additions & 0 deletions src/codegen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2267,6 +2267,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
// No side effects, so if it's unreferenced, do nothing.
if (inst.base.isUnused())
return MCValue{ .dead = {} };
if (inst.lhs.ty.zigTypeTag() == .ErrorSet or inst.rhs.ty.zigTypeTag() == .ErrorSet)
return self.fail(inst.base.src, "TODO implement cmp for errors", .{});
switch (arch) {
.x86_64 => {
try self.code.ensureCapacity(self.code.items.len + 8);
Expand Down

0 comments on commit e9a038c

Please sign in to comment.