mirror of
https://github.com/ziglang/zig.git
synced 2026-01-21 06:45:24 +00:00
self-hosted: function types use table lookup
This commit is contained in:
parent
1d4a94b635
commit
2ea08561cf
@ -168,6 +168,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)
|
||||
//}
|
||||
|
||||
const fn_type = fn_val.base.typ.cast(Type.Fn).?;
|
||||
const fn_type_normal = &fn_type.key.data.Normal;
|
||||
|
||||
try addLLVMFnAttr(ofile, llvm_fn, "nounwind");
|
||||
//add_uwtable_attr(g, fn_table_entry->llvm_value);
|
||||
@ -209,7 +210,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)
|
||||
// addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)err_ret_trace_arg_index, "nonnull");
|
||||
//}
|
||||
|
||||
const cur_ret_ptr = if (fn_type.return_type.handleIsPtr()) llvm.GetParam(llvm_fn, 0) else null;
|
||||
const cur_ret_ptr = if (fn_type_normal.return_type.handleIsPtr()) llvm.GetParam(llvm_fn, 0) else null;
|
||||
|
||||
// build all basic blocks
|
||||
for (code.basic_block_list.toSlice()) |bb| {
|
||||
|
||||
@ -220,12 +220,14 @@ pub const Compilation = struct {
|
||||
int_type_table: event.Locked(IntTypeTable),
|
||||
array_type_table: event.Locked(ArrayTypeTable),
|
||||
ptr_type_table: event.Locked(PtrTypeTable),
|
||||
fn_type_table: event.Locked(FnTypeTable),
|
||||
|
||||
c_int_types: [CInt.list.len]*Type.Int,
|
||||
|
||||
const IntTypeTable = std.HashMap(*const Type.Int.Key, *Type.Int, Type.Int.Key.hash, Type.Int.Key.eql);
|
||||
const ArrayTypeTable = std.HashMap(*const Type.Array.Key, *Type.Array, Type.Array.Key.hash, Type.Array.Key.eql);
|
||||
const PtrTypeTable = std.HashMap(*const Type.Pointer.Key, *Type.Pointer, Type.Pointer.Key.hash, Type.Pointer.Key.eql);
|
||||
const FnTypeTable = std.HashMap(*const Type.Fn.Key, *Type.Fn, Type.Fn.Key.hash, Type.Fn.Key.eql);
|
||||
const TypeTable = std.HashMap([]const u8, *Type, mem.hash_slice_u8, mem.eql_slice_u8);
|
||||
|
||||
const CompileErrList = std.ArrayList(*Msg);
|
||||
@ -384,6 +386,7 @@ pub const Compilation = struct {
|
||||
.int_type_table = event.Locked(IntTypeTable).init(loop, IntTypeTable.init(loop.allocator)),
|
||||
.array_type_table = event.Locked(ArrayTypeTable).init(loop, ArrayTypeTable.init(loop.allocator)),
|
||||
.ptr_type_table = event.Locked(PtrTypeTable).init(loop, PtrTypeTable.init(loop.allocator)),
|
||||
.fn_type_table = event.Locked(FnTypeTable).init(loop, FnTypeTable.init(loop.allocator)),
|
||||
.c_int_types = undefined,
|
||||
|
||||
.meta_type = undefined,
|
||||
@ -414,6 +417,7 @@ pub const Compilation = struct {
|
||||
comp.int_type_table.private_data.deinit();
|
||||
comp.array_type_table.private_data.deinit();
|
||||
comp.ptr_type_table.private_data.deinit();
|
||||
comp.fn_type_table.private_data.deinit();
|
||||
comp.arena_allocator.deinit();
|
||||
comp.loop.allocator.destroy(comp);
|
||||
}
|
||||
@ -1160,10 +1164,47 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {
|
||||
fn_decl.value = Decl.Fn.Val{ .Fn = fn_val };
|
||||
symbol_name_consumed = true;
|
||||
|
||||
// Define local parameter variables
|
||||
//for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
|
||||
// FnTypeParamInfo *param_info = &fn_type_id->param_info[i];
|
||||
// AstNode *param_decl_node = get_param_decl_node(fn_table_entry, i);
|
||||
// Buf *param_name;
|
||||
// bool is_var_args = param_decl_node && param_decl_node->data.param_decl.is_var_args;
|
||||
// if (param_decl_node && !is_var_args) {
|
||||
// param_name = param_decl_node->data.param_decl.name;
|
||||
// } else {
|
||||
// param_name = buf_sprintf("arg%" ZIG_PRI_usize "", i);
|
||||
// }
|
||||
// if (param_name == nullptr) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// TypeTableEntry *param_type = param_info->type;
|
||||
// bool is_noalias = param_info->is_noalias;
|
||||
|
||||
// if (is_noalias && get_codegen_ptr_type(param_type) == nullptr) {
|
||||
// add_node_error(g, param_decl_node, buf_sprintf("noalias on non-pointer parameter"));
|
||||
// }
|
||||
|
||||
// VariableTableEntry *var = add_variable(g, param_decl_node, fn_table_entry->child_scope,
|
||||
// param_name, true, create_const_runtime(param_type), nullptr);
|
||||
// var->src_arg_index = i;
|
||||
// fn_table_entry->child_scope = var->child_scope;
|
||||
// var->shadowable = var->shadowable || is_var_args;
|
||||
|
||||
// if (type_has_bits(param_type)) {
|
||||
// fn_table_entry->variable_list.append(var);
|
||||
// }
|
||||
|
||||
// if (fn_type->data.fn.gen_param_info) {
|
||||
// var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index;
|
||||
// }
|
||||
//}
|
||||
|
||||
const analyzed_code = try await (async comp.genAndAnalyzeCode(
|
||||
&fndef_scope.base,
|
||||
body_node,
|
||||
fn_type.return_type,
|
||||
fn_type.key.data.Normal.return_type,
|
||||
) catch unreachable);
|
||||
errdefer analyzed_code.destroy(comp.gpa());
|
||||
|
||||
@ -1199,14 +1240,13 @@ async fn analyzeFnType(comp: *Compilation, scope: *Scope, fn_proto: *ast.Node.Fn
|
||||
|
||||
var params = ArrayList(Type.Fn.Param).init(comp.gpa());
|
||||
var params_consumed = false;
|
||||
defer if (params_consumed) {
|
||||
defer if (!params_consumed) {
|
||||
for (params.toSliceConst()) |param| {
|
||||
param.typ.base.deref(comp);
|
||||
}
|
||||
params.deinit();
|
||||
};
|
||||
|
||||
const is_var_args = false;
|
||||
{
|
||||
var it = fn_proto.params.iterator(0);
|
||||
while (it.next()) |param_node_ptr| {
|
||||
@ -1219,8 +1259,29 @@ async fn analyzeFnType(comp: *Compilation, scope: *Scope, fn_proto: *ast.Node.Fn
|
||||
});
|
||||
}
|
||||
}
|
||||
const fn_type = try Type.Fn.create(comp, return_type, params.toOwnedSlice(), is_var_args);
|
||||
|
||||
const key = Type.Fn.Key{
|
||||
.alignment = null,
|
||||
.data = Type.Fn.Key.Data{
|
||||
.Normal = Type.Fn.Normal{
|
||||
.return_type = return_type,
|
||||
.params = params.toOwnedSlice(),
|
||||
.is_var_args = false, // TODO
|
||||
.cc = Type.Fn.CallingConvention.Auto, // TODO
|
||||
},
|
||||
},
|
||||
};
|
||||
params_consumed = true;
|
||||
var key_consumed = false;
|
||||
defer if (!key_consumed) {
|
||||
for (key.data.Normal.params) |param| {
|
||||
param.typ.base.deref(comp);
|
||||
}
|
||||
comp.gpa().free(key.data.Normal.params);
|
||||
};
|
||||
|
||||
const fn_type = try await (async Type.Fn.get(comp, key) catch unreachable);
|
||||
key_consumed = true;
|
||||
errdefer fn_type.base.base.deref(comp);
|
||||
|
||||
return fn_type;
|
||||
|
||||
@ -281,11 +281,13 @@ pub const Inst = struct {
|
||||
return error.SemanticAnalysisFailed;
|
||||
};
|
||||
|
||||
if (fn_type.params.len != self.params.args.len) {
|
||||
const fn_type_param_count = fn_type.paramCount();
|
||||
|
||||
if (fn_type_param_count != self.params.args.len) {
|
||||
try ira.addCompileError(
|
||||
self.base.span,
|
||||
"expected {} arguments, found {}",
|
||||
fn_type.params.len,
|
||||
fn_type_param_count,
|
||||
self.params.args.len,
|
||||
);
|
||||
return error.SemanticAnalysisFailed;
|
||||
@ -299,7 +301,7 @@ pub const Inst = struct {
|
||||
.fn_ref = fn_ref,
|
||||
.args = args,
|
||||
});
|
||||
new_inst.val = IrVal{ .KnownType = fn_type.return_type };
|
||||
new_inst.val = IrVal{ .KnownType = fn_type.key.data.Normal.return_type };
|
||||
return new_inst;
|
||||
}
|
||||
|
||||
|
||||
@ -221,57 +221,267 @@ pub const Type = struct {
|
||||
|
||||
pub const Fn = struct {
|
||||
base: Type,
|
||||
return_type: *Type,
|
||||
params: []Param,
|
||||
is_var_args: bool,
|
||||
key: Key,
|
||||
garbage_node: std.atomic.Stack(*Fn).Node,
|
||||
|
||||
pub const Key = struct {
|
||||
data: Data,
|
||||
alignment: ?u32,
|
||||
|
||||
pub const Data = union(enum) {
|
||||
Generic: Generic,
|
||||
Normal: Normal,
|
||||
};
|
||||
|
||||
pub fn hash(self: *const Key) u32 {
|
||||
var result: u32 = 0;
|
||||
result +%= hashAny(self.alignment, 0);
|
||||
switch (self.data) {
|
||||
Data.Generic => |generic| {
|
||||
result +%= hashAny(generic.param_count, 1);
|
||||
switch (generic.cc) {
|
||||
CallingConvention.Async => |allocator_type| result +%= hashAny(allocator_type, 2),
|
||||
else => result +%= hashAny(CallingConvention(generic.cc), 3),
|
||||
}
|
||||
},
|
||||
Data.Normal => |normal| {
|
||||
result +%= hashAny(normal.return_type, 4);
|
||||
result +%= hashAny(normal.is_var_args, 5);
|
||||
result +%= hashAny(normal.cc, 6);
|
||||
for (normal.params) |param| {
|
||||
result +%= hashAny(param.is_noalias, 7);
|
||||
result +%= hashAny(param.typ, 8);
|
||||
}
|
||||
},
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn eql(self: *const Key, other: *const Key) bool {
|
||||
if ((self.alignment == null) != (other.alignment == null)) return false;
|
||||
if (self.alignment) |self_align| {
|
||||
if (self_align != other.alignment.?) return false;
|
||||
}
|
||||
if (@TagType(Data)(self.data) != @TagType(Data)(other.data)) return false;
|
||||
switch (self.data) {
|
||||
Data.Generic => |*self_generic| {
|
||||
const other_generic = &other.data.Generic;
|
||||
if (self_generic.param_count != other_generic.param_count) return false;
|
||||
if (CallingConvention(self_generic.cc) != CallingConvention(other_generic.cc)) return false;
|
||||
switch (self_generic.cc) {
|
||||
CallingConvention.Async => |self_allocator_type| {
|
||||
const other_allocator_type = other_generic.cc.Async;
|
||||
if (self_allocator_type != other_allocator_type) return false;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
},
|
||||
Data.Normal => |*self_normal| {
|
||||
const other_normal = &other.data.Normal;
|
||||
if (self_normal.cc != other_normal.cc) return false;
|
||||
if (self_normal.is_var_args != other_normal.is_var_args) return false;
|
||||
if (self_normal.return_type != other_normal.return_type) return false;
|
||||
for (self_normal.params) |*self_param, i| {
|
||||
const other_param = &other_normal.params[i];
|
||||
if (self_param.is_noalias != other_param.is_noalias) return false;
|
||||
if (self_param.typ != other_param.typ) return false;
|
||||
}
|
||||
},
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn deref(key: Key, comp: *Compilation) void {
|
||||
switch (key.data) {
|
||||
Key.Data.Generic => |generic| {
|
||||
switch (generic.cc) {
|
||||
CallingConvention.Async => |allocator_type| allocator_type.base.deref(comp),
|
||||
else => {},
|
||||
}
|
||||
},
|
||||
Key.Data.Normal => |normal| {
|
||||
normal.return_type.base.deref(comp);
|
||||
for (normal.params) |param| {
|
||||
param.typ.base.deref(comp);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ref(key: Key) void {
|
||||
switch (key.data) {
|
||||
Key.Data.Generic => |generic| {
|
||||
switch (generic.cc) {
|
||||
CallingConvention.Async => |allocator_type| allocator_type.base.ref(),
|
||||
else => {},
|
||||
}
|
||||
},
|
||||
Key.Data.Normal => |normal| {
|
||||
normal.return_type.base.ref();
|
||||
for (normal.params) |param| {
|
||||
param.typ.base.ref();
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const Normal = struct {
|
||||
params: []Param,
|
||||
return_type: *Type,
|
||||
is_var_args: bool,
|
||||
cc: CallingConvention,
|
||||
};
|
||||
|
||||
pub const Generic = struct {
|
||||
param_count: usize,
|
||||
cc: CC,
|
||||
|
||||
pub const CC = union(CallingConvention) {
|
||||
Auto,
|
||||
C,
|
||||
Cold,
|
||||
Naked,
|
||||
Stdcall,
|
||||
Async: *Type, // allocator type
|
||||
};
|
||||
};
|
||||
|
||||
pub const CallingConvention = enum {
|
||||
Auto,
|
||||
C,
|
||||
Cold,
|
||||
Naked,
|
||||
Stdcall,
|
||||
Async,
|
||||
};
|
||||
|
||||
pub const Param = struct {
|
||||
is_noalias: bool,
|
||||
typ: *Type,
|
||||
};
|
||||
|
||||
pub fn create(comp: *Compilation, return_type: *Type, params: []Param, is_var_args: bool) !*Fn {
|
||||
const result = try comp.gpa().create(Fn{
|
||||
.base = undefined,
|
||||
.return_type = return_type,
|
||||
.params = params,
|
||||
.is_var_args = is_var_args,
|
||||
});
|
||||
errdefer comp.gpa().destroy(result);
|
||||
fn ccFnTypeStr(cc: CallingConvention) []const u8 {
|
||||
return switch (cc) {
|
||||
CallingConvention.Auto => "",
|
||||
CallingConvention.C => "extern ",
|
||||
CallingConvention.Cold => "coldcc ",
|
||||
CallingConvention.Naked => "nakedcc ",
|
||||
CallingConvention.Stdcall => "stdcallcc ",
|
||||
CallingConvention.Async => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
result.base.init(comp, Id.Fn, "TODO fn type name");
|
||||
pub fn paramCount(self: *Fn) usize {
|
||||
return switch (self.key.data) {
|
||||
Key.Data.Generic => |generic| generic.param_count,
|
||||
Key.Data.Normal => |normal| normal.params.len,
|
||||
};
|
||||
}
|
||||
|
||||
result.return_type.base.ref();
|
||||
for (result.params) |param| {
|
||||
param.typ.base.ref();
|
||||
/// takes ownership of key.Normal.params on success
|
||||
pub async fn get(comp: *Compilation, key: Key) !*Fn {
|
||||
{
|
||||
const held = await (async comp.fn_type_table.acquire() catch unreachable);
|
||||
defer held.release();
|
||||
|
||||
if (held.value.get(&key)) |entry| {
|
||||
entry.value.base.base.ref();
|
||||
return entry.value;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
key.ref();
|
||||
errdefer key.deref(comp);
|
||||
|
||||
const self = try comp.gpa().create(Fn{
|
||||
.base = undefined,
|
||||
.key = key,
|
||||
.garbage_node = undefined,
|
||||
});
|
||||
errdefer comp.gpa().destroy(self);
|
||||
|
||||
var name_buf = try std.Buffer.initSize(comp.gpa(), 0);
|
||||
defer name_buf.deinit();
|
||||
|
||||
const name_stream = &std.io.BufferOutStream.init(&name_buf).stream;
|
||||
|
||||
switch (key.data) {
|
||||
Key.Data.Generic => |generic| {
|
||||
switch (generic.cc) {
|
||||
CallingConvention.Async => |async_allocator_type| {
|
||||
try name_stream.print("async<{}> ", async_allocator_type.name);
|
||||
},
|
||||
else => {
|
||||
const cc_str = ccFnTypeStr(generic.cc);
|
||||
try name_stream.write(cc_str);
|
||||
},
|
||||
}
|
||||
try name_stream.write("fn(");
|
||||
var param_i: usize = 0;
|
||||
while (param_i < generic.param_count) : (param_i += 1) {
|
||||
const arg = if (param_i == 0) "var" else ", var";
|
||||
try name_stream.write(arg);
|
||||
}
|
||||
try name_stream.write(")");
|
||||
if (key.alignment) |alignment| {
|
||||
try name_stream.print(" align<{}>", alignment);
|
||||
}
|
||||
try name_stream.write(" var");
|
||||
},
|
||||
Key.Data.Normal => |normal| {
|
||||
const cc_str = ccFnTypeStr(normal.cc);
|
||||
try name_stream.print("{}fn(", cc_str);
|
||||
for (normal.params) |param, i| {
|
||||
if (i != 0) try name_stream.write(", ");
|
||||
if (param.is_noalias) try name_stream.write("noalias ");
|
||||
try name_stream.write(param.typ.name);
|
||||
}
|
||||
if (normal.is_var_args) {
|
||||
if (normal.params.len != 0) try name_stream.write(", ");
|
||||
try name_stream.write("...");
|
||||
}
|
||||
try name_stream.write(")");
|
||||
if (key.alignment) |alignment| {
|
||||
try name_stream.print(" align<{}>", alignment);
|
||||
}
|
||||
try name_stream.print(" {}", normal.return_type.name);
|
||||
},
|
||||
}
|
||||
|
||||
self.base.init(comp, Id.Fn, name_buf.toOwnedSlice());
|
||||
|
||||
{
|
||||
const held = await (async comp.fn_type_table.acquire() catch unreachable);
|
||||
defer held.release();
|
||||
|
||||
_ = try held.value.put(&self.key, self);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn destroy(self: *Fn, comp: *Compilation) void {
|
||||
self.return_type.base.deref(comp);
|
||||
for (self.params) |param| {
|
||||
param.typ.base.deref(comp);
|
||||
}
|
||||
self.key.deref(comp);
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Fn, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
|
||||
const llvm_return_type = switch (self.return_type.id) {
|
||||
const normal = &self.key.data.Normal;
|
||||
const llvm_return_type = switch (normal.return_type.id) {
|
||||
Type.Id.Void => llvm.VoidTypeInContext(llvm_context) orelse return error.OutOfMemory,
|
||||
else => try self.return_type.getLlvmType(allocator, llvm_context),
|
||||
else => try normal.return_type.getLlvmType(allocator, llvm_context),
|
||||
};
|
||||
const llvm_param_types = try allocator.alloc(llvm.TypeRef, self.params.len);
|
||||
const llvm_param_types = try allocator.alloc(llvm.TypeRef, normal.params.len);
|
||||
defer allocator.free(llvm_param_types);
|
||||
for (llvm_param_types) |*llvm_param_type, i| {
|
||||
llvm_param_type.* = try self.params[i].typ.getLlvmType(allocator, llvm_context);
|
||||
llvm_param_type.* = try normal.params[i].typ.getLlvmType(allocator, llvm_context);
|
||||
}
|
||||
|
||||
return llvm.FunctionType(
|
||||
llvm_return_type,
|
||||
llvm_param_types.ptr,
|
||||
@intCast(c_uint, llvm_param_types.len),
|
||||
@boolToInt(self.is_var_args),
|
||||
@boolToInt(normal.is_var_args),
|
||||
) orelse error.OutOfMemory;
|
||||
}
|
||||
};
|
||||
@ -347,8 +557,10 @@ pub const Type = struct {
|
||||
is_signed: bool,
|
||||
|
||||
pub fn hash(self: *const Key) u32 {
|
||||
const rands = [2]u32{ 0xa4ba6498, 0x75fc5af7 };
|
||||
return rands[@boolToInt(self.is_signed)] *% self.bit_count;
|
||||
var result: u32 = 0;
|
||||
result +%= hashAny(self.is_signed, 0);
|
||||
result +%= hashAny(self.bit_count, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn eql(self: *const Key, other: *const Key) bool {
|
||||
@ -443,15 +655,16 @@ pub const Type = struct {
|
||||
alignment: Align,
|
||||
|
||||
pub fn hash(self: *const Key) u32 {
|
||||
const align_hash = switch (self.alignment) {
|
||||
var result: u32 = 0;
|
||||
result +%= switch (self.alignment) {
|
||||
Align.Abi => 0xf201c090,
|
||||
Align.Override => |x| x,
|
||||
Align.Override => |x| hashAny(x, 0),
|
||||
};
|
||||
return hash_usize(@ptrToInt(self.child_type)) *%
|
||||
hash_enum(self.mut) *%
|
||||
hash_enum(self.vol) *%
|
||||
hash_enum(self.size) *%
|
||||
align_hash;
|
||||
result +%= hashAny(self.child_type, 1);
|
||||
result +%= hashAny(self.mut, 2);
|
||||
result +%= hashAny(self.vol, 3);
|
||||
result +%= hashAny(self.size, 4);
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn eql(self: *const Key, other: *const Key) bool {
|
||||
@ -605,7 +818,10 @@ pub const Type = struct {
|
||||
len: usize,
|
||||
|
||||
pub fn hash(self: *const Key) u32 {
|
||||
return hash_usize(@ptrToInt(self.elem_type)) *% hash_usize(self.len);
|
||||
var result: u32 = 0;
|
||||
result +%= hashAny(self.elem_type, 0);
|
||||
result +%= hashAny(self.len, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn eql(self: *const Key, other: *const Key) bool {
|
||||
@ -818,27 +1034,37 @@ pub const Type = struct {
|
||||
};
|
||||
};
|
||||
|
||||
fn hash_usize(x: usize) u32 {
|
||||
return switch (@sizeOf(usize)) {
|
||||
4 => x,
|
||||
8 => @truncate(u32, x *% 0xad44ee2d8e3fc13d),
|
||||
else => @compileError("implement this hash function"),
|
||||
};
|
||||
}
|
||||
|
||||
fn hash_enum(x: var) u32 {
|
||||
const rands = []u32{
|
||||
0x85ebf64f,
|
||||
0x3fcb3211,
|
||||
0x240a4e8e,
|
||||
0x40bb0e3c,
|
||||
0x78be45af,
|
||||
0x1ca98e37,
|
||||
0xec56053a,
|
||||
0x906adc48,
|
||||
0xd4fe9763,
|
||||
0x54c80dac,
|
||||
};
|
||||
comptime assert(@memberCount(@typeOf(x)) < rands.len);
|
||||
return rands[@enumToInt(x)];
|
||||
fn hashAny(x: var, comptime seed: u64) u32 {
|
||||
switch (@typeInfo(@typeOf(x))) {
|
||||
builtin.TypeId.Int => |info| {
|
||||
comptime var rng = comptime std.rand.DefaultPrng.init(seed);
|
||||
const unsigned_x = @bitCast(@IntType(false, info.bits), x);
|
||||
if (info.bits <= 32) {
|
||||
return u32(unsigned_x) *% comptime rng.random.scalar(u32);
|
||||
} else {
|
||||
return @truncate(u32, unsigned_x *% comptime rng.random.scalar(@typeOf(unsigned_x)));
|
||||
}
|
||||
},
|
||||
builtin.TypeId.Pointer => |info| {
|
||||
switch (info.size) {
|
||||
builtin.TypeInfo.Pointer.Size.One => return hashAny(@ptrToInt(x), seed),
|
||||
builtin.TypeInfo.Pointer.Size.Many => @compileError("implement hash function"),
|
||||
builtin.TypeInfo.Pointer.Size.Slice => @compileError("implement hash function"),
|
||||
}
|
||||
},
|
||||
builtin.TypeId.Enum => return hashAny(@enumToInt(x), seed),
|
||||
builtin.TypeId.Bool => {
|
||||
comptime var rng = comptime std.rand.DefaultPrng.init(seed);
|
||||
const vals = comptime [2]u32{ rng.random.scalar(u32), rng.random.scalar(u32) };
|
||||
return vals[@boolToInt(x)];
|
||||
},
|
||||
builtin.TypeId.Optional => {
|
||||
if (x) |non_opt| {
|
||||
return hashAny(non_opt, seed);
|
||||
} else {
|
||||
return hashAny(u32(1), seed);
|
||||
}
|
||||
},
|
||||
else => @compileError("implement hash function for " ++ @typeName(@typeOf(x))),
|
||||
}
|
||||
}
|
||||
|
||||
@ -3941,7 +3941,7 @@ AstNode *get_param_decl_node(FnTableEntry *fn_entry, size_t index) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, VariableTableEntry **arg_vars) {
|
||||
static void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry) {
|
||||
TypeTableEntry *fn_type = fn_table_entry->type_entry;
|
||||
assert(!fn_type->data.fn.is_generic);
|
||||
FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
|
||||
@ -3979,10 +3979,6 @@ static void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entr
|
||||
if (fn_type->data.fn.gen_param_info) {
|
||||
var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index;
|
||||
}
|
||||
|
||||
if (arg_vars) {
|
||||
arg_vars[i] = var;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4082,7 +4078,7 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
|
||||
if (!fn_table_entry->child_scope)
|
||||
fn_table_entry->child_scope = &fn_table_entry->fndef_scope->base;
|
||||
|
||||
define_local_param_variables(g, fn_table_entry, nullptr);
|
||||
define_local_param_variables(g, fn_table_entry);
|
||||
|
||||
TypeTableEntry *fn_type = fn_table_entry->type_entry;
|
||||
assert(!fn_type->data.fn.is_generic);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user