diff --git a/src/Compilation.zig b/src/Compilation.zig index 6604dbd..ef81403 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -695,7 +695,7 @@ pub const Module = struct { casts: BlockList(Cast) = .{}, string_literal_types: data_structures.AutoArrayHashMap(u32, Type.Index) = .{}, array_types: data_structures.AutoArrayHashMap(Array, Type.Index) = .{}, - entry_point: ?u32 = null, + entry_point: Function.Index = Function.Index.invalid, pub const Descriptor = struct { main_package_path: []const u8, diff --git a/src/backend/elf.zig b/src/backend/elf.zig index 14fab53..7d5d188 100644 --- a/src/backend/elf.zig +++ b/src/backend/elf.zig @@ -7,58 +7,96 @@ const Allocator = data_structures.Allocator; const ArrayList = data_structures.ArrayList; const emit = @import("emit.zig"); +const page_size = 0x1000; -pub const Writer = struct { - bytes: ArrayList(u8), - allocator: Allocator, +pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, page_size) { + var file = try std.ArrayListAlignedUnmanaged(u8, 0x1000).initCapacity(image.allocator, 0x100000); + _ = try image.insertSection(0, .{ + .name = "", + .size = page_size, + .alignment = page_size, + .flags = .{ + .read = true, + .write = false, + .execute = false, + }, + .type = .loadable_program, + }); - pub fn init(allocator: Allocator) !Writer { - return .{ - .bytes = try ArrayList(u8).initCapacity(allocator, 0x10000), - .allocator = allocator, - }; + const symbol_table_index = try image.addSection(.{ + .name = ".symtab", + .size = page_size, + .alignment = @alignOf(SymbolTable.Entry), + .flags = .{ + .read = false, + .write = false, + .execute = false, + }, + .type = .symbol_table, + }); + const string_table_index = try image.addSection(.{ + .name = ".strtab", + .size = page_size, + .alignment = 1, + .flags = .{ + .read = false, + .write = false, + .execute = false, + }, + .type = .string_table, + }); + const section_header_string_table_index = try image.addSection(.{ + .name = ".shstrtab", + .size = page_size, + .alignment = 1, + .flags = .{ + .read = false, + .write = false, + .execute = false, + }, + .type = .string_table, + }); + + const base_virtual_address = 0x400000; + const text_section_index = 1; + + const program_header_count = blk: { + var result: usize = 0; + for (image.sections.items) |section| { + result += @intFromBool(switch (section.type) { + .null => false, + .loadable_program => true, + .string_table => false, + .symbol_table => false, + }); + } + break :blk result; + }; + + var symbol_name_offset: u32 = 0; + + image.writeToSection(symbol_table_index, std.mem.asBytes(&SymbolTable.Entry{ + .name_offset = symbol_name_offset, + .information = 0, + .other = 0, + .section_header_index = 0, + .value = 0, + .size = 0, + })); + + image.writeToSection(string_table_index, ""); + image.writeByteToSection(string_table_index, 0); + symbol_name_offset += 1; + + for (image.sections.items) |section| { + image.writeToSection(section_header_string_table_index, section.name); + image.writeByteToSection(section_header_string_table_index, 0); } - pub fn getHeader(writer: *Writer) *Header { - return @ptrCast(@alignCast(writer.bytes.items.ptr)); - } + { + var program_segment_offset: usize = 0; - pub fn writeToMemory(writer: *Writer, image: *const emit.Result) !void { - const section_fields = @typeInfo(@TypeOf(image.sections)).Struct.fields; - const section_count = blk: { - var result: u16 = 0; - inline for (section_fields) |section_field| { - const section_size = @field(image.sections, section_field.name).index; - result += @intFromBool(section_size > 0); - } - break :blk result; - }; - - const program_header_count = section_count; - const program_start_offset = @sizeOf(Header) + program_header_count * @sizeOf(ProgramHeader); - - var section_offsets: [section_fields.len]u32 = undefined; - - const program_end_offset = blk: { - var result: u32 = program_start_offset; - inline for (section_fields, 0..) |section_field, section_index| { - const section = &@field(image.sections, section_field.name); - if (section.index > 0) { - const section_offset = std.mem.alignForward(u32, result, section.alignment); - section_offsets[section_index] = section_offset; - result = std.mem.alignForward(u32, section_offset + @as(u32, @intCast(section.index)), section.alignment); - } - } - - break :blk result; - }; - - const elf_file_end_offset = program_end_offset + @sizeOf(SectionHeader) * section_count; - try writer.bytes.resize(writer.allocator, elf_file_end_offset); - - const base_address = 0x200000; - - writer.getHeader().* = Header{ + image.writeToSection(0, std.mem.asBytes(&Header{ .endianness = .little, .machine = switch (image.target.cpu.arch) { .x86_64 => .AMD64, @@ -68,79 +106,134 @@ pub const Writer = struct { .linux => .systemv, else => unreachable, }, - .entry = base_address + section_offsets[0] + image.entry_point, - .section_header_offset = program_end_offset, - .program_header_count = program_header_count, - .section_header_count = section_count, - .name_section_header_index = 0, - }; + .entry = 0, + .section_header_offset = 0, + .program_header_count = @intCast(program_header_count), + .section_header_count = @intCast(image.sections.items.len), + .section_header_string_table_index = @intCast(section_header_string_table_index), + })); - var program_header_offset: usize = @sizeOf(Header); - var section_header_offset = program_end_offset; - inline for (section_fields, section_offsets) |section_field, section_offset| { - const section_name = section_field.name; - const section = &@field(image.sections, section_name); - if (section.index > 0) { - const program_header: *ProgramHeader = @ptrCast(@alignCast(writer.bytes.items[program_header_offset..].ptr)); - program_header.* = .{ - .type = .load, - .flags = .{ - .executable = equal(u8, section_name, "text"), - .writable = equal(u8, section_name, "data"), - .readable = true, - }, - .offset = 0, - .virtual_address = base_address, - .physical_address = base_address, - .size_in_file = section.index, - .size_in_memory = section.index, - .alignment = 0, - }; + for (image.sections.items, 0..) |section, section_index| { + switch (section.type) { + .loadable_program => { + program_segment_offset = std.mem.alignForward(usize, program_segment_offset, section.alignment); + const virtual_address = base_virtual_address + program_segment_offset; + const program_segment_size = switch (section_index) { + 0 => @sizeOf(Header) + @sizeOf(ProgramHeader) * program_header_count, + else => section.index, + }; + image.writeToSection(0, std.mem.asBytes(&ProgramHeader{ + .type = .load, + .flags = ProgramHeader.Flags{ + .executable = section.flags.execute, + .writable = section.flags.write, + .readable = section.flags.read, + }, + .offset = program_segment_offset, + .virtual_address = virtual_address, + .physical_address = virtual_address, + .size_in_file = program_segment_size, + .size_in_memory = program_segment_size, + .alignment = section.alignment, + })); - const source = section.content[0..section.index]; - const destination = writer.bytes.items[section_offset..][0..source.len]; - @memcpy(destination, source); - - const section_header: *SectionHeader = @ptrCast(@alignCast(writer.bytes.items[section_header_offset..].ptr)); - section_header.* = .{ - .name_offset = 0, - .type = .program_data, - .flags = .{ - .alloc = equal(u8, section_name, "text"), - .executable = equal(u8, section_name, "text"), - .writable = equal(u8, section_name, "data"), - }, - .address = base_address + section_offset, - .offset = section_offset, - .size = section.index, - .link = 0, - .info = 0, - .alignment = 0, - .entry_size = 0, - }; + program_segment_offset += program_segment_size; + }, + .null, + .string_table, + .symbol_table, + => {}, } } } - pub fn writeToFile(writer: *const Writer, file_path: []const u8) !void { - std.debug.print("Writing file to {s}\n", .{file_path}); - const flags = switch (@import("builtin").os.tag) { - .windows => .{}, - else => .{ - .mode = 0o777, - }, + { + var section_offset: usize = 0; + var section_headers = try ArrayList(SectionHeader).initCapacity(image.allocator, image.sections.items.len); + var section_name_offset: u32 = 0; + + for (image.sections.items, 0..) |section, section_i| { + section_offset = std.mem.alignForward(usize, section_offset, section.alignment); + const virtual_address = base_virtual_address + section_offset; + + for (section.symbol_table.keys(), section.symbol_table.values()) |symbol_name, symbol_offset| { + const symbol_address = virtual_address + symbol_offset; + image.writeToSection(symbol_table_index, std.mem.asBytes(&SymbolTable.Entry{ + .name_offset = symbol_name_offset, + .information = 0x10, + .other = 0, + .section_header_index = @intCast(section_i), + .value = symbol_address, + .size = 0, + })); + + image.writeToSection(string_table_index, symbol_name); + image.writeByteToSection(string_table_index, 0); + + symbol_name_offset += @intCast(symbol_name.len + 1); + } + + const source = section.content[0..section.index]; + file.items.len = section_offset + source.len; + try file.replaceRange(image.allocator, section_offset, source.len, source); + + section_headers.appendAssumeCapacity(SectionHeader{ + .name_offset = section_name_offset, + .type = switch (section_i) { + 0 => .null, + else => switch (section.type) { + .loadable_program => .program_data, + .string_table => .string_table, + .symbol_table => .symbol_table, + .null => .null, + }, + }, + .flags = .{ + .alloc = true, + .executable = section.flags.execute, + .writable = section.flags.write, + }, + .virtual_address = virtual_address, + .file_offset = section_offset, + .size = section.index, + .link = switch (section.type) { + .symbol_table => @intCast(string_table_index), + else => 0, + }, + .info = switch (section.type) { + .symbol_table => 1, + else => 0, + }, + .alignment = 0, + .entry_size = switch (section.type) { + .symbol_table => @sizeOf(SymbolTable.Entry), + else => 0, + }, + }); + + section_offset += section.index; + section_name_offset += @intCast(section.name.len + 1); + } + + const section_header_offset = std.mem.alignForward(usize, section_offset, @alignOf(SectionHeader)); + const section_header_bytes = std.mem.sliceAsBytes(section_headers.items); + try file.ensureTotalCapacity(image.allocator, section_header_offset + section_header_bytes.len); + file.items.len = section_header_offset + section_header_bytes.len; + try file.replaceRange(image.allocator, section_header_offset, section_header_bytes.len, section_header_bytes); + + const _start_offset = blk: { + const entry_offset = image.sections.items[text_section_index].symbol_table.values()[image.entry_point]; + const text_section_virtual_address = section_headers.items[text_section_index].virtual_address; + break :blk text_section_virtual_address + entry_offset; }; - const file_descriptor = try std.fs.cwd().createFile(file_path, flags); - try file_descriptor.writeAll(writer.bytes.items); - file_descriptor.close(); + + const header: *Header = @ptrCast(file.items.ptr); + header.section_header_offset = section_header_offset; + header.entry = _start_offset; } - pub fn writeToFileAbsolute(writer: *const Writer, absolute_file_path: []const u8) !void { - const file = try std.fs.createFileAbsolute(absolute_file_path, .{}); - defer file.close(); - try file.writeAll(writer.bytes.items); - } -}; + return file; +} const Header = extern struct { magic: u8 = 0x7f, @@ -163,7 +256,7 @@ const Header = extern struct { program_header_count: u16 = 1, section_header_size: u16 = @sizeOf(SectionHeader), section_header_count: u16, - name_section_header_index: u16, + section_header_string_table_index: u16, const BitCount = enum(u8) { @"32" = 1, @@ -197,14 +290,14 @@ const Header = extern struct { }; const ProgramHeader = extern struct { - type: Type = .load, + type: Type, flags: Flags, offset: u64, virtual_address: u64, physical_address: u64, size_in_file: u64, size_in_memory: u64, - alignment: u64 = 0, + alignment: u64, const Type = enum(u32) { null = 0, @@ -232,8 +325,8 @@ const SectionHeader = extern struct { name_offset: u32, type: Type, flags: Flags, - address: u64, - offset: u64, + virtual_address: u64, + file_offset: u64, size: u64, // section index link: u32, @@ -279,3 +372,14 @@ const SectionHeader = extern struct { _reserved: u53 = 0, }; }; + +const SymbolTable = extern struct { + const Entry = extern struct { + name_offset: u32, + information: u8, + other: u8, + section_header_index: u16, + value: u64, + size: u64, + }; +}; diff --git a/src/backend/emit.zig b/src/backend/emit.zig index ce6aca2..e1395fa 100644 --- a/src/backend/emit.zig +++ b/src/backend/emit.zig @@ -24,38 +24,130 @@ const jit_callconv = .SysV; const Section = struct { content: []align(page_size) u8, index: usize = 0, - alignment: u32 = 0x10, + alignment: u32, + name: []const u8, + flags: Flags, + type: Type, + symbol_table: std.StringArrayHashMapUnmanaged(u32) = .{}, + + const Type = enum { + null, + loadable_program, + string_table, + symbol_table, + }; + + const Flags = packed struct { + read: bool, + write: bool, + execute: bool, + }; }; pub const Result = struct { - sections: struct { - text: Section, - rodata: Section, - data: Section, - }, - entry_point: u32 = 0, + sections: ArrayList(Section) = .{}, + // sections: struct { + // text: Section, + // rodata: Section, + // data: Section, + // }, + entry_point: u32, target: std.Target, + allocator: Allocator, - pub fn create(target: std.Target) !Result { - return Result{ - .sections = .{ - .text = .{ .content = try mmap(page_size, .{ .executable = true }) }, - .rodata = .{ .content = try mmap(page_size, .{ .executable = false }) }, - .data = .{ .content = try mmap(page_size, .{ .executable = false }) }, - }, + const text_section_index = 0; + + pub fn create(allocator: Allocator, target: std.Target, entry_point_index: u32) !Result { + var result = Result{ + // .sections = .{ + // .text = .{ .content = try mmap(page_size, .{ .executable = true }) }, + // .rodata = .{ .content = try mmap(page_size, .{ .executable = false }) }, + // .data = .{ .content = try mmap(page_size, .{ .executable = false }) }, + // }, .target = target, + .allocator = allocator, + .entry_point = entry_point_index, }; + + _ = try result.addSection(.{ + .name = ".text", + .size = 0x1000, + .alignment = 0x1000, + .flags = .{ + .execute = true, + .read = true, + .write = false, + }, + .type = .loadable_program, + }); + + return result; + } + + const SectionCreation = struct { + name: []const u8, + size: usize, + alignment: u32, + flags: Section.Flags, + type: Section.Type, + }; + + pub fn addSection(result: *Result, arguments: SectionCreation) !usize { + const index = result.sections.items.len; + assert(std.mem.isAligned(arguments.size, page_size)); + + try result.sections.append(result.allocator, .{ + .content = try mmap(arguments.size, .{ .executable = arguments.flags.execute }), + .alignment = arguments.alignment, + .name = arguments.name, + .flags = arguments.flags, + .type = arguments.type, + }); + + return index; + } + + pub fn insertSection(result: *Result, index: usize, arguments: SectionCreation) !usize { + assert(std.mem.isAligned(arguments.size, page_size)); + try result.sections.insert(result.allocator, index, .{ + .content = try mmap(arguments.size, .{ .executable = arguments.flags.execute }), + .alignment = arguments.alignment, + .name = arguments.name, + .flags = arguments.flags, + .type = arguments.type, + }); + + return index; + } + + pub fn alignSection(result: *Result, index: usize, alignment: usize) void { + const index_ptr = &result.sections.items[index].index; + index_ptr.* = std.mem.alignForward(usize, index_ptr.*, alignment); + } + + pub fn writeToSection(image: *Result, section_index: usize, bytes: []const u8) void { + const section = &image.sections.items[section_index]; + const destination = section.content[section.index..][0..bytes.len]; + @memcpy(destination, bytes); + section.index += bytes.len; + } + + pub fn writeByteToSection(image: *Result, section_index: usize, byte: u8) void { + const section = &image.sections.items[section_index]; + section.content[section.index] = byte; + section.index += 1; + } + + pub fn getTextSection(result: *Result) *Section { + return &result.sections.items[0]; } pub fn appendCode(image: *Result, code: []const u8) void { - const destination = image.sections.text.content[image.sections.text.index..][0..code.len]; - @memcpy(destination, code); - image.sections.text.index += code.len; + image.writeToSection(text_section_index, code); } pub fn appendCodeByte(image: *Result, code_byte: u8) void { - image.sections.text.content[image.sections.text.index] = code_byte; - image.sections.text.index += 1; + image.writeByteToSection(text_section_index, code_byte); } fn getEntryPoint(image: *const Result, comptime FunctionType: type) *const FunctionType { @@ -70,16 +162,31 @@ pub const Result = struct { return @as(*const FunctionType, @ptrCast(&image.sections.text.content[image.entry_point])); } - fn writeElf(image: *const Result, allocator: Allocator, executable_relative_path: []const u8) !void { - var writer = try elf.Writer.init(allocator); - try writer.writeToMemory(image); - try writer.writeToFile(executable_relative_path); + fn writeElf(image: *Result, executable_relative_path: []const u8) !void { + const file_in_memory = try elf.writeToMemory(image); + try writeFile(file_in_memory.items, executable_relative_path); } - fn writePe(image: *const Result, allocator: Allocator, executable_relative_path: []const u8) !void { - var writer = try pe.Writer.init(allocator); - try writer.writeToMemory(image); - try writer.writeToFile(executable_relative_path); + fn writeFile(bytes: []const u8, path: []const u8) !void { + const flags = switch (@import("builtin").os.tag) { + .windows => .{}, + else => .{ + .mode = 0o777, + }, + }; + + const file_descriptor = try std.fs.cwd().createFile(path, flags); + try file_descriptor.writeAll(bytes); + file_descriptor.close(); + } + + fn writePe(image: *Result, executable_relative_path: []const u8) !void { + _ = executable_relative_path; + _ = image; + // var writer = try pe.Writer.init(allocator); + // try writer.writeToMemory(image); + // try writer.writeToFile(executable_relative_path); + unreachable; } }; @@ -124,15 +231,13 @@ pub fn get(comptime arch: std.Target.Cpu.Arch) type { var mir = try backend.MIR.selectInstructions(allocator, intermediate, descriptor.target); try mir.allocateRegisters(); const os = descriptor.target.os.tag; - _ = os; const image = try mir.encode(); - _ = image; - // switch (os) { - // .linux => try image.writeElf(allocator, descriptor.executable_path), - // .windows => try image.writePe(allocator, descriptor.executable_path), - // else => unreachable, - // } + switch (os) { + .linux => try image.writeElf(descriptor.executable_path), + .windows => try image.writePe(descriptor.executable_path), + else => unreachable, + } }, else => { const file = try std.fs.cwd().readFileAlloc(allocator, "main", std.math.maxInt(u64)); diff --git a/src/backend/intermediate_representation.zig b/src/backend/intermediate_representation.zig index 839e029..73d2d07 100644 --- a/src/backend/intermediate_representation.zig +++ b/src/backend/intermediate_representation.zig @@ -42,7 +42,7 @@ pub const Result = struct { casts: BlockList(Cast) = .{}, readonly_data: ArrayList(u8) = .{}, module: *Module, - entry_point: u32 = 0, + entry_point: Function.Index = Function.Index.invalid, pub fn getFunctionName(ir: *Result, function_index: Function.Declaration.Index) []const u8 { return ir.module.getName(ir.module.function_name_map.get(@bitCast(function_index)).?).?; @@ -58,13 +58,20 @@ pub fn initialize(compilation: *Compilation, module: *Module) !*Result { }; builder.ir.module = module; - builder.ir.entry_point = module.entry_point orelse unreachable; + var sema_function_index = function_iterator.getCurrentIndex(); while (function_iterator.next()) |sema_function| { const function_index = try builder.buildFunction(sema_function); - _ = function_index; + if (sema_function_index.eq(module.entry_point)) { + assert(!function_index.invalid); + builder.ir.entry_point = function_index; + } + + sema_function_index = function_iterator.getCurrentIndex(); } + assert(!builder.ir.entry_point.invalid); + return &builder.ir; } @@ -398,7 +405,7 @@ pub const Builder = struct { return builder.ir.function_definitions.get(builder.current_function_index); } - fn buildFunction(builder: *Builder, sema_function: Compilation.Function) !void { + fn buildFunction(builder: *Builder, sema_function: Compilation.Function) !Function.Index { const sema_prototype = builder.module.function_prototypes.get(builder.module.types.get(sema_function.prototype).function); const function_declaration_allocation = try builder.ir.function_declarations.addOne(builder.allocator); const function_declaration = function_declaration_allocation.ptr; @@ -425,7 +432,7 @@ pub const Builder = struct { } switch (sema_prototype.attributes.@"extern") { - true => {}, + true => return Function.Index.invalid, false => { const function_allocation = try builder.ir.function_definitions.append(builder.allocator, .{ .ir = &builder.ir, @@ -495,6 +502,8 @@ pub const Builder = struct { builder.currentFunction().current_stack_offset = std.mem.alignForward(usize, builder.currentFunction().current_stack_offset, 0x10); try builder.optimizeFunction(builder.currentFunction()); + + return function_allocation.index; }, } } diff --git a/src/backend/x86_64.zig b/src/backend/x86_64.zig index 6bf50c4..7bdda85 100644 --- a/src/backend/x86_64.zig +++ b/src/backend/x86_64.zig @@ -35,20 +35,23 @@ pub const Logger = enum { register_allocation_instruction_avoid_copy, register_allocation_function_after, register_allocation_operand_list_verification, + encoding, pub var bitset = std.EnumSet(Logger).initMany(&.{ .instruction_selection_ir_function, + .instruction_selection_mir_function, // .instruction_selection_register_operand_list, - .register_allocation_block, + // .register_allocation_block, // .register_allocation_problematic_hint, // .register_allocation_assignment, // .register_allocation_reload, - .register_allocation_function_before, + // .register_allocation_function_before, // .register_allocation_new_instruction, // .register_allocation_new_instruction_function_before, // .register_allocation_instruction_avoid_copy, .register_allocation_function_after, - .register_allocation_operand_list_verification, + // .register_allocation_operand_list_verification, + .encoding, }); }; @@ -1238,33 +1241,6 @@ const InstructionSelection = struct { try instruction_selection.instruction_cache.append(mir.allocator, instr); }, } - // const instruction_descriptor = instruction_descriptors.getPtrConst(instruction_id); - // - // switch (integer.value.unsigned == 0) { - // true => switch (value_type) { - // .i32 => .mov32r0, - // else => |t| @panic(@tagName(t)), - // }, - // false => blk: { - // - // const destination_register = try mir.createVirtualRegister(destination_register_class); - // const destination_operand = mir.constrainOperandRegisterClass(instruction_descriptor, destination_register, 0, .{ .type = .def }); - // - // const instr = try mir.buildInstruction(instruction_selection, instruction_id, &.{ - // destination_operand, - // Operand{ - // .id = .immediate, - // .u = .{ - // .immediate = integer.value.unsigned, - // }, - // .flags = .{}, - // }, - // }); - // try instruction_selection.instruction_cache.append(mir.allocator, instr); - // - // break :blk destination_register; - // }, - // } } fn getAddressingModeFromIr(instruction_selection: *InstructionSelection, mir: *MIR, ir_instruction_index: ir.Instruction.Index) AddressingMode { @@ -1293,17 +1269,6 @@ const InstructionSelection = struct { unreachable; } } - // const gop = try instruction_selection.local_value_map.getOrPut(allocator, ir_instruction_index); - // if (gop.found_existing) { - // const stored_register = gop.value_ptr.*; - // if (std.meta.eql(stored_register, register)) { - // unreachable; - // } else { - // std.debug.panic("Register mismatch: Stored: {} Got: {}", .{ stored_register, register }); - // } - // } else { - // gop.value_ptr.* = register; - // } } fn lowerArguments(instruction_selection: *InstructionSelection, mir: *MIR, ir_function: *ir.Function) !void { @@ -1478,20 +1443,24 @@ const Instruction = struct { mov64mr, mov32ri, mov32ri64, + mov32rr, movsx64rm32, movsx64rr32, ret, syscall, ud2, + xor32rr, }; pub const Descriptor = struct { operands: []const Operand.Reference = &.{}, - opcode: u16 = 0, + opcode: u16, format: Format = .pseudo, - flags: Flags, + flags: Flags = .{}, + const Flags = packed struct { - implicit_def: bool, + implicit_def: bool = false, + two_byte_prefix: bool = false, }; const Format = enum { @@ -1501,6 +1470,7 @@ const Instruction = struct { mrm_dest_mem, mrm_source_mem, mrm_source_reg, + mrm_dest_reg, }; }; @@ -1738,7 +1708,7 @@ pub const Operand = struct { }; const PCRelative = union(enum) { - function_declaration: ir.Function.Declaration.Index, + function_declaration: MIR.Function.Index, string_literal: ir.StringLiteral.Index, imm32: i32, imm8: i8, @@ -1794,18 +1764,17 @@ const register_class_operand_matcher = std.EnumArray(Operand.Id, Register.Class) const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descriptor).init(.{ .call64pcrel32 = .{ .format = .no_operands, + .opcode = 0xe8, .operands = &.{ .{ .id = .i64i32imm_brtarget, .kind = .src, }, }, - .flags = .{ - .implicit_def = false, - }, }, .copy = .{ .format = .pseudo, + .opcode = 0, .operands = &.{ .{ .id = .unknown, @@ -1816,12 +1785,10 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri .kind = .src, }, }, - .flags = .{ - .implicit_def = false, - }, }, .lea64r = .{ .format = .mrm_source_mem, + .opcode = 0x8d, .operands = &.{ .{ .id = .gp64, @@ -1832,24 +1799,20 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri .kind = .src, }, }, - .flags = .{ - .implicit_def = false, - }, }, .mov32r0 = .{ .format = .pseudo, + .opcode = 0, .operands = &.{ .{ .id = .gp32, .kind = .dst, }, }, - .flags = .{ - .implicit_def = false, - }, }, .mov32rm = .{ .format = .mrm_source_mem, + .opcode = 0x8b, .operands = &.{ .{ .id = .gp32, @@ -1860,12 +1823,10 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri .kind = .src, }, }, - .flags = .{ - .implicit_def = false, - }, }, .mov64rm = .{ .format = .mrm_source_mem, + .opcode = 0x8b, .operands = &.{ .{ .id = .gp64, @@ -1876,12 +1837,24 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri .kind = .src, }, }, - .flags = .{ - .implicit_def = false, + }, + .mov32rr = .{ + .format = .mrm_dest_reg, + .opcode = 0x89, + .operands = &.{ + .{ + .id = .gp32, + .kind = .dst, + }, + .{ + .id = .gp32, + .kind = .src, + }, }, }, .mov32mr = .{ .format = .mrm_dest_mem, + .opcode = 0x89, .operands = &.{ .{ .id = .i32mem, @@ -1892,12 +1865,10 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri .kind = .src, }, }, - .flags = .{ - .implicit_def = false, - }, }, .mov64mr = .{ .format = .mrm_dest_mem, + .opcode = 0x89, .operands = &.{ .{ .id = .i64mem, @@ -1908,12 +1879,10 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri .kind = .src, }, }, - .flags = .{ - .implicit_def = false, - }, }, .mov32ri = .{ .format = .add_reg, + .opcode = 0xb8, .operands = &.{ .{ .id = .gp32, @@ -1924,12 +1893,10 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri .kind = .src, }, }, - .flags = .{ - .implicit_def = false, - }, }, .mov32ri64 = .{ .format = .pseudo, + .opcode = 0, .operands = &.{ .{ .id = .gp64, @@ -1940,12 +1907,10 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri .kind = .src, }, }, - .flags = .{ - .implicit_def = false, - }, }, .movsx64rm32 = .{ - .format = .mrm_source_reg, + .format = .mrm_source_mem, + .opcode = 0x63, .operands = &.{ .{ .id = .gp64, @@ -1956,12 +1921,10 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri .kind = .src, }, }, - .flags = .{ - .implicit_def = false, - }, }, .movsx64rr32 = .{ .format = .mrm_source_reg, + .opcode = 0x63, .operands = &.{ .{ .id = .gp64, @@ -1972,34 +1935,45 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri .kind = .src, }, }, - .flags = .{ - .implicit_def = false, - }, }, .ret = .{ .format = .no_operands, + .opcode = 0xc3, .operands = &.{ .{ .id = .unknown, .kind = .src, }, }, - .flags = .{ - .implicit_def = false, - }, }, .syscall = .{ .format = .no_operands, + .opcode = 0x05, .operands = &.{}, .flags = .{ - .implicit_def = false, + .two_byte_prefix = true, }, }, .ud2 = .{ .format = .no_operands, + .opcode = 0x0b, .operands = &.{}, .flags = .{ - .implicit_def = false, + .two_byte_prefix = true, + }, + }, + .xor32rr = .{ + .format = .mrm_dest_reg, + .opcode = 0x31, + .operands = &.{ + .{ + .id = .gp32, + .kind = .dst, + }, + .{ + .id = .gp32, + .kind = .src, + }, }, }, }); @@ -2052,6 +2026,8 @@ pub const MIR = struct { operands: BlockList(Operand) = .{}, instruction_selections: ArrayList(InstructionSelection) = .{}, virtual_registers: BlockList(Register.Virtual) = .{}, + function_declaration_map: std.AutoHashMapUnmanaged(ir.Function.Declaration.Index, Function.Index) = .{}, + entry_point: u32 = 0, pub fn selectInstructions(allocator: Allocator, intermediate: *ir.Result, target: std.Target) !*MIR { logln(.codegen, .instruction_selection_block, "\n[INSTRUCTION SELECTION]\n", .{}); @@ -2066,15 +2042,16 @@ pub const MIR = struct { try mir.functions.ensureCapacity(allocator, intermediate.function_definitions.len); try mir.instruction_selections.ensureUnusedCapacity(allocator, intermediate.function_definitions.len); - var function_definition_iterator = intermediate.function_definitions.iterator(); + var ir_function_definition_iterator = intermediate.function_definitions.iterator(); + try mir.function_declaration_map.ensureTotalCapacity(mir.allocator, @intCast(intermediate.function_definitions.len)); - while (function_definition_iterator.nextPointer()) |ir_function| { + while (ir_function_definition_iterator.nextPointer()) |ir_function| { const fn_name = mir.ir.getFunctionName(ir_function.declaration); - logln(.codegen, .instruction_selection_ir_function, "Selecting instructions for {}", .{ir_function}); const instruction_selection = mir.instruction_selections.addOneAssumeCapacity(); const function_allocation = try mir.functions.addOne(mir.allocator); const function = function_allocation.ptr; + mir.function_declaration_map.putAssumeCapacityNoClobber(ir_function.declaration, function_allocation.index); function.* = .{ .mir = mir, .instruction_selection = instruction_selection, @@ -2083,12 +2060,29 @@ pub const MIR = struct { instruction_selection.* = .{ .function = function, }; + } + + var function_iterator = mir.functions.iterator(); + ir_function_definition_iterator = intermediate.function_definitions.iterator(); + + var entry_point: ?u32 = null; + var ir_function_index = ir_function_definition_iterator.getCurrentIndex(); + while (ir_function_definition_iterator.nextPointer()) |ir_function| { + const function_index = function_iterator.getCurrentIndex(); + const function = function_iterator.nextPointer() orelse unreachable; + logln(.codegen, .instruction_selection_ir_function, "Selecting instructions for {}", .{ir_function}); + const instruction_selection = function.instruction_selection; + + if (ir_function_index.eq(intermediate.entry_point)) { + entry_point = function_index.uniqueInteger(); + } const ir_function_declaration = mir.ir.function_declarations.get(ir_function.declaration); const calling_convention = calling_conventions.get(ir_function_declaration.calling_convention); try instruction_selection.block_map.ensureUnusedCapacity(allocator, @intCast(ir_function.blocks.items.len)); try function.blocks.ensureTotalCapacity(allocator, ir_function.blocks.items.len); + for (ir_function.blocks.items) |block| { const block_allocation = try mir.blocks.append(allocator, .{}); instruction_selection.block_map.putAssumeCapacity(block, block_allocation.index); @@ -2521,7 +2515,7 @@ pub const MIR = struct { .id = .i64i32imm_brtarget, .u = .{ .pc_relative = .{ - .function_declaration = ir_call.function, + .function_declaration = mir.function_declaration_map.get(ir_call.function).?, }, }, .flags = .{}, @@ -2605,8 +2599,12 @@ pub const MIR = struct { try instruction_selection.emitLiveInCopies(mir, function.blocks.items[0]); logln(.codegen, .instruction_selection_ir_function, "Selected instructions for {}", .{function}); + + ir_function_index = ir_function_definition_iterator.getCurrentIndex(); } + mir.entry_point = entry_point orelse unreachable; + return mir; } @@ -3666,10 +3664,337 @@ pub const MIR = struct { unreachable; } - pub fn encode(mir: *MIR) !emit.Result { - _ = mir; - // unreachable; - return undefined; + fn getGP32Encoding(operand: Operand) Encoding.GP32 { + assert(operand.id == .gp32); + const physical_register = operand.u.register.index.physical; + const gp_register_encoding: Encoding.GP32 = switch (physical_register) { + .eax => .a, + .edi => .di, + else => |t| @panic(@tagName(t)), + }; + + return gp_register_encoding; + } + + fn getGP64Encoding(operand: Operand) Encoding.GP64 { + assert(operand.id == .gp64); + const physical_register = operand.u.register.index.physical; + const gp_register_encoding: Encoding.GP64 = switch (physical_register) { + .rax => .a, + .rdi => .di, + else => |t| @panic(@tagName(t)), + }; + + return gp_register_encoding; + } + + pub fn encode(mir: *MIR) !*emit.Result { + const image = try mir.allocator.create(emit.Result); + image.* = try emit.Result.create(mir.allocator, mir.target, mir.entry_point); + + var function_iterator = mir.functions.iterator(); + + var function_offsets = std.AutoArrayHashMapUnmanaged(Function.Index, u32){}; + try function_offsets.ensureTotalCapacity(mir.allocator, mir.functions.len); + try image.sections.items[0].symbol_table.ensureTotalCapacity(mir.allocator, mir.functions.len); + + while (function_iterator.nextPointer()) |function| { + const function_index = mir.functions.indexOf(function); + logln(.codegen, .encoding, "\n{s}:", .{function.name}); + + const function_offset: u32 = @intCast(image.getTextSection().index); + + function_offsets.putAssumeCapacityNoClobber(function_index, function_offset); + image.sections.items[0].symbol_table.putAssumeCapacityNoClobber(function.name, function_offset); + + const stack_size = blk: { + var result: u32 = 0; + + for (function.instruction_selection.stack_objects.items) |stack_object| { + assert(std.mem.isAligned(result, stack_object.alignment)); + result += @intCast(stack_object.size); + } + + break :blk result; + }; + + if (stack_size != 0) { + image.appendCodeByte(0x55); // push rbp + image.appendCode(&.{ 0x48, 0x89, 0xe5 }); // mov rbp, rsp + + // sub rsp, stack_offset + if (std.math.cast(u8, stack_size)) |stack_size_u8| { + image.appendCode(&.{ 0x48, 0x83, 0xec, stack_size_u8 }); + } else { + unreachable; + } + } + + for (function.blocks.items) |block_index| { + const block = mir.blocks.get(block_index); + for (block.instructions.items) |instruction_index| { + const instruction = mir.instructions.get(instruction_index); + + const instruction_offset = image.getTextSection().index; + + switch (instruction.id) { + .mov32r0 => { + assert(instruction.operands.items.len == 1); + const operand = mir.operands.get(instruction.operands.items[0]); + const gp_register_encoding = getGP32Encoding(operand.*); + const new_instruction_id = Instruction.Id.xor32rr; + const instruction_descriptor = instruction_descriptors.get(new_instruction_id); + const opcode: u8 = @intCast(instruction_descriptor.opcode); + image.appendCodeByte(opcode); + const direct = true; + const modrm = ModRm{ + .rm = @intCast(@intFromEnum(gp_register_encoding)), + .reg = @intCast(@intFromEnum(gp_register_encoding)), + .mod = @as(u2, @intFromBool(direct)) << 1 | @intFromBool(direct), + }; + image.appendCodeByte(@bitCast(modrm)); + }, + .ret => {}, + .mov32mr => { + assert(instruction.operands.items.len == 2); + const source_operand = mir.operands.get(instruction.operands.items[1]); + const source_gp32 = getGP32Encoding(source_operand.*); + + const destination_operand = mir.operands.get(instruction.operands.items[0]); + assert(destination_operand.u == .memory); + const memory = destination_operand.u.memory; + const instruction_descriptor = instruction_descriptors.get(instruction.id); + const opcode: u8 = @intCast(instruction_descriptor.opcode); + image.appendCodeByte(opcode); + + const modrm = ModRm{ + .rm = @intFromEnum(Encoding.GP32.bp), + .reg = @intCast(@intFromEnum(source_gp32)), + .mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true), + }; + image.appendCodeByte(@bitCast(modrm)); + + switch (memory.addressing_mode.base) { + .frame_index => |frame_index| { + const stack_offset = blk: { + var computed_stack_offset: usize = 0; + for (function.instruction_selection.stack_objects.items[0 .. frame_index + 1]) |stack_object| { + assert(std.mem.isAligned(computed_stack_offset, stack_object.alignment)); + computed_stack_offset += stack_object.size; + } + + break :blk -@as(i64, @intCast(computed_stack_offset)); + }; + const displacement_bytes: u3 = if (std.math.cast(i8, stack_offset)) |_| @sizeOf(i8) else if (std.math.cast(i32, stack_offset)) |_| @sizeOf(i32) else unreachable; + + const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes]; + image.appendCode(stack_bytes); + }, + else => |t| @panic(@tagName(t)), + } + }, + .mov32rm => { + assert(instruction.operands.items.len == 2); + + const instruction_descriptor = instruction_descriptors.get(instruction.id); + const opcode: u8 = @intCast(instruction_descriptor.opcode); + image.appendCodeByte(opcode); + + const destination_operand = mir.operands.get(instruction.operands.items[0]); + const destination_gp32 = getGP32Encoding(destination_operand.*); + + const source_operand = mir.operands.get(instruction.operands.items[1]); + assert(source_operand.u == .memory); + const source_memory = source_operand.u.memory; + + const modrm = ModRm{ + .rm = @intFromEnum(Encoding.GP32.bp), + .reg = @intCast(@intFromEnum(destination_gp32)), + .mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true), + }; + image.appendCodeByte(@bitCast(modrm)); + + switch (source_memory.addressing_mode.base) { + .frame_index => |frame_index| { + const stack_offset = blk: { + var computed_stack_offset: usize = 0; + for (function.instruction_selection.stack_objects.items[0 .. frame_index + 1]) |stack_object| { + assert(std.mem.isAligned(computed_stack_offset, stack_object.alignment)); + computed_stack_offset += stack_object.size; + } + + break :blk -@as(i64, @intCast(computed_stack_offset)); + }; + const displacement_bytes: u3 = if (std.math.cast(i8, stack_offset)) |_| @sizeOf(i8) else if (std.math.cast(i32, stack_offset)) |_| @sizeOf(i32) else unreachable; + + const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes]; + image.appendCode(stack_bytes); + }, + else => |t| @panic(@tagName(t)), + } + }, + .mov32ri64 => { + assert(instruction.operands.items.len == 2); + const source_operand = mir.operands.get(instruction.operands.items[1]); + const source_immediate: u32 = @intCast(source_operand.u.immediate); + + const destination_operand = mir.operands.get(instruction.operands.items[0]); + const destination_gp64 = getGP64Encoding(destination_operand.*); + const destination_gp32 = switch (destination_gp64) { + inline else => |gp64| @field(Encoding.GP32, @tagName(gp64)), + }; + + const opcode = @as(u8, 0xb8) | @as(u3, @intCast(@intFromEnum(destination_gp32))); + image.appendCodeByte(opcode); + + image.appendCode(std.mem.asBytes(&source_immediate)); + }, + .movsx64rm32 => { + assert(instruction.operands.items.len == 2); + + const destination_operand = mir.operands.get(instruction.operands.items[0]); + const destination_register = getGP64Encoding(destination_operand.*); + + const source_operand = mir.operands.get(instruction.operands.items[1]); + const source_memory = source_operand.u.memory; + + const rex = Rex{ + .b = false, + .x = false, + .r = false, + .w = true, + }; + image.appendCodeByte(@bitCast(rex)); + + const instruction_descriptor = instruction_descriptors.get(instruction.id); + const opcode: u8 = @intCast(instruction_descriptor.opcode); + image.appendCodeByte(opcode); + + const modrm = ModRm{ + .rm = @intFromEnum(Encoding.GP32.bp), + .reg = @intCast(@intFromEnum(destination_register)), + .mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true), + }; + image.appendCodeByte(@bitCast(modrm)); + + switch (source_memory.addressing_mode.base) { + .frame_index => |frame_index| { + const stack_offset = blk: { + var computed_stack_offset: usize = 0; + for (function.instruction_selection.stack_objects.items[0 .. frame_index + 1]) |stack_object| { + assert(std.mem.isAligned(computed_stack_offset, stack_object.alignment)); + computed_stack_offset += stack_object.size; + } + + break :blk -@as(i64, @intCast(computed_stack_offset)); + }; + const displacement_bytes: u3 = if (std.math.cast(i8, stack_offset)) |_| @sizeOf(i8) else if (std.math.cast(i32, stack_offset)) |_| @sizeOf(i32) else unreachable; + + const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes]; + image.appendCode(stack_bytes); + }, + else => |t| @panic(@tagName(t)), + } + }, + .syscall => image.appendCode(&.{ 0x0f, 0x05 }), + .ud2 => image.appendCode(&.{ 0x0f, 0x0b }), + .call64pcrel32 => { + // TODO: emit relocation + assert(instruction.operands.items.len == 1); + const operand = mir.operands.get(instruction.operands.items[0]); + const instruction_descriptor = instruction_descriptors.get(instruction.id); + const opcode: u8 = @intCast(instruction_descriptor.opcode); + image.appendCodeByte(opcode); + + switch (operand.u) { + .pc_relative => |pc_relative| { + // TODO: fix + const callee = pc_relative.function_declaration; + const caller = function_index; + + const instruction_len = 5; + + if (callee.uniqueInteger() <= caller.uniqueInteger()) { + const callee_offset: i64 = @intCast(function_offsets.get(callee).?); + const caller_offset: i64 = @intCast(instruction_offset + instruction_len); + const offset: i32 = @intCast(callee_offset - caller_offset); + image.appendCode(std.mem.asBytes(&offset)); + } else { + image.appendCode(&.{ 0, 0, 0, 0 }); + unreachable; + } + }, + else => |t| @panic(@tagName(t)), + } + }, + .copy => { + assert(instruction.operands.items.len == 2); + const destination_operand = mir.operands.get(instruction.operands.items[0]); + const source_operand = mir.operands.get(instruction.operands.items[1]); + assert(destination_operand.id == source_operand.id); + + // const destination_physical_register = destination_operand.u.register.index.physical; + // _ = destination_physical_register; + // const source_physical_register = source_operand.u.register.index.physical; + switch (destination_operand.id) { + .gp32 => { + image.appendCodeByte(0x89); + + const destination_register = getGP32Encoding(destination_operand.*); + const source_register = getGP32Encoding(source_operand.*); + const modrm = ModRm{ + .rm = @intCast(@intFromEnum(destination_register)), + .reg = @intCast(@intFromEnum(source_register)), + .mod = @as(u2, @intFromBool(true)) << 1 | @intFromBool(true), + }; + image.appendCodeByte(@bitCast(modrm)); + }, + else => |t| @panic(@tagName(t)), + } + }, + else => |t| @panic(@tagName(t)), + } + + if (instruction_offset != image.getTextSection().index) { + const print_tags = true; + if (print_tags) { + var offset = @tagName(instruction.id).len + 2; + log(.codegen, .encoding, "{s}: ", .{@tagName(instruction.id)}); + const margin = 16; + while (offset < margin) : (offset += 1) { + log(.codegen, .encoding, " ", .{}); + } + } + for (image.getTextSection().content[instruction_offset..image.getTextSection().index]) |byte| { + log(.codegen, .encoding, "0x{x:0>2} ", .{byte}); + } + log(.codegen, .encoding, "\n", .{}); + } + } + } + + const last_block_index = function.blocks.items[function.blocks.items.len - 1]; + const last_block = mir.blocks.get(last_block_index); + const last_block_last_instruction_index = last_block.instructions.items[last_block.instructions.items.len - 1]; + const last_block_last_instruction = mir.instructions.get(last_block_last_instruction_index); + + if (last_block_last_instruction.id == .ret) { + if (stack_size != 0) { + // add rsp, stack_offset + if (std.math.cast(u8, stack_size)) |stack_size_u8| { + image.appendCode(&.{ 0x48, 0x83, 0xc4, stack_size_u8 }); + } else { + unreachable; + } + + image.appendCodeByte(0x5d); // pop rbp + } + + image.appendCodeByte(0xc3); + } + } + + return image; } fn getRegisterListHead(mir: *MIR, instruction_selection: *InstructionSelection, register: Register) *Operand.Index { @@ -3691,6 +4016,10 @@ pub const MIR = struct { mir: *MIR, name: []const u8, + pub const List = BlockList(@This()); + pub const Index = List.Index; + pub const Allocation = List.Allocation; + pub fn format(function: *const Function, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { const function_name = function.name; try writer.print("{s}:\n", .{function_name}); @@ -3820,39 +4149,50 @@ pub const MIR = struct { } }; -// const ModRm = packed struct(u8) { -// rm: u3, -// reg: u3, -// mod: u2, -// }; +const ModRm = packed struct(u8) { + rm: u3, + reg: u3, + mod: u2, +}; -// const Rex = packed struct(u8) { -// b: bool, -// x: bool, -// r: bool, -// w: bool, -// fixed: u4 = 0b0100, -// -// fn create(args: struct { -// rm: ?GPRegister = null, -// reg: ?GPRegister = null, -// sib: bool = false, -// rm_size: ?Size = null, -// }) ?Rex { -// const rex_byte = Rex{ -// .b = if (args.rm) |rm| @intFromEnum(rm) > std.math.maxInt(u3) else false, -// .x = args.sib, -// .r = if (args.reg) |reg| @intFromEnum(reg) > std.math.maxInt(u3) else false, -// .w = if (args.rm_size) |rm_size| rm_size == .eight else false, -// }; -// -// if (@as(u4, @truncate(@as(u8, @bitCast(rex_byte)))) != 0) { -// return rex_byte; -// } else { -// return null; -// } -// } -// }; +const Rex = packed struct(u8) { + b: bool, + x: bool, + r: bool, + w: bool, + fixed: u4 = 0b0100, + + // fn create32RR(args: struct { + // rm: Encoding.GP32, + // reg: Encoding.GP32, + // sib: bool = false, + // }) ?Rex { + // if (args.sib) { + // unreachable; + // } else { + // } + // } + + // fn create(args: struct { + // rm: ?GPRegister = null, + // reg: ?GPRegister = null, + // sib: bool = false, + // rm_size: ?Size = null, + // }) ?Rex { + // const rex_byte = Rex{ + // .b = if (args.rm) |rm| @intFromEnum(rm) > std.math.maxInt(u3) else false, + // .x = args.sib, + // .r = if (args.reg) |reg| @intFromEnum(reg) > std.math.maxInt(u3) else false, + // .w = if (args.rm_size) |rm_size| rm_size == .eight else false, + // }; + // + // if (@as(u4, @truncate(@as(u8, @bitCast(rex_byte)))) != 0) { + // return rex_byte; + // } else { + // return null; + // } + // } +}; fn getIrType(intermediate: *ir.Result, ir_instruction_index: ir.Instruction.Index) ir.Type { const ir_instruction = intermediate.instructions.get(ir_instruction_index); @@ -3903,6 +4243,45 @@ fn getSubregistersRecursive(allocator: Allocator, set: *RegisterSet, reg: Regist } } +const Encoding = struct { + const GP32 = enum(u4) { + a = 0, + c = 1, + d = 2, + b = 3, + sp = 4, + bp = 5, + si = 6, + di = 7, + r8 = 8, + r9 = 9, + r10 = 10, + r11 = 11, + r12 = 12, + r13 = 13, + r14 = 14, + r15 = 15, + }; + const GP64 = enum(u4) { + a = 0, + c = 1, + d = 2, + b = 3, + sp = 4, + bp = 5, + si = 6, + di = 7, + r8 = 8, + r9 = 9, + r10 = 10, + r11 = 11, + r12 = 12, + r13 = 13, + r14 = 14, + r15 = 15, + }; +}; + const LiveRegister = struct { last_use: Instruction.Index = Instruction.Index.invalid, virtual: Register.Virtual.Index, diff --git a/src/frontend/semantic_analyzer.zig b/src/frontend/semantic_analyzer.zig index 415fc4f..82ed488 100644 --- a/src/frontend/semantic_analyzer.zig +++ b/src/frontend/semantic_analyzer.zig @@ -1492,7 +1492,7 @@ pub fn initialize(compilation: *Compilation, module: *Module, package: *Package, if (equal(u8, declaration_name, "_start")) { const value = module.values.get(decl.init_value); module.entry_point = switch (value.*) { - .function => |function_index| function_index.uniqueInteger(), + .function => |function_index| function_index, .unresolved => panic("Unresolved declaration: {s}\n", .{declaration_name}), else => |t| @panic(@tagName(t)), };