mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
self-hosted: implement Decl lookup
* Take advantage of coercing anonymous struct literals to struct types. * Reworks Module to favor Zig source as the primary use case. Breaks ZIR compilation, which will have to be restored in a future commit. * Decl uses src_index rather then src, pointing to an AST Decl node index, or ZIR Module Decl index, rather than a byte offset. * ZIR instructions have an `analyzed_inst` field instead of Module having a hash table. * Module.Fn loses the `fn_type` field since it is redundant with its `owner_decl` `TypedValue` type. * Implement Type and Value copying. A ZIR Const instruction's TypedValue is copied to the Decl arena during analysis, which allows freeing the ZIR text instructions post-analysis. * Don't flush the ELF file if there are compilation errors. * Function return types allow arbitrarily complex expressions. * AST->ZIR for function calls and return statements.
This commit is contained in:
parent
b4eac0414a
commit
7e58c56ca7
@ -2260,6 +2260,8 @@ pub const Node = struct {
|
||||
}
|
||||
};
|
||||
|
||||
/// TODO break this into separate Break, Continue, Return AST Nodes to save memory.
|
||||
/// Could be further broken into LabeledBreak, LabeledContinue, and ReturnVoid to save even more.
|
||||
pub const ControlFlowExpression = struct {
|
||||
base: Node = Node{ .id = .ControlFlowExpression },
|
||||
ltoken: TokenIndex,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -21,3 +21,11 @@ pub const Managed = struct {
|
||||
self.* = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
/// Assumes arena allocation. Does a recursive copy.
|
||||
pub fn copy(self: TypedValue, allocator: *Allocator) error{OutOfMemory}!TypedValue {
|
||||
return TypedValue{
|
||||
.ty = try self.ty.copy(allocator),
|
||||
.val = try self.val.copy(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
@ -178,6 +178,7 @@ const Function = struct {
|
||||
.ptrtoint => return self.genPtrToInt(inst.cast(ir.Inst.PtrToInt).?),
|
||||
.bitcast => return self.genBitCast(inst.cast(ir.Inst.BitCast).?),
|
||||
.ret => return self.genRet(inst.cast(ir.Inst.Ret).?),
|
||||
.retvoid => return self.genRetVoid(inst.cast(ir.Inst.RetVoid).?),
|
||||
.cmp => return self.genCmp(inst.cast(ir.Inst.Cmp).?),
|
||||
.condbr => return self.genCondBr(inst.cast(ir.Inst.CondBr).?),
|
||||
.isnull => return self.genIsNull(inst.cast(ir.Inst.IsNull).?),
|
||||
@ -213,7 +214,7 @@ const Function = struct {
|
||||
try self.code.resize(self.code.items.len + 7);
|
||||
self.code.items[self.code.items.len - 7 ..][0..3].* = [3]u8{ 0xff, 0x14, 0x25 };
|
||||
mem.writeIntLittle(u32, self.code.items[self.code.items.len - 4 ..][0..4], got_addr);
|
||||
const return_type = func.fn_type.fnReturnType();
|
||||
const return_type = func.owner_decl.typed_value.most_recent.typed_value.ty.fnReturnType();
|
||||
switch (return_type.zigTypeTag()) {
|
||||
.Void => return MCValue{ .none = {} },
|
||||
.NoReturn => return MCValue{ .unreach = {} },
|
||||
@ -230,16 +231,28 @@ const Function = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn genRet(self: *Function, inst: *ir.Inst.Ret) !MCValue {
|
||||
fn ret(self: *Function, src: usize, mcv: MCValue) !MCValue {
|
||||
if (mcv != .none) {
|
||||
return self.fail(src, "TODO implement return with non-void operand", .{});
|
||||
}
|
||||
switch (self.target.cpu.arch) {
|
||||
.i386, .x86_64 => {
|
||||
try self.code.append(0xc3); // ret
|
||||
},
|
||||
else => return self.fail(inst.base.src, "TODO implement return for {}", .{self.target.cpu.arch}),
|
||||
else => return self.fail(src, "TODO implement return for {}", .{self.target.cpu.arch}),
|
||||
}
|
||||
return .unreach;
|
||||
}
|
||||
|
||||
fn genRet(self: *Function, inst: *ir.Inst.Ret) !MCValue {
|
||||
const operand = try self.resolveInst(inst.args.operand);
|
||||
return self.ret(inst.base.src, operand);
|
||||
}
|
||||
|
||||
fn genRetVoid(self: *Function, inst: *ir.Inst.RetVoid) !MCValue {
|
||||
return self.ret(inst.base.src, .none);
|
||||
}
|
||||
|
||||
fn genCmp(self: *Function, inst: *ir.Inst.Cmp) !MCValue {
|
||||
switch (self.target.cpu.arch) {
|
||||
else => return self.fail(inst.base.src, "TODO implement cmp for {}", .{self.target.cpu.arch}),
|
||||
|
||||
@ -26,6 +26,7 @@ pub const Inst = struct {
|
||||
isnull,
|
||||
ptrtoint,
|
||||
ret,
|
||||
retvoid,
|
||||
unreach,
|
||||
};
|
||||
|
||||
@ -146,6 +147,14 @@ pub const Inst = struct {
|
||||
pub const Ret = struct {
|
||||
pub const base_tag = Tag.ret;
|
||||
base: Inst,
|
||||
args: struct {
|
||||
operand: *Inst,
|
||||
},
|
||||
};
|
||||
|
||||
pub const RetVoid = struct {
|
||||
pub const base_tag = Tag.retvoid;
|
||||
base: Inst,
|
||||
args: void,
|
||||
};
|
||||
|
||||
|
||||
@ -956,10 +956,10 @@ pub const ElfFile = struct {
|
||||
try self.offset_table_free_list.ensureCapacity(self.allocator, self.local_symbols.items.len);
|
||||
|
||||
if (self.local_symbol_free_list.popOrNull()) |i| {
|
||||
//std.debug.warn("reusing symbol index {} for {}\n", .{i, decl.name});
|
||||
std.debug.warn("reusing symbol index {} for {}\n", .{i, decl.name});
|
||||
decl.link.local_sym_index = i;
|
||||
} else {
|
||||
//std.debug.warn("allocating symbol index {} for {}\n", .{self.local_symbols.items.len, decl.name});
|
||||
std.debug.warn("allocating symbol index {} for {}\n", .{self.local_symbols.items.len, decl.name});
|
||||
decl.link.local_sym_index = @intCast(u32, self.local_symbols.items.len);
|
||||
_ = self.local_symbols.addOneAssumeCapacity();
|
||||
}
|
||||
@ -1002,7 +1002,7 @@ pub const ElfFile = struct {
|
||||
defer code_buffer.deinit();
|
||||
|
||||
const typed_value = decl.typed_value.most_recent.typed_value;
|
||||
const code = switch (try codegen.generateSymbol(self, decl.src, typed_value, &code_buffer)) {
|
||||
const code = switch (try codegen.generateSymbol(self, decl.src(), typed_value, &code_buffer)) {
|
||||
.externally_managed => |x| x,
|
||||
.appended => code_buffer.items,
|
||||
.fail => |em| {
|
||||
@ -1027,11 +1027,11 @@ pub const ElfFile = struct {
|
||||
!mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
|
||||
if (need_realloc) {
|
||||
const vaddr = try self.growTextBlock(&decl.link, code.len, required_alignment);
|
||||
//std.debug.warn("growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr });
|
||||
std.debug.warn("growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr });
|
||||
if (vaddr != local_sym.st_value) {
|
||||
local_sym.st_value = vaddr;
|
||||
|
||||
//std.debug.warn(" (writing new offset table entry)\n", .{});
|
||||
std.debug.warn(" (writing new offset table entry)\n", .{});
|
||||
self.offset_table.items[decl.link.offset_table_index] = vaddr;
|
||||
try self.writeOffsetTableEntry(decl.link.offset_table_index);
|
||||
}
|
||||
@ -1049,7 +1049,7 @@ pub const ElfFile = struct {
|
||||
const decl_name = mem.spanZ(decl.name);
|
||||
const name_str_index = try self.makeString(decl_name);
|
||||
const vaddr = try self.allocateTextBlock(&decl.link, code.len, required_alignment);
|
||||
//std.debug.warn("allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr });
|
||||
std.debug.warn("allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr });
|
||||
errdefer self.freeTextBlock(&decl.link);
|
||||
|
||||
local_sym.* = .{
|
||||
|
||||
@ -54,6 +54,7 @@ pub const Type = extern union {
|
||||
.@"undefined" => return .Undefined,
|
||||
|
||||
.fn_noreturn_no_args => return .Fn,
|
||||
.fn_void_no_args => return .Fn,
|
||||
.fn_naked_noreturn_no_args => return .Fn,
|
||||
.fn_ccc_void_no_args => return .Fn,
|
||||
|
||||
@ -163,6 +164,77 @@ pub const Type = extern union {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn copy(self: Type, allocator: *Allocator) error{OutOfMemory}!Type {
|
||||
if (self.tag_if_small_enough < Tag.no_payload_count) {
|
||||
return Type{ .tag_if_small_enough = self.tag_if_small_enough };
|
||||
} else switch (self.ptr_otherwise.tag) {
|
||||
.u8,
|
||||
.i8,
|
||||
.isize,
|
||||
.usize,
|
||||
.c_short,
|
||||
.c_ushort,
|
||||
.c_int,
|
||||
.c_uint,
|
||||
.c_long,
|
||||
.c_ulong,
|
||||
.c_longlong,
|
||||
.c_ulonglong,
|
||||
.c_longdouble,
|
||||
.c_void,
|
||||
.f16,
|
||||
.f32,
|
||||
.f64,
|
||||
.f128,
|
||||
.bool,
|
||||
.void,
|
||||
.type,
|
||||
.anyerror,
|
||||
.comptime_int,
|
||||
.comptime_float,
|
||||
.noreturn,
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.const_slice_u8,
|
||||
=> unreachable,
|
||||
|
||||
.array_u8_sentinel_0 => return self.copyPayloadShallow(allocator, Payload.Array_u8_Sentinel0),
|
||||
.array => {
|
||||
const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(Payload.Array);
|
||||
new_payload.* = .{
|
||||
.base = payload.base,
|
||||
.len = payload.len,
|
||||
.elem_type = try payload.elem_type.copy(allocator),
|
||||
};
|
||||
return Type{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
.single_const_pointer => {
|
||||
const payload = @fieldParentPtr(Payload.SingleConstPointer, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(Payload.SingleConstPointer);
|
||||
new_payload.* = .{
|
||||
.base = payload.base,
|
||||
.pointee_type = try payload.pointee_type.copy(allocator),
|
||||
};
|
||||
return Type{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
.int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned),
|
||||
.int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned),
|
||||
}
|
||||
}
|
||||
|
||||
fn copyPayloadShallow(self: Type, allocator: *Allocator, comptime T: type) error{OutOfMemory}!Type {
|
||||
const payload = @fieldParentPtr(T, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(T);
|
||||
new_payload.* = payload.*;
|
||||
return Type{ .ptr_otherwise = &new_payload.base };
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
self: Type,
|
||||
comptime fmt: []const u8,
|
||||
@ -206,6 +278,7 @@ pub const Type = extern union {
|
||||
|
||||
.const_slice_u8 => return out_stream.writeAll("[]const u8"),
|
||||
.fn_noreturn_no_args => return out_stream.writeAll("fn() noreturn"),
|
||||
.fn_void_no_args => return out_stream.writeAll("fn() void"),
|
||||
.fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
|
||||
.fn_ccc_void_no_args => return out_stream.writeAll("fn() callconv(.C) void"),
|
||||
.single_const_pointer_to_comptime_int => return out_stream.writeAll("*const comptime_int"),
|
||||
@ -269,6 +342,7 @@ pub const Type = extern union {
|
||||
.@"null" => return Value.initTag(.null_type),
|
||||
.@"undefined" => return Value.initTag(.undefined_type),
|
||||
.fn_noreturn_no_args => return Value.initTag(.fn_noreturn_no_args_type),
|
||||
.fn_void_no_args => return Value.initTag(.fn_void_no_args_type),
|
||||
.fn_naked_noreturn_no_args => return Value.initTag(.fn_naked_noreturn_no_args_type),
|
||||
.fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type),
|
||||
.single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),
|
||||
@ -303,6 +377,7 @@ pub const Type = extern union {
|
||||
.bool,
|
||||
.anyerror,
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
@ -333,6 +408,7 @@ pub const Type = extern union {
|
||||
.i8,
|
||||
.bool,
|
||||
.fn_noreturn_no_args, // represents machine code; not a pointer
|
||||
.fn_void_no_args, // represents machine code; not a pointer
|
||||
.fn_naked_noreturn_no_args, // represents machine code; not a pointer
|
||||
.fn_ccc_void_no_args, // represents machine code; not a pointer
|
||||
.array_u8_sentinel_0,
|
||||
@ -420,6 +496,7 @@ pub const Type = extern union {
|
||||
.array_u8_sentinel_0,
|
||||
.const_slice_u8,
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.int_unsigned,
|
||||
@ -466,6 +543,7 @@ pub const Type = extern union {
|
||||
.single_const_pointer,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.int_unsigned,
|
||||
@ -509,6 +587,7 @@ pub const Type = extern union {
|
||||
.array,
|
||||
.array_u8_sentinel_0,
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.int_unsigned,
|
||||
@ -553,6 +632,7 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.int_unsigned,
|
||||
@ -597,6 +677,7 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.single_const_pointer,
|
||||
@ -642,6 +723,7 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.single_const_pointer,
|
||||
@ -675,6 +757,7 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.array,
|
||||
@ -721,6 +804,7 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.array,
|
||||
@ -777,6 +861,7 @@ pub const Type = extern union {
|
||||
pub fn fnParamLen(self: Type) usize {
|
||||
return switch (self.tag()) {
|
||||
.fn_noreturn_no_args => 0,
|
||||
.fn_void_no_args => 0,
|
||||
.fn_naked_noreturn_no_args => 0,
|
||||
.fn_ccc_void_no_args => 0,
|
||||
|
||||
@ -823,6 +908,7 @@ pub const Type = extern union {
|
||||
pub fn fnParamTypes(self: Type, types: []Type) void {
|
||||
switch (self.tag()) {
|
||||
.fn_noreturn_no_args => return,
|
||||
.fn_void_no_args => return,
|
||||
.fn_naked_noreturn_no_args => return,
|
||||
.fn_ccc_void_no_args => return,
|
||||
|
||||
@ -869,7 +955,10 @@ pub const Type = extern union {
|
||||
return switch (self.tag()) {
|
||||
.fn_noreturn_no_args => Type.initTag(.noreturn),
|
||||
.fn_naked_noreturn_no_args => Type.initTag(.noreturn),
|
||||
.fn_ccc_void_no_args => Type.initTag(.void),
|
||||
|
||||
.fn_void_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
=> Type.initTag(.void),
|
||||
|
||||
.f16,
|
||||
.f32,
|
||||
@ -913,6 +1002,7 @@ pub const Type = extern union {
|
||||
pub fn fnCallingConvention(self: Type) std.builtin.CallingConvention {
|
||||
return switch (self.tag()) {
|
||||
.fn_noreturn_no_args => .Unspecified,
|
||||
.fn_void_no_args => .Unspecified,
|
||||
.fn_naked_noreturn_no_args => .Naked,
|
||||
.fn_ccc_void_no_args => .C,
|
||||
|
||||
@ -958,6 +1048,7 @@ pub const Type = extern union {
|
||||
pub fn fnIsVarArgs(self: Type) bool {
|
||||
return switch (self.tag()) {
|
||||
.fn_noreturn_no_args => false,
|
||||
.fn_void_no_args => false,
|
||||
.fn_naked_noreturn_no_args => false,
|
||||
.fn_ccc_void_no_args => false,
|
||||
|
||||
@ -1033,6 +1124,7 @@ pub const Type = extern union {
|
||||
.@"null",
|
||||
.@"undefined",
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.array,
|
||||
@ -1070,6 +1162,7 @@ pub const Type = extern union {
|
||||
.type,
|
||||
.anyerror,
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
@ -1126,6 +1219,7 @@ pub const Type = extern union {
|
||||
.type,
|
||||
.anyerror,
|
||||
.fn_noreturn_no_args,
|
||||
.fn_void_no_args,
|
||||
.fn_naked_noreturn_no_args,
|
||||
.fn_ccc_void_no_args,
|
||||
.single_const_pointer_to_comptime_int,
|
||||
@ -1180,6 +1274,7 @@ pub const Type = extern union {
|
||||
@"null",
|
||||
@"undefined",
|
||||
fn_noreturn_no_args,
|
||||
fn_void_no_args,
|
||||
fn_naked_noreturn_no_args,
|
||||
fn_ccc_void_no_args,
|
||||
single_const_pointer_to_comptime_int,
|
||||
|
||||
@ -49,6 +49,7 @@ pub const Value = extern union {
|
||||
null_type,
|
||||
undefined_type,
|
||||
fn_noreturn_no_args_type,
|
||||
fn_void_no_args_type,
|
||||
fn_naked_noreturn_no_args_type,
|
||||
fn_ccc_void_no_args_type,
|
||||
single_const_pointer_to_comptime_int_type,
|
||||
@ -107,6 +108,109 @@ pub const Value = extern union {
|
||||
return @fieldParentPtr(T, "base", self.ptr_otherwise);
|
||||
}
|
||||
|
||||
pub fn copy(self: Value, allocator: *Allocator) error{OutOfMemory}!Value {
|
||||
if (self.tag_if_small_enough < Tag.no_payload_count) {
|
||||
return Value{ .tag_if_small_enough = self.tag_if_small_enough };
|
||||
} else switch (self.ptr_otherwise.tag) {
|
||||
.u8_type,
|
||||
.i8_type,
|
||||
.isize_type,
|
||||
.usize_type,
|
||||
.c_short_type,
|
||||
.c_ushort_type,
|
||||
.c_int_type,
|
||||
.c_uint_type,
|
||||
.c_long_type,
|
||||
.c_ulong_type,
|
||||
.c_longlong_type,
|
||||
.c_ulonglong_type,
|
||||
.c_longdouble_type,
|
||||
.f16_type,
|
||||
.f32_type,
|
||||
.f64_type,
|
||||
.f128_type,
|
||||
.c_void_type,
|
||||
.bool_type,
|
||||
.void_type,
|
||||
.type_type,
|
||||
.anyerror_type,
|
||||
.comptime_int_type,
|
||||
.comptime_float_type,
|
||||
.noreturn_type,
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.undef,
|
||||
.zero,
|
||||
.the_one_possible_value,
|
||||
.null_value,
|
||||
.bool_true,
|
||||
.bool_false,
|
||||
=> unreachable,
|
||||
|
||||
.ty => {
|
||||
const payload = @fieldParentPtr(Payload.Ty, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(Payload.Ty);
|
||||
new_payload.* = .{
|
||||
.base = payload.base,
|
||||
.ty = try payload.ty.copy(allocator),
|
||||
};
|
||||
return Value{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
.int_u64 => return self.copyPayloadShallow(allocator, Payload.Int_u64),
|
||||
.int_i64 => return self.copyPayloadShallow(allocator, Payload.Int_i64),
|
||||
.int_big_positive => {
|
||||
@panic("TODO implement copying of big ints");
|
||||
},
|
||||
.int_big_negative => {
|
||||
@panic("TODO implement copying of big ints");
|
||||
},
|
||||
.function => return self.copyPayloadShallow(allocator, Payload.Function),
|
||||
.ref_val => {
|
||||
const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(Payload.RefVal);
|
||||
new_payload.* = .{
|
||||
.base = payload.base,
|
||||
.val = try payload.val.copy(allocator),
|
||||
};
|
||||
return Value{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
.decl_ref => return self.copyPayloadShallow(allocator, Payload.DeclRef),
|
||||
.elem_ptr => {
|
||||
const payload = @fieldParentPtr(Payload.ElemPtr, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(Payload.ElemPtr);
|
||||
new_payload.* = .{
|
||||
.base = payload.base,
|
||||
.array_ptr = try payload.array_ptr.copy(allocator),
|
||||
.index = payload.index,
|
||||
};
|
||||
return Value{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
.bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),
|
||||
.repeated => {
|
||||
const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(Payload.Repeated);
|
||||
new_payload.* = .{
|
||||
.base = payload.base,
|
||||
.val = try payload.val.copy(allocator),
|
||||
};
|
||||
return Value{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn copyPayloadShallow(self: Value, allocator: *Allocator, comptime T: type) error{OutOfMemory}!Value {
|
||||
const payload = @fieldParentPtr(T, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(T);
|
||||
new_payload.* = payload.*;
|
||||
return Value{ .ptr_otherwise = &new_payload.base };
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
self: Value,
|
||||
comptime fmt: []const u8,
|
||||
@ -144,6 +248,7 @@ pub const Value = extern union {
|
||||
.null_type => return out_stream.writeAll("@TypeOf(null)"),
|
||||
.undefined_type => return out_stream.writeAll("@TypeOf(undefined)"),
|
||||
.fn_noreturn_no_args_type => return out_stream.writeAll("fn() noreturn"),
|
||||
.fn_void_no_args_type => return out_stream.writeAll("fn() void"),
|
||||
.fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
|
||||
.fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"),
|
||||
.single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
|
||||
@ -229,6 +334,7 @@ pub const Value = extern union {
|
||||
.null_type => Type.initTag(.@"null"),
|
||||
.undefined_type => Type.initTag(.@"undefined"),
|
||||
.fn_noreturn_no_args_type => Type.initTag(.fn_noreturn_no_args),
|
||||
.fn_void_no_args_type => Type.initTag(.fn_void_no_args),
|
||||
.fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args),
|
||||
.fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args),
|
||||
.single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
|
||||
@ -286,6 +392,7 @@ pub const Value = extern union {
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
@ -345,6 +452,7 @@ pub const Value = extern union {
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
@ -405,6 +513,7 @@ pub const Value = extern union {
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
@ -470,6 +579,7 @@ pub const Value = extern union {
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
@ -564,6 +674,7 @@ pub const Value = extern union {
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
@ -620,6 +731,7 @@ pub const Value = extern union {
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
@ -721,6 +833,7 @@ pub const Value = extern union {
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
@ -783,6 +896,7 @@ pub const Value = extern union {
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
@ -862,6 +976,7 @@ pub const Value = extern union {
|
||||
.null_type,
|
||||
.undefined_type,
|
||||
.fn_noreturn_no_args_type,
|
||||
.fn_void_no_args_type,
|
||||
.fn_naked_noreturn_no_args_type,
|
||||
.fn_ccc_void_no_args_type,
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
@ -929,11 +1044,6 @@ pub const Value = extern union {
|
||||
len: u64,
|
||||
};
|
||||
|
||||
pub const SingleConstPtrType = struct {
|
||||
base: Payload = Payload{ .tag = .single_const_ptr_type },
|
||||
elem_type: *Type,
|
||||
};
|
||||
|
||||
/// Represents a pointer to another immutable value.
|
||||
pub const RefVal = struct {
|
||||
base: Payload = Payload{ .tag = .ref_val },
|
||||
|
||||
@ -25,6 +25,9 @@ pub const Inst = struct {
|
||||
/// Hash of slice into the source of the part after the = and before the next instruction.
|
||||
contents_hash: std.zig.SrcHash = undefined,
|
||||
|
||||
/// Pre-allocated field for mapping ZIR text instructions to post-analysis instructions.
|
||||
analyzed_inst: *ir.Inst = undefined,
|
||||
|
||||
/// These names are used directly as the instruction names in the text format.
|
||||
pub const Tag = enum {
|
||||
breakpoint,
|
||||
@ -37,6 +40,8 @@ pub const Inst = struct {
|
||||
/// The syntax `@foo` is equivalent to `declval("foo")`.
|
||||
/// declval is equivalent to declref followed by deref.
|
||||
declval,
|
||||
/// Same as declval but the parameter is a `*Module.Decl` rather than a name.
|
||||
declval_in_module,
|
||||
str,
|
||||
int,
|
||||
ptrtoint,
|
||||
@ -46,6 +51,7 @@ pub const Inst = struct {
|
||||
@"asm",
|
||||
@"unreachable",
|
||||
@"return",
|
||||
returnvoid,
|
||||
@"fn",
|
||||
fntype,
|
||||
@"export",
|
||||
@ -67,6 +73,7 @@ pub const Inst = struct {
|
||||
.call => Call,
|
||||
.declref => DeclRef,
|
||||
.declval => DeclVal,
|
||||
.declval_in_module => DeclValInModule,
|
||||
.compileerror => CompileError,
|
||||
.@"const" => Const,
|
||||
.str => Str,
|
||||
@ -78,6 +85,7 @@ pub const Inst = struct {
|
||||
.@"asm" => Asm,
|
||||
.@"unreachable" => Unreachable,
|
||||
.@"return" => Return,
|
||||
.returnvoid => ReturnVoid,
|
||||
.@"fn" => Fn,
|
||||
.@"export" => Export,
|
||||
.primitive => Primitive,
|
||||
@ -142,6 +150,16 @@ pub const Inst = struct {
|
||||
kw_args: struct {},
|
||||
};
|
||||
|
||||
pub const DeclValInModule = struct {
|
||||
pub const base_tag = Tag.declval_in_module;
|
||||
base: Inst,
|
||||
|
||||
positionals: struct {
|
||||
decl: *IrModule.Decl,
|
||||
},
|
||||
kw_args: struct {},
|
||||
};
|
||||
|
||||
pub const CompileError = struct {
|
||||
pub const base_tag = Tag.compileerror;
|
||||
base: Inst,
|
||||
@ -253,6 +271,16 @@ pub const Inst = struct {
|
||||
pub const base_tag = Tag.@"return";
|
||||
base: Inst,
|
||||
|
||||
positionals: struct {
|
||||
operand: *Inst,
|
||||
},
|
||||
kw_args: struct {},
|
||||
};
|
||||
|
||||
pub const ReturnVoid = struct {
|
||||
pub const base_tag = Tag.returnvoid;
|
||||
base: Inst,
|
||||
|
||||
positionals: struct {},
|
||||
kw_args: struct {},
|
||||
};
|
||||
@ -492,11 +520,19 @@ pub const Module = struct {
|
||||
|
||||
const InstPtrTable = std.AutoHashMap(*Inst, struct { inst: *Inst, index: ?usize });
|
||||
|
||||
const DeclAndIndex = struct {
|
||||
decl: *Inst,
|
||||
index: usize,
|
||||
};
|
||||
|
||||
/// TODO Look into making a table to speed this up.
|
||||
pub fn findDecl(self: Module, name: []const u8) ?*Inst {
|
||||
for (self.decls) |decl| {
|
||||
pub fn findDecl(self: Module, name: []const u8) ?DeclAndIndex {
|
||||
for (self.decls) |decl, i| {
|
||||
if (mem.eql(u8, decl.name, name)) {
|
||||
return decl;
|
||||
return DeclAndIndex{
|
||||
.decl = decl,
|
||||
.index = i,
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@ -540,6 +576,7 @@ pub const Module = struct {
|
||||
.call => return self.writeInstToStreamGeneric(stream, .call, decl, inst_table),
|
||||
.declref => return self.writeInstToStreamGeneric(stream, .declref, decl, inst_table),
|
||||
.declval => return self.writeInstToStreamGeneric(stream, .declval, decl, inst_table),
|
||||
.declval_in_module => return self.writeInstToStreamGeneric(stream, .declval_in_module, decl, inst_table),
|
||||
.compileerror => return self.writeInstToStreamGeneric(stream, .compileerror, decl, inst_table),
|
||||
.@"const" => return self.writeInstToStreamGeneric(stream, .@"const", decl, inst_table),
|
||||
.str => return self.writeInstToStreamGeneric(stream, .str, decl, inst_table),
|
||||
@ -551,6 +588,7 @@ pub const Module = struct {
|
||||
.@"asm" => return self.writeInstToStreamGeneric(stream, .@"asm", decl, inst_table),
|
||||
.@"unreachable" => return self.writeInstToStreamGeneric(stream, .@"unreachable", decl, inst_table),
|
||||
.@"return" => return self.writeInstToStreamGeneric(stream, .@"return", decl, inst_table),
|
||||
.returnvoid => return self.writeInstToStreamGeneric(stream, .returnvoid, decl, inst_table),
|
||||
.@"fn" => return self.writeInstToStreamGeneric(stream, .@"fn", decl, inst_table),
|
||||
.@"export" => return self.writeInstToStreamGeneric(stream, .@"export", decl, inst_table),
|
||||
.ref => return self.writeInstToStreamGeneric(stream, .ref, decl, inst_table),
|
||||
@ -636,6 +674,7 @@ pub const Module = struct {
|
||||
[]u8, []const u8 => return std.zig.renderStringLiteral(param, stream),
|
||||
BigIntConst => return stream.print("{}", .{param}),
|
||||
TypedValue => unreachable, // this is a special case
|
||||
*IrModule.Decl => unreachable, // this is a special case
|
||||
else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
|
||||
}
|
||||
}
|
||||
@ -649,6 +688,8 @@ pub const Module = struct {
|
||||
}
|
||||
} else if (inst.cast(Inst.DeclVal)) |decl_val| {
|
||||
try stream.print("@{}", .{decl_val.positionals.name});
|
||||
} else if (inst.cast(Inst.DeclValInModule)) |decl_val| {
|
||||
try stream.print("@{}", .{decl_val.positionals.decl.name});
|
||||
} else {
|
||||
//try stream.print("?", .{});
|
||||
unreachable;
|
||||
@ -996,6 +1037,7 @@ const Parser = struct {
|
||||
[]u8, []const u8 => return self.parseStringLiteral(),
|
||||
BigIntConst => return self.parseIntegerLiteral(),
|
||||
TypedValue => return self.fail("'const' is a special instruction; not legal in ZIR text", .{}),
|
||||
*IrModule.Decl => return self.fail("'declval_in_module' is a special instruction; not legal in ZIR text", .{}),
|
||||
else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
|
||||
}
|
||||
return self.fail("TODO parse parameter {}", .{@typeName(T)});
|
||||
@ -1105,7 +1147,7 @@ const EmitZIR = struct {
|
||||
}
|
||||
std.sort.sort(*IrModule.Decl, src_decls.items, {}, (struct {
|
||||
fn lessThan(context: void, a: *IrModule.Decl, b: *IrModule.Decl) bool {
|
||||
return a.src < b.src;
|
||||
return a.src_index < b.src_index;
|
||||
}
|
||||
}).lessThan);
|
||||
|
||||
@ -1113,7 +1155,7 @@ const EmitZIR = struct {
|
||||
for (src_decls.items) |ir_decl| {
|
||||
if (self.old_module.export_owners.getValue(ir_decl)) |exports| {
|
||||
for (exports) |module_export| {
|
||||
const declval = try self.emitDeclVal(ir_decl.src, mem.spanZ(module_export.exported_decl.name));
|
||||
const declval = try self.emitDeclVal(ir_decl.src(), mem.spanZ(module_export.exported_decl.name));
|
||||
const symbol_name = try self.emitStringLiteral(module_export.src, module_export.options.name);
|
||||
const export_inst = try self.arena.allocator.create(Inst.Export);
|
||||
export_inst.* = .{
|
||||
@ -1131,7 +1173,7 @@ const EmitZIR = struct {
|
||||
try self.decls.append(self.allocator, &export_inst.base);
|
||||
}
|
||||
} else {
|
||||
const new_decl = try self.emitTypedValue(ir_decl.src, ir_decl.typed_value.most_recent.typed_value);
|
||||
const new_decl = try self.emitTypedValue(ir_decl.src(), ir_decl.typed_value.most_recent.typed_value);
|
||||
new_decl.name = try self.arena.allocator.dupe(u8, mem.spanZ(ir_decl.name));
|
||||
}
|
||||
}
|
||||
@ -1301,7 +1343,7 @@ const EmitZIR = struct {
|
||||
},
|
||||
}
|
||||
|
||||
const fn_type = try self.emitType(src, module_fn.fn_type);
|
||||
const fn_type = try self.emitType(src, typed_value.ty);
|
||||
|
||||
const arena_instrs = try self.arena.allocator.alloc(*Inst, instructions.items.len);
|
||||
mem.copy(*Inst, arena_instrs, instructions.items);
|
||||
@ -1399,7 +1441,23 @@ const EmitZIR = struct {
|
||||
break :blk &new_inst.base;
|
||||
},
|
||||
.unreach => try self.emitTrivial(inst.src, Inst.Unreachable),
|
||||
.ret => try self.emitTrivial(inst.src, Inst.Return),
|
||||
.ret => blk: {
|
||||
const old_inst = inst.cast(ir.Inst.Ret).?;
|
||||
const new_inst = try self.arena.allocator.create(Inst.Return);
|
||||
new_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = inst.src,
|
||||
.tag = Inst.Return.base_tag,
|
||||
},
|
||||
.positionals = .{
|
||||
.operand = try self.resolveInst(inst_table, old_inst.args.operand),
|
||||
},
|
||||
.kw_args = .{},
|
||||
};
|
||||
break :blk &new_inst.base;
|
||||
},
|
||||
.retvoid => try self.emitTrivial(inst.src, Inst.ReturnVoid),
|
||||
.constant => unreachable, // excluded from function bodies
|
||||
.assembly => blk: {
|
||||
const old_inst = inst.cast(ir.Inst.Assembly).?;
|
||||
|
||||
@ -7473,6 +7473,12 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n
|
||||
continue;
|
||||
}
|
||||
ZigValue *field_val = const_val->data.x_struct.fields[i];
|
||||
if (field_val == nullptr) {
|
||||
add_node_error(g, type_struct_field->decl_node,
|
||||
buf_sprintf("compiler bug: generating const value for struct field '%s'",
|
||||
buf_ptr(type_struct_field->name)));
|
||||
codegen_report_errors_and_exit(g);
|
||||
}
|
||||
ZigType *field_type = field_val->type;
|
||||
assert(field_type != nullptr);
|
||||
if ((err = ensure_const_val_repr(nullptr, g, nullptr, field_val, field_type))) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user