mirror of
https://github.com/ziglang/zig.git
synced 2026-01-21 06:45:24 +00:00
self-hosted: improve handling of anonymous decls
* anonymous decls have automatically generated names and symbols, and participate in the same memory management as named decls. * the Ref instruction is deleted * the DeclRef instruction now takes a `[]const u8` and DeclRefStr takes an arbitrary string instruction operand. * introduce a `zir.Decl` type for ZIR Module decls which holds content_hash and name - fields that are not needed for `zir.Inst` which are created as part of semantic analysis. This improves the function signatures of Module.zig and lowers memory usage. * the Str instruction is now defined to create an anonymous Decl and reference it.
This commit is contained in:
parent
6938245fcc
commit
d9c1d8fed3
@ -63,6 +63,8 @@ failed_exports: std.AutoHashMap(*Export, *ErrorMsg),
|
||||
/// previous analysis.
|
||||
generation: u32 = 0,
|
||||
|
||||
next_anon_name_index: usize = 0,
|
||||
|
||||
/// Candidates for deletion. After a semantic analysis update completes, this list
|
||||
/// contains Decls that need to be deleted if they end up having no references to them.
|
||||
deletion_set: std.ArrayListUnmanaged(*Decl) = .{},
|
||||
@ -193,8 +195,8 @@ pub const Decl = struct {
|
||||
.zir_module => {
|
||||
const zir_module = @fieldParentPtr(Scope.ZIRModule, "base", self.scope);
|
||||
const module = zir_module.contents.module;
|
||||
const decl_inst = module.decls[self.src_index];
|
||||
return decl_inst.src;
|
||||
const src_decl = module.decls[self.src_index];
|
||||
return src_decl.inst.src;
|
||||
},
|
||||
.block => unreachable,
|
||||
.gen_zir => unreachable,
|
||||
@ -999,9 +1001,9 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
|
||||
};
|
||||
const decl_name = mem.spanZ(decl.name);
|
||||
// We already detected deletions, so we know this will be found.
|
||||
const src_decl = zir_module.findDecl(decl_name).?;
|
||||
decl.src_index = src_decl.index;
|
||||
self.reAnalyzeDecl(decl, src_decl.decl) catch |err| switch (err) {
|
||||
const src_decl_and_index = zir_module.findDecl(decl_name).?;
|
||||
decl.src_index = src_decl_and_index.index;
|
||||
self.reAnalyzeDecl(decl, src_decl_and_index.decl.inst) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.AnalysisFail => continue,
|
||||
};
|
||||
@ -1280,10 +1282,7 @@ fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerE
|
||||
}
|
||||
}
|
||||
|
||||
// Decl lookup
|
||||
const namespace = scope.namespace();
|
||||
const name_hash = namespace.fullyQualifiedNameHash(ident_name);
|
||||
if (self.decl_table.getValue(name_hash)) |decl| {
|
||||
if (self.lookupDeclName(scope, ident_name)) |decl| {
|
||||
const src = tree.token_locs[ident.token].start;
|
||||
return try self.addZIRInst(scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{});
|
||||
}
|
||||
@ -1307,24 +1306,26 @@ fn astGenStringLiteral(self: *Module, scope: *Scope, str_lit: *ast.Node.StringLi
|
||||
};
|
||||
|
||||
const src = tree.token_locs[str_lit.token].start;
|
||||
const str_inst = try self.addZIRInst(scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{});
|
||||
return self.addZIRInst(scope, src, zir.Inst.Ref, .{ .operand = str_inst }, .{});
|
||||
return self.addZIRInst(scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{});
|
||||
}
|
||||
|
||||
fn astGenIntegerLiteral(self: *Module, scope: *Scope, int_lit: *ast.Node.IntegerLiteral) InnerError!*zir.Inst {
|
||||
const arena = scope.arena();
|
||||
const tree = scope.tree();
|
||||
var bytes = tree.tokenSlice(int_lit.token);
|
||||
const base = if (mem.startsWith(u8, bytes, "0x"))
|
||||
const prefixed_bytes = tree.tokenSlice(int_lit.token);
|
||||
const base = if (mem.startsWith(u8, prefixed_bytes, "0x"))
|
||||
16
|
||||
else if (mem.startsWith(u8, bytes, "0o"))
|
||||
else if (mem.startsWith(u8, prefixed_bytes, "0o"))
|
||||
8
|
||||
else if (mem.startsWith(u8, bytes, "0b"))
|
||||
else if (mem.startsWith(u8, prefixed_bytes, "0b"))
|
||||
2
|
||||
else
|
||||
@as(u8, 10);
|
||||
|
||||
if (base != 10) bytes = bytes[2..];
|
||||
const bytes = if (base == 10)
|
||||
prefixed_bytes
|
||||
else
|
||||
prefixed_bytes[2..];
|
||||
|
||||
if (std.fmt.parseInt(u64, bytes, base)) |small_int| {
|
||||
const int_payload = try arena.create(Value.Payload.Int_u64);
|
||||
@ -1647,9 +1648,9 @@ fn analyzeRootZIRModule(self: *Module, root_scope: *Scope.ZIRModule) !void {
|
||||
// appendAssumeCapacity.
|
||||
try self.work_queue.ensureUnusedCapacity(src_module.decls.len);
|
||||
|
||||
for (src_module.decls) |decl| {
|
||||
if (decl.cast(zir.Inst.Export)) |export_inst| {
|
||||
_ = try self.resolveDecl(&root_scope.base, &export_inst.base);
|
||||
for (src_module.decls) |src_decl| {
|
||||
if (src_decl.inst.cast(zir.Inst.Export)) |export_inst| {
|
||||
_ = try self.resolveDecl(&root_scope.base, src_decl);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1662,7 +1663,7 @@ fn analyzeRootZIRModule(self: *Module, root_scope: *Scope.ZIRModule) !void {
|
||||
=> {
|
||||
const src_module = try self.getSrcModule(root_scope);
|
||||
|
||||
var exports_to_resolve = std.ArrayList(*zir.Inst).init(self.allocator);
|
||||
var exports_to_resolve = std.ArrayList(*zir.Decl).init(self.allocator);
|
||||
defer exports_to_resolve.deinit();
|
||||
|
||||
// Keep track of the decls that we expect to see in this file so that
|
||||
@ -1687,8 +1688,8 @@ fn analyzeRootZIRModule(self: *Module, root_scope: *Scope.ZIRModule) !void {
|
||||
try self.markOutdatedDecl(decl);
|
||||
decl.contents_hash = src_decl.contents_hash;
|
||||
}
|
||||
} else if (src_decl.cast(zir.Inst.Export)) |export_inst| {
|
||||
try exports_to_resolve.append(&export_inst.base);
|
||||
} else if (src_decl.inst.cast(zir.Inst.Export)) |export_inst| {
|
||||
try exports_to_resolve.append(src_decl);
|
||||
}
|
||||
}
|
||||
{
|
||||
@ -1700,8 +1701,8 @@ fn analyzeRootZIRModule(self: *Module, root_scope: *Scope.ZIRModule) !void {
|
||||
try self.deleteDecl(kv.key);
|
||||
}
|
||||
}
|
||||
for (exports_to_resolve.items) |export_inst| {
|
||||
_ = try self.resolveDecl(&root_scope.base, export_inst);
|
||||
for (exports_to_resolve.items) |export_decl| {
|
||||
_ = try self.resolveDecl(&root_scope.base, export_decl);
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -1945,7 +1946,7 @@ fn createNewDecl(
|
||||
return new_decl;
|
||||
}
|
||||
|
||||
fn analyzeNewDecl(self: *Module, new_decl: *Decl, old_inst: *zir.Inst) InnerError!void {
|
||||
fn analyzeNewDecl(self: *Module, new_decl: *Decl, src_decl: *zir.Decl) InnerError!void {
|
||||
var decl_scope: Scope.DeclAnalysis = .{
|
||||
.decl = new_decl,
|
||||
.arena = std.heap.ArenaAllocator.init(self.allocator),
|
||||
@ -1954,7 +1955,7 @@ fn analyzeNewDecl(self: *Module, new_decl: *Decl, old_inst: *zir.Inst) InnerErro
|
||||
|
||||
new_decl.analysis = .in_progress;
|
||||
|
||||
const typed_value = self.analyzeConstInst(&decl_scope.base, old_inst) catch |err| switch (err) {
|
||||
const typed_value = self.analyzeConstInst(&decl_scope.base, src_decl.inst) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.AnalysisFail => {
|
||||
switch (new_decl.analysis) {
|
||||
@ -1986,33 +1987,32 @@ fn analyzeNewDecl(self: *Module, new_decl: *Decl, old_inst: *zir.Inst) InnerErro
|
||||
}
|
||||
}
|
||||
|
||||
fn resolveDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Decl {
|
||||
assert(old_inst.name.len == 0);
|
||||
fn resolveDecl(self: *Module, scope: *Scope, src_decl: *zir.Decl) InnerError!*Decl {
|
||||
// If the name is empty, then we make this an anonymous Decl.
|
||||
const scope_decl = scope.decl().?;
|
||||
const new_decl = try self.allocateNewDecl(scope, scope_decl.src_index, old_inst.contents_hash);
|
||||
try self.analyzeNewDecl(new_decl, old_inst);
|
||||
const new_decl = try self.allocateNewDecl(scope, scope_decl.src_index, src_decl.contents_hash);
|
||||
try self.analyzeNewDecl(new_decl, src_decl);
|
||||
return new_decl;
|
||||
//const name_hash = Decl.hashSimpleName(old_inst.name);
|
||||
//const name_hash = Decl.hashSimpleName(src_decl.name);
|
||||
//if (self.decl_table.get(name_hash)) |kv| {
|
||||
// const decl = kv.value;
|
||||
// decl.src = old_inst.src;
|
||||
// try self.reAnalyzeDecl(decl, old_inst);
|
||||
// decl.src = src_decl.src;
|
||||
// try self.reAnalyzeDecl(decl, src_decl);
|
||||
// return decl;
|
||||
//} else if (old_inst.cast(zir.Inst.DeclVal)) |decl_val| {
|
||||
//} else if (src_decl.cast(zir.Inst.DeclVal)) |decl_val| {
|
||||
// // This is just a named reference to another decl.
|
||||
// return self.analyzeDeclVal(scope, decl_val);
|
||||
//} else {
|
||||
// const new_decl = try self.createNewDecl(scope, old_inst.name, old_inst.src, name_hash, old_inst.contents_hash);
|
||||
// try self.analyzeNewDecl(new_decl, old_inst);
|
||||
// const new_decl = try self.createNewDecl(scope, src_decl.name, src_decl.src, name_hash, src_decl.contents_hash);
|
||||
// try self.analyzeNewDecl(new_decl, src_decl);
|
||||
|
||||
// return new_decl;
|
||||
//}
|
||||
}
|
||||
|
||||
/// Declares a dependency on the decl.
|
||||
fn resolveCompleteDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Decl {
|
||||
const decl = try self.resolveDecl(scope, old_inst);
|
||||
fn resolveCompleteDecl(self: *Module, scope: *Scope, src_decl: *zir.Decl) InnerError!*Decl {
|
||||
const decl = try self.resolveDecl(scope, src_decl);
|
||||
switch (decl.analysis) {
|
||||
.unreferenced => unreachable,
|
||||
.in_progress => unreachable,
|
||||
@ -2163,7 +2163,6 @@ fn newZIRInst(
|
||||
inst.* = .{
|
||||
.base = .{
|
||||
.tag = T.base_tag,
|
||||
.name = "",
|
||||
.src = src,
|
||||
},
|
||||
.positionals = positionals,
|
||||
@ -2220,19 +2219,6 @@ fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue)
|
||||
return &const_inst.base;
|
||||
}
|
||||
|
||||
fn constStr(self: *Module, scope: *Scope, src: usize, str: []const u8) !*Inst {
|
||||
const ty_payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0);
|
||||
ty_payload.* = .{ .len = str.len };
|
||||
|
||||
const bytes_payload = try scope.arena().create(Value.Payload.Bytes);
|
||||
bytes_payload.* = .{ .data = str };
|
||||
|
||||
return self.constInst(scope, src, .{
|
||||
.ty = Type.initPayload(&ty_payload.base),
|
||||
.val = Value.initPayload(&bytes_payload.base),
|
||||
});
|
||||
}
|
||||
|
||||
fn constType(self: *Module, scope: *Scope, src: usize, ty: Type) !*Inst {
|
||||
return self.constInst(scope, src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
@ -2339,15 +2325,10 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
|
||||
.compileerror => return self.analyzeInstCompileError(scope, old_inst.cast(zir.Inst.CompileError).?),
|
||||
.@"const" => return self.analyzeInstConst(scope, old_inst.cast(zir.Inst.Const).?),
|
||||
.declref => return self.analyzeInstDeclRef(scope, old_inst.cast(zir.Inst.DeclRef).?),
|
||||
.declref_str => return self.analyzeInstDeclRefStr(scope, old_inst.cast(zir.Inst.DeclRefStr).?),
|
||||
.declval => return self.analyzeInstDeclVal(scope, old_inst.cast(zir.Inst.DeclVal).?),
|
||||
.declval_in_module => return self.analyzeInstDeclValInModule(scope, old_inst.cast(zir.Inst.DeclValInModule).?),
|
||||
.str => {
|
||||
const bytes = old_inst.cast(zir.Inst.Str).?.positionals.bytes;
|
||||
// The bytes references memory inside the ZIR module, which can get deallocated
|
||||
// after semantic analysis is complete. We need the memory to be in the Decl's arena.
|
||||
const arena_bytes = try scope.arena().dupe(u8, bytes);
|
||||
return self.constStr(scope, old_inst.src, arena_bytes);
|
||||
},
|
||||
.str => return self.analyzeInstStr(scope, old_inst.cast(zir.Inst.Str).?),
|
||||
.int => {
|
||||
const big_int = old_inst.cast(zir.Inst.Int).?.positionals.int;
|
||||
return self.constIntBig(scope, old_inst.src, Type.initTag(.comptime_int), big_int);
|
||||
@ -2363,7 +2344,6 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
|
||||
.@"fn" => return self.analyzeInstFn(scope, old_inst.cast(zir.Inst.Fn).?),
|
||||
.@"export" => return self.analyzeInstExport(scope, old_inst.cast(zir.Inst.Export).?),
|
||||
.primitive => return self.analyzeInstPrimitive(scope, old_inst.cast(zir.Inst.Primitive).?),
|
||||
.ref => return self.analyzeInstRef(scope, old_inst.cast(zir.Inst.Ref).?),
|
||||
.fntype => return self.analyzeInstFnType(scope, old_inst.cast(zir.Inst.FnType).?),
|
||||
.intcast => return self.analyzeInstIntCast(scope, old_inst.cast(zir.Inst.IntCast).?),
|
||||
.bitcast => return self.analyzeInstBitCast(scope, old_inst.cast(zir.Inst.BitCast).?),
|
||||
@ -2376,9 +2356,75 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
|
||||
}
|
||||
}
|
||||
|
||||
fn analyzeInstStr(self: *Module, scope: *Scope, str_inst: *zir.Inst.Str) InnerError!*Inst {
|
||||
// The bytes references memory inside the ZIR module, which can get deallocated
|
||||
// after semantic analysis is complete. We need the memory to be in the new anonymous Decl's arena.
|
||||
var new_decl_arena = std.heap.ArenaAllocator.init(self.allocator);
|
||||
const arena_bytes = try new_decl_arena.allocator.dupe(u8, str_inst.positionals.bytes);
|
||||
|
||||
const ty_payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0);
|
||||
ty_payload.* = .{ .len = arena_bytes.len };
|
||||
|
||||
const bytes_payload = try scope.arena().create(Value.Payload.Bytes);
|
||||
bytes_payload.* = .{ .data = arena_bytes };
|
||||
|
||||
const new_decl = try self.createAnonymousDecl(scope, &new_decl_arena, .{
|
||||
.ty = Type.initPayload(&ty_payload.base),
|
||||
.val = Value.initPayload(&bytes_payload.base),
|
||||
});
|
||||
return self.analyzeDeclRef(scope, str_inst.base.src, new_decl);
|
||||
}
|
||||
|
||||
fn createAnonymousDecl(
|
||||
self: *Module,
|
||||
scope: *Scope,
|
||||
decl_arena: *std.heap.ArenaAllocator,
|
||||
typed_value: TypedValue,
|
||||
) !*Decl {
|
||||
var name_buf: [32]u8 = undefined;
|
||||
const name_index = self.getNextAnonNameIndex();
|
||||
const name = std.fmt.bufPrint(&name_buf, "unnamed_{}", .{name_index}) catch unreachable;
|
||||
const name_hash = scope.namespace().fullyQualifiedNameHash(name);
|
||||
const scope_decl = scope.decl().?;
|
||||
const src_hash: std.zig.SrcHash = undefined;
|
||||
const new_decl = try self.createNewDecl(scope, name, scope_decl.src_index, name_hash, src_hash);
|
||||
const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
|
||||
|
||||
decl_arena_state.* = decl_arena.state;
|
||||
new_decl.typed_value = .{
|
||||
.most_recent = .{
|
||||
.typed_value = typed_value,
|
||||
.arena = decl_arena_state,
|
||||
},
|
||||
};
|
||||
new_decl.analysis = .complete;
|
||||
new_decl.generation = self.generation;
|
||||
|
||||
// TODO: This generates the Decl into the machine code file if it is of a type that is non-zero size.
|
||||
// We should be able to further improve the compiler to not omit Decls which are only referenced at
|
||||
// compile-time and not runtime.
|
||||
if (typed_value.ty.hasCodeGenBits()) {
|
||||
try self.bin_file.allocateDeclIndexes(new_decl);
|
||||
try self.work_queue.writeItem(.{ .codegen_decl = new_decl });
|
||||
}
|
||||
|
||||
return new_decl;
|
||||
}
|
||||
|
||||
fn getNextAnonNameIndex(self: *Module) usize {
|
||||
return @atomicRmw(usize, &self.next_anon_name_index, .Add, 1, .Monotonic);
|
||||
}
|
||||
|
||||
fn lookupDeclName(self: *Module, scope: *Scope, ident_name: []const u8) ?*Decl {
|
||||
const namespace = scope.namespace();
|
||||
const name_hash = namespace.fullyQualifiedNameHash(ident_name);
|
||||
return self.decl_table.getValue(name_hash);
|
||||
}
|
||||
|
||||
fn analyzeInstExport(self: *Module, scope: *Scope, export_inst: *zir.Inst.Export) InnerError!*Inst {
|
||||
const symbol_name = try self.resolveConstString(scope, export_inst.positionals.symbol_name);
|
||||
const exported_decl = try self.resolveCompleteDecl(scope, export_inst.positionals.value);
|
||||
const exported_decl = self.lookupDeclName(scope, export_inst.positionals.decl_name) orelse
|
||||
return self.fail(scope, export_inst.base.src, "decl '{}' not found", .{export_inst.positionals.decl_name});
|
||||
try self.analyzeExport(scope, export_inst.base.src, symbol_name, exported_decl);
|
||||
return self.constVoid(scope, export_inst.base.src);
|
||||
}
|
||||
@ -2392,26 +2438,13 @@ fn analyzeInstBreakpoint(self: *Module, scope: *Scope, inst: *zir.Inst.Breakpoin
|
||||
return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, {});
|
||||
}
|
||||
|
||||
fn analyzeInstRef(self: *Module, scope: *Scope, inst: *zir.Inst.Ref) InnerError!*Inst {
|
||||
const decl = try self.resolveCompleteDecl(scope, inst.positionals.operand);
|
||||
return self.analyzeDeclRef(scope, inst.base.src, decl);
|
||||
fn analyzeInstDeclRefStr(self: *Module, scope: *Scope, inst: *zir.Inst.DeclRefStr) InnerError!*Inst {
|
||||
const decl_name = try self.resolveConstString(scope, inst.positionals.name);
|
||||
return self.analyzeDeclRefByName(scope, inst.base.src, decl_name);
|
||||
}
|
||||
|
||||
fn analyzeInstDeclRef(self: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) InnerError!*Inst {
|
||||
const decl_name = try self.resolveConstString(scope, inst.positionals.name);
|
||||
// This will need to get more fleshed out when there are proper structs & namespaces.
|
||||
const namespace = scope.namespace();
|
||||
if (namespace.cast(Scope.File)) |scope_file| {
|
||||
return self.fail(scope, inst.base.src, "TODO implement declref for zig source", .{});
|
||||
} else if (namespace.cast(Scope.ZIRModule)) |zir_module| {
|
||||
const src_decl = zir_module.contents.module.findDecl(decl_name) orelse
|
||||
return self.fail(scope, inst.positionals.name.src, "use of undeclared identifier '{}'", .{decl_name});
|
||||
|
||||
const decl = try self.resolveCompleteDecl(scope, src_decl.decl);
|
||||
return self.analyzeDeclRef(scope, inst.base.src, decl);
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
return self.analyzeDeclRefByName(scope, inst.base.src, inst.positionals.name);
|
||||
}
|
||||
|
||||
fn analyzeDeclVal(self: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Decl {
|
||||
@ -2465,6 +2498,12 @@ fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) InnerEr
|
||||
});
|
||||
}
|
||||
|
||||
fn analyzeDeclRefByName(self: *Module, scope: *Scope, src: usize, decl_name: []const u8) InnerError!*Inst {
|
||||
const decl = self.lookupDeclName(scope, decl_name) orelse
|
||||
return self.fail(scope, src, "decl '{}' not found", .{decl_name});
|
||||
return self.analyzeDeclRef(scope, src, decl);
|
||||
}
|
||||
|
||||
fn analyzeInstCall(self: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
|
||||
const func = try self.resolveInst(scope, inst.positionals.func);
|
||||
if (func.ty.zigTypeTag() != .Fn)
|
||||
|
||||
@ -12,19 +12,23 @@ const TypedValue = @import("TypedValue.zig");
|
||||
const ir = @import("ir.zig");
|
||||
const IrModule = @import("Module.zig");
|
||||
|
||||
/// This struct is relevent only for the ZIR Module text format. It is not used for
|
||||
/// semantic analysis of Zig source code.
|
||||
pub const Decl = struct {
|
||||
name: []const u8,
|
||||
|
||||
/// Hash of slice into the source of the part after the = and before the next instruction.
|
||||
contents_hash: std.zig.SrcHash,
|
||||
|
||||
inst: *Inst,
|
||||
};
|
||||
|
||||
/// These are instructions that correspond to the ZIR text format. See `ir.Inst` for
|
||||
/// in-memory, analyzed instructions with types and values.
|
||||
/// TODO Separate into Decl and Inst. Decl will have extra fields, and will make the
|
||||
/// undefined default field value of contents_hash no longer needed.
|
||||
pub const Inst = struct {
|
||||
tag: Tag,
|
||||
/// Byte offset into the source.
|
||||
src: usize,
|
||||
name: []const u8,
|
||||
|
||||
/// 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,
|
||||
|
||||
@ -37,11 +41,14 @@ pub const Inst = struct {
|
||||
@"const",
|
||||
/// Represents a pointer to a global decl by name.
|
||||
declref,
|
||||
/// Represents a pointer to a global decl by string name.
|
||||
declref_str,
|
||||
/// 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,
|
||||
/// String Literal. Makes an anonymous Decl and then takes a pointer to it.
|
||||
str,
|
||||
int,
|
||||
ptrtoint,
|
||||
@ -56,7 +63,6 @@ pub const Inst = struct {
|
||||
fntype,
|
||||
@"export",
|
||||
primitive,
|
||||
ref,
|
||||
intcast,
|
||||
bitcast,
|
||||
elemptr,
|
||||
@ -72,6 +78,7 @@ pub const Inst = struct {
|
||||
.breakpoint => Breakpoint,
|
||||
.call => Call,
|
||||
.declref => DeclRef,
|
||||
.declref_str => DeclRefStr,
|
||||
.declval => DeclVal,
|
||||
.declval_in_module => DeclValInModule,
|
||||
.compileerror => CompileError,
|
||||
@ -89,7 +96,6 @@ pub const Inst = struct {
|
||||
.@"fn" => Fn,
|
||||
.@"export" => Export,
|
||||
.primitive => Primitive,
|
||||
.ref => Ref,
|
||||
.fntype => FnType,
|
||||
.intcast => IntCast,
|
||||
.bitcast => BitCast,
|
||||
@ -134,6 +140,16 @@ pub const Inst = struct {
|
||||
pub const base_tag = Tag.declref;
|
||||
base: Inst,
|
||||
|
||||
positionals: struct {
|
||||
name: []const u8,
|
||||
},
|
||||
kw_args: struct {},
|
||||
};
|
||||
|
||||
pub const DeclRefStr = struct {
|
||||
pub const base_tag = Tag.declref_str;
|
||||
base: Inst,
|
||||
|
||||
positionals: struct {
|
||||
name: *Inst,
|
||||
},
|
||||
@ -316,17 +332,7 @@ pub const Inst = struct {
|
||||
|
||||
positionals: struct {
|
||||
symbol_name: *Inst,
|
||||
value: *Inst,
|
||||
},
|
||||
kw_args: struct {},
|
||||
};
|
||||
|
||||
pub const Ref = struct {
|
||||
pub const base_tag = Tag.ref;
|
||||
base: Inst,
|
||||
|
||||
positionals: struct {
|
||||
operand: *Inst,
|
||||
decl_name: []const u8,
|
||||
},
|
||||
kw_args: struct {},
|
||||
};
|
||||
@ -500,7 +506,7 @@ pub const ErrorMsg = struct {
|
||||
};
|
||||
|
||||
pub const Module = struct {
|
||||
decls: []*Inst,
|
||||
decls: []*Decl,
|
||||
arena: std.heap.ArenaAllocator,
|
||||
error_msg: ?ErrorMsg = null,
|
||||
|
||||
@ -519,10 +525,10 @@ pub const Module = struct {
|
||||
self.writeToStream(std.heap.page_allocator, std.io.getStdErr().outStream()) catch {};
|
||||
}
|
||||
|
||||
const InstPtrTable = std.AutoHashMap(*Inst, struct { inst: *Inst, index: ?usize });
|
||||
const InstPtrTable = std.AutoHashMap(*Inst, struct { inst: *Inst, index: ?usize, name: []const u8 });
|
||||
|
||||
const DeclAndIndex = struct {
|
||||
decl: *Inst,
|
||||
decl: *Decl,
|
||||
index: usize,
|
||||
};
|
||||
|
||||
@ -549,18 +555,18 @@ pub const Module = struct {
|
||||
try inst_table.ensureCapacity(self.decls.len);
|
||||
|
||||
for (self.decls) |decl, decl_i| {
|
||||
try inst_table.putNoClobber(decl, .{ .inst = decl, .index = null });
|
||||
try inst_table.putNoClobber(decl.inst, .{ .inst = decl.inst, .index = null, .name = decl.name });
|
||||
|
||||
if (decl.cast(Inst.Fn)) |fn_inst| {
|
||||
if (decl.inst.cast(Inst.Fn)) |fn_inst| {
|
||||
for (fn_inst.positionals.body.instructions) |inst, inst_i| {
|
||||
try inst_table.putNoClobber(inst, .{ .inst = inst, .index = inst_i });
|
||||
try inst_table.putNoClobber(inst, .{ .inst = inst, .index = inst_i, .name = undefined });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (self.decls) |decl, i| {
|
||||
try stream.print("@{} ", .{decl.name});
|
||||
try self.writeInstToStream(stream, decl, &inst_table);
|
||||
try self.writeInstToStream(stream, decl.inst, &inst_table);
|
||||
try stream.writeByte('\n');
|
||||
}
|
||||
}
|
||||
@ -568,41 +574,41 @@ pub const Module = struct {
|
||||
fn writeInstToStream(
|
||||
self: Module,
|
||||
stream: var,
|
||||
decl: *Inst,
|
||||
inst: *Inst,
|
||||
inst_table: *const InstPtrTable,
|
||||
) @TypeOf(stream).Error!void {
|
||||
// TODO I tried implementing this with an inline for loop and hit a compiler bug
|
||||
switch (decl.tag) {
|
||||
.breakpoint => return self.writeInstToStreamGeneric(stream, .breakpoint, decl, inst_table),
|
||||
.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),
|
||||
.int => return self.writeInstToStreamGeneric(stream, .int, decl, inst_table),
|
||||
.ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, decl, inst_table),
|
||||
.fieldptr => return self.writeInstToStreamGeneric(stream, .fieldptr, decl, inst_table),
|
||||
.deref => return self.writeInstToStreamGeneric(stream, .deref, decl, inst_table),
|
||||
.as => return self.writeInstToStreamGeneric(stream, .as, decl, inst_table),
|
||||
.@"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),
|
||||
.primitive => return self.writeInstToStreamGeneric(stream, .primitive, decl, inst_table),
|
||||
.fntype => return self.writeInstToStreamGeneric(stream, .fntype, decl, inst_table),
|
||||
.intcast => return self.writeInstToStreamGeneric(stream, .intcast, decl, inst_table),
|
||||
.bitcast => return self.writeInstToStreamGeneric(stream, .bitcast, decl, inst_table),
|
||||
.elemptr => return self.writeInstToStreamGeneric(stream, .elemptr, decl, inst_table),
|
||||
.add => return self.writeInstToStreamGeneric(stream, .add, decl, inst_table),
|
||||
.cmp => return self.writeInstToStreamGeneric(stream, .cmp, decl, inst_table),
|
||||
.condbr => return self.writeInstToStreamGeneric(stream, .condbr, decl, inst_table),
|
||||
.isnull => return self.writeInstToStreamGeneric(stream, .isnull, decl, inst_table),
|
||||
.isnonnull => return self.writeInstToStreamGeneric(stream, .isnonnull, decl, inst_table),
|
||||
switch (inst.tag) {
|
||||
.breakpoint => return self.writeInstToStreamGeneric(stream, .breakpoint, inst, inst_table),
|
||||
.call => return self.writeInstToStreamGeneric(stream, .call, inst, inst_table),
|
||||
.declref => return self.writeInstToStreamGeneric(stream, .declref, inst, inst_table),
|
||||
.declref_str => return self.writeInstToStreamGeneric(stream, .declref_str, inst, inst_table),
|
||||
.declval => return self.writeInstToStreamGeneric(stream, .declval, inst, inst_table),
|
||||
.declval_in_module => return self.writeInstToStreamGeneric(stream, .declval_in_module, inst, inst_table),
|
||||
.compileerror => return self.writeInstToStreamGeneric(stream, .compileerror, inst, inst_table),
|
||||
.@"const" => return self.writeInstToStreamGeneric(stream, .@"const", inst, inst_table),
|
||||
.str => return self.writeInstToStreamGeneric(stream, .str, inst, inst_table),
|
||||
.int => return self.writeInstToStreamGeneric(stream, .int, inst, inst_table),
|
||||
.ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, inst, inst_table),
|
||||
.fieldptr => return self.writeInstToStreamGeneric(stream, .fieldptr, inst, inst_table),
|
||||
.deref => return self.writeInstToStreamGeneric(stream, .deref, inst, inst_table),
|
||||
.as => return self.writeInstToStreamGeneric(stream, .as, inst, inst_table),
|
||||
.@"asm" => return self.writeInstToStreamGeneric(stream, .@"asm", inst, inst_table),
|
||||
.@"unreachable" => return self.writeInstToStreamGeneric(stream, .@"unreachable", inst, inst_table),
|
||||
.@"return" => return self.writeInstToStreamGeneric(stream, .@"return", inst, inst_table),
|
||||
.returnvoid => return self.writeInstToStreamGeneric(stream, .returnvoid, inst, inst_table),
|
||||
.@"fn" => return self.writeInstToStreamGeneric(stream, .@"fn", inst, inst_table),
|
||||
.@"export" => return self.writeInstToStreamGeneric(stream, .@"export", inst, inst_table),
|
||||
.primitive => return self.writeInstToStreamGeneric(stream, .primitive, inst, inst_table),
|
||||
.fntype => return self.writeInstToStreamGeneric(stream, .fntype, inst, inst_table),
|
||||
.intcast => return self.writeInstToStreamGeneric(stream, .intcast, inst, inst_table),
|
||||
.bitcast => return self.writeInstToStreamGeneric(stream, .bitcast, inst, inst_table),
|
||||
.elemptr => return self.writeInstToStreamGeneric(stream, .elemptr, inst, inst_table),
|
||||
.add => return self.writeInstToStreamGeneric(stream, .add, inst, inst_table),
|
||||
.cmp => return self.writeInstToStreamGeneric(stream, .cmp, inst, inst_table),
|
||||
.condbr => return self.writeInstToStreamGeneric(stream, .condbr, inst, inst_table),
|
||||
.isnull => return self.writeInstToStreamGeneric(stream, .isnull, inst, inst_table),
|
||||
.isnonnull => return self.writeInstToStreamGeneric(stream, .isnonnull, inst, inst_table),
|
||||
}
|
||||
}
|
||||
|
||||
@ -685,7 +691,7 @@ pub const Module = struct {
|
||||
if (info.index) |i| {
|
||||
try stream.print("%{}", .{info.index});
|
||||
} else {
|
||||
try stream.print("@{}", .{info.inst.name});
|
||||
try stream.print("@{}", .{info.name});
|
||||
}
|
||||
} else if (inst.cast(Inst.DeclVal)) |decl_val| {
|
||||
try stream.print("@{}", .{decl_val.positionals.name});
|
||||
@ -732,7 +738,7 @@ const Parser = struct {
|
||||
arena: std.heap.ArenaAllocator,
|
||||
i: usize,
|
||||
source: [:0]const u8,
|
||||
decls: std.ArrayListUnmanaged(*Inst),
|
||||
decls: std.ArrayListUnmanaged(*Decl),
|
||||
global_name_map: *std.StringHashMap(usize),
|
||||
error_msg: ?ErrorMsg = null,
|
||||
unnamed_index: usize,
|
||||
@ -761,12 +767,12 @@ const Parser = struct {
|
||||
skipSpace(self);
|
||||
try requireEatBytes(self, "=");
|
||||
skipSpace(self);
|
||||
const inst = try parseInstruction(self, &body_context, ident);
|
||||
const decl = try parseInstruction(self, &body_context, ident);
|
||||
const ident_index = body_context.instructions.items.len;
|
||||
if (try body_context.name_map.put(ident, ident_index)) |_| {
|
||||
return self.fail("redefinition of identifier '{}'", .{ident});
|
||||
}
|
||||
try body_context.instructions.append(inst);
|
||||
try body_context.instructions.append(decl.inst);
|
||||
continue;
|
||||
},
|
||||
' ', '\n' => continue,
|
||||
@ -916,7 +922,7 @@ const Parser = struct {
|
||||
return error.ParseFailure;
|
||||
}
|
||||
|
||||
fn parseInstruction(self: *Parser, body_ctx: ?*Body, name: []const u8) InnerError!*Inst {
|
||||
fn parseInstruction(self: *Parser, body_ctx: ?*Body, name: []const u8) InnerError!*Decl {
|
||||
const contents_start = self.i;
|
||||
const fn_name = try skipToAndOver(self, '(');
|
||||
inline for (@typeInfo(Inst.Tag).Enum.fields) |field| {
|
||||
@ -935,10 +941,9 @@ const Parser = struct {
|
||||
body_ctx: ?*Body,
|
||||
inst_name: []const u8,
|
||||
contents_start: usize,
|
||||
) InnerError!*Inst {
|
||||
) InnerError!*Decl {
|
||||
const inst_specific = try self.arena.allocator.create(InstType);
|
||||
inst_specific.base = .{
|
||||
.name = inst_name,
|
||||
.src = self.i,
|
||||
.tag = InstType.base_tag,
|
||||
};
|
||||
@ -988,10 +993,15 @@ const Parser = struct {
|
||||
}
|
||||
try requireEatBytes(self, ")");
|
||||
|
||||
inst_specific.base.contents_hash = std.zig.hashSrc(self.source[contents_start..self.i]);
|
||||
const decl = try self.arena.allocator.create(Decl);
|
||||
decl.* = .{
|
||||
.name = inst_name,
|
||||
.contents_hash = std.zig.hashSrc(self.source[contents_start..self.i]),
|
||||
.inst = &inst_specific.base,
|
||||
};
|
||||
//std.debug.warn("parsed {} = '{}'\n", .{ inst_specific.base.name, inst_specific.base.contents });
|
||||
|
||||
return &inst_specific.base;
|
||||
return decl;
|
||||
}
|
||||
|
||||
fn parseParameterGeneric(self: *Parser, comptime T: type, body_ctx: ?*Body) !T {
|
||||
@ -1075,7 +1085,6 @@ const Parser = struct {
|
||||
const declval = try self.arena.allocator.create(Inst.DeclVal);
|
||||
declval.* = .{
|
||||
.base = .{
|
||||
.name = try self.generateName(),
|
||||
.src = src,
|
||||
.tag = Inst.DeclVal.base_tag,
|
||||
},
|
||||
@ -1088,7 +1097,7 @@ const Parser = struct {
|
||||
if (local_ref) {
|
||||
return body_ctx.?.instructions.items[kv.value];
|
||||
} else {
|
||||
return self.decls.items[kv.value];
|
||||
return self.decls.items[kv.value].inst;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1107,7 +1116,7 @@ pub fn emit(allocator: *Allocator, old_module: IrModule) !Module {
|
||||
.old_module = &old_module,
|
||||
.next_auto_name = 0,
|
||||
.names = std.StringHashMap(void).init(allocator),
|
||||
.primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Inst).init(allocator),
|
||||
.primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Decl).init(allocator),
|
||||
};
|
||||
defer ctx.decls.deinit(allocator);
|
||||
defer ctx.names.deinit();
|
||||
@ -1126,10 +1135,10 @@ const EmitZIR = struct {
|
||||
allocator: *Allocator,
|
||||
arena: std.heap.ArenaAllocator,
|
||||
old_module: *const IrModule,
|
||||
decls: std.ArrayListUnmanaged(*Inst),
|
||||
decls: std.ArrayListUnmanaged(*Decl),
|
||||
names: std.StringHashMap(void),
|
||||
next_auto_name: usize,
|
||||
primitive_table: std.AutoHashMap(Inst.Primitive.Builtin, *Inst),
|
||||
primitive_table: std.AutoHashMap(Inst.Primitive.Builtin, *Decl),
|
||||
|
||||
fn emit(self: *EmitZIR) !void {
|
||||
// Put all the Decls in a list and sort them by name to avoid nondeterminism introduced
|
||||
@ -1156,22 +1165,20 @@ 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 symbol_name = try self.emitStringLiteral(module_export.src, module_export.options.name);
|
||||
const export_inst = try self.arena.allocator.create(Inst.Export);
|
||||
export_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = module_export.src,
|
||||
.tag = Inst.Export.base_tag,
|
||||
},
|
||||
.positionals = .{
|
||||
.symbol_name = symbol_name,
|
||||
.value = declval,
|
||||
.symbol_name = symbol_name.inst,
|
||||
.decl_name = mem.spanZ(module_export.exported_decl.name),
|
||||
},
|
||||
.kw_args = .{},
|
||||
};
|
||||
try self.decls.append(self.allocator, &export_inst.base);
|
||||
_ = try self.emitUnnamedDecl(&export_inst.base);
|
||||
}
|
||||
} else {
|
||||
const new_decl = try self.emitTypedValue(ir_decl.src(), ir_decl.typed_value.most_recent.typed_value);
|
||||
@ -1188,7 +1195,7 @@ const EmitZIR = struct {
|
||||
} else if (const_inst.val.cast(Value.Payload.DeclRef)) |declref| blk: {
|
||||
break :blk try self.emitDeclRef(inst.src, declref.decl);
|
||||
} else blk: {
|
||||
break :blk try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val });
|
||||
break :blk (try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val })).inst;
|
||||
};
|
||||
try inst_table.putNoClobber(inst, new_decl);
|
||||
return new_decl;
|
||||
@ -1201,7 +1208,6 @@ const EmitZIR = struct {
|
||||
const declval = try self.arena.allocator.create(Inst.DeclVal);
|
||||
declval.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = src,
|
||||
.tag = Inst.DeclVal.base_tag,
|
||||
},
|
||||
@ -1211,12 +1217,11 @@ const EmitZIR = struct {
|
||||
return &declval.base;
|
||||
}
|
||||
|
||||
fn emitComptimeIntVal(self: *EmitZIR, src: usize, val: Value) !*Inst {
|
||||
fn emitComptimeIntVal(self: *EmitZIR, src: usize, val: Value) !*Decl {
|
||||
const big_int_space = try self.arena.allocator.create(Value.BigIntSpace);
|
||||
const int_inst = try self.arena.allocator.create(Inst.Int);
|
||||
int_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = src,
|
||||
.tag = Inst.Int.base_tag,
|
||||
},
|
||||
@ -1225,34 +1230,29 @@ const EmitZIR = struct {
|
||||
},
|
||||
.kw_args = .{},
|
||||
};
|
||||
try self.decls.append(self.allocator, &int_inst.base);
|
||||
return &int_inst.base;
|
||||
return self.emitUnnamedDecl(&int_inst.base);
|
||||
}
|
||||
|
||||
fn emitDeclRef(self: *EmitZIR, src: usize, decl: *IrModule.Decl) !*Inst {
|
||||
const declval = try self.emitDeclVal(src, mem.spanZ(decl.name));
|
||||
const ref_inst = try self.arena.allocator.create(Inst.Ref);
|
||||
ref_inst.* = .{
|
||||
fn emitDeclRef(self: *EmitZIR, src: usize, module_decl: *IrModule.Decl) !*Inst {
|
||||
const declref_inst = try self.arena.allocator.create(Inst.DeclRef);
|
||||
declref_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = src,
|
||||
.tag = Inst.Ref.base_tag,
|
||||
.tag = Inst.DeclRef.base_tag,
|
||||
},
|
||||
.positionals = .{
|
||||
.operand = declval,
|
||||
.name = mem.spanZ(module_decl.name),
|
||||
},
|
||||
.kw_args = .{},
|
||||
};
|
||||
try self.decls.append(self.allocator, &ref_inst.base);
|
||||
|
||||
return &ref_inst.base;
|
||||
return &declref_inst.base;
|
||||
}
|
||||
|
||||
fn emitTypedValue(self: *EmitZIR, src: usize, typed_value: TypedValue) Allocator.Error!*Inst {
|
||||
fn emitTypedValue(self: *EmitZIR, src: usize, typed_value: TypedValue) Allocator.Error!*Decl {
|
||||
const allocator = &self.arena.allocator;
|
||||
if (typed_value.val.cast(Value.Payload.DeclRef)) |decl_ref| {
|
||||
const decl = decl_ref.decl;
|
||||
return self.emitDeclRef(src, decl);
|
||||
return try self.emitUnnamedDecl(try self.emitDeclRef(src, decl));
|
||||
}
|
||||
switch (typed_value.ty.zigTypeTag()) {
|
||||
.Pointer => {
|
||||
@ -1279,18 +1279,16 @@ const EmitZIR = struct {
|
||||
const as_inst = try self.arena.allocator.create(Inst.As);
|
||||
as_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = src,
|
||||
.tag = Inst.As.base_tag,
|
||||
},
|
||||
.positionals = .{
|
||||
.dest_type = try self.emitType(src, typed_value.ty),
|
||||
.value = try self.emitComptimeIntVal(src, typed_value.val),
|
||||
.dest_type = (try self.emitType(src, typed_value.ty)).inst,
|
||||
.value = (try self.emitComptimeIntVal(src, typed_value.val)).inst,
|
||||
},
|
||||
.kw_args = .{},
|
||||
};
|
||||
|
||||
return &as_inst.base;
|
||||
return self.emitUnnamedDecl(&as_inst.base);
|
||||
},
|
||||
.Type => {
|
||||
const ty = typed_value.val.toType();
|
||||
@ -1316,7 +1314,6 @@ const EmitZIR = struct {
|
||||
const fail_inst = try self.arena.allocator.create(Inst.CompileError);
|
||||
fail_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = src,
|
||||
.tag = Inst.CompileError.base_tag,
|
||||
},
|
||||
@ -1331,7 +1328,6 @@ const EmitZIR = struct {
|
||||
const fail_inst = try self.arena.allocator.create(Inst.CompileError);
|
||||
fail_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = src,
|
||||
.tag = Inst.CompileError.base_tag,
|
||||
},
|
||||
@ -1352,18 +1348,16 @@ const EmitZIR = struct {
|
||||
const fn_inst = try self.arena.allocator.create(Inst.Fn);
|
||||
fn_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = src,
|
||||
.tag = Inst.Fn.base_tag,
|
||||
},
|
||||
.positionals = .{
|
||||
.fn_type = fn_type,
|
||||
.fn_type = fn_type.inst,
|
||||
.body = .{ .instructions = arena_instrs },
|
||||
},
|
||||
.kw_args = .{},
|
||||
};
|
||||
try self.decls.append(self.allocator, &fn_inst.base);
|
||||
return &fn_inst.base;
|
||||
return self.emitUnnamedDecl(&fn_inst.base);
|
||||
},
|
||||
.Array => {
|
||||
// TODO more checks to make sure this can be emitted as a string literal
|
||||
@ -1379,7 +1373,6 @@ const EmitZIR = struct {
|
||||
const str_inst = try self.arena.allocator.create(Inst.Str);
|
||||
str_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = src,
|
||||
.tag = Inst.Str.base_tag,
|
||||
},
|
||||
@ -1388,8 +1381,7 @@ const EmitZIR = struct {
|
||||
},
|
||||
.kw_args = .{},
|
||||
};
|
||||
try self.decls.append(self.allocator, &str_inst.base);
|
||||
return &str_inst.base;
|
||||
return self.emitUnnamedDecl(&str_inst.base);
|
||||
},
|
||||
.Void => return self.emitPrimitive(src, .void_value),
|
||||
else => |t| std.debug.panic("TODO implement emitTypedValue for {}", .{@tagName(t)}),
|
||||
@ -1400,7 +1392,6 @@ const EmitZIR = struct {
|
||||
const new_inst = try self.arena.allocator.create(T);
|
||||
new_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = src,
|
||||
.tag = T.base_tag,
|
||||
},
|
||||
@ -1429,7 +1420,6 @@ const EmitZIR = struct {
|
||||
}
|
||||
new_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = inst.src,
|
||||
.tag = Inst.Call.base_tag,
|
||||
},
|
||||
@ -1447,7 +1437,6 @@ const EmitZIR = struct {
|
||||
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,
|
||||
},
|
||||
@ -1466,12 +1455,12 @@ const EmitZIR = struct {
|
||||
|
||||
const inputs = try self.arena.allocator.alloc(*Inst, old_inst.args.inputs.len);
|
||||
for (inputs) |*elem, i| {
|
||||
elem.* = try self.emitStringLiteral(inst.src, old_inst.args.inputs[i]);
|
||||
elem.* = (try self.emitStringLiteral(inst.src, old_inst.args.inputs[i])).inst;
|
||||
}
|
||||
|
||||
const clobbers = try self.arena.allocator.alloc(*Inst, old_inst.args.clobbers.len);
|
||||
for (clobbers) |*elem, i| {
|
||||
elem.* = try self.emitStringLiteral(inst.src, old_inst.args.clobbers[i]);
|
||||
elem.* = (try self.emitStringLiteral(inst.src, old_inst.args.clobbers[i])).inst;
|
||||
}
|
||||
|
||||
const args = try self.arena.allocator.alloc(*Inst, old_inst.args.args.len);
|
||||
@ -1481,18 +1470,17 @@ const EmitZIR = struct {
|
||||
|
||||
new_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = inst.src,
|
||||
.tag = Inst.Asm.base_tag,
|
||||
},
|
||||
.positionals = .{
|
||||
.asm_source = try self.emitStringLiteral(inst.src, old_inst.args.asm_source),
|
||||
.return_type = try self.emitType(inst.src, inst.ty),
|
||||
.asm_source = (try self.emitStringLiteral(inst.src, old_inst.args.asm_source)).inst,
|
||||
.return_type = (try self.emitType(inst.src, inst.ty)).inst,
|
||||
},
|
||||
.kw_args = .{
|
||||
.@"volatile" = old_inst.args.is_volatile,
|
||||
.output = if (old_inst.args.output) |o|
|
||||
try self.emitStringLiteral(inst.src, o)
|
||||
(try self.emitStringLiteral(inst.src, o)).inst
|
||||
else
|
||||
null,
|
||||
.inputs = inputs,
|
||||
@ -1507,7 +1495,6 @@ const EmitZIR = struct {
|
||||
const new_inst = try self.arena.allocator.create(Inst.PtrToInt);
|
||||
new_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = inst.src,
|
||||
.tag = Inst.PtrToInt.base_tag,
|
||||
},
|
||||
@ -1523,12 +1510,11 @@ const EmitZIR = struct {
|
||||
const new_inst = try self.arena.allocator.create(Inst.BitCast);
|
||||
new_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = inst.src,
|
||||
.tag = Inst.BitCast.base_tag,
|
||||
},
|
||||
.positionals = .{
|
||||
.dest_type = try self.emitType(inst.src, inst.ty),
|
||||
.dest_type = (try self.emitType(inst.src, inst.ty)).inst,
|
||||
.operand = try self.resolveInst(inst_table, old_inst.args.operand),
|
||||
},
|
||||
.kw_args = .{},
|
||||
@ -1540,7 +1526,6 @@ const EmitZIR = struct {
|
||||
const new_inst = try self.arena.allocator.create(Inst.Cmp);
|
||||
new_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = inst.src,
|
||||
.tag = Inst.Cmp.base_tag,
|
||||
},
|
||||
@ -1568,7 +1553,6 @@ const EmitZIR = struct {
|
||||
const new_inst = try self.arena.allocator.create(Inst.CondBr);
|
||||
new_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = inst.src,
|
||||
.tag = Inst.CondBr.base_tag,
|
||||
},
|
||||
@ -1586,7 +1570,6 @@ const EmitZIR = struct {
|
||||
const new_inst = try self.arena.allocator.create(Inst.IsNull);
|
||||
new_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = inst.src,
|
||||
.tag = Inst.IsNull.base_tag,
|
||||
},
|
||||
@ -1602,7 +1585,6 @@ const EmitZIR = struct {
|
||||
const new_inst = try self.arena.allocator.create(Inst.IsNonNull);
|
||||
new_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = inst.src,
|
||||
.tag = Inst.IsNonNull.base_tag,
|
||||
},
|
||||
@ -1619,7 +1601,7 @@ const EmitZIR = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn emitType(self: *EmitZIR, src: usize, ty: Type) Allocator.Error!*Inst {
|
||||
fn emitType(self: *EmitZIR, src: usize, ty: Type) Allocator.Error!*Decl {
|
||||
switch (ty.tag()) {
|
||||
.isize => return self.emitPrimitive(src, .isize),
|
||||
.usize => return self.emitPrimitive(src, .usize),
|
||||
@ -1652,26 +1634,24 @@ const EmitZIR = struct {
|
||||
ty.fnParamTypes(param_types);
|
||||
const emitted_params = try self.arena.allocator.alloc(*Inst, param_types.len);
|
||||
for (param_types) |param_type, i| {
|
||||
emitted_params[i] = try self.emitType(src, param_type);
|
||||
emitted_params[i] = (try self.emitType(src, param_type)).inst;
|
||||
}
|
||||
|
||||
const fntype_inst = try self.arena.allocator.create(Inst.FnType);
|
||||
fntype_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = src,
|
||||
.tag = Inst.FnType.base_tag,
|
||||
},
|
||||
.positionals = .{
|
||||
.param_types = emitted_params,
|
||||
.return_type = try self.emitType(src, ty.fnReturnType()),
|
||||
.return_type = (try self.emitType(src, ty.fnReturnType())).inst,
|
||||
},
|
||||
.kw_args = .{
|
||||
.cc = ty.fnCallingConvention(),
|
||||
},
|
||||
};
|
||||
try self.decls.append(self.allocator, &fntype_inst.base);
|
||||
return &fntype_inst.base;
|
||||
return self.emitUnnamedDecl(&fntype_inst.base);
|
||||
},
|
||||
else => std.debug.panic("TODO implement emitType for {}", .{ty}),
|
||||
},
|
||||
@ -1690,13 +1670,12 @@ const EmitZIR = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn emitPrimitive(self: *EmitZIR, src: usize, tag: Inst.Primitive.Builtin) !*Inst {
|
||||
fn emitPrimitive(self: *EmitZIR, src: usize, tag: Inst.Primitive.Builtin) !*Decl {
|
||||
const gop = try self.primitive_table.getOrPut(tag);
|
||||
if (!gop.found_existing) {
|
||||
const primitive_inst = try self.arena.allocator.create(Inst.Primitive);
|
||||
primitive_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = src,
|
||||
.tag = Inst.Primitive.base_tag,
|
||||
},
|
||||
@ -1705,17 +1684,15 @@ const EmitZIR = struct {
|
||||
},
|
||||
.kw_args = .{},
|
||||
};
|
||||
try self.decls.append(self.allocator, &primitive_inst.base);
|
||||
gop.kv.value = &primitive_inst.base;
|
||||
gop.kv.value = try self.emitUnnamedDecl(&primitive_inst.base);
|
||||
}
|
||||
return gop.kv.value;
|
||||
}
|
||||
|
||||
fn emitStringLiteral(self: *EmitZIR, src: usize, str: []const u8) !*Inst {
|
||||
fn emitStringLiteral(self: *EmitZIR, src: usize, str: []const u8) !*Decl {
|
||||
const str_inst = try self.arena.allocator.create(Inst.Str);
|
||||
str_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = src,
|
||||
.tag = Inst.Str.base_tag,
|
||||
},
|
||||
@ -1724,22 +1701,17 @@ const EmitZIR = struct {
|
||||
},
|
||||
.kw_args = .{},
|
||||
};
|
||||
try self.decls.append(self.allocator, &str_inst.base);
|
||||
return self.emitUnnamedDecl(&str_inst.base);
|
||||
}
|
||||
|
||||
const ref_inst = try self.arena.allocator.create(Inst.Ref);
|
||||
ref_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = src,
|
||||
.tag = Inst.Ref.base_tag,
|
||||
},
|
||||
.positionals = .{
|
||||
.operand = &str_inst.base,
|
||||
},
|
||||
.kw_args = .{},
|
||||
fn emitUnnamedDecl(self: *EmitZIR, inst: *Inst) !*Decl {
|
||||
const decl = try self.arena.allocator.create(Decl);
|
||||
decl.* = .{
|
||||
.name = try self.autoName(),
|
||||
.contents_hash = undefined,
|
||||
.inst = inst,
|
||||
};
|
||||
try self.decls.append(self.allocator, &ref_inst.base);
|
||||
|
||||
return &ref_inst.base;
|
||||
try self.decls.append(self.allocator, decl);
|
||||
return decl;
|
||||
}
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user