Commit 0f38f68696
Changed files (18)
src/codegen/c.zig
@@ -6,7 +6,6 @@ const log = std.log.scoped(.c);
const link = @import("../link.zig");
const Module = @import("../Module.zig");
const Compilation = @import("../Compilation.zig");
-const Air = @import("../Air.zig");
const Value = @import("../value.zig").Value;
const Type = @import("../type.zig").Type;
const TypedValue = @import("../TypedValue.zig");
@@ -14,6 +13,8 @@ const C = link.File.C;
const Decl = Module.Decl;
const trace = @import("../tracy.zig").trace;
const LazySrcLoc = Module.LazySrcLoc;
+const Air = @import("../Air.zig");
+const Liveness = @import("../Liveness.zig");
const Mutability = enum { Const, Mut };
@@ -37,7 +38,7 @@ const BlockData = struct {
result: CValue,
};
-pub const CValueMap = std.AutoHashMap(*Inst, CValue);
+pub const CValueMap = std.AutoHashMap(Air.Inst.Index, CValue);
pub const TypedefMap = std.ArrayHashMap(
Type,
struct { name: []const u8, rendered: []u8 },
@@ -93,6 +94,8 @@ pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) {
/// It is not available when generating .h file.
pub const Object = struct {
dg: DeclGen,
+ air: Air,
+ liveness: Liveness,
gpa: *mem.Allocator,
code: std.ArrayList(u8),
value_map: CValueMap,
@@ -102,7 +105,7 @@ pub const Object = struct {
next_block_index: usize = 0,
indent_writer: IndentWriter(std.ArrayList(u8).Writer),
- fn resolveInst(o: *Object, inst: *Inst) !CValue {
+ fn resolveInst(o: *Object, inst: Air.Inst.Index) !CValue {
if (inst.value()) |_| {
return CValue{ .constant = inst };
}
src/codegen/llvm.zig
@@ -277,6 +277,9 @@ pub const Object = struct {
}
pub fn updateDecl(self: *Object, module: *Module, decl: *Module.Decl) !void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
var dg: DeclGen = .{
.object = self,
.module = module,
src/codegen/spirv.zig
@@ -159,7 +159,8 @@ pub const DeclGen = struct {
/// The SPIR-V module code should be put in.
spv: *SPIRVModule,
- air: *const Air,
+ air: Air,
+ liveness: Liveness,
/// An array of function argument result-ids. Each index corresponds with the
/// function argument of the same index.
src/codegen/wasm.zig
@@ -9,13 +9,14 @@ const wasm = std.wasm;
const Module = @import("../Module.zig");
const Decl = Module.Decl;
-const Air = @import("../Air.zig");
const Type = @import("../type.zig").Type;
const Value = @import("../value.zig").Value;
const Compilation = @import("../Compilation.zig");
const LazySrcLoc = Module.LazySrcLoc;
const link = @import("../link.zig");
const TypedValue = @import("../TypedValue.zig");
+const Air = @import("../Air.zig");
+const Liveness = @import("../Liveness.zig");
/// Wasm Value, created when generating an instruction
const WValue = union(enum) {
@@ -491,6 +492,8 @@ pub const Context = struct {
/// Reference to the function declaration the code
/// section belongs to
decl: *Decl,
+ air: Air,
+ liveness: Liveness,
gpa: *mem.Allocator,
/// Table to save `WValue`'s generated by an `Inst`
values: ValueTable,
@@ -710,52 +713,53 @@ pub const Context = struct {
}
}
+ pub fn genFunc(self: *Context, func: *Module.Fn) InnerError!Result {
+ try self.genFunctype();
+
+ // Write instructions
+ // TODO: check for and handle death of instructions
+
+ // Reserve space to write the size after generating the code as well as space for locals count
+ try self.code.resize(10);
+
+ try self.genBody(func.body);
+
+ // finally, write our local types at the 'offset' position
+ {
+ leb.writeUnsignedFixed(5, self.code.items[5..10], @intCast(u32, self.locals.items.len));
+
+ // offset into 'code' section where we will put our locals types
+ var local_offset: usize = 10;
+
+ // emit the actual locals amount
+ for (self.locals.items) |local| {
+ var buf: [6]u8 = undefined;
+ leb.writeUnsignedFixed(5, buf[0..5], @as(u32, 1));
+ buf[5] = local;
+ try self.code.insertSlice(local_offset, &buf);
+ local_offset += 6;
+ }
+ }
+
+ const writer = self.code.writer();
+ try writer.writeByte(wasm.opcode(.end));
+
+ // Fill in the size of the generated code to the reserved space at the
+ // beginning of the buffer.
+ const size = self.code.items.len - 5 + self.decl.fn_link.wasm.idx_refs.items.len * 5;
+ leb.writeUnsignedFixed(5, self.code.items[0..5], @intCast(u32, size));
+
+ // codegen data has been appended to `code`
+ return Result.appended;
+ }
+
/// Generates the wasm bytecode for the function declaration belonging to `Context`
pub fn gen(self: *Context, typed_value: TypedValue) InnerError!Result {
switch (typed_value.ty.zigTypeTag()) {
.Fn => {
try self.genFunctype();
-
- // Write instructions
- // TODO: check for and handle death of instructions
- const mod_fn = blk: {
- if (typed_value.val.castTag(.function)) |func| break :blk func.data;
- if (typed_value.val.castTag(.extern_fn)) |_| return Result.appended; // don't need code body for extern functions
- unreachable;
- };
-
- // Reserve space to write the size after generating the code as well as space for locals count
- try self.code.resize(10);
-
- try self.genBody(mod_fn.body);
-
- // finally, write our local types at the 'offset' position
- {
- leb.writeUnsignedFixed(5, self.code.items[5..10], @intCast(u32, self.locals.items.len));
-
- // offset into 'code' section where we will put our locals types
- var local_offset: usize = 10;
-
- // emit the actual locals amount
- for (self.locals.items) |local| {
- var buf: [6]u8 = undefined;
- leb.writeUnsignedFixed(5, buf[0..5], @as(u32, 1));
- buf[5] = local;
- try self.code.insertSlice(local_offset, &buf);
- local_offset += 6;
- }
- }
-
- const writer = self.code.writer();
- try writer.writeByte(wasm.opcode(.end));
-
- // Fill in the size of the generated code to the reserved space at the
- // beginning of the buffer.
- const size = self.code.items.len - 5 + self.decl.fn_link.wasm.idx_refs.items.len * 5;
- leb.writeUnsignedFixed(5, self.code.items[0..5], @intCast(u32, size));
-
- // codegen data has been appended to `code`
- return Result.appended;
+ if (typed_value.val.castTag(.extern_fn)) |_| return Result.appended; // don't need code body for extern functions
+ return self.fail("TODO implement wasm codegen for function pointers", .{});
},
.Array => {
if (typed_value.val.castTag(.bytes)) |payload| {
src/link/C.zig
@@ -2,14 +2,17 @@ const std = @import("std");
const mem = std.mem;
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
+const fs = std.fs;
+
+const C = @This();
const Module = @import("../Module.zig");
const Compilation = @import("../Compilation.zig");
-const fs = std.fs;
const codegen = @import("../codegen/c.zig");
const link = @import("../link.zig");
const trace = @import("../tracy.zig").trace;
-const C = @This();
const Type = @import("../type.zig").Type;
+const Air = @import("../Air.zig");
+const Liveness = @import("../Liveness.zig");
pub const base_tag: link.File.Tag = .c;
pub const zig_h = @embedFile("C/zig.h");
@@ -95,10 +98,7 @@ fn deinitDecl(gpa: *Allocator, decl: *Module.Decl) void {
decl.fn_link.c.typedefs.deinit(gpa);
}
-pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
- const tracy = trace(@src());
- defer tracy.end();
-
+pub fn finishUpdateDecl(self: *C, module: *Module, decl: *Module.Decl, air: Air, liveness: Liveness) !void {
// Keep track of all decls so we can iterate over them on flush().
_ = try self.decl_table.getOrPut(self.base.allocator, decl);
@@ -126,6 +126,8 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
.code = code.toManaged(module.gpa),
.value_map = codegen.CValueMap.init(module.gpa),
.indent_writer = undefined, // set later so we can get a pointer to object.code
+ .air = air,
+ .liveness = liveness,
};
object.indent_writer = .{ .underlying_writer = object.code.writer() };
defer {
@@ -157,6 +159,20 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
code.shrinkAndFree(module.gpa, code.items.len);
}
+pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ return self.finishUpdateDecl(module, func.owner_decl, air, liveness);
+}
+
+pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ return self.finishUpdateDecl(module, decl, undefined, undefined);
+}
+
pub fn updateDeclLineNumber(self: *C, module: *Module, decl: *Module.Decl) !void {
// The C backend does not have the ability to fix line numbers without re-generating
// the entire Decl.
src/link/Coff.zig
@@ -1,6 +1,7 @@
const Coff = @This();
const std = @import("std");
+const builtin = @import("builtin");
const log = std.log.scoped(.link);
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
@@ -17,6 +18,8 @@ const build_options = @import("build_options");
const Cache = @import("../Cache.zig");
const mingw = @import("../mingw.zig");
const llvm_backend = @import("../codegen/llvm.zig");
+const Air = @import("../Air.zig");
+const Liveness = @import("../Liveness.zig");
const allocation_padding = 4 / 3;
const minimum_text_block_size = 64 * allocation_padding;
@@ -653,19 +656,58 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {
}
}
-pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
- // TODO COFF/PE debug information
- // TODO Implement exports
+pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
+ if (build_options.skip_non_native and builtin.object_format != .coff and builtin.object_format != .pe) {
+ @panic("Attempted to compile for object format that was disabled by build configuration");
+ }
+ if (build_options.have_llvm) {
+ if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(module, func, air, liveness);
+ }
const tracy = trace(@src());
defer tracy.end();
- if (build_options.have_llvm)
- if (self.llvm_object) |llvm_object| return try llvm_object.updateDecl(module, decl);
+ var code_buffer = std.ArrayList(u8).init(self.base.allocator);
+ defer code_buffer.deinit();
+
+ const res = try codegen.generateFunction(
+ &self.base,
+ decl.srcLoc(),
+ func,
+ air,
+ liveness,
+ &code_buffer,
+ .none,
+ );
+ const code = switch (res) {
+ .externally_managed => |x| x,
+ .appended => code_buffer.items,
+ .fail => |em| {
+ decl.analysis = .codegen_failure;
+ try module.failed_decls.put(module.gpa, decl, em);
+ return;
+ },
+ };
+
+ return self.finishUpdateDecl(module, func.owner_decl, code);
+}
+
+pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
+ if (build_options.skip_non_native and builtin.object_format != .coff and builtin.object_format != .pe) {
+ @panic("Attempted to compile for object format that was disabled by build configuration");
+ }
+ if (build_options.have_llvm) {
+ if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl);
+ }
+ const tracy = trace(@src());
+ defer tracy.end();
if (decl.val.tag() == .extern_fn) {
return; // TODO Should we do more when front-end analyzed extern decl?
}
+ // TODO COFF/PE debug information
+ // TODO Implement exports
+
var code_buffer = std.ArrayList(u8).init(self.base.allocator);
defer code_buffer.deinit();
@@ -683,6 +725,10 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
},
};
+ return self.finishUpdateDecl(module, func.owner_decl, code);
+}
+
+fn finishUpdateDecl(self: *Coff, decl: *Module.Decl, code: []const u8) !void {
const required_alignment = decl.ty.abiAlignment(self.base.options.target);
const curr_size = decl.link.coff.size;
if (curr_size != 0) {
src/link/Elf.zig
@@ -1,6 +1,7 @@
const Elf = @This();
const std = @import("std");
+const builtin = @import("builtin");
const mem = std.mem;
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
@@ -10,7 +11,6 @@ const log = std.log.scoped(.link);
const DW = std.dwarf;
const leb128 = std.leb;
-const Air = @import("../Air.zig");
const Module = @import("../Module.zig");
const Compilation = @import("../Compilation.zig");
const codegen = @import("../codegen.zig");
@@ -26,6 +26,8 @@ const glibc = @import("../glibc.zig");
const musl = @import("../musl.zig");
const Cache = @import("../Cache.zig");
const llvm_backend = @import("../codegen/llvm.zig");
+const Air = @import("../Air.zig");
+const Liveness = @import("../Liveness.zig");
const default_entry_addr = 0x8000000;
@@ -2155,138 +2157,17 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
}
}
-pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
- const tracy = trace(@src());
- defer tracy.end();
-
- if (build_options.have_llvm)
- if (self.llvm_object) |llvm_object| return try llvm_object.updateDecl(module, decl);
-
- if (decl.val.tag() == .extern_fn) {
- return; // TODO Should we do more when front-end analyzed extern decl?
- }
- if (decl.val.castTag(.variable)) |payload| {
- const variable = payload.data;
- if (variable.is_extern) {
- return; // TODO Should we do more when front-end analyzed extern decl?
- }
- }
-
- var code_buffer = std.ArrayList(u8).init(self.base.allocator);
- defer code_buffer.deinit();
-
- var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator);
- defer dbg_line_buffer.deinit();
-
- var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator);
- defer dbg_info_buffer.deinit();
-
- var dbg_info_type_relocs: File.DbgInfoTypeRelocsTable = .{};
- defer {
- var it = dbg_info_type_relocs.valueIterator();
- while (it.next()) |value| {
- value.relocs.deinit(self.base.allocator);
- }
- dbg_info_type_relocs.deinit(self.base.allocator);
- }
-
- const is_fn: bool = switch (decl.ty.zigTypeTag()) {
- .Fn => true,
- else => false,
- };
- if (is_fn) {
- // For functions we need to add a prologue to the debug line program.
- try dbg_line_buffer.ensureCapacity(26);
-
- const func = decl.val.castTag(.function).?.data;
- const line_off = @intCast(u28, decl.src_line + func.lbrace_line);
-
- const ptr_width_bytes = self.ptrWidthBytes();
- dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{
- DW.LNS_extended_op,
- ptr_width_bytes + 1,
- DW.LNE_set_address,
- });
- // This is the "relocatable" vaddr, corresponding to `code_buffer` index `0`.
- assert(dbg_line_vaddr_reloc_index == dbg_line_buffer.items.len);
- dbg_line_buffer.items.len += ptr_width_bytes;
-
- dbg_line_buffer.appendAssumeCapacity(DW.LNS_advance_line);
- // This is the "relocatable" relative line offset from the previous function's end curly
- // to this function's begin curly.
- assert(self.getRelocDbgLineOff() == dbg_line_buffer.items.len);
- // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later.
- leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line_off);
-
- dbg_line_buffer.appendAssumeCapacity(DW.LNS_set_file);
- assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len);
- // Once we support more than one source file, this will have the ability to be more
- // than one possible value.
- const file_index = 1;
- leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index);
-
- // Emit a line for the begin curly with prologue_end=false. The codegen will
- // do the work of setting prologue_end=true and epilogue_begin=true.
- dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy);
-
- // .debug_info subprogram
- const decl_name_with_null = decl.name[0 .. mem.lenZ(decl.name) + 1];
- try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 25 + decl_name_with_null.len);
-
- const fn_ret_type = decl.ty.fnReturnType();
- const fn_ret_has_bits = fn_ret_type.hasCodeGenBits();
- if (fn_ret_has_bits) {
- dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);
- } else {
- dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram_retvoid);
- }
- // These get overwritten after generating the machine code. These values are
- // "relocations" and have to be in this fixed place so that functions can be
- // moved in virtual address space.
- assert(dbg_info_low_pc_reloc_index == dbg_info_buffer.items.len);
- dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT_low_pc, DW.FORM_addr
- assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len);
- dbg_info_buffer.items.len += 4; // DW.AT_high_pc, DW.FORM_data4
- if (fn_ret_has_bits) {
- const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, fn_ret_type);
- if (!gop.found_existing) {
- gop.value_ptr.* = .{
- .off = undefined,
- .relocs = .{},
- };
- }
- try gop.value_ptr.relocs.append(self.base.allocator, @intCast(u32, dbg_info_buffer.items.len));
- dbg_info_buffer.items.len += 4; // DW.AT_type, DW.FORM_ref4
- }
- dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT_name, DW.FORM_string
- } else {
- // TODO implement .debug_info for global variables
+fn deinitRelocs(gpa: *Allocator, table: *File.DbgInfoTypeRelocsTable) void {
+ var it = table.valueIterator();
+ while (it.next()) |value| {
+ value.relocs.deinit(gpa);
}
- const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
- const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
- .ty = decl.ty,
- .val = decl_val,
- }, &code_buffer, .{
- .dwarf = .{
- .dbg_line = &dbg_line_buffer,
- .dbg_info = &dbg_info_buffer,
- .dbg_info_type_relocs = &dbg_info_type_relocs,
- },
- });
- const code = switch (res) {
- .externally_managed => |x| x,
- .appended => code_buffer.items,
- .fail => |em| {
- decl.analysis = .codegen_failure;
- try module.failed_decls.put(module.gpa, decl, em);
- return;
- },
- };
+ table.deinit(gpa);
+}
+fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8) !*elf.Elf64_Sym {
const required_alignment = decl.ty.abiAlignment(self.base.options.target);
- const stt_bits: u8 = if (is_fn) elf.STT_FUNC else elf.STT_OBJECT;
-
assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes()
const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index];
if (local_sym.st_size != 0) {
@@ -2338,128 +2219,16 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
const file_offset = self.sections.items[self.text_section_index.?].sh_offset + section_offset;
try self.base.file.?.pwriteAll(code, file_offset);
- const target_endian = self.base.options.target.cpu.arch.endian();
-
- const text_block = &decl.link.elf;
-
- // If the Decl is a function, we need to update the .debug_line program.
- if (is_fn) {
- // Perform the relocations based on vaddr.
- switch (self.ptr_width) {
- .p32 => {
- {
- const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..4];
- mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian);
- }
- {
- const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..4];
- mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian);
- }
- },
- .p64 => {
- {
- const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..8];
- mem.writeInt(u64, ptr, local_sym.st_value, target_endian);
- }
- {
- const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..8];
- mem.writeInt(u64, ptr, local_sym.st_value, target_endian);
- }
- },
- }
- {
- const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4];
- mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_size), target_endian);
- }
-
- try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence });
-
- // Now we have the full contents and may allocate a region to store it.
-
- // This logic is nearly identical to the logic below in `updateDeclDebugInfoAllocation` for
- // `TextBlock` and the .debug_info. If you are editing this logic, you
- // probably need to edit that logic too.
-
- const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];
- const src_fn = &decl.fn_link.elf;
- src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
- if (self.dbg_line_fn_last) |last| not_first: {
- if (src_fn.next) |next| {
- // Update existing function - non-last item.
- if (src_fn.off + src_fn.len + min_nop_size > next.off) {
- // It grew too big, so we move it to a new location.
- if (src_fn.prev) |prev| {
- self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {};
- prev.next = src_fn.next;
- }
- assert(src_fn.prev != next);
- next.prev = src_fn.prev;
- src_fn.next = null;
- // Populate where it used to be with NOPs.
- const file_pos = debug_line_sect.sh_offset + src_fn.off;
- try self.pwriteDbgLineNops(0, &[0]u8{}, src_fn.len, file_pos);
- // TODO Look at the free list before appending at the end.
- src_fn.prev = last;
- last.next = src_fn;
- self.dbg_line_fn_last = src_fn;
-
- src_fn.off = last.off + padToIdeal(last.len);
- }
- } else if (src_fn.prev == null) {
- if (src_fn == last) {
- // Special case: there is only 1 function and it is being updated.
- // In this case there is nothing to do. The function's length has
- // already been updated, and the logic below takes care of
- // resizing the .debug_line section.
- break :not_first;
- }
- // Append new function.
- // TODO Look at the free list before appending at the end.
- src_fn.prev = last;
- last.next = src_fn;
- self.dbg_line_fn_last = src_fn;
-
- src_fn.off = last.off + padToIdeal(last.len);
- }
- } else {
- // This is the first function of the Line Number Program.
- self.dbg_line_fn_first = src_fn;
- self.dbg_line_fn_last = src_fn;
-
- src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes());
- }
-
- const last_src_fn = self.dbg_line_fn_last.?;
- const needed_size = last_src_fn.off + last_src_fn.len;
- if (needed_size != debug_line_sect.sh_size) {
- if (needed_size > self.allocatedSize(debug_line_sect.sh_offset)) {
- const new_offset = self.findFreeSpace(needed_size, 1);
- const existing_size = last_src_fn.off;
- log.debug("moving .debug_line section: {d} bytes from 0x{x} to 0x{x}", .{
- existing_size,
- debug_line_sect.sh_offset,
- new_offset,
- });
- const amt = try self.base.file.?.copyRangeAll(debug_line_sect.sh_offset, self.base.file.?, new_offset, existing_size);
- if (amt != existing_size) return error.InputOutput;
- debug_line_sect.sh_offset = new_offset;
- }
- debug_line_sect.sh_size = needed_size;
- self.shdr_table_dirty = true; // TODO look into making only the one section dirty
- self.debug_line_header_dirty = true;
- }
- const prev_padding_size: u32 = if (src_fn.prev) |prev| src_fn.off - (prev.off + prev.len) else 0;
- const next_padding_size: u32 = if (src_fn.next) |next| next.off - (src_fn.off + src_fn.len) else 0;
-
- // We only have support for one compilation unit so far, so the offsets are directly
- // from the .debug_line section.
- const file_pos = debug_line_sect.sh_offset + src_fn.off;
- try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos);
-
- // .debug_info - End the TAG_subprogram children.
- try dbg_info_buffer.append(0);
- }
+ return local_sym;
+}
+fn finishUpdateDecl(
+ self: *Elf,
+ module: *Module,
+ decl: *Module.Decl,
+ dbg_info_type_relocs: *File.DbgInfoTypeRelocsTable,
+ dbg_info_buffer: *std.ArrayList(u8),
+) !void {
// Now we emit the .debug_info types of the Decl. These will count towards the size of
// the buffer, so we have to do it before computing the offset, and we can't perform the actual
// relocations yet.
@@ -2467,12 +2236,15 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
var it = dbg_info_type_relocs.iterator();
while (it.next()) |entry| {
entry.value_ptr.off = @intCast(u32, dbg_info_buffer.items.len);
- try self.addDbgInfoType(entry.key_ptr.*, &dbg_info_buffer);
+ try self.addDbgInfoType(entry.key_ptr.*, dbg_info_buffer);
}
}
+ const text_block = &decl.link.elf;
try self.updateDeclDebugInfoAllocation(text_block, @intCast(u32, dbg_info_buffer.items.len));
+ const target_endian = self.base.options.target.cpu.arch.endian();
+
{
// Now that we have the offset assigned we can finally perform type relocations.
var it = dbg_info_type_relocs.valueIterator();
@@ -2495,6 +2267,290 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
return self.updateDeclExports(module, decl, decl_exports);
}
+pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
+ if (build_options.skip_non_native and builtin.object_format != .elf) {
+ @panic("Attempted to compile for object format that was disabled by build configuration");
+ }
+ if (build_options.have_llvm) {
+ if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(module, func, air, liveness);
+ }
+
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ var code_buffer = std.ArrayList(u8).init(self.base.allocator);
+ defer code_buffer.deinit();
+
+ var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator);
+ defer dbg_line_buffer.deinit();
+
+ var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator);
+ defer dbg_info_buffer.deinit();
+
+ var dbg_info_type_relocs: File.DbgInfoTypeRelocsTable = .{};
+ defer deinitRelocs(self.base.allocator, &dbg_info_type_relocs);
+
+ // For functions we need to add a prologue to the debug line program.
+ try dbg_line_buffer.ensureCapacity(26);
+
+ const decl = func.owner_decl;
+ const line_off = @intCast(u28, decl.src_line + func.lbrace_line);
+
+ const ptr_width_bytes = self.ptrWidthBytes();
+ dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{
+ DW.LNS_extended_op,
+ ptr_width_bytes + 1,
+ DW.LNE_set_address,
+ });
+ // This is the "relocatable" vaddr, corresponding to `code_buffer` index `0`.
+ assert(dbg_line_vaddr_reloc_index == dbg_line_buffer.items.len);
+ dbg_line_buffer.items.len += ptr_width_bytes;
+
+ dbg_line_buffer.appendAssumeCapacity(DW.LNS_advance_line);
+ // This is the "relocatable" relative line offset from the previous function's end curly
+ // to this function's begin curly.
+ assert(self.getRelocDbgLineOff() == dbg_line_buffer.items.len);
+ // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later.
+ leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line_off);
+
+ dbg_line_buffer.appendAssumeCapacity(DW.LNS_set_file);
+ assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len);
+ // Once we support more than one source file, this will have the ability to be more
+ // than one possible value.
+ const file_index = 1;
+ leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index);
+
+ // Emit a line for the begin curly with prologue_end=false. The codegen will
+ // do the work of setting prologue_end=true and epilogue_begin=true.
+ dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy);
+
+ // .debug_info subprogram
+ const decl_name_with_null = decl.name[0 .. mem.lenZ(decl.name) + 1];
+ try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 25 + decl_name_with_null.len);
+
+ const fn_ret_type = decl.ty.fnReturnType();
+ const fn_ret_has_bits = fn_ret_type.hasCodeGenBits();
+ if (fn_ret_has_bits) {
+ dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);
+ } else {
+ dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram_retvoid);
+ }
+ // These get overwritten after generating the machine code. These values are
+ // "relocations" and have to be in this fixed place so that functions can be
+ // moved in virtual address space.
+ assert(dbg_info_low_pc_reloc_index == dbg_info_buffer.items.len);
+ dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT_low_pc, DW.FORM_addr
+ assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len);
+ dbg_info_buffer.items.len += 4; // DW.AT_high_pc, DW.FORM_data4
+ if (fn_ret_has_bits) {
+ const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, fn_ret_type);
+ if (!gop.found_existing) {
+ gop.value_ptr.* = .{
+ .off = undefined,
+ .relocs = .{},
+ };
+ }
+ try gop.value_ptr.relocs.append(self.base.allocator, @intCast(u32, dbg_info_buffer.items.len));
+ dbg_info_buffer.items.len += 4; // DW.AT_type, DW.FORM_ref4
+ }
+ dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT_name, DW.FORM_string
+
+ const res = try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{
+ .dwarf = .{
+ .dbg_line = &dbg_line_buffer,
+ .dbg_info = &dbg_info_buffer,
+ .dbg_info_type_relocs = &dbg_info_type_relocs,
+ },
+ });
+ const code = switch (res) {
+ .externally_managed => |x| x,
+ .appended => code_buffer.items,
+ .fail => |em| {
+ decl.analysis = .codegen_failure;
+ try module.failed_decls.put(module.gpa, decl, em);
+ return;
+ },
+ };
+
+ const local_sym = try self.updateDeclCode(decl, code, elf.STT_FUNC);
+
+ const target_endian = self.base.options.target.cpu.arch.endian();
+
+ // Since the Decl is a function, we need to update the .debug_line program.
+ // Perform the relocations based on vaddr.
+ switch (self.ptr_width) {
+ .p32 => {
+ {
+ const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..4];
+ mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian);
+ }
+ {
+ const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..4];
+ mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian);
+ }
+ },
+ .p64 => {
+ {
+ const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..8];
+ mem.writeInt(u64, ptr, local_sym.st_value, target_endian);
+ }
+ {
+ const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..8];
+ mem.writeInt(u64, ptr, local_sym.st_value, target_endian);
+ }
+ },
+ }
+ {
+ const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4];
+ mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_size), target_endian);
+ }
+
+ try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence });
+
+ // Now we have the full contents and may allocate a region to store it.
+
+ // This logic is nearly identical to the logic below in `updateDeclDebugInfoAllocation` for
+ // `TextBlock` and the .debug_info. If you are editing this logic, you
+ // probably need to edit that logic too.
+
+ const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];
+ const src_fn = &decl.fn_link.elf;
+ src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
+ if (self.dbg_line_fn_last) |last| not_first: {
+ if (src_fn.next) |next| {
+ // Update existing function - non-last item.
+ if (src_fn.off + src_fn.len + min_nop_size > next.off) {
+ // It grew too big, so we move it to a new location.
+ if (src_fn.prev) |prev| {
+ self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {};
+ prev.next = src_fn.next;
+ }
+ assert(src_fn.prev != next);
+ next.prev = src_fn.prev;
+ src_fn.next = null;
+ // Populate where it used to be with NOPs.
+ const file_pos = debug_line_sect.sh_offset + src_fn.off;
+ try self.pwriteDbgLineNops(0, &[0]u8{}, src_fn.len, file_pos);
+ // TODO Look at the free list before appending at the end.
+ src_fn.prev = last;
+ last.next = src_fn;
+ self.dbg_line_fn_last = src_fn;
+
+ src_fn.off = last.off + padToIdeal(last.len);
+ }
+ } else if (src_fn.prev == null) {
+ if (src_fn == last) {
+ // Special case: there is only 1 function and it is being updated.
+ // In this case there is nothing to do. The function's length has
+ // already been updated, and the logic below takes care of
+ // resizing the .debug_line section.
+ break :not_first;
+ }
+ // Append new function.
+ // TODO Look at the free list before appending at the end.
+ src_fn.prev = last;
+ last.next = src_fn;
+ self.dbg_line_fn_last = src_fn;
+
+ src_fn.off = last.off + padToIdeal(last.len);
+ }
+ } else {
+ // This is the first function of the Line Number Program.
+ self.dbg_line_fn_first = src_fn;
+ self.dbg_line_fn_last = src_fn;
+
+ src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes());
+ }
+
+ const last_src_fn = self.dbg_line_fn_last.?;
+ const needed_size = last_src_fn.off + last_src_fn.len;
+ if (needed_size != debug_line_sect.sh_size) {
+ if (needed_size > self.allocatedSize(debug_line_sect.sh_offset)) {
+ const new_offset = self.findFreeSpace(needed_size, 1);
+ const existing_size = last_src_fn.off;
+ log.debug("moving .debug_line section: {d} bytes from 0x{x} to 0x{x}", .{
+ existing_size,
+ debug_line_sect.sh_offset,
+ new_offset,
+ });
+ const amt = try self.base.file.?.copyRangeAll(debug_line_sect.sh_offset, self.base.file.?, new_offset, existing_size);
+ if (amt != existing_size) return error.InputOutput;
+ debug_line_sect.sh_offset = new_offset;
+ }
+ debug_line_sect.sh_size = needed_size;
+ self.shdr_table_dirty = true; // TODO look into making only the one section dirty
+ self.debug_line_header_dirty = true;
+ }
+ const prev_padding_size: u32 = if (src_fn.prev) |prev| src_fn.off - (prev.off + prev.len) else 0;
+ const next_padding_size: u32 = if (src_fn.next) |next| next.off - (src_fn.off + src_fn.len) else 0;
+
+ // We only have support for one compilation unit so far, so the offsets are directly
+ // from the .debug_line section.
+ const file_pos = debug_line_sect.sh_offset + src_fn.off;
+ try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos);
+
+ // .debug_info - End the TAG_subprogram children.
+ try dbg_info_buffer.append(0);
+
+ return self.finishUpdateDecl(module, decl, &dbg_info_type_relocs, &dbg_info_buffer);
+}
+
+pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
+ if (build_options.skip_non_native and builtin.object_format != .elf) {
+ @panic("Attempted to compile for object format that was disabled by build configuration");
+ }
+ if (build_options.have_llvm) {
+ if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl);
+ }
+
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ if (decl.val.tag() == .extern_fn) {
+ return; // TODO Should we do more when front-end analyzed extern decl?
+ }
+ if (decl.val.castTag(.variable)) |payload| {
+ const variable = payload.data;
+ if (variable.is_extern) {
+ return; // TODO Should we do more when front-end analyzed extern decl?
+ }
+ }
+
+ var code_buffer = std.ArrayList(u8).init(self.base.allocator);
+ defer code_buffer.deinit();
+
+ var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator);
+ defer dbg_info_buffer.deinit();
+
+ var dbg_info_type_relocs: File.DbgInfoTypeRelocsTable = .{};
+ defer deinitRelocs(self.base.allocator, &dbg_info_type_relocs);
+
+ // TODO implement .debug_info for global variables
+ const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
+ const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
+ .ty = decl.ty,
+ .val = decl_val,
+ }, &code_buffer, .{
+ .dwarf = .{
+ .dbg_line = &dbg_line_buffer,
+ .dbg_info = &dbg_info_buffer,
+ .dbg_info_type_relocs = &dbg_info_type_relocs,
+ },
+ });
+ const code = switch (res) {
+ .externally_managed => |x| x,
+ .appended => code_buffer.items,
+ .fail => |em| {
+ decl.analysis = .codegen_failure;
+ try module.failed_decls.put(module.gpa, decl, em);
+ return;
+ },
+ };
+
+ _ = try self.updateDeclCode(decl, code, elf.STT_OBJECT);
+ return self.finishUpdateDecl(module, decl, &dbg_info_type_relocs, &dbg_info_buffer);
+}
+
/// Asserts the type has codegen bits.
fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !void {
switch (ty.zigTypeTag()) {
src/link/MachO.zig
@@ -1,6 +1,7 @@
const MachO = @This();
const std = @import("std");
+const builtin = @import("builtin");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const fmt = std.fmt;
@@ -22,6 +23,8 @@ const link = @import("../link.zig");
const File = link.File;
const Cache = @import("../Cache.zig");
const target_util = @import("../target.zig");
+const Air = @import("../Air.zig");
+const Liveness = @import("../Liveness.zig");
const DebugSymbols = @import("MachO/DebugSymbols.zig");
const Trie = @import("MachO/Trie.zig");
@@ -1132,7 +1135,55 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
};
}
+pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
+ if (build_options.skip_non_native and builtin.object_format != .macho) {
+ @panic("Attempted to compile for object format that was disabled by build configuration");
+ }
+ if (build_options.have_llvm) {
+ if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(module, func, air, liveness);
+ }
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ const decl = func.owner_decl;
+
+ var code_buffer = std.ArrayList(u8).init(self.base.allocator);
+ defer code_buffer.deinit();
+
+ var debug_buffers = if (self.d_sym) |*ds| try ds.initDeclDebugBuffers(self.base.allocator, module, decl) else null;
+ defer {
+ if (debug_buffers) |*dbg| {
+ dbg.dbg_line_buffer.deinit();
+ dbg.dbg_info_buffer.deinit();
+ var it = dbg.dbg_info_type_relocs.valueIterator();
+ while (it.next()) |value| {
+ value.relocs.deinit(self.base.allocator);
+ }
+ dbg.dbg_info_type_relocs.deinit(self.base.allocator);
+ }
+ }
+
+ const res = if (debug_buffers) |*dbg|
+ try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{
+ .dwarf = .{
+ .dbg_line = &dbg.dbg_line_buffer,
+ .dbg_info = &dbg.dbg_info_buffer,
+ .dbg_info_type_relocs = &dbg.dbg_info_type_relocs,
+ },
+ })
+ else
+ try codegen.generateSymbol(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none);
+
+ return self.finishUpdateDecl(module, decl, res);
+}
+
pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
+ if (build_options.skip_non_native and builtin.object_format != .macho) {
+ @panic("Attempted to compile for object format that was disabled by build configuration");
+ }
+ if (build_options.have_llvm) {
+ if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl);
+ }
const tracy = trace(@src());
defer tracy.end();
@@ -1173,6 +1224,10 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
.val = decl.val,
}, &code_buffer, .none);
+ return self.finishUpdateDecl(module, decl, res);
+}
+
+fn finishUpdateDecl(self: *MachO, module: *Module, decl: *Module.Decl, res: codegen.Result) !void {
const code = switch (res) {
.externally_managed => |x| x,
.appended => code_buffer.items,
src/link/Plan9.zig
@@ -2,18 +2,21 @@
//! would be to add incremental linking in a similar way as ELF does.
const Plan9 = @This();
-
-const std = @import("std");
const link = @import("../link.zig");
const Module = @import("../Module.zig");
const Compilation = @import("../Compilation.zig");
const aout = @import("Plan9/aout.zig");
const codegen = @import("../codegen.zig");
const trace = @import("../tracy.zig").trace;
-const mem = std.mem;
const File = link.File;
-const Allocator = std.mem.Allocator;
+const build_options = @import("build_options");
+const Air = @import("../Air.zig");
+const Liveness = @import("../Liveness.zig");
+const std = @import("std");
+const builtin = @import("builtin");
+const mem = std.mem;
+const Allocator = std.mem.Allocator;
const log = std.log.scoped(.link);
const assert = std.debug.assert;
@@ -120,6 +123,19 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 {
return self;
}
+pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
+ if (build_options.skip_non_native and builtin.object_format != .plan9) {
+ @panic("Attempted to compile for object format that was disabled by build configuration");
+ }
+ _ = module;
+ // Keep track of all decls so we can iterate over them on flush().
+ _ = try self.decl_table.getOrPut(self.base.allocator, func.owner_decl);
+
+ _ = air;
+ _ = liveness;
+ @panic("TODO Plan9 needs to keep track of Air and Liveness so it can use them later");
+}
+
pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void {
_ = module;
_ = try self.decl_table.getOrPut(self.base.allocator, decl);
@@ -138,6 +154,9 @@ pub fn flush(self: *Plan9, comp: *Compilation) !void {
}
pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
+ if (build_options.skip_non_native and builtin.object_format != .plan9) {
+ @panic("Attempted to compile for object format that was disabled by build configuration");
+ }
_ = comp;
const tracy = trace(@src());
defer tracy.end();
@@ -199,7 +218,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
}
}
if (std.mem.eql(u8, exp.options.name, "_start")) {
- std.debug.assert(decl.link.plan9.type == .t); // we tried to link a non-function as the entry
+ assert(decl.link.plan9.type == .t); // we tried to link a non-function as the entry
self.entry_decl = decl;
}
if (exp.link.plan9) |i| {
src/link/SpirV.zig
@@ -36,6 +36,8 @@ const ResultId = codegen.ResultId;
const trace = @import("../tracy.zig").trace;
const build_options = @import("build_options");
const spec = @import("../codegen/spirv/spec.zig");
+const Air = @import("../Air.zig");
+const Liveness = @import("../Liveness.zig");
// TODO: Should this struct be used at all rather than just a hashmap of aux data for every decl?
pub const FnData = struct {
@@ -101,7 +103,23 @@ pub fn deinit(self: *SpirV) void {
self.decl_table.deinit(self.base.allocator);
}
+pub fn updateFunc(self: *SpirV, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
+ if (build_options.skip_non_native) {
+ @panic("Attempted to compile for architecture that was disabled by build configuration");
+ }
+ _ = module;
+ // Keep track of all decls so we can iterate over them on flush().
+ _ = try self.decl_table.getOrPut(self.base.allocator, func.owner_decl);
+
+ _ = air;
+ _ = liveness;
+ @panic("TODO SPIR-V needs to keep track of Air and Liveness so it can use them later");
+}
+
pub fn updateDecl(self: *SpirV, module: *Module, decl: *Module.Decl) !void {
+ if (build_options.skip_non_native) {
+ @panic("Attempted to compile for architecture that was disabled by build configuration");
+ }
_ = module;
// Keep track of all decls so we can iterate over them on flush().
_ = try self.decl_table.getOrPut(self.base.allocator, decl);
@@ -132,13 +150,13 @@ pub fn flush(self: *SpirV, comp: *Compilation) !void {
}
pub fn flushModule(self: *SpirV, comp: *Compilation) !void {
- const tracy = trace(@src());
- defer tracy.end();
-
if (build_options.skip_non_native) {
@panic("Attempted to compile for architecture that was disabled by build configuration");
}
+ const tracy = trace(@src());
+ defer tracy.end();
+
const module = self.base.options.module.?;
const target = comp.getTarget();
src/link/Wasm.zig
@@ -1,6 +1,7 @@
const Wasm = @This();
const std = @import("std");
+const builtin = @import("builtin");
const mem = std.mem;
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
@@ -18,6 +19,8 @@ const build_options = @import("build_options");
const wasi_libc = @import("../wasi_libc.zig");
const Cache = @import("../Cache.zig");
const TypedValue = @import("../TypedValue.zig");
+const Air = @import("../Air.zig");
+const Liveness = @import("../Liveness.zig");
pub const base_tag = link.File.Tag.wasm;
@@ -186,11 +189,60 @@ pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void {
}
}
+pub fn updateFunc(self: *Wasm, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
+ if (build_options.skip_non_native and builtin.object_format != .wasm) {
+ @panic("Attempted to compile for object format that was disabled by build configuration");
+ }
+ if (build_options.have_llvm) {
+ if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(module, func, air, liveness);
+ }
+ const decl = func.owner_decl;
+ assert(decl.link.wasm.init); // Must call allocateDeclIndexes()
+
+ const fn_data = &decl.fn_link.wasm;
+ fn_data.functype.items.len = 0;
+ fn_data.code.items.len = 0;
+ fn_data.idx_refs.items.len = 0;
+
+ var context = codegen.Context{
+ .gpa = self.base.allocator,
+ .air = air,
+ .liveness = liveness,
+ .values = .{},
+ .code = fn_data.code.toManaged(self.base.allocator),
+ .func_type_data = fn_data.functype.toManaged(self.base.allocator),
+ .decl = decl,
+ .err_msg = undefined,
+ .locals = .{},
+ .target = self.base.options.target,
+ .global_error_set = self.base.options.module.?.global_error_set,
+ };
+ defer context.deinit();
+
+ // generate the 'code' section for the function declaration
+ const result = context.genFunc(func) catch |err| switch (err) {
+ error.CodegenFail => {
+ decl.analysis = .codegen_failure;
+ try module.failed_decls.put(module.gpa, decl, context.err_msg);
+ return;
+ },
+ else => |e| return e,
+ };
+ return self.finishUpdateDecl(decl, result);
+}
+
// Generate code for the Decl, storing it in memory to be later written to
// the file on flush().
pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
- std.debug.assert(decl.link.wasm.init); // Must call allocateDeclIndexes()
+ if (build_options.skip_non_native and builtin.object_format != .wasm) {
+ @panic("Attempted to compile for object format that was disabled by build configuration");
+ }
+ if (build_options.have_llvm) {
+ if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl);
+ }
+ assert(decl.link.wasm.init); // Must call allocateDeclIndexes()
+ // TODO don't use this for non-functions
const fn_data = &decl.fn_link.wasm;
fn_data.functype.items.len = 0;
fn_data.code.items.len = 0;
@@ -218,7 +270,10 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
},
else => |e| return e,
};
+ return self.finishUpdateDecl(decl, result);
+}
+fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, result: codegen.Result) !void {
const code: []const u8 = switch (result) {
.appended => @as([]const u8, context.code.items),
.externally_managed => |payload| payload,
@@ -521,7 +576,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
var data_offset = offset_table_size;
while (cur) |cur_block| : (cur = cur_block.next) {
if (cur_block.size == 0) continue;
- std.debug.assert(cur_block.init);
+ assert(cur_block.init);
const offset = (cur_block.offset_index) * ptr_width;
var buf: [4]u8 = undefined;
src/codegen.zig
@@ -282,7 +282,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
return struct {
gpa: *Allocator,
- air: *const Air,
+ air: Air,
+ liveness: Liveness,
bin_file: *link.File,
target: *const std.Target,
mod_fn: *const Module.Fn,
@@ -468,8 +469,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
var function = Self{
.gpa = bin_file.allocator,
- .air = &air,
- .liveness = &liveness,
+ .air = air,
+ .liveness = liveness,
.target = &bin_file.options.target,
.bin_file = bin_file,
.mod_fn = module_fn,
src/Compilation.zig
@@ -2027,7 +2027,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
defer liveness.deinit(gpa);
if (std.builtin.mode == .Debug and self.verbose_air) {
- func.dump(module.*);
+ @panic("TODO implement dumping AIR and liveness");
}
assert(decl.ty.hasCodeGenBits());
src/link.zig
@@ -1,4 +1,5 @@
const std = @import("std");
+const builtin = @import("builtin");
const mem = std.mem;
const Allocator = std.mem.Allocator;
const fs = std.fs;
@@ -14,8 +15,10 @@ const Cache = @import("Cache.zig");
const build_options = @import("build_options");
const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
const wasi_libc = @import("wasi_libc.zig");
+const Air = @import("Air.zig");
+const Liveness = @import("Liveness.zig");
-pub const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version;
+pub const producer_string = if (builtin.is_test) "zig test" else "zig " ++ build_options.version;
pub const Emit = struct {
/// Where the output will go.
@@ -313,13 +316,34 @@ pub const File = struct {
log.debug("updateDecl {*} ({s}), type={}", .{ decl, decl.name, decl.ty });
assert(decl.has_tv);
switch (base.tag) {
- .coff => return @fieldParentPtr(Coff, "base", base).updateDecl(module, decl),
- .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl),
+ // zig fmt: off
+ .coff => return @fieldParentPtr(Coff, "base", base).updateDecl(module, decl),
+ .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl),
.macho => return @fieldParentPtr(MachO, "base", base).updateDecl(module, decl),
- .c => return @fieldParentPtr(C, "base", base).updateDecl(module, decl),
- .wasm => return @fieldParentPtr(Wasm, "base", base).updateDecl(module, decl),
+ .c => return @fieldParentPtr(C, "base", base).updateDecl(module, decl),
+ .wasm => return @fieldParentPtr(Wasm, "base", base).updateDecl(module, decl),
.spirv => return @fieldParentPtr(SpirV, "base", base).updateDecl(module, decl),
.plan9 => return @fieldParentPtr(Plan9, "base", base).updateDecl(module, decl),
+ // zig fmt: on
+ }
+ }
+
+ /// May be called before or after updateDeclExports but must be called
+ /// after allocateDeclIndexes for any given Decl.
+ pub fn updateFunc(base: *File, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
+ log.debug("updateFunc {*} ({s}), type={}", .{
+ func.owner_decl, func.owner_decl.name, func.owner_decl.ty,
+ });
+ switch (base.tag) {
+ // zig fmt: off
+ .coff => return @fieldParentPtr(Coff, "base", base).updateFunc(module, func, air, liveness),
+ .elf => return @fieldParentPtr(Elf, "base", base).updateFunc(module, func, air, liveness),
+ .macho => return @fieldParentPtr(MachO, "base", base).updateFunc(module, func, air, liveness),
+ .c => return @fieldParentPtr(C, "base", base).updateFunc(module, func, air, liveness),
+ .wasm => return @fieldParentPtr(Wasm, "base", base).updateFunc(module, func, air, liveness),
+ .spirv => return @fieldParentPtr(SpirV, "base", base).updateFunc(module, func, air, liveness),
+ .plan9 => return @fieldParentPtr(Plan9, "base", base).updateFunc(module, func, air, liveness),
+ // zig fmt: on
}
}
src/Liveness.zig
@@ -50,7 +50,7 @@ pub fn analyze(gpa: *Allocator, air: Air) Allocator.Error!Liveness {
var a: Analysis = .{
.gpa = gpa,
- .air = &air,
+ .air = air,
.table = .{},
.tomb_bits = try gpa.alloc(
usize,
@@ -65,7 +65,7 @@ pub fn analyze(gpa: *Allocator, air: Air) Allocator.Error!Liveness {
defer a.table.deinit(gpa);
const main_body = air.getMainBody();
- try a.table.ensureTotalCapacity(main_body.len);
+ try a.table.ensureTotalCapacity(gpa, @intCast(u32, main_body.len));
try analyzeWithContext(&a, null, main_body);
return Liveness{
.tomb_bits = a.tomb_bits,
@@ -108,9 +108,10 @@ const OperandInt = std.math.Log2Int(Bpi);
/// In-progress data; on successful analysis converted into `Liveness`.
const Analysis = struct {
gpa: *Allocator,
- air: *const Air,
+ air: Air,
table: std.AutoHashMapUnmanaged(Air.Inst.Index, void),
tomb_bits: []usize,
+ special: std.AutoHashMapUnmanaged(Air.Inst.Index, u32),
extra: std.ArrayListUnmanaged(u32),
fn storeTombBits(a: *Analysis, inst: Air.Inst.Index, tomb_bits: Bpi) void {
@@ -165,7 +166,7 @@ fn analyzeWithContext(
fn analyzeInst(
a: *Analysis,
- new_set: ?*std.AutoHashMap(Air.Inst.Index, void),
+ new_set: ?*std.AutoHashMapUnmanaged(Air.Inst.Index, void),
inst: Air.Inst.Index,
) Allocator.Error!void {
const gpa = a.gpa;
src/Module.zig
@@ -769,11 +769,6 @@ pub const Fn = struct {
success,
};
- /// For debugging purposes.
- pub fn dump(func: *Fn, mod: Module) void {
- ir.dumpFn(mod, func);
- }
-
pub fn deinit(func: *Fn, gpa: *Allocator) void {
if (func.getInferredErrorSet()) |map| {
map.deinit(gpa);
src/Sema.zig
@@ -69,7 +69,7 @@ const LazySrcLoc = Module.LazySrcLoc;
const RangeSet = @import("RangeSet.zig");
const target_util = @import("target.zig");
-pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Index);
+pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref);
pub fn deinit(sema: *Sema) void {
const gpa = sema.gpa;
@@ -158,344 +158,344 @@ pub fn analyzeBody(
var i: usize = 0;
while (true) {
const inst = body[i];
- const air_inst = switch (tags[inst]) {
+ const air_inst: Air.Inst.Ref = switch (tags[inst]) {
// zig fmt: off
.arg => try sema.zirArg(block, inst),
- .alloc => try sema.zirAlloc(block, inst),
- .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
- .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
- .alloc_inferred_comptime => try sema.zirAllocInferredComptime(block, inst),
- .alloc_mut => try sema.zirAllocMut(block, inst),
- .alloc_comptime => try sema.zirAllocComptime(block, inst),
- .anyframe_type => try sema.zirAnyframeType(block, inst),
- .array_cat => try sema.zirArrayCat(block, inst),
- .array_mul => try sema.zirArrayMul(block, inst),
- .array_type => try sema.zirArrayType(block, inst),
- .array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst),
- .vector_type => try sema.zirVectorType(block, inst),
- .as => try sema.zirAs(block, inst),
- .as_node => try sema.zirAsNode(block, inst),
- .bit_and => try sema.zirBitwise(block, inst, .bit_and),
- .bit_not => try sema.zirBitNot(block, inst),
- .bit_or => try sema.zirBitwise(block, inst, .bit_or),
- .bitcast => try sema.zirBitcast(block, inst),
- .bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst),
- .block => try sema.zirBlock(block, inst),
- .suspend_block => try sema.zirSuspendBlock(block, inst),
- .bool_not => try sema.zirBoolNot(block, inst),
- .bool_and => try sema.zirBoolOp(block, inst, false),
- .bool_or => try sema.zirBoolOp(block, inst, true),
- .bool_br_and => try sema.zirBoolBr(block, inst, false),
- .bool_br_or => try sema.zirBoolBr(block, inst, true),
- .c_import => try sema.zirCImport(block, inst),
- .call => try sema.zirCall(block, inst, .auto, false),
- .call_chkused => try sema.zirCall(block, inst, .auto, true),
- .call_compile_time => try sema.zirCall(block, inst, .compile_time, false),
- .call_nosuspend => try sema.zirCall(block, inst, .no_async, false),
- .call_async => try sema.zirCall(block, inst, .async_kw, false),
- .cmp_eq => try sema.zirCmp(block, inst, .eq),
- .cmp_gt => try sema.zirCmp(block, inst, .gt),
- .cmp_gte => try sema.zirCmp(block, inst, .gte),
- .cmp_lt => try sema.zirCmp(block, inst, .lt),
- .cmp_lte => try sema.zirCmp(block, inst, .lte),
- .cmp_neq => try sema.zirCmp(block, inst, .neq),
- .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),
- .decl_ref => try sema.zirDeclRef(block, inst),
- .decl_val => try sema.zirDeclVal(block, inst),
- .load => try sema.zirLoad(block, inst),
- .elem_ptr => try sema.zirElemPtr(block, inst),
- .elem_ptr_node => try sema.zirElemPtrNode(block, inst),
- .elem_val => try sema.zirElemVal(block, inst),
- .elem_val_node => try sema.zirElemValNode(block, inst),
- .elem_type => try sema.zirElemType(block, inst),
- .enum_literal => try sema.zirEnumLiteral(block, inst),
- .enum_to_int => try sema.zirEnumToInt(block, inst),
- .int_to_enum => try sema.zirIntToEnum(block, inst),
- .err_union_code => try sema.zirErrUnionCode(block, inst),
- .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst),
- .err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true),
- .err_union_payload_safe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, true),
- .err_union_payload_unsafe => try sema.zirErrUnionPayload(block, inst, false),
- .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, false),
- .error_union_type => try sema.zirErrorUnionType(block, inst),
- .error_value => try sema.zirErrorValue(block, inst),
- .error_to_int => try sema.zirErrorToInt(block, inst),
- .int_to_error => try sema.zirIntToError(block, inst),
- .field_ptr => try sema.zirFieldPtr(block, inst),
- .field_ptr_named => try sema.zirFieldPtrNamed(block, inst),
- .field_val => try sema.zirFieldVal(block, inst),
- .field_val_named => try sema.zirFieldValNamed(block, inst),
- .func => try sema.zirFunc(block, inst, false),
- .func_inferred => try sema.zirFunc(block, inst, true),
- .import => try sema.zirImport(block, inst),
- .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
- .int => try sema.zirInt(block, inst),
- .int_big => try sema.zirIntBig(block, inst),
- .float => try sema.zirFloat(block, inst),
- .float128 => try sema.zirFloat128(block, inst),
- .int_type => try sema.zirIntType(block, inst),
- .is_non_err => try sema.zirIsNonErr(block, inst),
- .is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst),
- .is_non_null => try sema.zirIsNonNull(block, inst),
- .is_non_null_ptr => try sema.zirIsNonNullPtr(block, inst),
- .loop => try sema.zirLoop(block, inst),
- .merge_error_sets => try sema.zirMergeErrorSets(block, inst),
- .negate => try sema.zirNegate(block, inst, .sub),
- .negate_wrap => try sema.zirNegate(block, inst, .subwrap),
- .optional_payload_safe => try sema.zirOptionalPayload(block, inst, true),
- .optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, inst, true),
- .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false),
- .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false),
- .optional_type => try sema.zirOptionalType(block, inst),
- .param_type => try sema.zirParamType(block, inst),
- .ptr_type => try sema.zirPtrType(block, inst),
- .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst),
- .ref => try sema.zirRef(block, inst),
- .ret_err_value_code => try sema.zirRetErrValueCode(block, inst),
- .shl => try sema.zirShl(block, inst),
- .shr => try sema.zirShr(block, inst),
- .slice_end => try sema.zirSliceEnd(block, inst),
- .slice_sentinel => try sema.zirSliceSentinel(block, inst),
- .slice_start => try sema.zirSliceStart(block, inst),
- .str => try sema.zirStr(block, inst),
- .switch_block => try sema.zirSwitchBlock(block, inst, false, .none),
- .switch_block_multi => try sema.zirSwitchBlockMulti(block, inst, false, .none),
- .switch_block_else => try sema.zirSwitchBlock(block, inst, false, .@"else"),
- .switch_block_else_multi => try sema.zirSwitchBlockMulti(block, inst, false, .@"else"),
- .switch_block_under => try sema.zirSwitchBlock(block, inst, false, .under),
- .switch_block_under_multi => try sema.zirSwitchBlockMulti(block, inst, false, .under),
- .switch_block_ref => try sema.zirSwitchBlock(block, inst, true, .none),
- .switch_block_ref_multi => try sema.zirSwitchBlockMulti(block, inst, true, .none),
- .switch_block_ref_else => try sema.zirSwitchBlock(block, inst, true, .@"else"),
- .switch_block_ref_else_multi => try sema.zirSwitchBlockMulti(block, inst, true, .@"else"),
- .switch_block_ref_under => try sema.zirSwitchBlock(block, inst, true, .under),
- .switch_block_ref_under_multi => try sema.zirSwitchBlockMulti(block, inst, true, .under),
- .switch_capture => try sema.zirSwitchCapture(block, inst, false, false),
- .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true),
- .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false),
- .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true),
- .switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false),
- .switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),
- .type_info => try sema.zirTypeInfo(block, inst),
- .size_of => try sema.zirSizeOf(block, inst),
- .bit_size_of => try sema.zirBitSizeOf(block, inst),
- .typeof => try sema.zirTypeof(block, inst),
- .typeof_elem => try sema.zirTypeofElem(block, inst),
- .log2_int_type => try sema.zirLog2IntType(block, inst),
- .typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst),
- .xor => try sema.zirBitwise(block, inst, .xor),
- .struct_init_empty => try sema.zirStructInitEmpty(block, inst),
- .struct_init => try sema.zirStructInit(block, inst, false),
- .struct_init_ref => try sema.zirStructInit(block, inst, true),
- .struct_init_anon => try sema.zirStructInitAnon(block, inst, false),
- .struct_init_anon_ref => try sema.zirStructInitAnon(block, inst, true),
- .array_init => try sema.zirArrayInit(block, inst, false),
- .array_init_ref => try sema.zirArrayInit(block, inst, true),
- .array_init_anon => try sema.zirArrayInitAnon(block, inst, false),
- .array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true),
- .union_init_ptr => try sema.zirUnionInitPtr(block, inst),
- .field_type => try sema.zirFieldType(block, inst),
- .field_type_ref => try sema.zirFieldTypeRef(block, inst),
- .ptr_to_int => try sema.zirPtrToInt(block, inst),
- .align_of => try sema.zirAlignOf(block, inst),
- .bool_to_int => try sema.zirBoolToInt(block, inst),
- .embed_file => try sema.zirEmbedFile(block, inst),
- .error_name => try sema.zirErrorName(block, inst),
- .tag_name => try sema.zirTagName(block, inst),
- .reify => try sema.zirReify(block, inst),
- .type_name => try sema.zirTypeName(block, inst),
- .frame_type => try sema.zirFrameType(block, inst),
- .frame_size => try sema.zirFrameSize(block, inst),
- .float_to_int => try sema.zirFloatToInt(block, inst),
- .int_to_float => try sema.zirIntToFloat(block, inst),
- .int_to_ptr => try sema.zirIntToPtr(block, inst),
- .float_cast => try sema.zirFloatCast(block, inst),
- .int_cast => try sema.zirIntCast(block, inst),
- .err_set_cast => try sema.zirErrSetCast(block, inst),
- .ptr_cast => try sema.zirPtrCast(block, inst),
- .truncate => try sema.zirTruncate(block, inst),
- .align_cast => try sema.zirAlignCast(block, inst),
- .has_decl => try sema.zirHasDecl(block, inst),
- .has_field => try sema.zirHasField(block, inst),
- .clz => try sema.zirClz(block, inst),
- .ctz => try sema.zirCtz(block, inst),
- .pop_count => try sema.zirPopCount(block, inst),
- .byte_swap => try sema.zirByteSwap(block, inst),
- .bit_reverse => try sema.zirBitReverse(block, inst),
- .div_exact => try sema.zirDivExact(block, inst),
- .div_floor => try sema.zirDivFloor(block, inst),
- .div_trunc => try sema.zirDivTrunc(block, inst),
- .mod => try sema.zirMod(block, inst),
- .rem => try sema.zirRem(block, inst),
- .shl_exact => try sema.zirShlExact(block, inst),
- .shr_exact => try sema.zirShrExact(block, inst),
- .bit_offset_of => try sema.zirBitOffsetOf(block, inst),
- .offset_of => try sema.zirOffsetOf(block, inst),
- .cmpxchg_strong => try sema.zirCmpxchg(block, inst),
- .cmpxchg_weak => try sema.zirCmpxchg(block, inst),
- .splat => try sema.zirSplat(block, inst),
- .reduce => try sema.zirReduce(block, inst),
- .shuffle => try sema.zirShuffle(block, inst),
- .atomic_load => try sema.zirAtomicLoad(block, inst),
- .atomic_rmw => try sema.zirAtomicRmw(block, inst),
- .atomic_store => try sema.zirAtomicStore(block, inst),
- .mul_add => try sema.zirMulAdd(block, inst),
- .builtin_call => try sema.zirBuiltinCall(block, inst),
- .field_ptr_type => try sema.zirFieldPtrType(block, inst),
- .field_parent_ptr => try sema.zirFieldParentPtr(block, inst),
- .memcpy => try sema.zirMemcpy(block, inst),
- .memset => try sema.zirMemset(block, inst),
- .builtin_async_call => try sema.zirBuiltinAsyncCall(block, inst),
- .@"resume" => try sema.zirResume(block, inst),
- .@"await" => try sema.zirAwait(block, inst, false),
- .await_nosuspend => try sema.zirAwait(block, inst, true),
- .extended => try sema.zirExtended(block, inst),
-
- .sqrt => try sema.zirUnaryMath(block, inst),
- .sin => try sema.zirUnaryMath(block, inst),
- .cos => try sema.zirUnaryMath(block, inst),
- .exp => try sema.zirUnaryMath(block, inst),
- .exp2 => try sema.zirUnaryMath(block, inst),
- .log => try sema.zirUnaryMath(block, inst),
- .log2 => try sema.zirUnaryMath(block, inst),
- .log10 => try sema.zirUnaryMath(block, inst),
- .fabs => try sema.zirUnaryMath(block, inst),
- .floor => try sema.zirUnaryMath(block, inst),
- .ceil => try sema.zirUnaryMath(block, inst),
- .trunc => try sema.zirUnaryMath(block, inst),
- .round => try sema.zirUnaryMath(block, inst),
-
- .opaque_decl => try sema.zirOpaqueDecl(block, inst, .parent),
- .opaque_decl_anon => try sema.zirOpaqueDecl(block, inst, .anon),
- .opaque_decl_func => try sema.zirOpaqueDecl(block, inst, .func),
- .error_set_decl => try sema.zirErrorSetDecl(block, inst, .parent),
- .error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon),
- .error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func),
-
- .add => try sema.zirArithmetic(block, inst),
- .addwrap => try sema.zirArithmetic(block, inst),
- .div => try sema.zirArithmetic(block, inst),
- .mod_rem => try sema.zirArithmetic(block, inst),
- .mul => try sema.zirArithmetic(block, inst),
- .mulwrap => try sema.zirArithmetic(block, inst),
- .sub => try sema.zirArithmetic(block, inst),
- .subwrap => try sema.zirArithmetic(block, inst),
-
- // Instructions that we know to *always* be noreturn based solely on their tag.
- // These functions match the return type of analyzeBody so that we can
- // tail call them here.
- .break_inline => return inst,
- .condbr => return sema.zirCondbr(block, inst),
- .@"break" => return sema.zirBreak(block, inst),
- .compile_error => return sema.zirCompileError(block, inst),
- .ret_coerce => return sema.zirRetCoerce(block, inst, true),
- .ret_node => return sema.zirRetNode(block, inst),
- .ret_err_value => return sema.zirRetErrValue(block, inst),
- .@"unreachable" => return sema.zirUnreachable(block, inst),
- .repeat => return sema.zirRepeat(block, inst),
- .panic => return sema.zirPanic(block, inst),
- // zig fmt: on
-
- // Instructions that we know can *never* be noreturn based solely on
- // their tag. We avoid needlessly checking if they are noreturn and
- // continue the loop.
- // We also know that they cannot be referenced later, so we avoid
- // putting them into the map.
- .breakpoint => {
- try sema.zirBreakpoint(block, inst);
- i += 1;
- continue;
- },
- .fence => {
- try sema.zirFence(block, inst);
- i += 1;
- continue;
- },
- .dbg_stmt => {
- try sema.zirDbgStmt(block, inst);
- i += 1;
- continue;
- },
- .ensure_err_payload_void => {
- try sema.zirEnsureErrPayloadVoid(block, inst);
- i += 1;
- continue;
- },
- .ensure_result_non_error => {
- try sema.zirEnsureResultNonError(block, inst);
- i += 1;
- continue;
- },
- .ensure_result_used => {
- try sema.zirEnsureResultUsed(block, inst);
- i += 1;
- continue;
- },
- .set_eval_branch_quota => {
- try sema.zirSetEvalBranchQuota(block, inst);
- i += 1;
- continue;
- },
- .store => {
- try sema.zirStore(block, inst);
- i += 1;
- continue;
- },
- .store_node => {
- try sema.zirStoreNode(block, inst);
- i += 1;
- continue;
- },
- .store_to_block_ptr => {
- try sema.zirStoreToBlockPtr(block, inst);
- i += 1;
- continue;
- },
- .store_to_inferred_ptr => {
- try sema.zirStoreToInferredPtr(block, inst);
- i += 1;
- continue;
- },
- .resolve_inferred_alloc => {
- try sema.zirResolveInferredAlloc(block, inst);
- i += 1;
- continue;
- },
- .validate_struct_init_ptr => {
- try sema.zirValidateStructInitPtr(block, inst);
- i += 1;
- continue;
- },
- .validate_array_init_ptr => {
- try sema.zirValidateArrayInitPtr(block, inst);
- i += 1;
- continue;
- },
- .@"export" => {
- try sema.zirExport(block, inst);
- i += 1;
- continue;
- },
- .set_align_stack => {
- try sema.zirSetAlignStack(block, inst);
- i += 1;
- continue;
- },
- .set_cold => {
- try sema.zirSetCold(block, inst);
- i += 1;
- continue;
- },
- .set_float_mode => {
- try sema.zirSetFloatMode(block, inst);
- i += 1;
- continue;
- },
- .set_runtime_safety => {
- try sema.zirSetRuntimeSafety(block, inst);
- i += 1;
- continue;
- },
+ //.alloc => try sema.zirAlloc(block, inst),
+ //.alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
+ //.alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
+ //.alloc_inferred_comptime => try sema.zirAllocInferredComptime(block, inst),
+ //.alloc_mut => try sema.zirAllocMut(block, inst),
+ //.alloc_comptime => try sema.zirAllocComptime(block, inst),
+ //.anyframe_type => try sema.zirAnyframeType(block, inst),
+ //.array_cat => try sema.zirArrayCat(block, inst),
+ //.array_mul => try sema.zirArrayMul(block, inst),
+ //.array_type => try sema.zirArrayType(block, inst),
+ //.array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst),
+ //.vector_type => try sema.zirVectorType(block, inst),
+ //.as => try sema.zirAs(block, inst),
+ //.as_node => try sema.zirAsNode(block, inst),
+ //.bit_and => try sema.zirBitwise(block, inst, .bit_and),
+ //.bit_not => try sema.zirBitNot(block, inst),
+ //.bit_or => try sema.zirBitwise(block, inst, .bit_or),
+ //.bitcast => try sema.zirBitcast(block, inst),
+ //.bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst),
+ //.block => try sema.zirBlock(block, inst),
+ //.suspend_block => try sema.zirSuspendBlock(block, inst),
+ //.bool_not => try sema.zirBoolNot(block, inst),
+ //.bool_and => try sema.zirBoolOp(block, inst, false),
+ //.bool_or => try sema.zirBoolOp(block, inst, true),
+ //.bool_br_and => try sema.zirBoolBr(block, inst, false),
+ //.bool_br_or => try sema.zirBoolBr(block, inst, true),
+ //.c_import => try sema.zirCImport(block, inst),
+ //.call => try sema.zirCall(block, inst, .auto, false),
+ //.call_chkused => try sema.zirCall(block, inst, .auto, true),
+ //.call_compile_time => try sema.zirCall(block, inst, .compile_time, false),
+ //.call_nosuspend => try sema.zirCall(block, inst, .no_async, false),
+ //.call_async => try sema.zirCall(block, inst, .async_kw, false),
+ //.cmp_eq => try sema.zirCmp(block, inst, .eq),
+ //.cmp_gt => try sema.zirCmp(block, inst, .gt),
+ //.cmp_gte => try sema.zirCmp(block, inst, .gte),
+ //.cmp_lt => try sema.zirCmp(block, inst, .lt),
+ //.cmp_lte => try sema.zirCmp(block, inst, .lte),
+ //.cmp_neq => try sema.zirCmp(block, inst, .neq),
+ //.coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),
+ //.decl_ref => try sema.zirDeclRef(block, inst),
+ //.decl_val => try sema.zirDeclVal(block, inst),
+ //.load => try sema.zirLoad(block, inst),
+ //.elem_ptr => try sema.zirElemPtr(block, inst),
+ //.elem_ptr_node => try sema.zirElemPtrNode(block, inst),
+ //.elem_val => try sema.zirElemVal(block, inst),
+ //.elem_val_node => try sema.zirElemValNode(block, inst),
+ //.elem_type => try sema.zirElemType(block, inst),
+ //.enum_literal => try sema.zirEnumLiteral(block, inst),
+ //.enum_to_int => try sema.zirEnumToInt(block, inst),
+ //.int_to_enum => try sema.zirIntToEnum(block, inst),
+ //.err_union_code => try sema.zirErrUnionCode(block, inst),
+ //.err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst),
+ //.err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true),
+ //.err_union_payload_safe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, true),
+ //.err_union_payload_unsafe => try sema.zirErrUnionPayload(block, inst, false),
+ //.err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, false),
+ //.error_union_type => try sema.zirErrorUnionType(block, inst),
+ //.error_value => try sema.zirErrorValue(block, inst),
+ //.error_to_int => try sema.zirErrorToInt(block, inst),
+ //.int_to_error => try sema.zirIntToError(block, inst),
+ //.field_ptr => try sema.zirFieldPtr(block, inst),
+ //.field_ptr_named => try sema.zirFieldPtrNamed(block, inst),
+ //.field_val => try sema.zirFieldVal(block, inst),
+ //.field_val_named => try sema.zirFieldValNamed(block, inst),
+ //.func => try sema.zirFunc(block, inst, false),
+ //.func_inferred => try sema.zirFunc(block, inst, true),
+ //.import => try sema.zirImport(block, inst),
+ //.indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
+ //.int => try sema.zirInt(block, inst),
+ //.int_big => try sema.zirIntBig(block, inst),
+ //.float => try sema.zirFloat(block, inst),
+ //.float128 => try sema.zirFloat128(block, inst),
+ //.int_type => try sema.zirIntType(block, inst),
+ //.is_non_err => try sema.zirIsNonErr(block, inst),
+ //.is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst),
+ //.is_non_null => try sema.zirIsNonNull(block, inst),
+ //.is_non_null_ptr => try sema.zirIsNonNullPtr(block, inst),
+ //.loop => try sema.zirLoop(block, inst),
+ //.merge_error_sets => try sema.zirMergeErrorSets(block, inst),
+ //.negate => try sema.zirNegate(block, inst, .sub),
+ //.negate_wrap => try sema.zirNegate(block, inst, .subwrap),
+ //.optional_payload_safe => try sema.zirOptionalPayload(block, inst, true),
+ //.optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, inst, true),
+ //.optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false),
+ //.optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false),
+ //.optional_type => try sema.zirOptionalType(block, inst),
+ //.param_type => try sema.zirParamType(block, inst),
+ //.ptr_type => try sema.zirPtrType(block, inst),
+ //.ptr_type_simple => try sema.zirPtrTypeSimple(block, inst),
+ //.ref => try sema.zirRef(block, inst),
+ //.ret_err_value_code => try sema.zirRetErrValueCode(block, inst),
+ //.shl => try sema.zirShl(block, inst),
+ //.shr => try sema.zirShr(block, inst),
+ //.slice_end => try sema.zirSliceEnd(block, inst),
+ //.slice_sentinel => try sema.zirSliceSentinel(block, inst),
+ //.slice_start => try sema.zirSliceStart(block, inst),
+ //.str => try sema.zirStr(block, inst),
+ //.switch_block => try sema.zirSwitchBlock(block, inst, false, .none),
+ //.switch_block_multi => try sema.zirSwitchBlockMulti(block, inst, false, .none),
+ //.switch_block_else => try sema.zirSwitchBlock(block, inst, false, .@"else"),
+ //.switch_block_else_multi => try sema.zirSwitchBlockMulti(block, inst, false, .@"else"),
+ //.switch_block_under => try sema.zirSwitchBlock(block, inst, false, .under),
+ //.switch_block_under_multi => try sema.zirSwitchBlockMulti(block, inst, false, .under),
+ //.switch_block_ref => try sema.zirSwitchBlock(block, inst, true, .none),
+ //.switch_block_ref_multi => try sema.zirSwitchBlockMulti(block, inst, true, .none),
+ //.switch_block_ref_else => try sema.zirSwitchBlock(block, inst, true, .@"else"),
+ //.switch_block_ref_else_multi => try sema.zirSwitchBlockMulti(block, inst, true, .@"else"),
+ //.switch_block_ref_under => try sema.zirSwitchBlock(block, inst, true, .under),
+ //.switch_block_ref_under_multi => try sema.zirSwitchBlockMulti(block, inst, true, .under),
+ //.switch_capture => try sema.zirSwitchCapture(block, inst, false, false),
+ //.switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true),
+ //.switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false),
+ //.switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true),
+ //.switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false),
+ //.switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),
+ //.type_info => try sema.zirTypeInfo(block, inst),
+ //.size_of => try sema.zirSizeOf(block, inst),
+ //.bit_size_of => try sema.zirBitSizeOf(block, inst),
+ //.typeof => try sema.zirTypeof(block, inst),
+ //.typeof_elem => try sema.zirTypeofElem(block, inst),
+ //.log2_int_type => try sema.zirLog2IntType(block, inst),
+ //.typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst),
+ //.xor => try sema.zirBitwise(block, inst, .xor),
+ //.struct_init_empty => try sema.zirStructInitEmpty(block, inst),
+ //.struct_init => try sema.zirStructInit(block, inst, false),
+ //.struct_init_ref => try sema.zirStructInit(block, inst, true),
+ //.struct_init_anon => try sema.zirStructInitAnon(block, inst, false),
+ //.struct_init_anon_ref => try sema.zirStructInitAnon(block, inst, true),
+ //.array_init => try sema.zirArrayInit(block, inst, false),
+ //.array_init_ref => try sema.zirArrayInit(block, inst, true),
+ //.array_init_anon => try sema.zirArrayInitAnon(block, inst, false),
+ //.array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true),
+ //.union_init_ptr => try sema.zirUnionInitPtr(block, inst),
+ //.field_type => try sema.zirFieldType(block, inst),
+ //.field_type_ref => try sema.zirFieldTypeRef(block, inst),
+ //.ptr_to_int => try sema.zirPtrToInt(block, inst),
+ //.align_of => try sema.zirAlignOf(block, inst),
+ //.bool_to_int => try sema.zirBoolToInt(block, inst),
+ //.embed_file => try sema.zirEmbedFile(block, inst),
+ //.error_name => try sema.zirErrorName(block, inst),
+ //.tag_name => try sema.zirTagName(block, inst),
+ //.reify => try sema.zirReify(block, inst),
+ //.type_name => try sema.zirTypeName(block, inst),
+ //.frame_type => try sema.zirFrameType(block, inst),
+ //.frame_size => try sema.zirFrameSize(block, inst),
+ //.float_to_int => try sema.zirFloatToInt(block, inst),
+ //.int_to_float => try sema.zirIntToFloat(block, inst),
+ //.int_to_ptr => try sema.zirIntToPtr(block, inst),
+ //.float_cast => try sema.zirFloatCast(block, inst),
+ //.int_cast => try sema.zirIntCast(block, inst),
+ //.err_set_cast => try sema.zirErrSetCast(block, inst),
+ //.ptr_cast => try sema.zirPtrCast(block, inst),
+ //.truncate => try sema.zirTruncate(block, inst),
+ //.align_cast => try sema.zirAlignCast(block, inst),
+ //.has_decl => try sema.zirHasDecl(block, inst),
+ //.has_field => try sema.zirHasField(block, inst),
+ //.clz => try sema.zirClz(block, inst),
+ //.ctz => try sema.zirCtz(block, inst),
+ //.pop_count => try sema.zirPopCount(block, inst),
+ //.byte_swap => try sema.zirByteSwap(block, inst),
+ //.bit_reverse => try sema.zirBitReverse(block, inst),
+ //.div_exact => try sema.zirDivExact(block, inst),
+ //.div_floor => try sema.zirDivFloor(block, inst),
+ //.div_trunc => try sema.zirDivTrunc(block, inst),
+ //.mod => try sema.zirMod(block, inst),
+ //.rem => try sema.zirRem(block, inst),
+ //.shl_exact => try sema.zirShlExact(block, inst),
+ //.shr_exact => try sema.zirShrExact(block, inst),
+ //.bit_offset_of => try sema.zirBitOffsetOf(block, inst),
+ //.offset_of => try sema.zirOffsetOf(block, inst),
+ //.cmpxchg_strong => try sema.zirCmpxchg(block, inst),
+ //.cmpxchg_weak => try sema.zirCmpxchg(block, inst),
+ //.splat => try sema.zirSplat(block, inst),
+ //.reduce => try sema.zirReduce(block, inst),
+ //.shuffle => try sema.zirShuffle(block, inst),
+ //.atomic_load => try sema.zirAtomicLoad(block, inst),
+ //.atomic_rmw => try sema.zirAtomicRmw(block, inst),
+ //.atomic_store => try sema.zirAtomicStore(block, inst),
+ //.mul_add => try sema.zirMulAdd(block, inst),
+ //.builtin_call => try sema.zirBuiltinCall(block, inst),
+ //.field_ptr_type => try sema.zirFieldPtrType(block, inst),
+ //.field_parent_ptr => try sema.zirFieldParentPtr(block, inst),
+ //.memcpy => try sema.zirMemcpy(block, inst),
+ //.memset => try sema.zirMemset(block, inst),
+ //.builtin_async_call => try sema.zirBuiltinAsyncCall(block, inst),
+ //.@"resume" => try sema.zirResume(block, inst),
+ //.@"await" => try sema.zirAwait(block, inst, false),
+ //.await_nosuspend => try sema.zirAwait(block, inst, true),
+ //.extended => try sema.zirExtended(block, inst),
+
+ //.sqrt => try sema.zirUnaryMath(block, inst),
+ //.sin => try sema.zirUnaryMath(block, inst),
+ //.cos => try sema.zirUnaryMath(block, inst),
+ //.exp => try sema.zirUnaryMath(block, inst),
+ //.exp2 => try sema.zirUnaryMath(block, inst),
+ //.log => try sema.zirUnaryMath(block, inst),
+ //.log2 => try sema.zirUnaryMath(block, inst),
+ //.log10 => try sema.zirUnaryMath(block, inst),
+ //.fabs => try sema.zirUnaryMath(block, inst),
+ //.floor => try sema.zirUnaryMath(block, inst),
+ //.ceil => try sema.zirUnaryMath(block, inst),
+ //.trunc => try sema.zirUnaryMath(block, inst),
+ //.round => try sema.zirUnaryMath(block, inst),
+
+ //.opaque_decl => try sema.zirOpaqueDecl(block, inst, .parent),
+ //.opaque_decl_anon => try sema.zirOpaqueDecl(block, inst, .anon),
+ //.opaque_decl_func => try sema.zirOpaqueDecl(block, inst, .func),
+ //.error_set_decl => try sema.zirErrorSetDecl(block, inst, .parent),
+ //.error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon),
+ //.error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func),
+
+ //.add => try sema.zirArithmetic(block, inst),
+ //.addwrap => try sema.zirArithmetic(block, inst),
+ //.div => try sema.zirArithmetic(block, inst),
+ //.mod_rem => try sema.zirArithmetic(block, inst),
+ //.mul => try sema.zirArithmetic(block, inst),
+ //.mulwrap => try sema.zirArithmetic(block, inst),
+ //.sub => try sema.zirArithmetic(block, inst),
+ //.subwrap => try sema.zirArithmetic(block, inst),
+
+ //// Instructions that we know to *always* be noreturn based solely on their tag.
+ //// These functions match the return type of analyzeBody so that we can
+ //// tail call them here.
+ //.break_inline => return inst,
+ //.condbr => return sema.zirCondbr(block, inst),
+ //.@"break" => return sema.zirBreak(block, inst),
+ //.compile_error => return sema.zirCompileError(block, inst),
+ //.ret_coerce => return sema.zirRetCoerce(block, inst, true),
+ //.ret_node => return sema.zirRetNode(block, inst),
+ //.ret_err_value => return sema.zirRetErrValue(block, inst),
+ //.@"unreachable" => return sema.zirUnreachable(block, inst),
+ //.repeat => return sema.zirRepeat(block, inst),
+ //.panic => return sema.zirPanic(block, inst),
+ //// zig fmt: on
+
+ //// Instructions that we know can *never* be noreturn based solely on
+ //// their tag. We avoid needlessly checking if they are noreturn and
+ //// continue the loop.
+ //// We also know that they cannot be referenced later, so we avoid
+ //// putting them into the map.
+ //.breakpoint => {
+ // try sema.zirBreakpoint(block, inst);
+ // i += 1;
+ // continue;
+ //},
+ //.fence => {
+ // try sema.zirFence(block, inst);
+ // i += 1;
+ // continue;
+ //},
+ //.dbg_stmt => {
+ // try sema.zirDbgStmt(block, inst);
+ // i += 1;
+ // continue;
+ //},
+ //.ensure_err_payload_void => {
+ // try sema.zirEnsureErrPayloadVoid(block, inst);
+ // i += 1;
+ // continue;
+ //},
+ //.ensure_result_non_error => {
+ // try sema.zirEnsureResultNonError(block, inst);
+ // i += 1;
+ // continue;
+ //},
+ //.ensure_result_used => {
+ // try sema.zirEnsureResultUsed(block, inst);
+ // i += 1;
+ // continue;
+ //},
+ //.set_eval_branch_quota => {
+ // try sema.zirSetEvalBranchQuota(block, inst);
+ // i += 1;
+ // continue;
+ //},
+ //.store => {
+ // try sema.zirStore(block, inst);
+ // i += 1;
+ // continue;
+ //},
+ //.store_node => {
+ // try sema.zirStoreNode(block, inst);
+ // i += 1;
+ // continue;
+ //},
+ //.store_to_block_ptr => {
+ // try sema.zirStoreToBlockPtr(block, inst);
+ // i += 1;
+ // continue;
+ //},
+ //.store_to_inferred_ptr => {
+ // try sema.zirStoreToInferredPtr(block, inst);
+ // i += 1;
+ // continue;
+ //},
+ //.resolve_inferred_alloc => {
+ // try sema.zirResolveInferredAlloc(block, inst);
+ // i += 1;
+ // continue;
+ //},
+ //.validate_struct_init_ptr => {
+ // try sema.zirValidateStructInitPtr(block, inst);
+ // i += 1;
+ // continue;
+ //},
+ //.validate_array_init_ptr => {
+ // try sema.zirValidateArrayInitPtr(block, inst);
+ // i += 1;
+ // continue;
+ //},
+ //.@"export" => {
+ // try sema.zirExport(block, inst);
+ // i += 1;
+ // continue;
+ //},
+ //.set_align_stack => {
+ // try sema.zirSetAlignStack(block, inst);
+ // i += 1;
+ // continue;
+ //},
+ //.set_cold => {
+ // try sema.zirSetCold(block, inst);
+ // i += 1;
+ // continue;
+ //},
+ //.set_float_mode => {
+ // try sema.zirSetFloatMode(block, inst);
+ // i += 1;
+ // continue;
+ //},
+ //.set_runtime_safety => {
+ // try sema.zirSetRuntimeSafety(block, inst);
+ // i += 1;
+ // continue;
+ //},
// Special case instructions to handle comptime control flow.
.repeat_inline => {
@@ -505,37 +505,38 @@ pub fn analyzeBody(
i = 0;
continue;
},
- .block_inline => blk: {
- // Directly analyze the block body without introducing a new block.
- const inst_data = datas[inst].pl_node;
- const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
- const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
- const break_inst = try sema.analyzeBody(block, inline_body);
- const break_data = datas[break_inst].@"break";
- if (inst == break_data.block_inst) {
- break :blk try sema.resolveInst(break_data.operand);
- } else {
- return break_inst;
- }
- },
- .condbr_inline => blk: {
- const inst_data = datas[inst].pl_node;
- const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
- const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
- const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len];
- const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
- const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition);
- const inline_body = if (cond.val.toBool()) then_body else else_body;
- const break_inst = try sema.analyzeBody(block, inline_body);
- const break_data = datas[break_inst].@"break";
- if (inst == break_data.block_inst) {
- break :blk try sema.resolveInst(break_data.operand);
- } else {
- return break_inst;
- }
- },
+ //.block_inline => blk: {
+ // // Directly analyze the block body without introducing a new block.
+ // const inst_data = datas[inst].pl_node;
+ // const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
+ // const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
+ // const break_inst = try sema.analyzeBody(block, inline_body);
+ // const break_data = datas[break_inst].@"break";
+ // if (inst == break_data.block_inst) {
+ // break :blk try sema.resolveInst(break_data.operand);
+ // } else {
+ // return break_inst;
+ // }
+ //},
+ //.condbr_inline => blk: {
+ // const inst_data = datas[inst].pl_node;
+ // const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
+ // const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
+ // const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len];
+ // const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
+ // const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition);
+ // const inline_body = if (cond.val.toBool()) then_body else else_body;
+ // const break_inst = try sema.analyzeBody(block, inline_body);
+ // const break_data = datas[break_inst].@"break";
+ // if (inst == break_data.block_inst) {
+ // break :blk try sema.resolveInst(break_data.operand);
+ // } else {
+ // return break_inst;
+ // }
+ //},
+ else => @panic("TODO remove else prong"),
};
- if (air_inst.ty.isNoReturn())
+ if (sema.getAirType(air_inst).isNoReturn())
return always_noreturn;
try map.put(sema.gpa, inst, air_inst);
i += 1;
@@ -577,18 +578,13 @@ fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro
}
}
-/// TODO when we rework AIR memory layout, this function will no longer have a possible error.
-pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) error{OutOfMemory}!Air.Inst.Index {
+pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) Air.Inst.Ref {
var i: usize = @enumToInt(zir_ref);
// First section of indexes correspond to a set number of constant values.
if (i < Zir.Inst.Ref.typed_value_map.len) {
- // TODO when we rework AIR memory layout, this function can be as simple as:
- // if (zir_ref < Zir.const_inst_list.len + sema.param_count)
- // return zir_ref;
- // Until then we allocate memory for a new, mutable `ir.Inst` to match what
- // AIR expects.
- return sema.mod.constInst(sema.arena, .unneeded, Zir.Inst.Ref.typed_value_map[i]);
+ // We intentionally map the same indexes to the same values between ZIR and AIR.
+ return zir_ref;
}
i -= Zir.Inst.Ref.typed_value_map.len;
@@ -1256,7 +1252,7 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) In
return sema.analyzeLoad(block, src, result_ptr, result_ptr.src);
}
-fn zirArg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Air.Inst.Index {
+fn zirArg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
const arg_name = inst_data.get(sema.code);
const arg_index = sema.next_arg_index;
@@ -1271,7 +1267,7 @@ fn zirArg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Air
// Set the name of the Air.Arg instruction for use by codegen debug info.
const air_arg = sema.param_inst_list[arg_index];
- sema.air.instructions.items(.data)[air_arg].ty_str.str = inst_data.start;
+ sema.air_instructions.items(.data)[air_arg].ty_str.str = inst_data.start;
return air_arg;
}
@@ -7942,6 +7938,18 @@ fn enumFieldSrcLoc(
} else unreachable;
}
+fn getAirType(sema: *Sema, air_ref: Air.Inst.Ref) Type {
+ var i: usize = @enumToInt(air_ref);
+ if (i < Air.Inst.Ref.typed_value_map.len) {
+ return Air.Inst.Ref.typed_value_map[i].val.toType(undefined) catch unreachable;
+ }
+ i -= Air.Inst.Ref.typed_value_map.len;
+ const air_tags = sema.air_instructions.items(.tag);
+ const air_datas = sema.air_instructions.items(.data);
+ assert(air_tags[i] == .const_ty);
+ return air_datas[i].ty;
+}
+
pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {
switch (ty.tag()) {
.u8 => return .u8_type,
BRANCH_TODO
@@ -690,3 +690,8 @@ pub fn dumpInst(mod: *Module, scope: *Scope, inst: *ir.Inst) void {
}
}
+ /// For debugging purposes.
+ pub fn dump(func: *Fn, mod: Module) void {
+ ir.dumpFn(mod, func);
+ }
+