feature. See also
. The project being documented here (as the example) is the Zig library itself.
Builder.gepConstAssumeCapacity
fn gepConstAssumeCapacity(
self: *Builder,
comptime kind: Constant.GetElementPtr.Kind,
ty: Type,
base: Constant,
inrange: ?u16,
indices: []const Constant,
) Constant
File
Code
fn gepConstAssumeCapacity(
self: *Builder,
comptime kind: Constant.GetElementPtr.Kind,
ty: Type,
base: Constant,
inrange: ?u16,
indices: []const Constant,
) Constant {
const tag: Constant.Tag = switch (kind) {
.normal => .getelementptr,
.inbounds => .@"getelementptr inbounds",
};
const base_ty = base.typeOf(self);
const base_is_vector = base_ty.isVector(self);
const VectorInfo = struct {
kind: Type.Vector.Kind,
len: u32,
fn init(vector_ty: Type, builder: *const Builder) @This() {
return .{ .kind = vector_ty.vectorKind(builder), .len = vector_ty.vectorLen(builder) };
}
};
var vector_info: ?VectorInfo = if (base_is_vector) VectorInfo.init(base_ty, self) else null;
for (indices) |index| {
const index_ty = index.typeOf(self);
switch (index_ty.tag(self)) {
.integer => {},
.vector, .scalable_vector => {
const index_info = VectorInfo.init(index_ty, self);
if (vector_info) |info|
assert(std.meta.eql(info, index_info))
else
vector_info = index_info;
},
else => unreachable,
}
}
if (!base_is_vector) if (vector_info) |info| switch (info.kind) {
inline else => |vector_kind| _ = self.vectorTypeAssumeCapacity(vector_kind, info.len, base_ty),
};
const Key = struct {
type: Type,
base: Constant,
inrange: Constant.GetElementPtr.InRangeIndex,
indices: []const Constant,
};
const Adapter = struct {
builder: *const Builder,
pub fn hash(_: @This(), key: Key) u32 {
var hasher = std.hash.Wyhash.init(comptime std.hash.int(@backingInt(tag)));
hasher.update(std.mem.asBytes(&key.type));
hasher.update(std.mem.asBytes(&key.base));
hasher.update(std.mem.asBytes(&key.inrange));
hasher.update(std.mem.sliceAsBytes(key.indices));
return @truncate(hasher.final());
}
pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
if (ctx.builder.constant_items.items(.tag)[rhs_index] != tag) return false;
const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
var rhs_extra = ctx.builder.constantExtraDataTrail(Constant.GetElementPtr, rhs_data);
const rhs_indices =
rhs_extra.trail.next(rhs_extra.data.info.indices_len, Constant, ctx.builder);
return lhs_key.type == rhs_extra.data.type and lhs_key.base == rhs_extra.data.base and
lhs_key.inrange == rhs_extra.data.info.inrange and
std.mem.eql(Constant, lhs_key.indices, rhs_indices);
}
};
const data = Key{
.type = ty,
.base = base,
.inrange = if (inrange) |index| @fromBackingInt(@intCast(index)) else .none,
.indices = indices,
};
const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
if (!gop.found_existing) {
gop.key_ptr.* = {};
gop.value_ptr.* = {};
self.constant_items.appendAssumeCapacity(.{
.tag = tag,
.data = self.addConstantExtraAssumeCapacity(Constant.GetElementPtr{
.type = ty,
.base = base,
.info = .{ .indices_len = @intCast(indices.len), .inrange = data.inrange },
}),
});
self.constant_extra.appendSliceAssumeCapacity(@ptrCast(indices));
}
return @fromBackingInt(@intCast(gop.index));
}