add encoding and elf linking
This commit is contained in:
parent
30baa0b53d
commit
22243d296c
@ -695,7 +695,7 @@ pub const Module = struct {
|
|||||||
casts: BlockList(Cast) = .{},
|
casts: BlockList(Cast) = .{},
|
||||||
string_literal_types: data_structures.AutoArrayHashMap(u32, Type.Index) = .{},
|
string_literal_types: data_structures.AutoArrayHashMap(u32, Type.Index) = .{},
|
||||||
array_types: data_structures.AutoArrayHashMap(Array, 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 {
|
pub const Descriptor = struct {
|
||||||
main_package_path: []const u8,
|
main_package_path: []const u8,
|
||||||
|
@ -7,58 +7,96 @@ const Allocator = data_structures.Allocator;
|
|||||||
const ArrayList = data_structures.ArrayList;
|
const ArrayList = data_structures.ArrayList;
|
||||||
|
|
||||||
const emit = @import("emit.zig");
|
const emit = @import("emit.zig");
|
||||||
|
const page_size = 0x1000;
|
||||||
|
|
||||||
pub const Writer = struct {
|
pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, page_size) {
|
||||||
bytes: ArrayList(u8),
|
var file = try std.ArrayListAlignedUnmanaged(u8, 0x1000).initCapacity(image.allocator, 0x100000);
|
||||||
allocator: Allocator,
|
_ = 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 {
|
const symbol_table_index = try image.addSection(.{
|
||||||
return .{
|
.name = ".symtab",
|
||||||
.bytes = try ArrayList(u8).initCapacity(allocator, 0x10000),
|
.size = page_size,
|
||||||
.allocator = allocator,
|
.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 {
|
image.writeToSection(0, std.mem.asBytes(&Header{
|
||||||
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{
|
|
||||||
.endianness = .little,
|
.endianness = .little,
|
||||||
.machine = switch (image.target.cpu.arch) {
|
.machine = switch (image.target.cpu.arch) {
|
||||||
.x86_64 => .AMD64,
|
.x86_64 => .AMD64,
|
||||||
@ -68,79 +106,134 @@ pub const Writer = struct {
|
|||||||
.linux => .systemv,
|
.linux => .systemv,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
.entry = base_address + section_offsets[0] + image.entry_point,
|
.entry = 0,
|
||||||
.section_header_offset = program_end_offset,
|
.section_header_offset = 0,
|
||||||
.program_header_count = program_header_count,
|
.program_header_count = @intCast(program_header_count),
|
||||||
.section_header_count = section_count,
|
.section_header_count = @intCast(image.sections.items.len),
|
||||||
.name_section_header_index = 0,
|
.section_header_string_table_index = @intCast(section_header_string_table_index),
|
||||||
};
|
}));
|
||||||
|
|
||||||
var program_header_offset: usize = @sizeOf(Header);
|
for (image.sections.items, 0..) |section, section_index| {
|
||||||
var section_header_offset = program_end_offset;
|
switch (section.type) {
|
||||||
inline for (section_fields, section_offsets) |section_field, section_offset| {
|
.loadable_program => {
|
||||||
const section_name = section_field.name;
|
program_segment_offset = std.mem.alignForward(usize, program_segment_offset, section.alignment);
|
||||||
const section = &@field(image.sections, section_name);
|
const virtual_address = base_virtual_address + program_segment_offset;
|
||||||
if (section.index > 0) {
|
const program_segment_size = switch (section_index) {
|
||||||
const program_header: *ProgramHeader = @ptrCast(@alignCast(writer.bytes.items[program_header_offset..].ptr));
|
0 => @sizeOf(Header) + @sizeOf(ProgramHeader) * program_header_count,
|
||||||
program_header.* = .{
|
else => section.index,
|
||||||
.type = .load,
|
};
|
||||||
.flags = .{
|
image.writeToSection(0, std.mem.asBytes(&ProgramHeader{
|
||||||
.executable = equal(u8, section_name, "text"),
|
.type = .load,
|
||||||
.writable = equal(u8, section_name, "data"),
|
.flags = ProgramHeader.Flags{
|
||||||
.readable = true,
|
.executable = section.flags.execute,
|
||||||
},
|
.writable = section.flags.write,
|
||||||
.offset = 0,
|
.readable = section.flags.read,
|
||||||
.virtual_address = base_address,
|
},
|
||||||
.physical_address = base_address,
|
.offset = program_segment_offset,
|
||||||
.size_in_file = section.index,
|
.virtual_address = virtual_address,
|
||||||
.size_in_memory = section.index,
|
.physical_address = virtual_address,
|
||||||
.alignment = 0,
|
.size_in_file = program_segment_size,
|
||||||
};
|
.size_in_memory = program_segment_size,
|
||||||
|
.alignment = section.alignment,
|
||||||
|
}));
|
||||||
|
|
||||||
const source = section.content[0..section.index];
|
program_segment_offset += program_segment_size;
|
||||||
const destination = writer.bytes.items[section_offset..][0..source.len];
|
},
|
||||||
@memcpy(destination, source);
|
.null,
|
||||||
|
.string_table,
|
||||||
const section_header: *SectionHeader = @ptrCast(@alignCast(writer.bytes.items[section_header_offset..].ptr));
|
.symbol_table,
|
||||||
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,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeToFile(writer: *const Writer, file_path: []const u8) !void {
|
{
|
||||||
std.debug.print("Writing file to {s}\n", .{file_path});
|
var section_offset: usize = 0;
|
||||||
const flags = switch (@import("builtin").os.tag) {
|
var section_headers = try ArrayList(SectionHeader).initCapacity(image.allocator, image.sections.items.len);
|
||||||
.windows => .{},
|
var section_name_offset: u32 = 0;
|
||||||
else => .{
|
|
||||||
.mode = 0o777,
|
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);
|
const header: *Header = @ptrCast(file.items.ptr);
|
||||||
file_descriptor.close();
|
header.section_header_offset = section_header_offset;
|
||||||
|
header.entry = _start_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeToFileAbsolute(writer: *const Writer, absolute_file_path: []const u8) !void {
|
return file;
|
||||||
const file = try std.fs.createFileAbsolute(absolute_file_path, .{});
|
}
|
||||||
defer file.close();
|
|
||||||
try file.writeAll(writer.bytes.items);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Header = extern struct {
|
const Header = extern struct {
|
||||||
magic: u8 = 0x7f,
|
magic: u8 = 0x7f,
|
||||||
@ -163,7 +256,7 @@ const Header = extern struct {
|
|||||||
program_header_count: u16 = 1,
|
program_header_count: u16 = 1,
|
||||||
section_header_size: u16 = @sizeOf(SectionHeader),
|
section_header_size: u16 = @sizeOf(SectionHeader),
|
||||||
section_header_count: u16,
|
section_header_count: u16,
|
||||||
name_section_header_index: u16,
|
section_header_string_table_index: u16,
|
||||||
|
|
||||||
const BitCount = enum(u8) {
|
const BitCount = enum(u8) {
|
||||||
@"32" = 1,
|
@"32" = 1,
|
||||||
@ -197,14 +290,14 @@ const Header = extern struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ProgramHeader = extern struct {
|
const ProgramHeader = extern struct {
|
||||||
type: Type = .load,
|
type: Type,
|
||||||
flags: Flags,
|
flags: Flags,
|
||||||
offset: u64,
|
offset: u64,
|
||||||
virtual_address: u64,
|
virtual_address: u64,
|
||||||
physical_address: u64,
|
physical_address: u64,
|
||||||
size_in_file: u64,
|
size_in_file: u64,
|
||||||
size_in_memory: u64,
|
size_in_memory: u64,
|
||||||
alignment: u64 = 0,
|
alignment: u64,
|
||||||
|
|
||||||
const Type = enum(u32) {
|
const Type = enum(u32) {
|
||||||
null = 0,
|
null = 0,
|
||||||
@ -232,8 +325,8 @@ const SectionHeader = extern struct {
|
|||||||
name_offset: u32,
|
name_offset: u32,
|
||||||
type: Type,
|
type: Type,
|
||||||
flags: Flags,
|
flags: Flags,
|
||||||
address: u64,
|
virtual_address: u64,
|
||||||
offset: u64,
|
file_offset: u64,
|
||||||
size: u64,
|
size: u64,
|
||||||
// section index
|
// section index
|
||||||
link: u32,
|
link: u32,
|
||||||
@ -279,3 +372,14 @@ const SectionHeader = extern struct {
|
|||||||
_reserved: u53 = 0,
|
_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,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
@ -24,38 +24,130 @@ const jit_callconv = .SysV;
|
|||||||
const Section = struct {
|
const Section = struct {
|
||||||
content: []align(page_size) u8,
|
content: []align(page_size) u8,
|
||||||
index: usize = 0,
|
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 {
|
pub const Result = struct {
|
||||||
sections: struct {
|
sections: ArrayList(Section) = .{},
|
||||||
text: Section,
|
// sections: struct {
|
||||||
rodata: Section,
|
// text: Section,
|
||||||
data: Section,
|
// rodata: Section,
|
||||||
},
|
// data: Section,
|
||||||
entry_point: u32 = 0,
|
// },
|
||||||
|
entry_point: u32,
|
||||||
target: std.Target,
|
target: std.Target,
|
||||||
|
allocator: Allocator,
|
||||||
|
|
||||||
pub fn create(target: std.Target) !Result {
|
const text_section_index = 0;
|
||||||
return Result{
|
|
||||||
.sections = .{
|
pub fn create(allocator: Allocator, target: std.Target, entry_point_index: u32) !Result {
|
||||||
.text = .{ .content = try mmap(page_size, .{ .executable = true }) },
|
var result = Result{
|
||||||
.rodata = .{ .content = try mmap(page_size, .{ .executable = false }) },
|
// .sections = .{
|
||||||
.data = .{ .content = try mmap(page_size, .{ .executable = false }) },
|
// .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,
|
.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 {
|
pub fn appendCode(image: *Result, code: []const u8) void {
|
||||||
const destination = image.sections.text.content[image.sections.text.index..][0..code.len];
|
image.writeToSection(text_section_index, code);
|
||||||
@memcpy(destination, code);
|
|
||||||
image.sections.text.index += code.len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn appendCodeByte(image: *Result, code_byte: u8) void {
|
pub fn appendCodeByte(image: *Result, code_byte: u8) void {
|
||||||
image.sections.text.content[image.sections.text.index] = code_byte;
|
image.writeByteToSection(text_section_index, code_byte);
|
||||||
image.sections.text.index += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getEntryPoint(image: *const Result, comptime FunctionType: type) *const FunctionType {
|
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]));
|
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 {
|
fn writeElf(image: *Result, executable_relative_path: []const u8) !void {
|
||||||
var writer = try elf.Writer.init(allocator);
|
const file_in_memory = try elf.writeToMemory(image);
|
||||||
try writer.writeToMemory(image);
|
try writeFile(file_in_memory.items, executable_relative_path);
|
||||||
try writer.writeToFile(executable_relative_path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn writePe(image: *const Result, allocator: Allocator, executable_relative_path: []const u8) !void {
|
fn writeFile(bytes: []const u8, path: []const u8) !void {
|
||||||
var writer = try pe.Writer.init(allocator);
|
const flags = switch (@import("builtin").os.tag) {
|
||||||
try writer.writeToMemory(image);
|
.windows => .{},
|
||||||
try writer.writeToFile(executable_relative_path);
|
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);
|
var mir = try backend.MIR.selectInstructions(allocator, intermediate, descriptor.target);
|
||||||
try mir.allocateRegisters();
|
try mir.allocateRegisters();
|
||||||
const os = descriptor.target.os.tag;
|
const os = descriptor.target.os.tag;
|
||||||
_ = os;
|
|
||||||
const image = try mir.encode();
|
const image = try mir.encode();
|
||||||
_ = image;
|
|
||||||
|
|
||||||
// switch (os) {
|
switch (os) {
|
||||||
// .linux => try image.writeElf(allocator, descriptor.executable_path),
|
.linux => try image.writeElf(descriptor.executable_path),
|
||||||
// .windows => try image.writePe(allocator, descriptor.executable_path),
|
.windows => try image.writePe(descriptor.executable_path),
|
||||||
// else => unreachable,
|
else => unreachable,
|
||||||
// }
|
}
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
const file = try std.fs.cwd().readFileAlloc(allocator, "main", std.math.maxInt(u64));
|
const file = try std.fs.cwd().readFileAlloc(allocator, "main", std.math.maxInt(u64));
|
||||||
|
@ -42,7 +42,7 @@ pub const Result = struct {
|
|||||||
casts: BlockList(Cast) = .{},
|
casts: BlockList(Cast) = .{},
|
||||||
readonly_data: ArrayList(u8) = .{},
|
readonly_data: ArrayList(u8) = .{},
|
||||||
module: *Module,
|
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 {
|
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)).?).?;
|
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.module = module;
|
||||||
builder.ir.entry_point = module.entry_point orelse unreachable;
|
|
||||||
|
|
||||||
|
var sema_function_index = function_iterator.getCurrentIndex();
|
||||||
while (function_iterator.next()) |sema_function| {
|
while (function_iterator.next()) |sema_function| {
|
||||||
const function_index = try builder.buildFunction(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;
|
return &builder.ir;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,7 +405,7 @@ pub const Builder = struct {
|
|||||||
return builder.ir.function_definitions.get(builder.current_function_index);
|
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 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_allocation = try builder.ir.function_declarations.addOne(builder.allocator);
|
||||||
const function_declaration = function_declaration_allocation.ptr;
|
const function_declaration = function_declaration_allocation.ptr;
|
||||||
@ -425,7 +432,7 @@ pub const Builder = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (sema_prototype.attributes.@"extern") {
|
switch (sema_prototype.attributes.@"extern") {
|
||||||
true => {},
|
true => return Function.Index.invalid,
|
||||||
false => {
|
false => {
|
||||||
const function_allocation = try builder.ir.function_definitions.append(builder.allocator, .{
|
const function_allocation = try builder.ir.function_definitions.append(builder.allocator, .{
|
||||||
.ir = &builder.ir,
|
.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);
|
builder.currentFunction().current_stack_offset = std.mem.alignForward(usize, builder.currentFunction().current_stack_offset, 0x10);
|
||||||
try builder.optimizeFunction(builder.currentFunction());
|
try builder.optimizeFunction(builder.currentFunction());
|
||||||
|
|
||||||
|
return function_allocation.index;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,20 +35,23 @@ pub const Logger = enum {
|
|||||||
register_allocation_instruction_avoid_copy,
|
register_allocation_instruction_avoid_copy,
|
||||||
register_allocation_function_after,
|
register_allocation_function_after,
|
||||||
register_allocation_operand_list_verification,
|
register_allocation_operand_list_verification,
|
||||||
|
encoding,
|
||||||
|
|
||||||
pub var bitset = std.EnumSet(Logger).initMany(&.{
|
pub var bitset = std.EnumSet(Logger).initMany(&.{
|
||||||
.instruction_selection_ir_function,
|
.instruction_selection_ir_function,
|
||||||
|
.instruction_selection_mir_function,
|
||||||
// .instruction_selection_register_operand_list,
|
// .instruction_selection_register_operand_list,
|
||||||
.register_allocation_block,
|
// .register_allocation_block,
|
||||||
// .register_allocation_problematic_hint,
|
// .register_allocation_problematic_hint,
|
||||||
// .register_allocation_assignment,
|
// .register_allocation_assignment,
|
||||||
// .register_allocation_reload,
|
// .register_allocation_reload,
|
||||||
.register_allocation_function_before,
|
// .register_allocation_function_before,
|
||||||
// .register_allocation_new_instruction,
|
// .register_allocation_new_instruction,
|
||||||
// .register_allocation_new_instruction_function_before,
|
// .register_allocation_new_instruction_function_before,
|
||||||
// .register_allocation_instruction_avoid_copy,
|
// .register_allocation_instruction_avoid_copy,
|
||||||
.register_allocation_function_after,
|
.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);
|
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 {
|
fn getAddressingModeFromIr(instruction_selection: *InstructionSelection, mir: *MIR, ir_instruction_index: ir.Instruction.Index) AddressingMode {
|
||||||
@ -1293,17 +1269,6 @@ const InstructionSelection = struct {
|
|||||||
unreachable;
|
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 {
|
fn lowerArguments(instruction_selection: *InstructionSelection, mir: *MIR, ir_function: *ir.Function) !void {
|
||||||
@ -1478,20 +1443,24 @@ const Instruction = struct {
|
|||||||
mov64mr,
|
mov64mr,
|
||||||
mov32ri,
|
mov32ri,
|
||||||
mov32ri64,
|
mov32ri64,
|
||||||
|
mov32rr,
|
||||||
movsx64rm32,
|
movsx64rm32,
|
||||||
movsx64rr32,
|
movsx64rr32,
|
||||||
ret,
|
ret,
|
||||||
syscall,
|
syscall,
|
||||||
ud2,
|
ud2,
|
||||||
|
xor32rr,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Descriptor = struct {
|
pub const Descriptor = struct {
|
||||||
operands: []const Operand.Reference = &.{},
|
operands: []const Operand.Reference = &.{},
|
||||||
opcode: u16 = 0,
|
opcode: u16,
|
||||||
format: Format = .pseudo,
|
format: Format = .pseudo,
|
||||||
flags: Flags,
|
flags: Flags = .{},
|
||||||
|
|
||||||
const Flags = packed struct {
|
const Flags = packed struct {
|
||||||
implicit_def: bool,
|
implicit_def: bool = false,
|
||||||
|
two_byte_prefix: bool = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const Format = enum {
|
const Format = enum {
|
||||||
@ -1501,6 +1470,7 @@ const Instruction = struct {
|
|||||||
mrm_dest_mem,
|
mrm_dest_mem,
|
||||||
mrm_source_mem,
|
mrm_source_mem,
|
||||||
mrm_source_reg,
|
mrm_source_reg,
|
||||||
|
mrm_dest_reg,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1738,7 +1708,7 @@ pub const Operand = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const PCRelative = union(enum) {
|
const PCRelative = union(enum) {
|
||||||
function_declaration: ir.Function.Declaration.Index,
|
function_declaration: MIR.Function.Index,
|
||||||
string_literal: ir.StringLiteral.Index,
|
string_literal: ir.StringLiteral.Index,
|
||||||
imm32: i32,
|
imm32: i32,
|
||||||
imm8: i8,
|
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(.{
|
const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descriptor).init(.{
|
||||||
.call64pcrel32 = .{
|
.call64pcrel32 = .{
|
||||||
.format = .no_operands,
|
.format = .no_operands,
|
||||||
|
.opcode = 0xe8,
|
||||||
.operands = &.{
|
.operands = &.{
|
||||||
.{
|
.{
|
||||||
.id = .i64i32imm_brtarget,
|
.id = .i64i32imm_brtarget,
|
||||||
.kind = .src,
|
.kind = .src,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.flags = .{
|
|
||||||
.implicit_def = false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
.copy = .{
|
.copy = .{
|
||||||
.format = .pseudo,
|
.format = .pseudo,
|
||||||
|
.opcode = 0,
|
||||||
.operands = &.{
|
.operands = &.{
|
||||||
.{
|
.{
|
||||||
.id = .unknown,
|
.id = .unknown,
|
||||||
@ -1816,12 +1785,10 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri
|
|||||||
.kind = .src,
|
.kind = .src,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.flags = .{
|
|
||||||
.implicit_def = false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
.lea64r = .{
|
.lea64r = .{
|
||||||
.format = .mrm_source_mem,
|
.format = .mrm_source_mem,
|
||||||
|
.opcode = 0x8d,
|
||||||
.operands = &.{
|
.operands = &.{
|
||||||
.{
|
.{
|
||||||
.id = .gp64,
|
.id = .gp64,
|
||||||
@ -1832,24 +1799,20 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri
|
|||||||
.kind = .src,
|
.kind = .src,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.flags = .{
|
|
||||||
.implicit_def = false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
.mov32r0 = .{
|
.mov32r0 = .{
|
||||||
.format = .pseudo,
|
.format = .pseudo,
|
||||||
|
.opcode = 0,
|
||||||
.operands = &.{
|
.operands = &.{
|
||||||
.{
|
.{
|
||||||
.id = .gp32,
|
.id = .gp32,
|
||||||
.kind = .dst,
|
.kind = .dst,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.flags = .{
|
|
||||||
.implicit_def = false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
.mov32rm = .{
|
.mov32rm = .{
|
||||||
.format = .mrm_source_mem,
|
.format = .mrm_source_mem,
|
||||||
|
.opcode = 0x8b,
|
||||||
.operands = &.{
|
.operands = &.{
|
||||||
.{
|
.{
|
||||||
.id = .gp32,
|
.id = .gp32,
|
||||||
@ -1860,12 +1823,10 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri
|
|||||||
.kind = .src,
|
.kind = .src,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.flags = .{
|
|
||||||
.implicit_def = false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
.mov64rm = .{
|
.mov64rm = .{
|
||||||
.format = .mrm_source_mem,
|
.format = .mrm_source_mem,
|
||||||
|
.opcode = 0x8b,
|
||||||
.operands = &.{
|
.operands = &.{
|
||||||
.{
|
.{
|
||||||
.id = .gp64,
|
.id = .gp64,
|
||||||
@ -1876,12 +1837,24 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri
|
|||||||
.kind = .src,
|
.kind = .src,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.flags = .{
|
},
|
||||||
.implicit_def = false,
|
.mov32rr = .{
|
||||||
|
.format = .mrm_dest_reg,
|
||||||
|
.opcode = 0x89,
|
||||||
|
.operands = &.{
|
||||||
|
.{
|
||||||
|
.id = .gp32,
|
||||||
|
.kind = .dst,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.id = .gp32,
|
||||||
|
.kind = .src,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.mov32mr = .{
|
.mov32mr = .{
|
||||||
.format = .mrm_dest_mem,
|
.format = .mrm_dest_mem,
|
||||||
|
.opcode = 0x89,
|
||||||
.operands = &.{
|
.operands = &.{
|
||||||
.{
|
.{
|
||||||
.id = .i32mem,
|
.id = .i32mem,
|
||||||
@ -1892,12 +1865,10 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri
|
|||||||
.kind = .src,
|
.kind = .src,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.flags = .{
|
|
||||||
.implicit_def = false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
.mov64mr = .{
|
.mov64mr = .{
|
||||||
.format = .mrm_dest_mem,
|
.format = .mrm_dest_mem,
|
||||||
|
.opcode = 0x89,
|
||||||
.operands = &.{
|
.operands = &.{
|
||||||
.{
|
.{
|
||||||
.id = .i64mem,
|
.id = .i64mem,
|
||||||
@ -1908,12 +1879,10 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri
|
|||||||
.kind = .src,
|
.kind = .src,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.flags = .{
|
|
||||||
.implicit_def = false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
.mov32ri = .{
|
.mov32ri = .{
|
||||||
.format = .add_reg,
|
.format = .add_reg,
|
||||||
|
.opcode = 0xb8,
|
||||||
.operands = &.{
|
.operands = &.{
|
||||||
.{
|
.{
|
||||||
.id = .gp32,
|
.id = .gp32,
|
||||||
@ -1924,12 +1893,10 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri
|
|||||||
.kind = .src,
|
.kind = .src,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.flags = .{
|
|
||||||
.implicit_def = false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
.mov32ri64 = .{
|
.mov32ri64 = .{
|
||||||
.format = .pseudo,
|
.format = .pseudo,
|
||||||
|
.opcode = 0,
|
||||||
.operands = &.{
|
.operands = &.{
|
||||||
.{
|
.{
|
||||||
.id = .gp64,
|
.id = .gp64,
|
||||||
@ -1940,12 +1907,10 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri
|
|||||||
.kind = .src,
|
.kind = .src,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.flags = .{
|
|
||||||
.implicit_def = false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
.movsx64rm32 = .{
|
.movsx64rm32 = .{
|
||||||
.format = .mrm_source_reg,
|
.format = .mrm_source_mem,
|
||||||
|
.opcode = 0x63,
|
||||||
.operands = &.{
|
.operands = &.{
|
||||||
.{
|
.{
|
||||||
.id = .gp64,
|
.id = .gp64,
|
||||||
@ -1956,12 +1921,10 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri
|
|||||||
.kind = .src,
|
.kind = .src,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.flags = .{
|
|
||||||
.implicit_def = false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
.movsx64rr32 = .{
|
.movsx64rr32 = .{
|
||||||
.format = .mrm_source_reg,
|
.format = .mrm_source_reg,
|
||||||
|
.opcode = 0x63,
|
||||||
.operands = &.{
|
.operands = &.{
|
||||||
.{
|
.{
|
||||||
.id = .gp64,
|
.id = .gp64,
|
||||||
@ -1972,34 +1935,45 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri
|
|||||||
.kind = .src,
|
.kind = .src,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.flags = .{
|
|
||||||
.implicit_def = false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
.ret = .{
|
.ret = .{
|
||||||
.format = .no_operands,
|
.format = .no_operands,
|
||||||
|
.opcode = 0xc3,
|
||||||
.operands = &.{
|
.operands = &.{
|
||||||
.{
|
.{
|
||||||
.id = .unknown,
|
.id = .unknown,
|
||||||
.kind = .src,
|
.kind = .src,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.flags = .{
|
|
||||||
.implicit_def = false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
.syscall = .{
|
.syscall = .{
|
||||||
.format = .no_operands,
|
.format = .no_operands,
|
||||||
|
.opcode = 0x05,
|
||||||
.operands = &.{},
|
.operands = &.{},
|
||||||
.flags = .{
|
.flags = .{
|
||||||
.implicit_def = false,
|
.two_byte_prefix = true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.ud2 = .{
|
.ud2 = .{
|
||||||
.format = .no_operands,
|
.format = .no_operands,
|
||||||
|
.opcode = 0x0b,
|
||||||
.operands = &.{},
|
.operands = &.{},
|
||||||
.flags = .{
|
.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) = .{},
|
operands: BlockList(Operand) = .{},
|
||||||
instruction_selections: ArrayList(InstructionSelection) = .{},
|
instruction_selections: ArrayList(InstructionSelection) = .{},
|
||||||
virtual_registers: BlockList(Register.Virtual) = .{},
|
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 {
|
pub fn selectInstructions(allocator: Allocator, intermediate: *ir.Result, target: std.Target) !*MIR {
|
||||||
logln(.codegen, .instruction_selection_block, "\n[INSTRUCTION SELECTION]\n", .{});
|
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.functions.ensureCapacity(allocator, intermediate.function_definitions.len);
|
||||||
try mir.instruction_selections.ensureUnusedCapacity(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);
|
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 instruction_selection = mir.instruction_selections.addOneAssumeCapacity();
|
||||||
const function_allocation = try mir.functions.addOne(mir.allocator);
|
const function_allocation = try mir.functions.addOne(mir.allocator);
|
||||||
const function = function_allocation.ptr;
|
const function = function_allocation.ptr;
|
||||||
|
mir.function_declaration_map.putAssumeCapacityNoClobber(ir_function.declaration, function_allocation.index);
|
||||||
function.* = .{
|
function.* = .{
|
||||||
.mir = mir,
|
.mir = mir,
|
||||||
.instruction_selection = instruction_selection,
|
.instruction_selection = instruction_selection,
|
||||||
@ -2083,12 +2060,29 @@ pub const MIR = struct {
|
|||||||
instruction_selection.* = .{
|
instruction_selection.* = .{
|
||||||
.function = function,
|
.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 ir_function_declaration = mir.ir.function_declarations.get(ir_function.declaration);
|
||||||
const calling_convention = calling_conventions.get(ir_function_declaration.calling_convention);
|
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 instruction_selection.block_map.ensureUnusedCapacity(allocator, @intCast(ir_function.blocks.items.len));
|
||||||
try function.blocks.ensureTotalCapacity(allocator, ir_function.blocks.items.len);
|
try function.blocks.ensureTotalCapacity(allocator, ir_function.blocks.items.len);
|
||||||
|
|
||||||
for (ir_function.blocks.items) |block| {
|
for (ir_function.blocks.items) |block| {
|
||||||
const block_allocation = try mir.blocks.append(allocator, .{});
|
const block_allocation = try mir.blocks.append(allocator, .{});
|
||||||
instruction_selection.block_map.putAssumeCapacity(block, block_allocation.index);
|
instruction_selection.block_map.putAssumeCapacity(block, block_allocation.index);
|
||||||
@ -2521,7 +2515,7 @@ pub const MIR = struct {
|
|||||||
.id = .i64i32imm_brtarget,
|
.id = .i64i32imm_brtarget,
|
||||||
.u = .{
|
.u = .{
|
||||||
.pc_relative = .{
|
.pc_relative = .{
|
||||||
.function_declaration = ir_call.function,
|
.function_declaration = mir.function_declaration_map.get(ir_call.function).?,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.flags = .{},
|
.flags = .{},
|
||||||
@ -2605,8 +2599,12 @@ pub const MIR = struct {
|
|||||||
try instruction_selection.emitLiveInCopies(mir, function.blocks.items[0]);
|
try instruction_selection.emitLiveInCopies(mir, function.blocks.items[0]);
|
||||||
|
|
||||||
logln(.codegen, .instruction_selection_ir_function, "Selected instructions for {}", .{function});
|
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;
|
return mir;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3666,10 +3664,337 @@ pub const MIR = struct {
|
|||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode(mir: *MIR) !emit.Result {
|
fn getGP32Encoding(operand: Operand) Encoding.GP32 {
|
||||||
_ = mir;
|
assert(operand.id == .gp32);
|
||||||
// unreachable;
|
const physical_register = operand.u.register.index.physical;
|
||||||
return undefined;
|
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 {
|
fn getRegisterListHead(mir: *MIR, instruction_selection: *InstructionSelection, register: Register) *Operand.Index {
|
||||||
@ -3691,6 +4016,10 @@ pub const MIR = struct {
|
|||||||
mir: *MIR,
|
mir: *MIR,
|
||||||
name: []const u8,
|
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 {
|
pub fn format(function: *const Function, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
|
||||||
const function_name = function.name;
|
const function_name = function.name;
|
||||||
try writer.print("{s}:\n", .{function_name});
|
try writer.print("{s}:\n", .{function_name});
|
||||||
@ -3820,39 +4149,50 @@ pub const MIR = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// const ModRm = packed struct(u8) {
|
const ModRm = packed struct(u8) {
|
||||||
// rm: u3,
|
rm: u3,
|
||||||
// reg: u3,
|
reg: u3,
|
||||||
// mod: u2,
|
mod: u2,
|
||||||
// };
|
};
|
||||||
|
|
||||||
// const Rex = packed struct(u8) {
|
const Rex = packed struct(u8) {
|
||||||
// b: bool,
|
b: bool,
|
||||||
// x: bool,
|
x: bool,
|
||||||
// r: bool,
|
r: bool,
|
||||||
// w: bool,
|
w: bool,
|
||||||
// fixed: u4 = 0b0100,
|
fixed: u4 = 0b0100,
|
||||||
//
|
|
||||||
// fn create(args: struct {
|
// fn create32RR(args: struct {
|
||||||
// rm: ?GPRegister = null,
|
// rm: Encoding.GP32,
|
||||||
// reg: ?GPRegister = null,
|
// reg: Encoding.GP32,
|
||||||
// sib: bool = false,
|
// sib: bool = false,
|
||||||
// rm_size: ?Size = null,
|
// }) ?Rex {
|
||||||
// }) ?Rex {
|
// if (args.sib) {
|
||||||
// const rex_byte = Rex{
|
// unreachable;
|
||||||
// .b = if (args.rm) |rm| @intFromEnum(rm) > std.math.maxInt(u3) else false,
|
// } else {
|
||||||
// .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,
|
|
||||||
// };
|
// fn create(args: struct {
|
||||||
//
|
// rm: ?GPRegister = null,
|
||||||
// if (@as(u4, @truncate(@as(u8, @bitCast(rex_byte)))) != 0) {
|
// reg: ?GPRegister = null,
|
||||||
// return rex_byte;
|
// sib: bool = false,
|
||||||
// } else {
|
// rm_size: ?Size = null,
|
||||||
// return 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 {
|
fn getIrType(intermediate: *ir.Result, ir_instruction_index: ir.Instruction.Index) ir.Type {
|
||||||
const ir_instruction = intermediate.instructions.get(ir_instruction_index);
|
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 {
|
const LiveRegister = struct {
|
||||||
last_use: Instruction.Index = Instruction.Index.invalid,
|
last_use: Instruction.Index = Instruction.Index.invalid,
|
||||||
virtual: Register.Virtual.Index,
|
virtual: Register.Virtual.Index,
|
||||||
|
@ -1492,7 +1492,7 @@ pub fn initialize(compilation: *Compilation, module: *Module, package: *Package,
|
|||||||
if (equal(u8, declaration_name, "_start")) {
|
if (equal(u8, declaration_name, "_start")) {
|
||||||
const value = module.values.get(decl.init_value);
|
const value = module.values.get(decl.init_value);
|
||||||
module.entry_point = switch (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}),
|
.unresolved => panic("Unresolved declaration: {s}\n", .{declaration_name}),
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user