hello_world: finish producing a hello world exe
Section manager redesign Linker relocations Using global strings String literal fixup in sema
This commit is contained in:
parent
73769beb32
commit
31185e6779
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -43,3 +43,5 @@ jobs:
|
|||||||
nat/first
|
nat/first
|
||||||
zig build run -- test/stack/main.nat
|
zig build run -- test/stack/main.nat
|
||||||
nat/stack
|
nat/stack
|
||||||
|
zig build run -- test/hello_world/main.nat
|
||||||
|
nat/hello_world
|
||||||
|
@ -10,22 +10,13 @@ const emit = @import("emit.zig");
|
|||||||
const page_size = 0x1000;
|
const page_size = 0x1000;
|
||||||
|
|
||||||
pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, page_size) {
|
pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, page_size) {
|
||||||
var file = try std.ArrayListAlignedUnmanaged(u8, 0x1000).initCapacity(image.allocator, 0x100000);
|
const allocator = image.section_manager.allocator;
|
||||||
_ = try image.insertSection(0, .{
|
|
||||||
.name = "",
|
|
||||||
.size = page_size,
|
|
||||||
.alignment = page_size,
|
|
||||||
.flags = .{
|
|
||||||
.read = true,
|
|
||||||
.write = false,
|
|
||||||
.execute = false,
|
|
||||||
},
|
|
||||||
.type = .loadable_program,
|
|
||||||
});
|
|
||||||
|
|
||||||
const symbol_table_index = try image.addSection(.{
|
try image.section_manager.addNullSection();
|
||||||
|
|
||||||
|
const symbol_table_index = try image.section_manager.addSection(.{
|
||||||
.name = ".symtab",
|
.name = ".symtab",
|
||||||
.size = page_size,
|
.size_guess = 50,
|
||||||
.alignment = @alignOf(SymbolTable.Entry),
|
.alignment = @alignOf(SymbolTable.Entry),
|
||||||
.flags = .{
|
.flags = .{
|
||||||
.read = false,
|
.read = false,
|
||||||
@ -34,9 +25,9 @@ pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, pag
|
|||||||
},
|
},
|
||||||
.type = .symbol_table,
|
.type = .symbol_table,
|
||||||
});
|
});
|
||||||
const string_table_index = try image.addSection(.{
|
const string_table_index = try image.section_manager.addSection(.{
|
||||||
.name = ".strtab",
|
.name = ".strtab",
|
||||||
.size = page_size,
|
.size_guess = 50,
|
||||||
.alignment = 1,
|
.alignment = 1,
|
||||||
.flags = .{
|
.flags = .{
|
||||||
.read = false,
|
.read = false,
|
||||||
@ -45,9 +36,9 @@ pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, pag
|
|||||||
},
|
},
|
||||||
.type = .string_table,
|
.type = .string_table,
|
||||||
});
|
});
|
||||||
const section_header_string_table_index = try image.addSection(.{
|
const section_header_string_table_index = try image.section_manager.addSection(.{
|
||||||
.name = ".shstrtab",
|
.name = ".shstrtab",
|
||||||
.size = page_size,
|
.size_guess = 50,
|
||||||
.alignment = 1,
|
.alignment = 1,
|
||||||
.flags = .{
|
.flags = .{
|
||||||
.read = false,
|
.read = false,
|
||||||
@ -62,7 +53,7 @@ pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, pag
|
|||||||
|
|
||||||
const program_header_count = blk: {
|
const program_header_count = blk: {
|
||||||
var result: usize = 0;
|
var result: usize = 0;
|
||||||
for (image.sections.items) |section| {
|
for (image.section_manager.sections.items) |section| {
|
||||||
result += @intFromBool(switch (section.type) {
|
result += @intFromBool(switch (section.type) {
|
||||||
.null => false,
|
.null => false,
|
||||||
.loadable_program => true,
|
.loadable_program => true,
|
||||||
@ -75,7 +66,7 @@ pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, pag
|
|||||||
|
|
||||||
var symbol_name_offset: u32 = 0;
|
var symbol_name_offset: u32 = 0;
|
||||||
|
|
||||||
image.writeToSection(symbol_table_index, std.mem.asBytes(&SymbolTable.Entry{
|
try image.section_manager.appendToSection(symbol_table_index, std.mem.asBytes(&SymbolTable.Entry{
|
||||||
.name_offset = symbol_name_offset,
|
.name_offset = symbol_name_offset,
|
||||||
.information = 0,
|
.information = 0,
|
||||||
.other = 0,
|
.other = 0,
|
||||||
@ -84,19 +75,16 @@ pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, pag
|
|||||||
.size = 0,
|
.size = 0,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
image.writeToSection(string_table_index, "");
|
try image.section_manager.appendToSection(string_table_index, "");
|
||||||
image.writeByteToSection(string_table_index, 0);
|
try image.section_manager.appendByteToSection(string_table_index, 0);
|
||||||
symbol_name_offset += 1;
|
symbol_name_offset += 1;
|
||||||
|
|
||||||
for (image.sections.items) |section| {
|
for (image.section_manager.sections.items) |section| {
|
||||||
image.writeToSection(section_header_string_table_index, section.name);
|
try image.section_manager.appendToSection(section_header_string_table_index, section.name);
|
||||||
image.writeByteToSection(section_header_string_table_index, 0);
|
try image.section_manager.appendByteToSection(section_header_string_table_index, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
try image.section_manager.appendToSection(0, std.mem.asBytes(&Header{
|
||||||
var program_segment_offset: usize = 0;
|
|
||||||
|
|
||||||
image.writeToSection(0, std.mem.asBytes(&Header{
|
|
||||||
.endianness = .little,
|
.endianness = .little,
|
||||||
.machine = switch (image.target.cpu.arch) {
|
.machine = switch (image.target.cpu.arch) {
|
||||||
.x86_64 => .AMD64,
|
.x86_64 => .AMD64,
|
||||||
@ -106,23 +94,26 @@ pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, pag
|
|||||||
.linux => .systemv,
|
.linux => .systemv,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
.entry = 0,
|
.entry = 0, // overwritten later
|
||||||
.section_header_offset = 0,
|
.section_header_offset = 0, // overwritten later
|
||||||
.program_header_count = @intCast(program_header_count),
|
.program_header_count = @intCast(program_header_count),
|
||||||
.section_header_count = @intCast(image.sections.items.len),
|
.section_header_count = @intCast(image.section_manager.sections.items.len),
|
||||||
.section_header_string_table_index = @intCast(section_header_string_table_index),
|
.section_header_string_table_index = @intCast(section_header_string_table_index),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
for (image.sections.items, 0..) |section, section_index| {
|
var program_segment_offset: usize = 0;
|
||||||
|
|
||||||
|
for (image.section_manager.sections.items, 0..) |section, section_index| {
|
||||||
switch (section.type) {
|
switch (section.type) {
|
||||||
.loadable_program => {
|
.loadable_program => {
|
||||||
program_segment_offset = std.mem.alignForward(usize, program_segment_offset, section.alignment);
|
program_segment_offset = std.mem.alignForward(usize, program_segment_offset, section.alignment);
|
||||||
const virtual_address = base_virtual_address + program_segment_offset;
|
const virtual_address = base_virtual_address + program_segment_offset;
|
||||||
const program_segment_size = switch (section_index) {
|
const program_segment_size = switch (section_index) {
|
||||||
0 => @sizeOf(Header) + @sizeOf(ProgramHeader) * program_header_count,
|
0 => @sizeOf(Header) + @sizeOf(ProgramHeader) * program_header_count,
|
||||||
else => section.index,
|
else => section.bytes.items.len,
|
||||||
};
|
};
|
||||||
image.writeToSection(0, std.mem.asBytes(&ProgramHeader{
|
|
||||||
|
try image.section_manager.appendToSection(0, std.mem.asBytes(&ProgramHeader{
|
||||||
.type = .load,
|
.type = .load,
|
||||||
.flags = ProgramHeader.Flags{
|
.flags = ProgramHeader.Flags{
|
||||||
.executable = section.flags.execute,
|
.executable = section.flags.execute,
|
||||||
@ -145,20 +136,22 @@ pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, pag
|
|||||||
=> {},
|
=> {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
{
|
var file = try std.ArrayListAlignedUnmanaged(u8, 0x1000).initCapacity(allocator, 0x100000);
|
||||||
var section_offset: usize = 0;
|
var section_headers = try ArrayList(SectionHeader).initCapacity(allocator, image.section_manager.sections.items.len);
|
||||||
var section_headers = try ArrayList(SectionHeader).initCapacity(image.allocator, image.sections.items.len);
|
|
||||||
var section_name_offset: u32 = 0;
|
var section_name_offset: u32 = 0;
|
||||||
|
|
||||||
for (image.sections.items, 0..) |section, section_i| {
|
for (image.section_manager.sections.items, 0..) |section, section_i| {
|
||||||
section_offset = std.mem.alignForward(usize, section_offset, section.alignment);
|
const section_offset = std.mem.alignForward(usize, file.items.len, section.alignment);
|
||||||
const virtual_address = base_virtual_address + section_offset;
|
const virtual_address = base_virtual_address + section_offset;
|
||||||
|
|
||||||
|
if (file.items.len < section_offset) {
|
||||||
|
try file.appendNTimes(allocator, 0, section_offset - file.items.len);
|
||||||
|
}
|
||||||
|
|
||||||
for (section.symbol_table.keys(), section.symbol_table.values()) |symbol_name, symbol_offset| {
|
for (section.symbol_table.keys(), section.symbol_table.values()) |symbol_name, symbol_offset| {
|
||||||
const symbol_address = virtual_address + symbol_offset;
|
const symbol_address = virtual_address + symbol_offset;
|
||||||
image.writeToSection(symbol_table_index, std.mem.asBytes(&SymbolTable.Entry{
|
try image.section_manager.appendToSection(symbol_table_index, std.mem.asBytes(&SymbolTable.Entry{
|
||||||
.name_offset = symbol_name_offset,
|
.name_offset = symbol_name_offset,
|
||||||
.information = 0x10,
|
.information = 0x10,
|
||||||
.other = 0,
|
.other = 0,
|
||||||
@ -167,15 +160,13 @@ pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, pag
|
|||||||
.size = 0,
|
.size = 0,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
image.writeToSection(string_table_index, symbol_name);
|
try image.section_manager.appendToSection(string_table_index, symbol_name);
|
||||||
image.writeByteToSection(string_table_index, 0);
|
try image.section_manager.appendByteToSection(string_table_index, 0);
|
||||||
|
|
||||||
symbol_name_offset += @intCast(symbol_name.len + 1);
|
symbol_name_offset += @intCast(symbol_name.len + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const source = section.content[0..section.index];
|
try file.appendSlice(image.section_manager.allocator, section.bytes.items);
|
||||||
file.items.len = section_offset + source.len;
|
|
||||||
try file.replaceRange(image.allocator, section_offset, source.len, source);
|
|
||||||
|
|
||||||
section_headers.appendAssumeCapacity(SectionHeader{
|
section_headers.appendAssumeCapacity(SectionHeader{
|
||||||
.name_offset = section_name_offset,
|
.name_offset = section_name_offset,
|
||||||
@ -195,7 +186,7 @@ pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, pag
|
|||||||
},
|
},
|
||||||
.virtual_address = virtual_address,
|
.virtual_address = virtual_address,
|
||||||
.file_offset = section_offset,
|
.file_offset = section_offset,
|
||||||
.size = section.index,
|
.size = section.bytes.items.len,
|
||||||
.link = switch (section.type) {
|
.link = switch (section.type) {
|
||||||
.symbol_table => @intCast(string_table_index),
|
.symbol_table => @intCast(string_table_index),
|
||||||
else => 0,
|
else => 0,
|
||||||
@ -211,18 +202,37 @@ pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, pag
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
section_offset += section.index;
|
|
||||||
section_name_offset += @intCast(section.name.len + 1);
|
section_name_offset += @intCast(section.name.len + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const section_header_offset = std.mem.alignForward(usize, section_offset, @alignOf(SectionHeader));
|
const section_header_offset = std.mem.alignForward(usize, file.items.len, @alignOf(SectionHeader));
|
||||||
const section_header_bytes = std.mem.sliceAsBytes(section_headers.items);
|
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.ensureTotalCapacity(allocator, section_header_offset + section_header_bytes.len);
|
||||||
try file.replaceRange(image.allocator, section_header_offset, section_header_bytes.len, section_header_bytes);
|
|
||||||
|
if (file.items.len < section_header_offset) {
|
||||||
|
file.appendNTimesAssumeCapacity(0, section_header_offset - file.items.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
file.appendSliceAssumeCapacity(section_header_bytes);
|
||||||
|
|
||||||
|
// At this point, the file array list is not going to grow, so it's safe to practice relocations
|
||||||
|
for (image.section_manager.linker_relocations.items) |relocation| {
|
||||||
|
const source_section_index = relocation.source.index + @intFromBool(image.section_manager.null);
|
||||||
|
const target_section_index = relocation.target.index + @intFromBool(image.section_manager.null);
|
||||||
|
const source_section_header = §ion_headers.items[source_section_index];
|
||||||
|
const target_section_header = §ion_headers.items[target_section_index];
|
||||||
|
const source_file_offset = source_section_header.file_offset + relocation.source.offset;
|
||||||
|
const source_virtual_address = source_section_header.virtual_address + relocation.source.offset;
|
||||||
|
const target_virtual_address = target_section_header.virtual_address + relocation.target.offset;
|
||||||
|
const displacement: i32 = @intCast(@as(i64, @intCast(target_virtual_address)) - @as(i64, @intCast(source_virtual_address)));
|
||||||
|
const address_file_offset: usize = @intCast(@as(i64, @intCast(source_file_offset)) + relocation.offset);
|
||||||
|
const address_file_pointer: *align(1) i32 = @ptrCast(&file.items[address_file_offset]);
|
||||||
|
address_file_pointer.* = displacement;
|
||||||
|
}
|
||||||
|
|
||||||
const _start_offset = blk: {
|
const _start_offset = blk: {
|
||||||
const entry_offset = image.sections.items[text_section_index].symbol_table.values()[image.entry_point];
|
const entry_offset = image.section_manager.sections.items[text_section_index].symbol_table.values()[image.entry_point];
|
||||||
const text_section_virtual_address = section_headers.items[text_section_index].virtual_address;
|
const text_section_virtual_address = section_headers.items[text_section_index].virtual_address;
|
||||||
break :blk text_section_virtual_address + entry_offset;
|
break :blk text_section_virtual_address + entry_offset;
|
||||||
};
|
};
|
||||||
@ -230,7 +240,6 @@ pub fn writeToMemory(image: *emit.Result) !std.ArrayListAlignedUnmanaged(u8, pag
|
|||||||
const header: *Header = @ptrCast(file.items.ptr);
|
const header: *Header = @ptrCast(file.items.ptr);
|
||||||
header.section_header_offset = section_header_offset;
|
header.section_header_offset = section_header_offset;
|
||||||
header.entry = _start_offset;
|
header.entry = _start_offset;
|
||||||
}
|
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ const ir = @import("intermediate_representation.zig");
|
|||||||
|
|
||||||
const data_structures = @import("../data_structures.zig");
|
const data_structures = @import("../data_structures.zig");
|
||||||
const ArrayList = data_structures.ArrayList;
|
const ArrayList = data_structures.ArrayList;
|
||||||
|
const ArrayListAligned = data_structures.ArrayListAligned;
|
||||||
const AutoHashMap = data_structures.AutoHashMap;
|
const AutoHashMap = data_structures.AutoHashMap;
|
||||||
const mmap = data_structures.mmap;
|
const mmap = data_structures.mmap;
|
||||||
|
|
||||||
@ -22,13 +23,12 @@ const macho = @import("macho.zig");
|
|||||||
const jit_callconv = .SysV;
|
const jit_callconv = .SysV;
|
||||||
|
|
||||||
const Section = struct {
|
const Section = struct {
|
||||||
content: []align(page_size) u8,
|
bytes: ArrayListAligned(u8, page_size),
|
||||||
index: usize = 0,
|
|
||||||
alignment: u32,
|
|
||||||
name: []const u8,
|
|
||||||
flags: Flags,
|
|
||||||
type: Type,
|
|
||||||
symbol_table: std.StringArrayHashMapUnmanaged(u32) = .{},
|
symbol_table: std.StringArrayHashMapUnmanaged(u32) = .{},
|
||||||
|
name: []const u8,
|
||||||
|
alignment: u32,
|
||||||
|
flags: Section.Flags,
|
||||||
|
type: Section.Type,
|
||||||
|
|
||||||
const Type = enum {
|
const Type = enum {
|
||||||
null,
|
null,
|
||||||
@ -44,60 +44,53 @@ const Section = struct {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Result = struct {
|
|
||||||
sections: ArrayList(Section) = .{},
|
|
||||||
// sections: struct {
|
|
||||||
// text: Section,
|
|
||||||
// rodata: Section,
|
|
||||||
// data: Section,
|
|
||||||
// },
|
|
||||||
entry_point: u32,
|
|
||||||
target: std.Target,
|
|
||||||
allocator: Allocator,
|
|
||||||
|
|
||||||
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 {
|
const SectionCreation = struct {
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
size: usize,
|
size_guess: usize,
|
||||||
alignment: u32,
|
alignment: u32,
|
||||||
flags: Section.Flags,
|
flags: Section.Flags,
|
||||||
type: Section.Type,
|
type: Section.Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn addSection(result: *Result, arguments: SectionCreation) !usize {
|
const Relocation = struct {
|
||||||
const index = result.sections.items.len;
|
source: struct {
|
||||||
assert(std.mem.isAligned(arguments.size, page_size));
|
offset: u32,
|
||||||
|
index: u16,
|
||||||
|
},
|
||||||
|
target: struct {
|
||||||
|
offset: u32,
|
||||||
|
index: u16,
|
||||||
|
},
|
||||||
|
offset: i8,
|
||||||
|
};
|
||||||
|
|
||||||
try result.sections.append(result.allocator, .{
|
pub const SectionManager = struct {
|
||||||
.content = try mmap(arguments.size, .{ .executable = arguments.flags.execute }),
|
sections: ArrayList(Section) = .{},
|
||||||
|
rodata: ?u16 = null,
|
||||||
|
null: bool = false,
|
||||||
|
linker_relocations: ArrayList(Relocation) = .{},
|
||||||
|
allocator: Allocator,
|
||||||
|
|
||||||
|
pub fn addSection(section_manager: *SectionManager, arguments: SectionCreation) !usize {
|
||||||
|
const index = section_manager.sections.items.len;
|
||||||
|
|
||||||
|
const r = try section_manager.insertSection(index, arguments);
|
||||||
|
assert(index == r);
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getTextSectionIndex(section_manager: *const SectionManager) u16 {
|
||||||
|
return @intCast(@intFromBool(section_manager.null));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getTextSection(section_manager: *SectionManager) *Section {
|
||||||
|
return §ion_manager.sections.items[section_manager.getTextSectionIndex()];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insertSection(section_manager: *SectionManager, index: usize, arguments: SectionCreation) !usize {
|
||||||
|
try section_manager.sections.insert(section_manager.allocator, index, .{
|
||||||
|
.bytes = try ArrayListAligned(u8, page_size).initCapacity(section_manager.allocator, arguments.size_guess),
|
||||||
.alignment = arguments.alignment,
|
.alignment = arguments.alignment,
|
||||||
.name = arguments.name,
|
.name = arguments.name,
|
||||||
.flags = arguments.flags,
|
.flags = arguments.flags,
|
||||||
@ -107,47 +100,63 @@ pub const Result = struct {
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insertSection(result: *Result, index: usize, arguments: SectionCreation) !usize {
|
pub fn addNullSection(section_manager: *SectionManager) !void {
|
||||||
assert(std.mem.isAligned(arguments.size, page_size));
|
const index = try section_manager.insertSection(0, .{
|
||||||
try result.sections.insert(result.allocator, index, .{
|
.name = "",
|
||||||
.content = try mmap(arguments.size, .{ .executable = arguments.flags.execute }),
|
.size_guess = page_size,
|
||||||
.alignment = arguments.alignment,
|
.alignment = page_size,
|
||||||
.name = arguments.name,
|
.flags = .{
|
||||||
.flags = arguments.flags,
|
.read = true,
|
||||||
.type = arguments.type,
|
.write = false,
|
||||||
|
.execute = false,
|
||||||
|
},
|
||||||
|
.type = .loadable_program,
|
||||||
});
|
});
|
||||||
|
assert(index == 0);
|
||||||
|
|
||||||
return index;
|
section_manager.null = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn alignSection(result: *Result, index: usize, alignment: usize) void {
|
pub fn appendByteToSection(section_manager: *SectionManager, section_index: usize, byte: u8) !void {
|
||||||
const index_ptr = &result.sections.items[index].index;
|
try section_manager.sections.items[section_index].bytes.append(section_manager.allocator, byte);
|
||||||
index_ptr.* = std.mem.alignForward(usize, index_ptr.*, alignment);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeToSection(image: *Result, section_index: usize, bytes: []const u8) void {
|
pub fn appendToSection(section_manager: *SectionManager, section_index: usize, bytes: []const u8) !void {
|
||||||
const section = &image.sections.items[section_index];
|
try section_manager.sections.items[section_index].bytes.appendSlice(section_manager.allocator, bytes);
|
||||||
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 {
|
pub fn getSectionOffset(section_manager: *SectionManager, section_index: usize) usize {
|
||||||
const section = &image.sections.items[section_index];
|
return section_manager.sections.items[section_index].bytes.items.len;
|
||||||
section.content[section.index] = byte;
|
|
||||||
section.index += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getTextSection(result: *Result) *Section {
|
pub fn getCodeOffset(section_manager: *SectionManager) usize {
|
||||||
return &result.sections.items[0];
|
return section_manager.getSectionOffset(text_section_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn appendCode(image: *Result, code: []const u8) void {
|
pub fn appendCode(section_manager: *SectionManager, code: []const u8) !void {
|
||||||
image.writeToSection(text_section_index, code);
|
try section_manager.appendToSection(text_section_index, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn appendCodeByte(image: *Result, code_byte: u8) void {
|
pub fn appendCodeByte(section_manager: *SectionManager, code_byte: u8) !void {
|
||||||
image.writeByteToSection(text_section_index, code_byte);
|
try section_manager.appendByteToSection(text_section_index, code_byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
const text_section_index = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Result = struct {
|
||||||
|
section_manager: SectionManager,
|
||||||
|
entry_point: u32,
|
||||||
|
target: std.Target,
|
||||||
|
|
||||||
|
pub fn create(section_manager: SectionManager, target: std.Target, entry_point_index: u32) !Result {
|
||||||
|
var result = Result{
|
||||||
|
.section_manager = section_manager,
|
||||||
|
.target = target,
|
||||||
|
.entry_point = entry_point_index,
|
||||||
|
};
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getEntryPoint(image: *const Result, comptime FunctionType: type) *const FunctionType {
|
fn getEntryPoint(image: *const Result, comptime FunctionType: type) *const FunctionType {
|
||||||
|
@ -15,6 +15,9 @@ const AutoArrayHashMap = data_structures.AutoArrayHashMap;
|
|||||||
const AutoHashMap = data_structures.AutoHashMap;
|
const AutoHashMap = data_structures.AutoHashMap;
|
||||||
const StringKeyMap = data_structures.StringKeyMap;
|
const StringKeyMap = data_structures.StringKeyMap;
|
||||||
|
|
||||||
|
const emit = @import("emit.zig");
|
||||||
|
const SectionManager = emit.SectionManager;
|
||||||
|
|
||||||
pub const Logger = enum {
|
pub const Logger = enum {
|
||||||
function,
|
function,
|
||||||
phi_removal,
|
phi_removal,
|
||||||
@ -40,9 +43,9 @@ pub const Result = struct {
|
|||||||
stack_references: BlockList(StackReference) = .{},
|
stack_references: BlockList(StackReference) = .{},
|
||||||
string_literals: BlockList(StringLiteral) = .{},
|
string_literals: BlockList(StringLiteral) = .{},
|
||||||
casts: BlockList(Cast) = .{},
|
casts: BlockList(Cast) = .{},
|
||||||
readonly_data: ArrayList(u8) = .{},
|
|
||||||
module: *Module,
|
module: *Module,
|
||||||
entry_point: Function.Index = Function.Index.invalid,
|
entry_point: Function.Index = Function.Index.invalid,
|
||||||
|
section_manager: emit.SectionManager,
|
||||||
|
|
||||||
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)).?).?;
|
||||||
@ -54,10 +57,26 @@ pub fn initialize(compilation: *Compilation, module: *Module) !*Result {
|
|||||||
const builder = try compilation.base_allocator.create(Builder);
|
const builder = try compilation.base_allocator.create(Builder);
|
||||||
builder.* = .{
|
builder.* = .{
|
||||||
.allocator = compilation.base_allocator,
|
.allocator = compilation.base_allocator,
|
||||||
|
.ir = .{
|
||||||
.module = module,
|
.module = module,
|
||||||
|
.section_manager = SectionManager{
|
||||||
|
.allocator = compilation.base_allocator,
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
builder.ir.module = module;
|
builder.ir.module = module;
|
||||||
|
_ = try builder.ir.section_manager.addSection(.{
|
||||||
|
.name = ".text",
|
||||||
|
.size_guess = 0,
|
||||||
|
.alignment = 0x1000,
|
||||||
|
.flags = .{
|
||||||
|
.execute = true,
|
||||||
|
.read = true,
|
||||||
|
.write = false,
|
||||||
|
},
|
||||||
|
.type = .loadable_program,
|
||||||
|
});
|
||||||
|
|
||||||
var sema_function_index = function_iterator.getCurrentIndex();
|
var sema_function_index = function_iterator.getCurrentIndex();
|
||||||
while (function_iterator.next()) |sema_function| {
|
while (function_iterator.next()) |sema_function| {
|
||||||
@ -260,7 +279,6 @@ pub const Instruction = union(enum) {
|
|||||||
|
|
||||||
pub const StringLiteral = struct {
|
pub const StringLiteral = struct {
|
||||||
offset: u32,
|
offset: u32,
|
||||||
hash: u32,
|
|
||||||
|
|
||||||
pub const List = BlockList(@This());
|
pub const List = BlockList(@This());
|
||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
@ -395,10 +413,7 @@ pub const Function = struct {
|
|||||||
|
|
||||||
pub const Builder = struct {
|
pub const Builder = struct {
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
ir: Result = .{
|
ir: Result,
|
||||||
.module = undefined,
|
|
||||||
},
|
|
||||||
module: *Module,
|
|
||||||
current_function_index: Function.Index = Function.Index.invalid,
|
current_function_index: Function.Index = Function.Index.invalid,
|
||||||
|
|
||||||
fn currentFunction(builder: *Builder) *Function {
|
fn currentFunction(builder: *Builder) *Function {
|
||||||
@ -406,7 +421,7 @@ pub const Builder = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn buildFunction(builder: *Builder, sema_function: Compilation.Function) !Function.Index {
|
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.ir.module.function_prototypes.get(builder.ir.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;
|
||||||
function_declaration.* = .{
|
function_declaration.* = .{
|
||||||
@ -420,7 +435,7 @@ pub const Builder = struct {
|
|||||||
if (sema_prototype.arguments) |sema_arguments| {
|
if (sema_prototype.arguments) |sema_arguments| {
|
||||||
try function_declaration.arguments.ensureTotalCapacity(builder.allocator, @intCast(sema_arguments.len));
|
try function_declaration.arguments.ensureTotalCapacity(builder.allocator, @intCast(sema_arguments.len));
|
||||||
for (sema_arguments) |sema_argument_declaration_index| {
|
for (sema_arguments) |sema_argument_declaration_index| {
|
||||||
const sema_argument_declaration = builder.module.declarations.get(sema_argument_declaration_index);
|
const sema_argument_declaration = builder.ir.module.declarations.get(sema_argument_declaration_index);
|
||||||
const argument_allocation = try builder.ir.arguments.append(builder.allocator, .{
|
const argument_allocation = try builder.ir.arguments.append(builder.allocator, .{
|
||||||
.type = try builder.translateType(sema_argument_declaration.type),
|
.type = try builder.translateType(sema_argument_declaration.type),
|
||||||
});
|
});
|
||||||
@ -445,7 +460,7 @@ pub const Builder = struct {
|
|||||||
// TODO: arguments
|
// TODO: arguments
|
||||||
function.current_basic_block = try builder.newBlock();
|
function.current_basic_block = try builder.newBlock();
|
||||||
|
|
||||||
const return_type = builder.module.types.get(sema_prototype.return_type);
|
const return_type = builder.ir.module.types.get(sema_prototype.return_type);
|
||||||
const is_noreturn = return_type.* == .noreturn;
|
const is_noreturn = return_type.* == .noreturn;
|
||||||
|
|
||||||
if (!is_noreturn) {
|
if (!is_noreturn) {
|
||||||
@ -486,7 +501,7 @@ pub const Builder = struct {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const sema_block = sema_function.getBodyBlock(builder.module);
|
const sema_block = sema_function.getBodyBlock(builder.ir.module);
|
||||||
try builder.block(sema_block, .{ .emit_exit_block = !is_noreturn });
|
try builder.block(sema_block, .{ .emit_exit_block = !is_noreturn });
|
||||||
|
|
||||||
if (!is_noreturn and sema_block.reaches_end) {
|
if (!is_noreturn and sema_block.reaches_end) {
|
||||||
@ -797,7 +812,7 @@ pub const Builder = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fn emitSyscallArgument(builder: *Builder, sema_syscall_argument_value_index: Compilation.Value.Index) !Instruction.Index {
|
fn emitSyscallArgument(builder: *Builder, sema_syscall_argument_value_index: Compilation.Value.Index) !Instruction.Index {
|
||||||
const sema_syscall_argument_value = builder.module.values.get(sema_syscall_argument_value_index);
|
const sema_syscall_argument_value = builder.ir.module.values.get(sema_syscall_argument_value_index);
|
||||||
return switch (sema_syscall_argument_value.*) {
|
return switch (sema_syscall_argument_value.*) {
|
||||||
.integer => |integer| try builder.processInteger(integer),
|
.integer => |integer| try builder.processInteger(integer),
|
||||||
.sign_extend => |cast_index| try builder.processCast(cast_index, .sign_extend),
|
.sign_extend => |cast_index| try builder.processCast(cast_index, .sign_extend),
|
||||||
@ -807,8 +822,8 @@ pub const Builder = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn processCast(builder: *Builder, sema_cast_index: Compilation.Cast.Index, cast_type: CastType) !Instruction.Index {
|
fn processCast(builder: *Builder, sema_cast_index: Compilation.Cast.Index, cast_type: CastType) !Instruction.Index {
|
||||||
const sema_cast = builder.module.casts.get(sema_cast_index);
|
const sema_cast = builder.ir.module.casts.get(sema_cast_index);
|
||||||
const sema_source_value = builder.module.values.get(sema_cast.value);
|
const sema_source_value = builder.ir.module.values.get(sema_cast.value);
|
||||||
const source_value = switch (sema_source_value.*) {
|
const source_value = switch (sema_source_value.*) {
|
||||||
.declaration_reference => |declaration_reference| try builder.loadDeclarationReference(declaration_reference.value),
|
.declaration_reference => |declaration_reference| try builder.loadDeclarationReference(declaration_reference.value),
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
@ -827,7 +842,7 @@ pub const Builder = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn processDeclarationReferenceRaw(builder: *Builder, declaration_index: Compilation.Declaration.Index) !Instruction.Index {
|
fn processDeclarationReferenceRaw(builder: *Builder, declaration_index: Compilation.Declaration.Index) !Instruction.Index {
|
||||||
const sema_declaration = builder.module.declarations.get(declaration_index);
|
const sema_declaration = builder.ir.module.declarations.get(declaration_index);
|
||||||
const result = switch (sema_declaration.scope_type) {
|
const result = switch (sema_declaration.scope_type) {
|
||||||
.local => builder.currentFunction().stack_map.get(declaration_index).?,
|
.local => builder.currentFunction().stack_map.get(declaration_index).?,
|
||||||
.global => unreachable,
|
.global => unreachable,
|
||||||
@ -863,7 +878,7 @@ pub const Builder = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn processSyscall(builder: *Builder, sema_syscall_index: Compilation.Syscall.Index) anyerror!Instruction.Index {
|
fn processSyscall(builder: *Builder, sema_syscall_index: Compilation.Syscall.Index) anyerror!Instruction.Index {
|
||||||
const sema_syscall = builder.module.syscalls.get(sema_syscall_index);
|
const sema_syscall = builder.ir.module.syscalls.get(sema_syscall_index);
|
||||||
var arguments = try ArrayList(Instruction.Index).initCapacity(builder.allocator, sema_syscall.argument_count + 1);
|
var arguments = try ArrayList(Instruction.Index).initCapacity(builder.allocator, sema_syscall.argument_count + 1);
|
||||||
|
|
||||||
const sema_syscall_number = sema_syscall.number;
|
const sema_syscall_number = sema_syscall.number;
|
||||||
@ -889,12 +904,12 @@ pub const Builder = struct {
|
|||||||
|
|
||||||
fn block(builder: *Builder, sema_block: *Compilation.Block, options: BlockOptions) anyerror!void {
|
fn block(builder: *Builder, sema_block: *Compilation.Block, options: BlockOptions) anyerror!void {
|
||||||
for (sema_block.statements.items) |sema_statement_index| {
|
for (sema_block.statements.items) |sema_statement_index| {
|
||||||
const sema_statement = builder.module.values.get(sema_statement_index);
|
const sema_statement = builder.ir.module.values.get(sema_statement_index);
|
||||||
switch (sema_statement.*) {
|
switch (sema_statement.*) {
|
||||||
.loop => |loop_index| {
|
.loop => |loop_index| {
|
||||||
const sema_loop = builder.module.loops.get(loop_index);
|
const sema_loop = builder.ir.module.loops.get(loop_index);
|
||||||
const sema_loop_condition = builder.module.values.get(sema_loop.condition);
|
const sema_loop_condition = builder.ir.module.values.get(sema_loop.condition);
|
||||||
const sema_loop_body = builder.module.values.get(sema_loop.body);
|
const sema_loop_body = builder.ir.module.values.get(sema_loop.body);
|
||||||
const condition: Compilation.Value.Index = switch (sema_loop_condition.*) {
|
const condition: Compilation.Value.Index = switch (sema_loop_condition.*) {
|
||||||
.bool => |bool_value| switch (bool_value) {
|
.bool => |bool_value| switch (bool_value) {
|
||||||
true => Compilation.Value.Index.invalid,
|
true => Compilation.Value.Index.invalid,
|
||||||
@ -920,7 +935,7 @@ pub const Builder = struct {
|
|||||||
.destination = loop_head_block,
|
.destination = loop_head_block,
|
||||||
});
|
});
|
||||||
|
|
||||||
const sema_body_block = builder.module.blocks.get(sema_loop_body.block);
|
const sema_body_block = builder.ir.module.blocks.get(sema_loop_body.block);
|
||||||
builder.currentFunction().current_basic_block = try builder.blockInsideBasicBlock(sema_body_block, loop_body_block);
|
builder.currentFunction().current_basic_block = try builder.blockInsideBasicBlock(sema_body_block, loop_body_block);
|
||||||
if (!loop_prologue_block.invalid) {
|
if (!loop_prologue_block.invalid) {
|
||||||
builder.ir.blocks.get(loop_prologue_block).seal();
|
builder.ir.blocks.get(loop_prologue_block).seal();
|
||||||
@ -950,7 +965,7 @@ pub const Builder = struct {
|
|||||||
.@"unreachable" = {},
|
.@"unreachable" = {},
|
||||||
}),
|
}),
|
||||||
.@"return" => |sema_ret_index| {
|
.@"return" => |sema_ret_index| {
|
||||||
const sema_ret = builder.module.returns.get(sema_ret_index);
|
const sema_ret = builder.ir.module.returns.get(sema_ret_index);
|
||||||
const return_value = try builder.emitReturnValue(sema_ret.value);
|
const return_value = try builder.emitReturnValue(sema_ret.value);
|
||||||
const phi_instruction = builder.ir.instructions.get(builder.currentFunction().return_phi_node);
|
const phi_instruction = builder.ir.instructions.get(builder.currentFunction().return_phi_node);
|
||||||
const phi = switch (phi_instruction.phi.invalid) {
|
const phi = switch (phi_instruction.phi.invalid) {
|
||||||
@ -976,10 +991,10 @@ pub const Builder = struct {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
.declaration => |sema_declaration_index| {
|
.declaration => |sema_declaration_index| {
|
||||||
const sema_declaration = builder.module.declarations.get(sema_declaration_index);
|
const sema_declaration = builder.ir.module.declarations.get(sema_declaration_index);
|
||||||
//logln("Name: {s}\n", .{builder.module.getName(sema_declaration.name).?});
|
//logln("Name: {s}\n", .{builder.module.getName(sema_declaration.name).?});
|
||||||
assert(sema_declaration.scope_type == .local);
|
assert(sema_declaration.scope_type == .local);
|
||||||
const declaration_type = builder.module.types.get(sema_declaration.type);
|
const declaration_type = builder.ir.module.types.get(sema_declaration.type);
|
||||||
switch (declaration_type.*) {
|
switch (declaration_type.*) {
|
||||||
.comptime_int => unreachable,
|
.comptime_int => unreachable,
|
||||||
else => {
|
else => {
|
||||||
@ -1011,7 +1026,7 @@ pub const Builder = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn emitDeclarationInitValue(builder: *Builder, declaration_init_value_index: Compilation.Value.Index) !Instruction.Index {
|
fn emitDeclarationInitValue(builder: *Builder, declaration_init_value_index: Compilation.Value.Index) !Instruction.Index {
|
||||||
const declaration_init_value = builder.module.values.get(declaration_init_value_index);
|
const declaration_init_value = builder.ir.module.values.get(declaration_init_value_index);
|
||||||
return switch (declaration_init_value.*) {
|
return switch (declaration_init_value.*) {
|
||||||
.call => |call_index| try builder.processCall(call_index),
|
.call => |call_index| try builder.processCall(call_index),
|
||||||
.integer => |integer| try builder.processInteger(integer),
|
.integer => |integer| try builder.processInteger(integer),
|
||||||
@ -1020,7 +1035,7 @@ pub const Builder = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn emitReturnValue(builder: *Builder, return_value_index: Compilation.Value.Index) !Instruction.Index {
|
fn emitReturnValue(builder: *Builder, return_value_index: Compilation.Value.Index) !Instruction.Index {
|
||||||
const return_value = builder.module.values.get(return_value_index);
|
const return_value = builder.ir.module.values.get(return_value_index);
|
||||||
return switch (return_value.*) {
|
return switch (return_value.*) {
|
||||||
.syscall => |syscall_index| try builder.processSyscall(syscall_index),
|
.syscall => |syscall_index| try builder.processSyscall(syscall_index),
|
||||||
.integer => |integer| try builder.processInteger(integer),
|
.integer => |integer| try builder.processInteger(integer),
|
||||||
@ -1064,7 +1079,7 @@ pub const Builder = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn emitCallArgument(builder: *Builder, call_argument_value_index: Compilation.Value.Index) !Instruction.Index {
|
fn emitCallArgument(builder: *Builder, call_argument_value_index: Compilation.Value.Index) !Instruction.Index {
|
||||||
const call_argument_value = builder.module.values.get(call_argument_value_index);
|
const call_argument_value = builder.ir.module.values.get(call_argument_value_index);
|
||||||
return switch (call_argument_value.*) {
|
return switch (call_argument_value.*) {
|
||||||
.integer => |integer| try builder.processInteger(integer),
|
.integer => |integer| try builder.processInteger(integer),
|
||||||
.declaration_reference => |declaration_reference| try builder.loadDeclarationReference(declaration_reference.value),
|
.declaration_reference => |declaration_reference| try builder.loadDeclarationReference(declaration_reference.value),
|
||||||
@ -1074,12 +1089,12 @@ pub const Builder = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn processCall(builder: *Builder, sema_call_index: Compilation.Call.Index) anyerror!Instruction.Index {
|
fn processCall(builder: *Builder, sema_call_index: Compilation.Call.Index) anyerror!Instruction.Index {
|
||||||
const sema_call = builder.module.calls.get(sema_call_index);
|
const sema_call = builder.ir.module.calls.get(sema_call_index);
|
||||||
const sema_argument_list_index = sema_call.arguments;
|
const sema_argument_list_index = sema_call.arguments;
|
||||||
const argument_list: []const Instruction.Index = switch (sema_argument_list_index.invalid) {
|
const argument_list: []const Instruction.Index = switch (sema_argument_list_index.invalid) {
|
||||||
false => blk: {
|
false => blk: {
|
||||||
var argument_list = ArrayList(Instruction.Index){};
|
var argument_list = ArrayList(Instruction.Index){};
|
||||||
const sema_argument_list = builder.module.argument_lists.get(sema_argument_list_index);
|
const sema_argument_list = builder.ir.module.argument_lists.get(sema_argument_list_index);
|
||||||
try argument_list.ensureTotalCapacity(builder.allocator, sema_argument_list.array.items.len);
|
try argument_list.ensureTotalCapacity(builder.allocator, sema_argument_list.array.items.len);
|
||||||
for (sema_argument_list.array.items) |sema_argument_value_index| {
|
for (sema_argument_list.array.items) |sema_argument_value_index| {
|
||||||
const argument_value_index = try builder.emitCallArgument(sema_argument_value_index);
|
const argument_value_index = try builder.emitCallArgument(sema_argument_value_index);
|
||||||
@ -1091,7 +1106,7 @@ pub const Builder = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const call_index = try builder.call(.{
|
const call_index = try builder.call(.{
|
||||||
.function = switch (builder.module.values.get(sema_call.value).*) {
|
.function = switch (builder.ir.module.values.get(sema_call.value).*) {
|
||||||
.function => |function_index| .{
|
.function => |function_index| .{
|
||||||
.index = function_index.index,
|
.index = function_index.index,
|
||||||
.block = function_index.block,
|
.block = function_index.block,
|
||||||
@ -1109,16 +1124,34 @@ pub const Builder = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn processStringLiteral(builder: *Builder, string_literal_hash: u32) !Instruction.Index {
|
fn processStringLiteral(builder: *Builder, string_literal_hash: u32) !Instruction.Index {
|
||||||
const string_literal = builder.module.string_literals.getValue(string_literal_hash).?;
|
const string_literal = builder.ir.module.string_literals.getValue(string_literal_hash).?;
|
||||||
|
|
||||||
const readonly_offset = builder.ir.readonly_data.items.len;
|
if (builder.ir.section_manager.rodata == null) {
|
||||||
try builder.ir.readonly_data.appendSlice(builder.allocator, string_literal);
|
const rodata_index = try builder.ir.section_manager.addSection(.{
|
||||||
try builder.ir.readonly_data.append(builder.allocator, 0);
|
.name = ".rodata",
|
||||||
|
.size_guess = 0,
|
||||||
|
.alignment = 0x1000,
|
||||||
|
.flags = .{
|
||||||
|
.read = true,
|
||||||
|
.write = false,
|
||||||
|
.execute = false,
|
||||||
|
},
|
||||||
|
.type = .loadable_program,
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.ir.section_manager.rodata = @intCast(rodata_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
const rodata_index = builder.ir.section_manager.rodata orelse unreachable;
|
||||||
|
const rodata_section_offset = builder.ir.section_manager.getSectionOffset(rodata_index);
|
||||||
|
|
||||||
|
try builder.ir.section_manager.appendToSection(rodata_index, string_literal);
|
||||||
|
try builder.ir.section_manager.appendByteToSection(rodata_index, 0);
|
||||||
|
|
||||||
const string_literal_allocation = try builder.ir.string_literals.append(builder.allocator, .{
|
const string_literal_allocation = try builder.ir.string_literals.append(builder.allocator, .{
|
||||||
.offset = @intCast(readonly_offset),
|
.offset = @intCast(rodata_section_offset),
|
||||||
.hash = string_literal_hash,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = try builder.append(.{
|
const result = try builder.append(.{
|
||||||
.load_string_literal = string_literal_allocation.index,
|
.load_string_literal = string_literal_allocation.index,
|
||||||
});
|
});
|
||||||
@ -1126,48 +1159,8 @@ pub const Builder = struct {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn emitValue(builder: *Builder, sema_value_index: Compilation.Value.Index) !Instruction.Index {
|
|
||||||
// const sema_value = builder.module.values.get(sema_value_index).*;
|
|
||||||
// return switch (sema_value) {
|
|
||||||
// .integer => |integer| try builder.append(.{
|
|
||||||
// .integer = integer,
|
|
||||||
// }),
|
|
||||||
// .call => |sema_call_index| try builder.processCall(sema_call_index),
|
|
||||||
// .declaration_reference => |sema_declaration_reference| blk: {
|
|
||||||
// },
|
|
||||||
// .syscall => |sema_syscall_index| try builder.processSyscall(sema_syscall_index),
|
|
||||||
// .string_literal => |string_literal_hash| blk: {
|
|
||||||
// const string_literal = builder.module.string_literals.getValue(string_literal_hash).?;
|
|
||||||
//
|
|
||||||
// const readonly_offset = builder.ir.readonly_data.items.len;
|
|
||||||
// try builder.ir.readonly_data.appendSlice(builder.allocator, string_literal);
|
|
||||||
//
|
|
||||||
// const string_literal_allocation = try builder.ir.string_literals.append(builder.allocator, .{
|
|
||||||
// .offset = @intCast(readonly_offset),
|
|
||||||
// .hash = string_literal_hash,
|
|
||||||
// });
|
|
||||||
// break :blk try builder.append(.{
|
|
||||||
// .string_literal = string_literal_allocation.index,
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// .sign_extend => |sema_cast_index| blk: {
|
|
||||||
// const sema_sign_extend = builder.module.casts.get(sema_cast_index);
|
|
||||||
//
|
|
||||||
// const sign_extend = try builder.ir.casts.append(builder.allocator, .{
|
|
||||||
// .value = try builder.emitValue(sema_sign_extend.value),
|
|
||||||
// .type = try builder.translateType(sema_sign_extend.type),
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// break :blk try builder.append(.{
|
|
||||||
// .sign_extend = sign_extend.index,
|
|
||||||
// });
|
|
||||||
// },
|
|
||||||
// else => |t| @panic(@tagName(t)),
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
|
|
||||||
fn translateType(builder: *Builder, type_index: Compilation.Type.Index) !Type {
|
fn translateType(builder: *Builder, type_index: Compilation.Type.Index) !Type {
|
||||||
const sema_type = builder.module.types.get(type_index);
|
const sema_type = builder.ir.module.types.get(type_index);
|
||||||
return switch (sema_type.*) {
|
return switch (sema_type.*) {
|
||||||
.integer => |integer| switch (integer.bit_count) {
|
.integer => |integer| switch (integer.bit_count) {
|
||||||
8 => .i8,
|
8 => .i8,
|
||||||
|
@ -1728,19 +1728,9 @@ pub const Operand = struct {
|
|||||||
global_offset: i32 = 0,
|
global_offset: i32 = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const PCRelative = union(enum) {
|
const PCRelative = struct {
|
||||||
function_declaration: MIR.Function.Index,
|
index: u32,
|
||||||
string_literal: ir.StringLiteral.Index,
|
section: u16,
|
||||||
imm32: i32,
|
|
||||||
imm8: i8,
|
|
||||||
|
|
||||||
fn function(ir_function_decl_index: ir.Function.Declaration.Index) Operand {
|
|
||||||
return Operand{
|
|
||||||
.i64i32imm_brtarget = PCRelative{
|
|
||||||
.function_declaration = ir_function_decl_index,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const Lea64Mem = struct {
|
const Lea64Mem = struct {
|
||||||
@ -1748,23 +1738,6 @@ pub const Operand = struct {
|
|||||||
scale: u8,
|
scale: u8,
|
||||||
scale_reg: ?Register,
|
scale_reg: ?Register,
|
||||||
displacement: PCRelative,
|
displacement: PCRelative,
|
||||||
|
|
||||||
fn stringLiteral(ir_load_string_literal_index: ir.StringLiteral.Index) Operand {
|
|
||||||
return Operand{
|
|
||||||
.id = .lea64mem,
|
|
||||||
.u = .{
|
|
||||||
.lea64mem = .{
|
|
||||||
.gp64 = null, // rip
|
|
||||||
.scale = 1,
|
|
||||||
.scale_reg = null,
|
|
||||||
.displacement = PCRelative{
|
|
||||||
.string_literal = ir_load_string_literal_index,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
.flags = .{},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const Immediate = u64;
|
const Immediate = u64;
|
||||||
@ -2561,7 +2534,8 @@ pub const MIR = struct {
|
|||||||
.id = .i64i32imm_brtarget,
|
.id = .i64i32imm_brtarget,
|
||||||
.u = .{
|
.u = .{
|
||||||
.pc_relative = .{
|
.pc_relative = .{
|
||||||
.function_declaration = mir.function_declaration_map.get(ir_call.function).?,
|
.index = @bitCast(mir.function_declaration_map.get(ir_call.function).?),
|
||||||
|
.section = @intCast(mir.ir.section_manager.getTextSectionIndex()),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.flags = .{},
|
.flags = .{},
|
||||||
@ -2624,6 +2598,7 @@ pub const MIR = struct {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.load_string_literal => |ir_load_string_literal_index| {
|
.load_string_literal => |ir_load_string_literal_index| {
|
||||||
|
const ir_load_string_literal = mir.ir.string_literals.get(ir_load_string_literal_index);
|
||||||
const virtual_register = try instruction_selection.getRegisterForValue(mir, ir_instruction_index);
|
const virtual_register = try instruction_selection.getRegisterForValue(mir, ir_instruction_index);
|
||||||
const virtual_operand = Operand{
|
const virtual_operand = Operand{
|
||||||
.id = .gp64,
|
.id = .gp64,
|
||||||
@ -2640,7 +2615,8 @@ pub const MIR = struct {
|
|||||||
.scale = 1,
|
.scale = 1,
|
||||||
.scale_reg = null,
|
.scale_reg = null,
|
||||||
.displacement = Operand.PCRelative{
|
.displacement = Operand.PCRelative{
|
||||||
.string_literal = ir_load_string_literal_index,
|
.index = ir_load_string_literal.offset,
|
||||||
|
.section = mir.ir.section_manager.rodata orelse unreachable,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -3792,32 +3768,32 @@ pub const MIR = struct {
|
|||||||
|
|
||||||
pub fn encode(mir: *MIR) !*emit.Result {
|
pub fn encode(mir: *MIR) !*emit.Result {
|
||||||
const image = try mir.allocator.create(emit.Result);
|
const image = try mir.allocator.create(emit.Result);
|
||||||
image.* = try emit.Result.create(mir.allocator, mir.target, mir.entry_point);
|
image.* = try emit.Result.create(mir.ir.section_manager, mir.target, mir.entry_point);
|
||||||
|
|
||||||
var function_iterator = mir.functions.iterator();
|
var function_iterator = mir.functions.iterator();
|
||||||
|
|
||||||
var function_offsets = std.AutoArrayHashMapUnmanaged(Function.Index, u32){};
|
var function_offsets = std.AutoArrayHashMapUnmanaged(Function.Index, u32){};
|
||||||
try function_offsets.ensureTotalCapacity(mir.allocator, mir.functions.len);
|
try function_offsets.ensureTotalCapacity(mir.allocator, mir.functions.len);
|
||||||
try image.sections.items[0].symbol_table.ensureTotalCapacity(mir.allocator, mir.functions.len);
|
try image.section_manager.getTextSection().symbol_table.ensureTotalCapacity(mir.allocator, mir.functions.len);
|
||||||
|
|
||||||
while (function_iterator.nextPointer()) |function| {
|
while (function_iterator.nextPointer()) |function| {
|
||||||
const function_index = mir.functions.indexOf(function);
|
const function_index = mir.functions.indexOf(function);
|
||||||
logln(.codegen, .encoding, "\n{s}:", .{function.name});
|
logln(.codegen, .encoding, "\n{s}:", .{function.name});
|
||||||
|
|
||||||
const function_offset: u32 = @intCast(image.getTextSection().index);
|
const function_offset: u32 = @intCast(image.section_manager.getCodeOffset());
|
||||||
|
|
||||||
function_offsets.putAssumeCapacityNoClobber(function_index, function_offset);
|
function_offsets.putAssumeCapacityNoClobber(function_index, function_offset);
|
||||||
image.sections.items[0].symbol_table.putAssumeCapacityNoClobber(function.name, function_offset);
|
image.section_manager.getTextSection().symbol_table.putAssumeCapacityNoClobber(function.name, function_offset);
|
||||||
|
|
||||||
const stack_size = std.mem.alignForward(u32, computeStackSize(function.instruction_selection.stack_objects.items), 0x10);
|
const stack_size = std.mem.alignForward(u32, computeStackSize(function.instruction_selection.stack_objects.items), 0x10);
|
||||||
|
|
||||||
if (stack_size != 0) {
|
if (stack_size != 0) {
|
||||||
image.appendCodeByte(0x55); // push rbp
|
try image.section_manager.appendCodeByte(0x55); // push rbp
|
||||||
image.appendCode(&.{ 0x48, 0x89, 0xe5 }); // mov rbp, rsp
|
try image.section_manager.appendCode(&.{ 0x48, 0x89, 0xe5 }); // mov rbp, rsp
|
||||||
|
|
||||||
// sub rsp, stack_offset
|
// sub rsp, stack_offset
|
||||||
if (std.math.cast(u8, stack_size)) |stack_size_u8| {
|
if (std.math.cast(u8, stack_size)) |stack_size_u8| {
|
||||||
image.appendCode(&.{ 0x48, 0x83, 0xec, stack_size_u8 });
|
try image.section_manager.appendCode(&.{ 0x48, 0x83, 0xec, stack_size_u8 });
|
||||||
} else {
|
} else {
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
@ -3828,7 +3804,7 @@ pub const MIR = struct {
|
|||||||
for (block.instructions.items) |instruction_index| {
|
for (block.instructions.items) |instruction_index| {
|
||||||
const instruction = mir.instructions.get(instruction_index);
|
const instruction = mir.instructions.get(instruction_index);
|
||||||
|
|
||||||
const instruction_offset = image.getTextSection().index;
|
const instruction_offset = image.section_manager.getCodeOffset();
|
||||||
|
|
||||||
switch (instruction.id) {
|
switch (instruction.id) {
|
||||||
.mov32r0 => {
|
.mov32r0 => {
|
||||||
@ -3838,14 +3814,14 @@ pub const MIR = struct {
|
|||||||
const new_instruction_id = Instruction.Id.xor32rr;
|
const new_instruction_id = Instruction.Id.xor32rr;
|
||||||
const instruction_descriptor = instruction_descriptors.get(new_instruction_id);
|
const instruction_descriptor = instruction_descriptors.get(new_instruction_id);
|
||||||
const opcode: u8 = @intCast(instruction_descriptor.opcode);
|
const opcode: u8 = @intCast(instruction_descriptor.opcode);
|
||||||
image.appendCodeByte(opcode);
|
try image.section_manager.appendCodeByte(opcode);
|
||||||
const direct = true;
|
const direct = true;
|
||||||
const modrm = ModRm{
|
const modrm = ModRm{
|
||||||
.rm = @intCast(@intFromEnum(gp_register_encoding)),
|
.rm = @intCast(@intFromEnum(gp_register_encoding)),
|
||||||
.reg = @intCast(@intFromEnum(gp_register_encoding)),
|
.reg = @intCast(@intFromEnum(gp_register_encoding)),
|
||||||
.mod = @as(u2, @intFromBool(direct)) << 1 | @intFromBool(direct),
|
.mod = @as(u2, @intFromBool(direct)) << 1 | @intFromBool(direct),
|
||||||
};
|
};
|
||||||
image.appendCodeByte(@bitCast(modrm));
|
try image.section_manager.appendCodeByte(@bitCast(modrm));
|
||||||
},
|
},
|
||||||
.ret => {},
|
.ret => {},
|
||||||
.mov32mr => {
|
.mov32mr => {
|
||||||
@ -3858,14 +3834,14 @@ pub const MIR = struct {
|
|||||||
const memory = destination_operand.u.memory;
|
const memory = destination_operand.u.memory;
|
||||||
const instruction_descriptor = instruction_descriptors.get(instruction.id);
|
const instruction_descriptor = instruction_descriptors.get(instruction.id);
|
||||||
const opcode: u8 = @intCast(instruction_descriptor.opcode);
|
const opcode: u8 = @intCast(instruction_descriptor.opcode);
|
||||||
image.appendCodeByte(opcode);
|
try image.section_manager.appendCodeByte(opcode);
|
||||||
|
|
||||||
const modrm = ModRm{
|
const modrm = ModRm{
|
||||||
.rm = @intFromEnum(Encoding.GP32.bp),
|
.rm = @intFromEnum(Encoding.GP32.bp),
|
||||||
.reg = @intCast(@intFromEnum(source_gp32)),
|
.reg = @intCast(@intFromEnum(source_gp32)),
|
||||||
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true),
|
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true),
|
||||||
};
|
};
|
||||||
image.appendCodeByte(@bitCast(modrm));
|
try image.section_manager.appendCodeByte(@bitCast(modrm));
|
||||||
|
|
||||||
switch (memory.addressing_mode.base) {
|
switch (memory.addressing_mode.base) {
|
||||||
.frame_index => |frame_index| {
|
.frame_index => |frame_index| {
|
||||||
@ -3873,7 +3849,7 @@ pub const MIR = struct {
|
|||||||
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 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];
|
const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes];
|
||||||
image.appendCode(stack_bytes);
|
try image.section_manager.appendCode(stack_bytes);
|
||||||
},
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
}
|
}
|
||||||
@ -3887,7 +3863,7 @@ pub const MIR = struct {
|
|||||||
.r = false,
|
.r = false,
|
||||||
.w = true,
|
.w = true,
|
||||||
};
|
};
|
||||||
image.appendCodeByte(@bitCast(rex));
|
try image.section_manager.appendCodeByte(@bitCast(rex));
|
||||||
|
|
||||||
const source_operand = mir.operands.get(instruction.operands.items[1]);
|
const source_operand = mir.operands.get(instruction.operands.items[1]);
|
||||||
const source_gp64 = getGP64Encoding(source_operand.*);
|
const source_gp64 = getGP64Encoding(source_operand.*);
|
||||||
@ -3897,14 +3873,14 @@ pub const MIR = struct {
|
|||||||
const memory = destination_operand.u.memory;
|
const memory = destination_operand.u.memory;
|
||||||
const instruction_descriptor = instruction_descriptors.get(instruction.id);
|
const instruction_descriptor = instruction_descriptors.get(instruction.id);
|
||||||
const opcode: u8 = @intCast(instruction_descriptor.opcode);
|
const opcode: u8 = @intCast(instruction_descriptor.opcode);
|
||||||
image.appendCodeByte(opcode);
|
try image.section_manager.appendCodeByte(opcode);
|
||||||
|
|
||||||
const modrm = ModRm{
|
const modrm = ModRm{
|
||||||
.rm = @intFromEnum(Encoding.GP64.bp),
|
.rm = @intFromEnum(Encoding.GP64.bp),
|
||||||
.reg = @intCast(@intFromEnum(source_gp64)),
|
.reg = @intCast(@intFromEnum(source_gp64)),
|
||||||
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true),
|
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true),
|
||||||
};
|
};
|
||||||
image.appendCodeByte(@bitCast(modrm));
|
try image.section_manager.appendCodeByte(@bitCast(modrm));
|
||||||
|
|
||||||
switch (memory.addressing_mode.base) {
|
switch (memory.addressing_mode.base) {
|
||||||
.frame_index => |frame_index| {
|
.frame_index => |frame_index| {
|
||||||
@ -3912,7 +3888,7 @@ pub const MIR = struct {
|
|||||||
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 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];
|
const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes];
|
||||||
image.appendCode(stack_bytes);
|
try image.section_manager.appendCode(stack_bytes);
|
||||||
},
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
}
|
}
|
||||||
@ -3922,7 +3898,7 @@ pub const MIR = struct {
|
|||||||
|
|
||||||
const instruction_descriptor = instruction_descriptors.get(instruction.id);
|
const instruction_descriptor = instruction_descriptors.get(instruction.id);
|
||||||
const opcode: u8 = @intCast(instruction_descriptor.opcode);
|
const opcode: u8 = @intCast(instruction_descriptor.opcode);
|
||||||
image.appendCodeByte(opcode);
|
try image.section_manager.appendCodeByte(opcode);
|
||||||
|
|
||||||
const destination_operand = mir.operands.get(instruction.operands.items[0]);
|
const destination_operand = mir.operands.get(instruction.operands.items[0]);
|
||||||
const destination_gp32 = getGP32Encoding(destination_operand.*);
|
const destination_gp32 = getGP32Encoding(destination_operand.*);
|
||||||
@ -3936,7 +3912,7 @@ pub const MIR = struct {
|
|||||||
.reg = @intCast(@intFromEnum(destination_gp32)),
|
.reg = @intCast(@intFromEnum(destination_gp32)),
|
||||||
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true),
|
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true),
|
||||||
};
|
};
|
||||||
image.appendCodeByte(@bitCast(modrm));
|
try image.section_manager.appendCodeByte(@bitCast(modrm));
|
||||||
|
|
||||||
switch (source_memory.addressing_mode.base) {
|
switch (source_memory.addressing_mode.base) {
|
||||||
.frame_index => |frame_index| {
|
.frame_index => |frame_index| {
|
||||||
@ -3944,7 +3920,7 @@ pub const MIR = struct {
|
|||||||
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 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];
|
const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes];
|
||||||
image.appendCode(stack_bytes);
|
try image.section_manager.appendCode(stack_bytes);
|
||||||
},
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
}
|
}
|
||||||
@ -3958,11 +3934,11 @@ pub const MIR = struct {
|
|||||||
.r = false,
|
.r = false,
|
||||||
.w = true,
|
.w = true,
|
||||||
};
|
};
|
||||||
image.appendCodeByte(@bitCast(rex));
|
try image.section_manager.appendCodeByte(@bitCast(rex));
|
||||||
|
|
||||||
const instruction_descriptor = instruction_descriptors.get(instruction.id);
|
const instruction_descriptor = instruction_descriptors.get(instruction.id);
|
||||||
const opcode: u8 = @intCast(instruction_descriptor.opcode);
|
const opcode: u8 = @intCast(instruction_descriptor.opcode);
|
||||||
image.appendCodeByte(opcode);
|
try image.section_manager.appendCodeByte(opcode);
|
||||||
|
|
||||||
const destination_operand = mir.operands.get(instruction.operands.items[0]);
|
const destination_operand = mir.operands.get(instruction.operands.items[0]);
|
||||||
const destination_gp64 = getGP64Encoding(destination_operand.*);
|
const destination_gp64 = getGP64Encoding(destination_operand.*);
|
||||||
@ -3976,7 +3952,7 @@ pub const MIR = struct {
|
|||||||
.reg = @intCast(@intFromEnum(destination_gp64)),
|
.reg = @intCast(@intFromEnum(destination_gp64)),
|
||||||
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true),
|
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true),
|
||||||
};
|
};
|
||||||
image.appendCodeByte(@bitCast(modrm));
|
try image.section_manager.appendCodeByte(@bitCast(modrm));
|
||||||
|
|
||||||
switch (source_memory.addressing_mode.base) {
|
switch (source_memory.addressing_mode.base) {
|
||||||
.frame_index => |frame_index| {
|
.frame_index => |frame_index| {
|
||||||
@ -3984,7 +3960,7 @@ pub const MIR = struct {
|
|||||||
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 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];
|
const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes];
|
||||||
image.appendCode(stack_bytes);
|
try image.section_manager.appendCode(stack_bytes);
|
||||||
},
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
}
|
}
|
||||||
@ -3999,9 +3975,9 @@ pub const MIR = struct {
|
|||||||
const destination_gp32 = getGP32Encoding(destination_operand.*);
|
const destination_gp32 = getGP32Encoding(destination_operand.*);
|
||||||
|
|
||||||
const opcode = @as(u8, 0xb8) | @as(u3, @intCast(@intFromEnum(destination_gp32)));
|
const opcode = @as(u8, 0xb8) | @as(u3, @intCast(@intFromEnum(destination_gp32)));
|
||||||
image.appendCodeByte(opcode);
|
try image.section_manager.appendCodeByte(opcode);
|
||||||
|
|
||||||
image.appendCode(std.mem.asBytes(&source_immediate));
|
try image.section_manager.appendCode(std.mem.asBytes(&source_immediate));
|
||||||
},
|
},
|
||||||
.mov32ri64 => {
|
.mov32ri64 => {
|
||||||
assert(instruction.operands.items.len == 2);
|
assert(instruction.operands.items.len == 2);
|
||||||
@ -4015,9 +3991,9 @@ pub const MIR = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const opcode = @as(u8, 0xb8) | @as(u3, @intCast(@intFromEnum(destination_gp32)));
|
const opcode = @as(u8, 0xb8) | @as(u3, @intCast(@intFromEnum(destination_gp32)));
|
||||||
image.appendCodeByte(opcode);
|
try image.section_manager.appendCodeByte(opcode);
|
||||||
|
|
||||||
image.appendCode(std.mem.asBytes(&source_immediate));
|
try image.section_manager.appendCode(std.mem.asBytes(&source_immediate));
|
||||||
},
|
},
|
||||||
.movsx64rm32 => {
|
.movsx64rm32 => {
|
||||||
assert(instruction.operands.items.len == 2);
|
assert(instruction.operands.items.len == 2);
|
||||||
@ -4034,18 +4010,18 @@ pub const MIR = struct {
|
|||||||
.r = false,
|
.r = false,
|
||||||
.w = true,
|
.w = true,
|
||||||
};
|
};
|
||||||
image.appendCodeByte(@bitCast(rex));
|
try image.section_manager.appendCodeByte(@bitCast(rex));
|
||||||
|
|
||||||
const instruction_descriptor = instruction_descriptors.get(instruction.id);
|
const instruction_descriptor = instruction_descriptors.get(instruction.id);
|
||||||
const opcode: u8 = @intCast(instruction_descriptor.opcode);
|
const opcode: u8 = @intCast(instruction_descriptor.opcode);
|
||||||
image.appendCodeByte(opcode);
|
try image.section_manager.appendCodeByte(opcode);
|
||||||
|
|
||||||
const modrm = ModRm{
|
const modrm = ModRm{
|
||||||
.rm = @intFromEnum(Encoding.GP32.bp),
|
.rm = @intFromEnum(Encoding.GP32.bp),
|
||||||
.reg = @intCast(@intFromEnum(destination_register)),
|
.reg = @intCast(@intFromEnum(destination_register)),
|
||||||
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true),
|
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true),
|
||||||
};
|
};
|
||||||
image.appendCodeByte(@bitCast(modrm));
|
try image.section_manager.appendCodeByte(@bitCast(modrm));
|
||||||
|
|
||||||
switch (source_memory.addressing_mode.base) {
|
switch (source_memory.addressing_mode.base) {
|
||||||
.frame_index => |frame_index| {
|
.frame_index => |frame_index| {
|
||||||
@ -4053,25 +4029,25 @@ pub const MIR = struct {
|
|||||||
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 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];
|
const stack_bytes = std.mem.asBytes(&stack_offset)[0..displacement_bytes];
|
||||||
image.appendCode(stack_bytes);
|
try image.section_manager.appendCode(stack_bytes);
|
||||||
},
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.syscall => image.appendCode(&.{ 0x0f, 0x05 }),
|
.syscall => try image.section_manager.appendCode(&.{ 0x0f, 0x05 }),
|
||||||
.ud2 => image.appendCode(&.{ 0x0f, 0x0b }),
|
.ud2 => try image.section_manager.appendCode(&.{ 0x0f, 0x0b }),
|
||||||
.call64pcrel32 => {
|
.call64pcrel32 => {
|
||||||
// TODO: emit relocation
|
// TODO: emit relocation
|
||||||
assert(instruction.operands.items.len == 1);
|
assert(instruction.operands.items.len == 1);
|
||||||
const operand = mir.operands.get(instruction.operands.items[0]);
|
const operand = mir.operands.get(instruction.operands.items[0]);
|
||||||
const instruction_descriptor = instruction_descriptors.get(instruction.id);
|
const instruction_descriptor = instruction_descriptors.get(instruction.id);
|
||||||
const opcode: u8 = @intCast(instruction_descriptor.opcode);
|
const opcode: u8 = @intCast(instruction_descriptor.opcode);
|
||||||
image.appendCodeByte(opcode);
|
try image.section_manager.appendCodeByte(opcode);
|
||||||
|
|
||||||
switch (operand.u) {
|
switch (operand.u) {
|
||||||
.pc_relative => |pc_relative| {
|
.pc_relative => |pc_relative| {
|
||||||
// TODO: fix
|
// TODO: fix
|
||||||
const callee = pc_relative.function_declaration;
|
const callee: Function.Index = @bitCast(pc_relative.index);
|
||||||
const caller = function_index;
|
const caller = function_index;
|
||||||
|
|
||||||
const instruction_len = 5;
|
const instruction_len = 5;
|
||||||
@ -4080,9 +4056,10 @@ pub const MIR = struct {
|
|||||||
const callee_offset: i64 = @intCast(function_offsets.get(callee).?);
|
const callee_offset: i64 = @intCast(function_offsets.get(callee).?);
|
||||||
const caller_offset: i64 = @intCast(instruction_offset + instruction_len);
|
const caller_offset: i64 = @intCast(instruction_offset + instruction_len);
|
||||||
const offset: i32 = @intCast(callee_offset - caller_offset);
|
const offset: i32 = @intCast(callee_offset - caller_offset);
|
||||||
image.appendCode(std.mem.asBytes(&offset));
|
try image.section_manager.appendCode(std.mem.asBytes(&offset));
|
||||||
} else {
|
} else {
|
||||||
image.appendCode(&.{ 0, 0, 0, 0 });
|
// TODO: handle relocation
|
||||||
|
try image.section_manager.appendCode(&.{ 0, 0, 0, 0 });
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -4097,7 +4074,7 @@ pub const MIR = struct {
|
|||||||
|
|
||||||
switch (destination_operand.id) {
|
switch (destination_operand.id) {
|
||||||
.gp32 => {
|
.gp32 => {
|
||||||
image.appendCodeByte(0x89);
|
try image.section_manager.appendCodeByte(0x89);
|
||||||
|
|
||||||
const destination_register = getGP32Encoding(destination_operand.*);
|
const destination_register = getGP32Encoding(destination_operand.*);
|
||||||
const source_register = getGP32Encoding(source_operand.*);
|
const source_register = getGP32Encoding(source_operand.*);
|
||||||
@ -4106,7 +4083,8 @@ pub const MIR = struct {
|
|||||||
.reg = @intCast(@intFromEnum(source_register)),
|
.reg = @intCast(@intFromEnum(source_register)),
|
||||||
.mod = @as(u2, @intFromBool(true)) << 1 | @intFromBool(true),
|
.mod = @as(u2, @intFromBool(true)) << 1 | @intFromBool(true),
|
||||||
};
|
};
|
||||||
image.appendCodeByte(@bitCast(modrm));
|
|
||||||
|
try image.section_manager.appendCodeByte(@bitCast(modrm));
|
||||||
},
|
},
|
||||||
.gp64 => {
|
.gp64 => {
|
||||||
const rex = Rex{
|
const rex = Rex{
|
||||||
@ -4115,9 +4093,9 @@ pub const MIR = struct {
|
|||||||
.r = false,
|
.r = false,
|
||||||
.w = true,
|
.w = true,
|
||||||
};
|
};
|
||||||
image.appendCodeByte(@bitCast(rex));
|
try image.section_manager.appendCodeByte(@bitCast(rex));
|
||||||
|
|
||||||
image.appendCodeByte(0x89);
|
try image.section_manager.appendCodeByte(0x89);
|
||||||
|
|
||||||
const destination_register = getGP64Encoding(destination_operand.*);
|
const destination_register = getGP64Encoding(destination_operand.*);
|
||||||
const source_register = getGP64Encoding(source_operand.*);
|
const source_register = getGP64Encoding(source_operand.*);
|
||||||
@ -4126,7 +4104,7 @@ pub const MIR = struct {
|
|||||||
.reg = @intCast(@intFromEnum(source_register)),
|
.reg = @intCast(@intFromEnum(source_register)),
|
||||||
.mod = @as(u2, @intFromBool(true)) << 1 | @intFromBool(true),
|
.mod = @as(u2, @intFromBool(true)) << 1 | @intFromBool(true),
|
||||||
};
|
};
|
||||||
image.appendCodeByte(@bitCast(modrm));
|
try image.section_manager.appendCodeByte(@bitCast(modrm));
|
||||||
},
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
}
|
}
|
||||||
@ -4139,11 +4117,11 @@ pub const MIR = struct {
|
|||||||
.r = false,
|
.r = false,
|
||||||
.w = true,
|
.w = true,
|
||||||
};
|
};
|
||||||
image.appendCodeByte(@bitCast(rex));
|
try image.section_manager.appendCodeByte(@bitCast(rex));
|
||||||
|
|
||||||
const instruction_descriptor = instruction_descriptors.get(instruction.id);
|
const instruction_descriptor = instruction_descriptors.get(instruction.id);
|
||||||
const opcode: u8 = @intCast(instruction_descriptor.opcode);
|
const opcode: u8 = @intCast(instruction_descriptor.opcode);
|
||||||
image.appendCodeByte(opcode);
|
try image.section_manager.appendCodeByte(opcode);
|
||||||
|
|
||||||
const destination_operand = mir.operands.get(instruction.operands.items[0]);
|
const destination_operand = mir.operands.get(instruction.operands.items[0]);
|
||||||
const destination_register = getGP64Encoding(destination_operand.*);
|
const destination_register = getGP64Encoding(destination_operand.*);
|
||||||
@ -4153,7 +4131,7 @@ pub const MIR = struct {
|
|||||||
.reg = @intCast(@intFromEnum(destination_register)),
|
.reg = @intCast(@intFromEnum(destination_register)),
|
||||||
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(false),
|
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(false),
|
||||||
};
|
};
|
||||||
image.appendCodeByte(@bitCast(modrm));
|
try image.section_manager.appendCodeByte(@bitCast(modrm));
|
||||||
|
|
||||||
const source_operand = mir.operands.get(instruction.operands.items[1]);
|
const source_operand = mir.operands.get(instruction.operands.items[1]);
|
||||||
switch (source_operand.u) {
|
switch (source_operand.u) {
|
||||||
@ -4162,19 +4140,30 @@ pub const MIR = struct {
|
|||||||
assert(lea64mem.scale == 1);
|
assert(lea64mem.scale == 1);
|
||||||
assert(lea64mem.scale_reg == null);
|
assert(lea64mem.scale_reg == null);
|
||||||
|
|
||||||
switch (lea64mem.displacement) {
|
if (lea64mem.displacement.section == image.section_manager.rodata orelse unreachable) {
|
||||||
.string_literal => unreachable,
|
try image.section_manager.linker_relocations.append(mir.allocator, .{
|
||||||
else => unreachable,
|
.source = .{
|
||||||
|
.offset = @intCast(image.section_manager.getCodeOffset() + @sizeOf(i32)),
|
||||||
|
.index = image.section_manager.getTextSectionIndex(),
|
||||||
|
},
|
||||||
|
.target = .{
|
||||||
|
.offset = lea64mem.displacement.index,
|
||||||
|
.index = lea64mem.displacement.section,
|
||||||
|
},
|
||||||
|
.offset = -@sizeOf(i32),
|
||||||
|
});
|
||||||
|
try image.section_manager.appendCode(&.{ 0, 0, 0, 0 });
|
||||||
|
} else {
|
||||||
|
unreachable;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
}
|
}
|
||||||
unreachable;
|
|
||||||
},
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
}
|
}
|
||||||
|
|
||||||
if (instruction_offset != image.getTextSection().index) {
|
if (instruction_offset != image.section_manager.getCodeOffset()) {
|
||||||
const print_tags = true;
|
const print_tags = true;
|
||||||
if (print_tags) {
|
if (print_tags) {
|
||||||
var offset = @tagName(instruction.id).len + 2;
|
var offset = @tagName(instruction.id).len + 2;
|
||||||
@ -4184,7 +4173,8 @@ pub const MIR = struct {
|
|||||||
log(.codegen, .encoding, " ", .{});
|
log(.codegen, .encoding, " ", .{});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (image.getTextSection().content[instruction_offset..image.getTextSection().index]) |byte| {
|
|
||||||
|
for (image.section_manager.getTextSection().bytes.items[instruction_offset..]) |byte| {
|
||||||
log(.codegen, .encoding, "0x{x:0>2} ", .{byte});
|
log(.codegen, .encoding, "0x{x:0>2} ", .{byte});
|
||||||
}
|
}
|
||||||
log(.codegen, .encoding, "\n", .{});
|
log(.codegen, .encoding, "\n", .{});
|
||||||
@ -4201,15 +4191,15 @@ pub const MIR = struct {
|
|||||||
if (stack_size != 0) {
|
if (stack_size != 0) {
|
||||||
// add rsp, stack_offset
|
// add rsp, stack_offset
|
||||||
if (std.math.cast(u8, stack_size)) |stack_size_u8| {
|
if (std.math.cast(u8, stack_size)) |stack_size_u8| {
|
||||||
image.appendCode(&.{ 0x48, 0x83, 0xc4, stack_size_u8 });
|
try image.section_manager.appendCode(&.{ 0x48, 0x83, 0xc4, stack_size_u8 });
|
||||||
} else {
|
} else {
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
image.appendCodeByte(0x5d); // pop rbp
|
try image.section_manager.appendCodeByte(0x5d); // pop rbp
|
||||||
}
|
}
|
||||||
|
|
||||||
image.appendCodeByte(0xc3);
|
try image.section_manager.appendCodeByte(0xc3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ const assert = std.debug.assert;
|
|||||||
pub const Allocator = std.mem.Allocator;
|
pub const Allocator = std.mem.Allocator;
|
||||||
pub const AutoArrayHashMap = std.AutoArrayHashMapUnmanaged;
|
pub const AutoArrayHashMap = std.AutoArrayHashMapUnmanaged;
|
||||||
pub const ArrayList = std.ArrayListUnmanaged;
|
pub const ArrayList = std.ArrayListUnmanaged;
|
||||||
|
pub const ArrayListAligned = std.ArrayListAlignedUnmanaged;
|
||||||
pub const AutoHashMap = std.AutoHashMapUnmanaged;
|
pub const AutoHashMap = std.AutoHashMapUnmanaged;
|
||||||
pub const HashMap = std.HashMapUnmanaged;
|
pub const HashMap = std.HashMapUnmanaged;
|
||||||
pub const SegmentedList = std.SegmentedList;
|
pub const SegmentedList = std.SegmentedList;
|
||||||
|
@ -982,11 +982,37 @@ const Analyzer = struct {
|
|||||||
fn processStringLiteral(analyzer: *Analyzer, scope_index: Scope.Index, node_index: Node.Index) !u32 {
|
fn processStringLiteral(analyzer: *Analyzer, scope_index: Scope.Index, node_index: Node.Index) !u32 {
|
||||||
const string_literal_node = analyzer.getScopeNode(scope_index, node_index);
|
const string_literal_node = analyzer.getScopeNode(scope_index, node_index);
|
||||||
assert(string_literal_node.id == .string_literal);
|
assert(string_literal_node.id == .string_literal);
|
||||||
const string_literal = analyzer.tokenStringLiteral(scope_index, string_literal_node.token);
|
const original_string_literal = analyzer.tokenStringLiteral(scope_index, string_literal_node.token);
|
||||||
|
const string_literal = for (original_string_literal) |ch| {
|
||||||
|
if (ch == '\\') {
|
||||||
|
break try fixupStringLiteral(analyzer.allocator, original_string_literal);
|
||||||
|
}
|
||||||
|
} else original_string_literal;
|
||||||
const string_key = try analyzer.module.addStringLiteral(analyzer.allocator, string_literal);
|
const string_key = try analyzer.module.addStringLiteral(analyzer.allocator, string_literal);
|
||||||
return string_key;
|
return string_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fixupStringLiteral(allocator: Allocator, string_literal: []const u8) ![]const u8 {
|
||||||
|
var result = try ArrayList(u8).initCapacity(allocator, string_literal.len - 1);
|
||||||
|
var i: usize = 0;
|
||||||
|
|
||||||
|
while (i < string_literal.len) : (i += 1) {
|
||||||
|
const ch = string_literal[i];
|
||||||
|
if (ch != '\\') {
|
||||||
|
result.appendAssumeCapacity(ch);
|
||||||
|
} else {
|
||||||
|
const next_ch: u8 = switch (string_literal[i + 1]) {
|
||||||
|
'n' => '\n',
|
||||||
|
else => |next_ch| panic("Unexpected character: {c}, 0x{x}", .{ next_ch, next_ch }),
|
||||||
|
};
|
||||||
|
result.appendAssumeCapacity(next_ch);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.items;
|
||||||
|
}
|
||||||
|
|
||||||
fn functionPrototypeReturnType(analyzer: *Analyzer, function_prototype_index: Function.Prototype.Index) Type.Index {
|
fn functionPrototypeReturnType(analyzer: *Analyzer, function_prototype_index: Function.Prototype.Index) Type.Index {
|
||||||
const function_prototype = analyzer.module.function_prototypes.get(function_prototype_index);
|
const function_prototype = analyzer.module.function_prototypes.get(function_prototype_index);
|
||||||
return function_prototype.return_type;
|
return function_prototype.return_type;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user