Fix register allocator for barebones use

This commit is contained in:
David Gonzalez Martin 2023-11-08 22:26:22 -06:00
parent b24bd8221e
commit 30baa0b53d
6 changed files with 305 additions and 383 deletions

View File

@ -5,5 +5,5 @@ comptime {
const _start = fn () noreturn { const _start = fn () noreturn {
const result = #import("main").main(); const result = #import("main").main();
std.os.exit(0); std.os.exit(result);
} }

View File

@ -100,7 +100,7 @@ fn parseArguments(allocator: Allocator) !Compilation.Module.Descriptor {
} }
} else if (!recognized_particular) std.debug.panic("Unrecognized particular log \"{s}\" in scope {s}", .{ particular_log_candidate, @tagName(log_scope) }); } else if (!recognized_particular) std.debug.panic("Unrecognized particular log \"{s}\" in scope {s}", .{ particular_log_candidate, @tagName(log_scope) });
} else { } else {
unreachable; // LogScope.Logger.bitset = @TypeOf(LogScope.Logger.bitset).initFull();
} }
logger_bitset.setPresent(log_scope, true); logger_bitset.setPresent(log_scope, true);
@ -1117,10 +1117,6 @@ pub const File = struct {
} }
}; };
pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, return_address: ?usize) noreturn {
std.builtin.default_panic(message, stack_trace, return_address);
}
const LoggerScope = enum { const LoggerScope = enum {
compilation, compilation,
lexer, lexer,
@ -1170,3 +1166,16 @@ pub fn log(comptime logger_scope: LoggerScope, logger: getLoggerScopeType(logger
std.fmt.format(writer, format, arguments) catch unreachable; std.fmt.format(writer, format, arguments) catch unreachable;
} }
} }
pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, return_address: ?usize) noreturn {
const print_stack_trace = true;
switch (print_stack_trace) {
true => std.builtin.default_panic(message, stack_trace, return_address),
false => {
writer.writeAll("\nPANIC: ") catch {};
writer.writeAll(message) catch {};
writer.writeByte('\n') catch {};
std.os.abort();
},
}
}

View File

@ -19,7 +19,9 @@ pub const Logger = enum {
function, function,
phi_removal, phi_removal,
pub var bitset = std.EnumSet(Logger).initEmpty(); pub var bitset = std.EnumSet(Logger).initMany(&.{
.function,
});
}; };
pub const Result = struct { pub const Result = struct {

View File

@ -487,7 +487,7 @@ pub fn interpretFile(allocator: Allocator, descriptor: Compilation.Module.Descri
_ = allocator; _ = allocator;
_ = descriptor; _ = descriptor;
const header: *const Header = @ptrCast(@alignCast(file.ptr)); const header: *const Header = @ptrCast(@alignCast(file.ptr));
print("Header : {}\n", .{header}); print("Header : {}", .{header});
assert(header.magic == Header.magic); assert(header.magic == Header.magic);
var text_segment: LoadCommand.Segment64 = undefined; var text_segment: LoadCommand.Segment64 = undefined;
@ -503,69 +503,69 @@ pub fn interpretFile(allocator: Allocator, descriptor: Compilation.Module.Descri
if (equal(u8, segment_load_command.name[0..text_segment_name.len], text_segment_name)) { if (equal(u8, segment_load_command.name[0..text_segment_name.len], text_segment_name)) {
text_segment = segment_load_command.*; text_segment = segment_load_command.*;
} }
print("SLC: {}\n", .{segment_load_command}); print("SLC: {}", .{segment_load_command});
print("segment name: {s}\n", .{segment_load_command.name}); print("segment name: {s}", .{segment_load_command.name});
const section_ptr: [*]const LoadCommand.Segment64.Section = @ptrFromInt(@intFromPtr(segment_load_command) + @sizeOf(LoadCommand.Segment64)); const section_ptr: [*]const LoadCommand.Segment64.Section = @ptrFromInt(@intFromPtr(segment_load_command) + @sizeOf(LoadCommand.Segment64));
const sections = section_ptr[0..segment_load_command.section_count]; const sections = section_ptr[0..segment_load_command.section_count];
for (sections) |section| { for (sections) |section| {
print("{}\n", .{section}); print("{}", .{section});
print("Section name: {s}. Segment name: {s}\n", .{ section.name, section.segment_name }); print("Section name: {s}. Segment name: {s}", .{ section.name, section.segment_name });
} }
}, },
.dyld_chained_fixups => { .dyld_chained_fixups => {
const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr));
print("command: {}\n", .{command}); print("command: {}", .{command});
}, },
.dyld_exports_trie => { .dyld_exports_trie => {
const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr));
print("command: {}\n", .{command}); print("command: {}", .{command});
}, },
.symbol_table => { .symbol_table => {
const command: *const LoadCommand.SymbolTable = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.SymbolTable = @ptrCast(@alignCast(load_command_ptr));
print("command: {}\n", .{command}); print("command: {}", .{command});
}, },
.symbol_table_information => { .symbol_table_information => {
const command: *const LoadCommand.SymbolTableInformation = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.SymbolTableInformation = @ptrCast(@alignCast(load_command_ptr));
print("command: {}\n", .{command}); print("command: {}", .{command});
}, },
.load_dylinker => { .load_dylinker => {
const command: *const LoadCommand.Dylinker = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.Dylinker = @ptrCast(@alignCast(load_command_ptr));
print("command: {}\n", .{command}); print("command: {}", .{command});
const name: [*:0]const u8 = @ptrFromInt(@intFromPtr(command) + command.name_offset); const name: [*:0]const u8 = @ptrFromInt(@intFromPtr(command) + command.name_offset);
print("Name: {s}\n", .{name}); print("Name: {s}", .{name});
}, },
.uuid_number => { .uuid_number => {
const command: *const LoadCommand.Uuid = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.Uuid = @ptrCast(@alignCast(load_command_ptr));
print("command: {}\n", .{command}); print("command: {}", .{command});
}, },
.minimum_os_version => { .minimum_os_version => {
const command: *const LoadCommand.MinimumVersion = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.MinimumVersion = @ptrCast(@alignCast(load_command_ptr));
print("command: {}\n", .{command}); print("command: {}", .{command});
}, },
.source_version => { .source_version => {
const command: *const LoadCommand.SourceVersion = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.SourceVersion = @ptrCast(@alignCast(load_command_ptr));
print("command: {}\n", .{command}); print("command: {}", .{command});
}, },
.dyld_main_entry_point => { .dyld_main_entry_point => {
const command: *const LoadCommand.EntryPoint = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.EntryPoint = @ptrCast(@alignCast(load_command_ptr));
print("command: {}\n", .{command}); print("command: {}", .{command});
}, },
.load_dylib => { .load_dylib => {
const command: *const LoadCommand.Dylib = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.Dylib = @ptrCast(@alignCast(load_command_ptr));
print("command: {}\n", .{command}); print("command: {}", .{command});
print("Dylib: {s}\n", .{@as([*:0]const u8, @ptrFromInt(@intFromPtr(load_command_ptr) + @sizeOf(LoadCommand.Dylib)))}); print("Dylib: {s}", .{@as([*:0]const u8, @ptrFromInt(@intFromPtr(load_command_ptr) + @sizeOf(LoadCommand.Dylib)))});
}, },
.function_starts => { .function_starts => {
const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr));
print("command: {}\n", .{command}); print("command: {}", .{command});
}, },
.data_in_code => { .data_in_code => {
const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr));
print("command: {}\n", .{command}); print("command: {}", .{command});
}, },
.code_signature => { .code_signature => {
const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr)); const command: *const LoadCommand.LinkeditData = @ptrCast(@alignCast(load_command_ptr));
print("command: {}\n", .{command}); print("command: {}", .{command});
}, },
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }

View File

@ -22,21 +22,21 @@ pub const Writer = struct {
} }
pub fn writeToMemory(writer: *Writer, image: *const emit.Result) !void { pub fn writeToMemory(writer: *Writer, image: *const emit.Result) !void {
print("File len: {}\n", .{writer.in_file.len}); print("File len: {}", .{writer.in_file.len});
const dos_header: *const ImageDosHeader = @ptrCast(@alignCast(writer.in_file.ptr)); const dos_header: *const ImageDosHeader = @ptrCast(@alignCast(writer.in_file.ptr));
print("File address: {}\n", .{dos_header.file_address_of_new_exe_header}); print("File address: {}", .{dos_header.file_address_of_new_exe_header});
print("File: {s}\n", .{writer.in_file[0x40..]}); print("File: {s}", .{writer.in_file[0x40..]});
for (writer.in_file[0x40..], 0..) |byte, index| { for (writer.in_file[0x40..], 0..) |byte, index| {
if (byte == 'T') { if (byte == 'T') {
print("Index: {}\n", .{index}); print("Index: {}", .{index});
break; break;
} }
} }
assert(dos_header.magic_number == ImageDosHeader.magic); assert(dos_header.magic_number == ImageDosHeader.magic);
// assert(dos_header.file_address_of_new_exe_header == @sizeOf(ImageDosHeader)); // assert(dos_header.file_address_of_new_exe_header == @sizeOf(ImageDosHeader));
print("{}\n", .{dos_header}); print("{}", .{dos_header});
const file_header: *const ImageFileHeader = @ptrCast(@alignCast(writer.in_file[dos_header.file_address_of_new_exe_header + 4 ..].ptr)); const file_header: *const ImageFileHeader = @ptrCast(@alignCast(writer.in_file[dos_header.file_address_of_new_exe_header + 4 ..].ptr));
print("File header: {}\n", .{file_header}); print("File header: {}", .{file_header});
writer.append(std.mem.asBytes(&ImageDosHeader{ writer.append(std.mem.asBytes(&ImageDosHeader{
.file_address_of_new_exe_header = 208, .file_address_of_new_exe_header = 208,

View File

@ -24,6 +24,7 @@ pub const Logger = enum {
instruction_selection_new_instruction, instruction_selection_new_instruction,
instruction_selection_cache_flush, instruction_selection_cache_flush,
instruction_selection_mir_function, instruction_selection_mir_function,
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,
@ -35,7 +36,20 @@ pub const Logger = enum {
register_allocation_function_after, register_allocation_function_after,
register_allocation_operand_list_verification, register_allocation_operand_list_verification,
pub var bitset = std.EnumSet(Logger).initEmpty(); pub var bitset = std.EnumSet(Logger).initMany(&.{
.instruction_selection_ir_function,
// .instruction_selection_register_operand_list,
.register_allocation_block,
// .register_allocation_problematic_hint,
// .register_allocation_assignment,
// .register_allocation_reload,
.register_allocation_function_before,
// .register_allocation_new_instruction,
// .register_allocation_new_instruction_function_before,
// .register_allocation_instruction_avoid_copy,
.register_allocation_function_after,
.register_allocation_operand_list_verification,
});
}; };
const Register = struct { const Register = struct {
@ -1025,7 +1039,7 @@ const InstructionSelection = struct {
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
}, },
else => std.debug.panic("Stack object size: {}\n", .{stack_object.size}), else => std.debug.panic("Stack object size: {}", .{stack_object.size}),
} }
} }
@ -1104,12 +1118,12 @@ const InstructionSelection = struct {
destination_operand, destination_operand,
source_operand, source_operand,
}); });
logln(.codegen, .register_allocation_new_instructions, "Inserting instruction at index {}\n", .{insert_before_instruction_index}); logln(.codegen, .register_allocation_new_instructions, "Inserting instruction at index {}", .{insert_before_instruction_index});
try mir.blocks.get(instruction_selection.current_block).instructions.insert(mir.allocator, insert_before_instruction_index, instruction_index); try mir.blocks.get(instruction_selection.current_block).instructions.insert(mir.allocator, insert_before_instruction_index, instruction_index);
}, },
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}, },
else => panic("Stack object size: {} bits\n", .{stack_object.size}), else => panic("Stack object size: {} bits", .{stack_object.size}),
} }
} }
@ -1285,7 +1299,7 @@ const InstructionSelection = struct {
// if (std.meta.eql(stored_register, register)) { // if (std.meta.eql(stored_register, register)) {
// unreachable; // unreachable;
// } else { // } else {
// std.debug.panic("Register mismatch: Stored: {} Got: {}\n", .{ stored_register, register }); // std.debug.panic("Register mismatch: Stored: {} Got: {}", .{ stored_register, register });
// } // }
// } else { // } else {
// gop.value_ptr.* = register; // gop.value_ptr.* = register;
@ -1365,9 +1379,7 @@ const InstructionSelection = struct {
}, },
}, },
}, },
.flags = .{ .flags = .{},
.type = .def,
},
}, },
}); });
@ -1537,18 +1549,25 @@ const Instruction = struct {
fn next(it: *I) ?ReturnValue.Index { fn next(it: *I) ?ReturnValue.Index {
const original_operand_index = it.index; const original_operand_index = it.index;
switch (it.index.invalid) { switch (it.index.invalid) {
false => switch (arguments.element) { false => switch (arguments.element) {
.instruction => { .instruction => {
const original_operand = it.mir.operands.get(original_operand_index); const original_operand = it.mir.operands.get(original_operand_index);
const instruction = original_operand.parent; const instruction = original_operand.parent;
// const i_desc = it.mir.instructions.get(instruction); // const i_desc = it.mir.instructions.get(instruction);
// print("Instruction: {}\n", .{i_desc.id}); // print("Instruction: {}", .{i_desc.id});
while (true) { while (true) {
it.advance(); it.advance();
if (it.index.invalid) break;
if (it.index.invalid) {
break;
}
const it_operand = it.mir.operands.get(it.index); const it_operand = it.mir.operands.get(it.index);
if (!it_operand.parent.eq(instruction)) break; if (!it_operand.parent.eq(instruction)) {
break;
}
} }
return instruction; return instruction;
@ -1576,16 +1595,8 @@ const Instruction = struct {
assert(!it.index.invalid); assert(!it.index.invalid);
it.advanceRaw(); it.advanceRaw();
if (!arguments.use) { switch (arguments.use) {
if (!it.index.invalid) { true => {
const operand = it.mir.operands.get(it.index);
if (operand.flags.type == .use) {
it.index = Operand.Index.invalid;
} else {
//TODO: assert that is not debug
}
}
} else {
while (!it.index.invalid) { while (!it.index.invalid) {
const operand = it.mir.operands.get(it.index); const operand = it.mir.operands.get(it.index);
if (!arguments.def and operand.flags.type == .def) { if (!arguments.def and operand.flags.type == .def) {
@ -1594,15 +1605,34 @@ const Instruction = struct {
break; break;
} }
} }
},
false => {
if (!it.index.invalid) {
const operand = it.mir.operands.get(it.index);
if (operand.flags.type == .use) {
it.index = Operand.Index.invalid;
} else {
//TODO: assert that is not debug
}
}
},
} }
} }
fn advanceRaw(it: *I) void { fn advanceRaw(it: *I) void {
assert(!it.index.invalid); assert(!it.index.invalid);
const current_operand = it.mir.operands.get(it.index); const old_index = it.index;
const current_operand = it.mir.operands.get(old_index);
assert(current_operand.u == .register); assert(current_operand.u == .register);
const next_index = current_operand.u.register.list.next; const next_index = current_operand.u.register.list.next;
it.index = next_index; it.index = next_index;
if (it.index.invalid) {
logln(.codegen, .register_allocation_problematic_hint, "[ITERATOR] O{} -> NULL operand index", .{old_index.uniqueInteger()});
} else {
const operand = it.mir.operands.get(it.index);
logln(.codegen, .register_allocation_problematic_hint, "[ITERATOR] O{} -> O{}: {}", .{ old_index.uniqueInteger(), it.index.uniqueInteger(), operand.flags });
}
} }
}; };
} }
@ -2024,7 +2054,7 @@ pub const MIR = struct {
virtual_registers: BlockList(Register.Virtual) = .{}, virtual_registers: BlockList(Register.Virtual) = .{},
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\n", .{}); logln(.codegen, .instruction_selection_block, "\n[INSTRUCTION SELECTION]\n", .{});
const mir = try allocator.create(MIR); const mir = try allocator.create(MIR);
mir.* = .{ mir.* = .{
.allocator = allocator, .allocator = allocator,
@ -2040,7 +2070,7 @@ pub const MIR = struct {
while (function_definition_iterator.nextPointer()) |ir_function| { while (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, "=========\n{}=========\n", .{ir_function}); 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);
@ -2108,7 +2138,7 @@ pub const MIR = struct {
instruction_selection.local_value_map.clearRetainingCapacity(); instruction_selection.local_value_map.clearRetainingCapacity();
logln(.codegen, .instruction_selection_new_instruction, "Instruction #{}\n", .{instruction_i}); logln(.codegen, .instruction_selection_new_instruction, "Instruction #{}", .{instruction_i});
switch (ir_instruction.*) { switch (ir_instruction.*) {
.ret => |ir_ret_index| { .ret => |ir_ret_index| {
@ -2174,7 +2204,7 @@ pub const MIR = struct {
const syscall_register_list = calling_convention.syscall_registers[0..ir_syscall.arguments.items.len]; const syscall_register_list = calling_convention.syscall_registers[0..ir_syscall.arguments.items.len];
for (ir_syscall.arguments.items, syscall_register_list) |ir_argument_index, syscall_register| { for (ir_syscall.arguments.items, syscall_register_list) |ir_argument_index, syscall_register| {
//print("index: {}\n", .{index}); //print("index: {}", .{index});
const source_register = try instruction_selection.getRegisterForValue(mir, ir_argument_index); const source_register = try instruction_selection.getRegisterForValue(mir, ir_argument_index);
const destination_register = Register{ const destination_register = Register{
.index = .{ .index = .{
@ -2445,12 +2475,12 @@ pub const MIR = struct {
.call => |ir_call_index| { .call => |ir_call_index| {
const ir_call = mir.ir.calls.get(ir_call_index); const ir_call = mir.ir.calls.get(ir_call_index);
for (ir_call.arguments, 0..) |ir_argument_index, index| { for (ir_call.arguments, 0..) |ir_argument_index, index| {
// print("index: {}\n", .{index}); // print("index: {}", .{index});
const source_register = try instruction_selection.getRegisterForValue(mir, ir_argument_index); const source_register = try instruction_selection.getRegisterForValue(mir, ir_argument_index);
const source_value_type = resolveType(getIrType(mir.ir, ir_argument_index)); const source_value_type = resolveType(getIrType(mir.ir, ir_argument_index));
const source_register_class = register_classes.get(source_value_type); const source_register_class = register_classes.get(source_value_type);
const argument_register = calling_convention.argument_registers.get(source_register_class)[index]; const argument_register = calling_convention.argument_registers.get(source_register_class)[index];
// print("Argument register: {}\n", .{argument_register}); // print("Argument register: {}", .{argument_register});
const destination_register = Register{ const destination_register = Register{
.index = .{ .index = .{
@ -2564,7 +2594,7 @@ pub const MIR = struct {
const instruction_index = instruction_selection.instruction_cache.items[i]; const instruction_index = instruction_selection.instruction_cache.items[i];
const instruction = mir.instructions.get(instruction_index); const instruction = mir.instructions.get(instruction_index);
logln(.codegen, .instruction_selection_cache_flush, "Inserting instruction #{} ({s}) into index {} (instruction count: {})\n", .{ instruction_index.uniqueInteger(), @tagName(instruction.id), block.current_stack_index, block.instructions.items.len }); logln(.codegen, .instruction_selection_cache_flush, "Inserting instruction #{} ({s}) into index {} (instruction count: {})", .{ instruction_index.uniqueInteger(), @tagName(instruction.id), block.current_stack_index, block.instructions.items.len });
try block.instructions.insert(mir.allocator, block.current_stack_index, instruction_index); try block.instructions.insert(mir.allocator, block.current_stack_index, instruction_index);
} }
@ -2574,7 +2604,7 @@ 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_mir_function, "=========\n{}=========\n", .{function}); logln(.codegen, .instruction_selection_ir_function, "Selected instructions for {}", .{function});
} }
return mir; return mir;
@ -2618,13 +2648,17 @@ pub const MIR = struct {
const head_index_ptr = mir.getRegisterListHead(instruction_selection, operand.u.register); const head_index_ptr = mir.getRegisterListHead(instruction_selection, operand.u.register);
const head_index = head_index_ptr.*; const head_index = head_index_ptr.*;
logln(.codegen, .instruction_selection_register_operand_list, "Adding register list metadata to operand #{}", .{operand_index.uniqueInteger()});
switch (head_index.invalid) { switch (head_index.invalid) {
false => { false => {
const head_operand = mir.operands.get(head_index); const head_operand = mir.operands.get(head_index);
assert(std.meta.eql(head_operand.u.register.index, operand.u.register.index)); assert(std.meta.eql(head_operand.u.register.index, operand.u.register.index));
const last_operand_index = head_operand.u.register.list.previous; const last_operand_index = head_operand.u.register.list.previous;
const last_operand = mir.operands.get(last_operand_index); const last_operand = mir.operands.get(last_operand_index);
assert(std.meta.eql(last_operand.u.register.index, operand.u.register.index)); assert(std.meta.eql(last_operand.u.register.index, operand.u.register.index));
head_operand.u.register.list.previous = operand_index; head_operand.u.register.list.previous = operand_index;
operand.u.register.list.previous = last_operand_index; operand.u.register.list.previous = last_operand_index;
@ -2640,6 +2674,8 @@ pub const MIR = struct {
} }
}, },
true => { true => {
logln(.codegen, .instruction_selection_register_operand_list, "List is empty, adding it to the top of the list", .{});
operand.u.register.list.previous = operand_index; operand.u.register.list.previous = operand_index;
operand.u.register.list.next = Operand.Index.invalid; operand.u.register.list.next = Operand.Index.invalid;
head_index_ptr.* = operand_index; head_index_ptr.* = operand_index;
@ -2668,6 +2704,7 @@ pub const MIR = struct {
false => mir.operands.get(operand_next), false => mir.operands.get(operand_next),
true => head, true => head,
}; };
next.u.register.list.previous = operand_previous; next.u.register.list.previous = operand_previous;
operand.u.register.list.previous = Operand.Index.invalid; operand.u.register.list.previous = Operand.Index.invalid;
@ -2680,7 +2717,7 @@ pub const MIR = struct {
else => unreachable, else => unreachable,
}; };
// print("Old: {}. New: {}\n", .{ old_register_class, new_register_class }); // print("Old: {}. New: {}", .{ old_register_class, new_register_class });
switch (old_register_class == new_register_class) { switch (old_register_class == new_register_class) {
true => return new_register_class, true => return new_register_class,
false => unreachable, false => unreachable,
@ -2692,7 +2729,7 @@ pub const MIR = struct {
assert(register.index == .virtual); assert(register.index == .virtual);
const operand_reference = instruction_descriptor.operands[operand_index]; const operand_reference = instruction_descriptor.operands[operand_index];
const operand_register_class = register_class_operand_matcher.get(operand_reference.id); const operand_register_class = register_class_operand_matcher.get(operand_reference.id);
// print("Constraint operand #{} with {} (out of {})\n", .{ operand_index, operand_register_class, operand_reference.id }); // print("Constraint operand #{} with {} (out of {})", .{ operand_index, operand_register_class, operand_reference.id });
// const register_class = op // const register_class = op
if (mir.constrainRegisterClass(register, operand_register_class) == null) { if (mir.constrainRegisterClass(register, operand_register_class) == null) {
@ -2802,8 +2839,8 @@ pub const MIR = struct {
// TODO: asserts // TODO: asserts
const assert_result = !operand.flags.isKill() or live_register.last_use.eq(instruction_index); const assert_result = !operand.flags.isKill() or live_register.last_use.eq(instruction_index);
if (assert_result) { if (assert_result) {
// logln("Existing live register at instruction #{}: {}\n", .{ instruction_index.uniqueInteger(), live_register }); // logln("Existing live register at instruction #{}: {}", .{ instruction_index.uniqueInteger(), live_register });
// logln("Function until now: {}\n", .{instruction_selection.function}); // logln("Function until now: {}", .{instruction_selection.function});
assert(assert_result); assert(assert_result);
} }
}, },
@ -2869,23 +2906,28 @@ pub const MIR = struct {
} }
} }
logln(.codegen, .register_allocation_problematic_hint, "Tracing copies for VR{} in instruction #{}", .{ virtual_register.uniqueInteger(), instruction_index.uniqueInteger() });
const maybe_hint2 = register_allocator.traceCopies(mir, instruction_selection, virtual_register); const maybe_hint2 = register_allocator.traceCopies(mir, instruction_selection, virtual_register);
if (maybe_hint2) |hint| { if (maybe_hint2) |hint| {
// TODO // TODO
const allocatable = true; const allocatable = true;
logln(.codegen, .register_allocation_problematic_hint, "Hint: {}. Register class: {s}", .{ hint, @tagName(register_class) });
if (hint == .physical and allocatable and isRegisterInClass(hint.physical, register_class) and !register_allocator.isRegisterUsedInInstruction(hint.physical, look_at_physical_register_uses)) { if (hint == .physical and allocatable and isRegisterInClass(hint.physical, register_class) and !register_allocator.isRegisterUsedInInstruction(hint.physical, look_at_physical_register_uses)) {
const physical_register = hint.physical; const physical_register = hint.physical;
if (register_allocator.register_states.get(physical_register) == .free) { if (register_allocator.register_states.get(physical_register) == .free) {
register_allocator.assignVirtualToPhysicalRegister(live_register, physical_register); register_allocator.assignVirtualToPhysicalRegister(live_register, physical_register);
return; return;
} else { } else {
logln(.codegen, .register_allocation_problematic_hint, "Second hint {s} not free\n", .{@tagName(physical_register)}); logln(.codegen, .register_allocation_problematic_hint, "Second hint {s} not free", .{@tagName(physical_register)});
} }
} else { } else {
unreachable; unreachable;
} }
} else { } else {
logln(.codegen, .register_allocation_problematic_hint, "Can't take hint for VR{} for instruction #{}\n", .{ virtual_register.uniqueInteger(), instruction_index.uniqueInteger() }); logln(.codegen, .register_allocation_problematic_hint, "Can't take hint for VR{} for instruction #{}", .{ virtual_register.uniqueInteger(), instruction_index.uniqueInteger() });
} }
const register_class_members = registers_by_class.get(register_class); const register_class_members = registers_by_class.get(register_class);
@ -2897,7 +2939,7 @@ pub const MIR = struct {
// for (register_class_members) |candidate_register| { // for (register_class_members) |candidate_register| {
// print("{s}, ", .{@tagName(candidate_register)}); // print("{s}, ", .{@tagName(candidate_register)});
// } // }
// print("\n", .{}); // print("", .{});
for (register_class_members) |candidate_register| { for (register_class_members) |candidate_register| {
if (register_allocator.isRegisterUsedInInstruction(candidate_register, look_at_physical_register_uses)) continue; if (register_allocator.isRegisterUsedInInstruction(candidate_register, look_at_physical_register_uses)) continue;
const spill_cost = register_allocator.computeSpillCost(candidate_register); const spill_cost = register_allocator.computeSpillCost(candidate_register);
@ -2954,48 +2996,72 @@ pub const MIR = struct {
_ = look_at_physical_register_uses; _ = look_at_physical_register_uses;
// TODO: register masks // TODO: register masks
// if (register_allocator.used_in_instruction.contains(physical_register)) {
// return true;
// }
// // TODO
// else {
// return false;
// }
if (register_allocator.used_in_instruction.contains(physical_register)) { const result = register_allocator.used_in_instruction.contains(physical_register);
return true; logln(.codegen, .register_allocation_problematic_hint, "Register {s} used in instruction: {}", .{ @tagName(physical_register), result });
} return result;
// TODO
//else if (look_at_physical_register_uses and register_classes.ph
else {
return false;
}
} }
fn traceCopyChain(register_allocator: *RegisterAllocator, mir: *MIR, instruction_selection: *InstructionSelection, register: Register) ?Register.Index { fn traceCopyChain(register_allocator: *RegisterAllocator, mir: *MIR, instruction_selection: *InstructionSelection, given_register: Register) ?Register.Index {
_ = register_allocator; _ = register_allocator;
const chain_length_limit = 3; const chain_length_limit = 3;
_ = chain_length_limit;
var chain_try_count: u32 = 0; var chain_try_count: u32 = 0;
_ = chain_try_count;
var register = given_register;
while (true) { while (true) {
switch (register.index) { switch (register.index) {
.physical => return register.index, .physical => return register.index,
.virtual => |vri| { .virtual => |vri| {
logln(.codegen, .register_allocation_problematic_hint, "[traceCopyChain] Operand: VR{}", .{vri.uniqueInteger()});
const virtual_head_index_ptr = mir.getRegisterListHead(instruction_selection, .{ const virtual_head_index_ptr = mir.getRegisterListHead(instruction_selection, .{
.index = .{ .index = .{
.virtual = vri, .virtual = vri,
}, },
}); });
logln(.codegen, .register_allocation_problematic_hint, "[traceCopyChain] Head operand for VR{}: O{}", .{ vri.uniqueInteger(), virtual_head_index_ptr.uniqueInteger() });
var vdef = Instruction.Iterator.Get(.{ var vdef = Instruction.Iterator.Get(.{
.use = false, .use = false,
.def = true, .def = true,
.element = .instruction, .element = .instruction,
}).new(mir, virtual_head_index_ptr.*); }).new(mir, virtual_head_index_ptr.*);
const vdef_instruction = vdef.nextPointer() orelse break; const operand_index = vdef.index;
if (vdef.nextPointer()) |_| break;
switch (vdef_instruction.id) { const vdef_instruction = vdef.next() orelse break;
logln(.codegen, .register_allocation_problematic_hint, "[traceCopyChain] VR{} defined in operand #{} of instruction #{}", .{ vri.uniqueInteger(), operand_index.uniqueInteger(), vdef_instruction.uniqueInteger() });
const next_operand = vdef.index;
if (vdef.next()) |unexpected_next_instruction| {
logln(.codegen, .register_allocation_problematic_hint, "[traceCopyChain] VR{} also defined in operand #{} unexpected next instruction #{}. Breaking...", .{ vri.uniqueInteger(), next_operand.uniqueInteger(), unexpected_next_instruction.uniqueInteger() });
break;
}
const instruction = mir.instructions.get(vdef_instruction);
switch (instruction.id) {
.copy => {
const copy_source_operand_index = instruction.operands.items[1];
const copy_source_operand = mir.operands.get(copy_source_operand_index);
register = copy_source_operand.u.register;
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
unreachable;
}, },
} }
chain_try_count += 1;
if (chain_try_count >= chain_length_limit) break;
} }
return null; return null;
@ -3007,18 +3073,33 @@ pub const MIR = struct {
.virtual = virtual_register_index, .virtual = virtual_register_index,
}, },
}); });
logln(.codegen, .register_allocation_problematic_hint, "[traceCopies] Tracing copies for VR{}. Head operand: #{}", .{ virtual_register_index.uniqueInteger(), head_index_ptr.uniqueInteger() });
var define_instructions = Instruction.Iterator.Get(.{ var define_instructions = Instruction.Iterator.Get(.{
.use = false, .use = false,
.def = true, .def = true,
.element = .instruction, .element = .instruction,
}).new(mir, head_index_ptr.*); }).new(mir, head_index_ptr.*);
if (!define_instructions.index.invalid) {
logln(.codegen, .register_allocation_problematic_hint, "[traceCopies] Next operand before loop: #{}", .{define_instructions.index.uniqueInteger()});
}
const definition_limit = 3; const definition_limit = 3;
var try_count: u32 = 0; var try_count: u32 = 0;
while (define_instructions.next()) |instruction_index| { while (define_instructions.next()) |instruction_index| {
logln(.codegen, .register_allocation_problematic_hint, "[traceCopies] Current instruction: #{}", .{instruction_index.uniqueInteger()});
if (!define_instructions.index.invalid) {
logln(.codegen, .register_allocation_problematic_hint, "[traceCopies] Next operand: #{}", .{define_instructions.index.uniqueInteger()});
} else {
// logln(.codegen, .register_allocation_problematic_hint, "[traceCopies] Next operand: invalid", .{});
}
const instruction = mir.instructions.get(instruction_index); const instruction = mir.instructions.get(instruction_index);
switch (instruction.id) { switch (instruction.id) {
.mov32rm => unreachable, .mov32rm => {},
.mov32r0 => {},
.copy => { .copy => {
const operand_index = instruction.operands.items[1]; const operand_index = instruction.operands.items[1];
const operand = mir.operands.get(operand_index); const operand = mir.operands.get(operand_index);
@ -3027,7 +3108,7 @@ pub const MIR = struct {
return register; return register;
} }
logln(.codegen, .register_allocation_problematic_hint, "Missed oportunity for register allocation tracing copy chain for VR{}\n", .{virtual_register_index.uniqueInteger()}); logln(.codegen, .register_allocation_problematic_hint, "[traceCopies] Missed oportunity for register allocation tracing copy chain for VR{}", .{virtual_register_index.uniqueInteger()});
}, },
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
@ -3048,7 +3129,7 @@ pub const MIR = struct {
.virtual = virtual_register, .virtual = virtual_register,
}); });
logln(.codegen, .register_allocation_assignment, "Assigning V{} to {s}\n", .{ virtual_register.uniqueInteger(), @tagName(register) }); logln(.codegen, .register_allocation_assignment, "Assigning V{} to {s}", .{ virtual_register.uniqueInteger(), @tagName(register) });
// TODO: debug info // TODO: debug info
} }
@ -3061,7 +3142,7 @@ pub const MIR = struct {
fn displacePhysicalRegister(register_allocator: *RegisterAllocator, mir: *MIR, instruction_selection: *InstructionSelection, instruction_index: Instruction.Index, physical_register: Register.Physical) !bool { fn displacePhysicalRegister(register_allocator: *RegisterAllocator, mir: *MIR, instruction_selection: *InstructionSelection, instruction_index: Instruction.Index, physical_register: Register.Physical) !bool {
const state = register_allocator.register_states.getPtr(physical_register); const state = register_allocator.register_states.getPtr(physical_register);
// print("Trying to displace register {s} with state {s}\n", .{ @tagName(physical_register), @tagName(state.*) }); // print("Trying to displace register {s} with state {s}", .{ @tagName(physical_register), @tagName(state.*) });
return switch (state.*) { return switch (state.*) {
.free => false, .free => false,
.preassigned => blk: { .preassigned => blk: {
@ -3084,7 +3165,7 @@ pub const MIR = struct {
fn reload(register_allocator: *RegisterAllocator, mir: *MIR, instruction_selection: *InstructionSelection, before_index: usize, virtual_register: Register.Virtual.Index, physical_register: Register.Physical) !void { fn reload(register_allocator: *RegisterAllocator, mir: *MIR, instruction_selection: *InstructionSelection, before_index: usize, virtual_register: Register.Virtual.Index, physical_register: Register.Physical) !void {
const frame_index = try register_allocator.getStackSpaceFor(mir, instruction_selection, virtual_register); const frame_index = try register_allocator.getStackSpaceFor(mir, instruction_selection, virtual_register);
const register_class = mir.virtual_registers.get(virtual_register).register_class; const register_class = mir.virtual_registers.get(virtual_register).register_class;
logln(.codegen, .register_allocation_reload, "Frame index: {}\n", .{frame_index}); logln(.codegen, .register_allocation_reload, "Frame index: {}", .{frame_index});
try instruction_selection.loadRegisterFromStackSlot(mir, before_index, physical_register, frame_index, register_class, virtual_register); try instruction_selection.loadRegisterFromStackSlot(mir, before_index, physical_register, frame_index, register_class, virtual_register);
} }
@ -3265,7 +3346,7 @@ pub const MIR = struct {
// // TODO: basic block liveins (regmasks?) // // TODO: basic block liveins (regmasks?)
// //
// const live_registers = register_allocator.live_virtual_registers.values(); // const live_registers = register_allocator.live_virtual_registers.values();
// print("Live register count: {}\n", .{live_registers.len}); // print("Live register count: {}", .{live_registers.len});
// //
// for (live_registers) |live_register| { // for (live_registers) |live_register| {
// const physical_register = live_register.physical; // const physical_register = live_register.physical;
@ -3321,7 +3402,7 @@ pub const MIR = struct {
} }
pub fn allocateRegisters(mir: *MIR) !void { pub fn allocateRegisters(mir: *MIR) !void {
logln(.codegen, .register_allocation_block, "[REGISTER ALLOCATION]\n\n", .{}); logln(.codegen, .register_allocation_block, "\n[REGISTER ALLOCATION]\n", .{});
const function_count = mir.functions.len; const function_count = mir.functions.len;
var function_iterator = mir.functions.iterator(); var function_iterator = mir.functions.iterator();
const register_count = @typeInfo(Register.Physical).Enum.fields.len; const register_count = @typeInfo(Register.Physical).Enum.fields.len;
@ -3332,7 +3413,7 @@ pub const MIR = struct {
for (0..function_count) |function_index| { for (0..function_count) |function_index| {
const function = function_iterator.nextPointer().?; const function = function_iterator.nextPointer().?;
const instruction_selection = &mir.instruction_selections.items[function_index]; const instruction_selection = &mir.instruction_selections.items[function_index];
logln(.codegen, .register_allocation_function_before, "Allocating registers for {}\n", .{function}); logln(.codegen, .register_allocation_function_before, "Allocating registers for {}", .{function});
var block_i: usize = function.blocks.items.len; var block_i: usize = function.blocks.items.len;
var register_allocator = try RegisterAllocator.init(mir, instruction_selection); var register_allocator = try RegisterAllocator.init(mir, instruction_selection);
@ -3350,43 +3431,61 @@ pub const MIR = struct {
const instruction_index = block.instructions.items[instruction_i]; const instruction_index = block.instructions.items[instruction_i];
const instruction = mir.instructions.get(instruction_index); const instruction = mir.instructions.get(instruction_index);
logln(.codegen, .register_allocation_new_instruction, "===============\nInstruction {} (#{})\n", .{ instruction_i, instruction_index.uniqueInteger() }); logln(.codegen, .register_allocation_new_instruction, "===============\nInstruction {} (#{})", .{ instruction_i, instruction_index.uniqueInteger() });
logln(.codegen, .register_allocation_new_instruction_function_before, "{}\n", .{function}); logln(.codegen, .register_allocation_new_instruction_function_before, "{}", .{function});
register_allocator.used_in_instruction = RegisterBitset.initEmpty(); register_allocator.used_in_instruction = RegisterBitset.initEmpty();
const max_operand_count = 32; var physical_register_use = false;
var define_bitset = std.StaticBitSet(max_operand_count).initEmpty(); var register_mask = false;
var physical_register_bitset = std.StaticBitSet(max_operand_count).initEmpty(); var virtual_register_definition = false;
var register_mask_bitset = std.StaticBitSet(max_operand_count).initEmpty(); var register_definition = false;
var virtual_register_define = false; var early_clobber = false;
var assign_live_throughs = false; var assign_live_throughs = false;
for (instruction.operands.items, 0..) |operand_index, operand_i| { for (instruction.operands.items, 0..) |operand_index, operand_i| {
_ = operand_i;
const operand = mir.operands.get(operand_index); const operand = mir.operands.get(operand_index);
switch (operand.u) { switch (operand.u) {
.register => |register| { .register => |register| switch (register.index) {
const is_define = operand.flags.type == .def; .virtual => {
const is_physical = register.index == .physical; if (operand.flags.type == .def) {
if (is_define and !is_physical) { register_definition = true;
virtual_register_define = true; virtual_register_definition = true;
if (operand.flags.early_clobber) {
early_clobber = true;
assign_live_throughs = true;
} }
define_bitset.setValue(operand_i, is_define);
physical_register_bitset.setValue(operand_i, is_physical); // TODO
if (is_physical and is_define) { }
const physical_register = register.index.physical; },
.physical => |physical_register| {
if (!register_allocator.reserved.contains(physical_register)) {
if (operand.flags.type == .def) {
register_definition = true;
const displaced_any = try register_allocator.definePhysicalRegister(mir, instruction_selection, instruction_index, physical_register); const displaced_any = try register_allocator.definePhysicalRegister(mir, instruction_selection, instruction_index, physical_register);
if (operand.flags.early_clobber) {
early_clobber = true;
}
if (!displaced_any) { if (!displaced_any) {
operand.flags.dead_or_kill = true; operand.flags.dead_or_kill = true;
} }
} }
if (operand.readsRegister()) {
physical_register_use = true;
}
}
},
}, },
else => {}, else => {},
} }
} }
if (define_bitset.count() > 0) { if (register_definition) {
if (virtual_register_define) { if (virtual_register_definition) {
var rearranged_implicit_operands = true; var rearranged_implicit_operands = true;
if (assign_live_throughs) { if (assign_live_throughs) {
unreachable; unreachable;
@ -3424,47 +3523,75 @@ pub const MIR = struct {
while (operand_i > 0) { while (operand_i > 0) {
operand_i -= 1; operand_i -= 1;
if (define_bitset.isSet(operand_i) and physical_register_bitset.isSet(operand_i)) {
const operand_index = instruction.operands.items[operand_i]; const operand_index = instruction.operands.items[operand_i];
const operand = mir.operands.get(operand_index); const operand = mir.operands.get(operand_index);
const physical_register = operand.u.register.index.physical; switch (operand.u) {
.register => |register| switch (operand.flags.type) {
.def => switch (register.index) {
.physical => |physical_register| {
register_allocator.freePhysicalRegister(physical_register); register_allocator.freePhysicalRegister(physical_register);
register_allocator.unmarkUsedRegisterInInstruction(physical_register); register_allocator.unmarkUsedRegisterInInstruction(physical_register);
},
.virtual => {},
},
.use => {},
},
else => {},
} }
} }
} }
if (register_mask_bitset.count() > 0) { if (register_mask) {
unreachable; unreachable;
} }
// Physical register use // Physical register use
if (physical_register_bitset.count() > 0) { if (physical_register_use) {
for (instruction.operands.items, 0..) |operand_index, operand_i| { for (instruction.operands.items) |operand_index| {
if (!define_bitset.isSet(operand_i) and physical_register_bitset.isSet(operand_i)) {
const operand = mir.operands.get(operand_index); const operand = mir.operands.get(operand_index);
const physical_register = operand.u.register.index.physical;
switch (operand.flags.type) {
.def => {},
.use => switch (operand.u) {
.register => |register| switch (register.index) {
.physical => |physical_register| {
if (!register_allocator.reserved.contains(physical_register)) { if (!register_allocator.reserved.contains(physical_register)) {
const displaced_any = try register_allocator.usePhysicalRegister(mir, instruction_selection, instruction_index, physical_register); const displaced_any = try register_allocator.usePhysicalRegister(mir, instruction_selection, instruction_index, physical_register);
if (!displaced_any) { if (!displaced_any) {
operand.flags.dead_or_kill = true; operand.flags.dead_or_kill = true;
} }
} }
},
.virtual => {},
},
else => {},
},
} }
} }
} }
var undef_use = false;
_ = undef_use;
var rearranged_implicit_operands = true; var rearranged_implicit_operands = true;
while (rearranged_implicit_operands) { while (rearranged_implicit_operands) {
rearranged_implicit_operands = false; rearranged_implicit_operands = false;
for (instruction.operands.items, 0..) |operand_index, operand_i| { for (instruction.operands.items, 0..) |operand_index, operand_i| {
if (!define_bitset.isSet(operand_i)) {
const operand = mir.operands.get(operand_index); const operand = mir.operands.get(operand_index);
if (operand.u == .register and operand.u.register.index == .virtual) { switch (operand.u) {
const virtual_register = operand.u.register.index.virtual; .register => |register| switch (operand.flags.type) {
rearranged_implicit_operands = try register_allocator.useVirtualRegister(mir, instruction_selection, instruction_index, virtual_register, @intCast(operand_i)); .def => {},
if (rearranged_implicit_operands) break; .use => switch (register.index) {
.physical => {},
.virtual => |virtual_register_index| {
if (operand.flags.undef) {
unreachable;
} }
rearranged_implicit_operands = try register_allocator.useVirtualRegister(mir, instruction_selection, instruction_index, virtual_register_index, @intCast(operand_i));
if (rearranged_implicit_operands) break;
},
},
},
else => {},
} }
} }
} }
@ -3475,7 +3602,7 @@ pub const MIR = struct {
if (std.meta.eql(dst_register, src_register)) { if (std.meta.eql(dst_register, src_register)) {
try register_allocator.coalesced.append(mir.allocator, instruction_index); try register_allocator.coalesced.append(mir.allocator, instruction_index);
logln(.codegen, .register_allocation_instruction_avoid_copy, "Avoiding copy...\n", .{}); logln(.codegen, .register_allocation_instruction_avoid_copy, "Avoiding copy...", .{});
} }
} }
} }
@ -3490,248 +3617,33 @@ pub const MIR = struct {
} else unreachable; } else unreachable;
} }
logln(.codegen, .register_allocation_function_after, "{}\n============\n", .{function}); logln(.codegen, .register_allocation_function_after, "Allocated registers for {}\n============", .{function});
} }
} }
// for (0..function_count) |function_index| { const clear_virtual_registers = true;
// const function = function_iterator.nextPointer().?; if (clear_virtual_registers) {
// const instruction_selection = &mir.instruction_selections.items[function_index]; mir.clearVirtualRegisters();
// print("FN {s}\n", .{function.name}); }
//
// var register_allocator = try RegisterAllocator.init(mir, instruction_selection);
//
// for (function.blocks.items) |block_index| {
// instruction_selection.current_block = block_index;
// register_allocator.coalesced.clearRetainingCapacity();
//
// const block = mir.blocks.get(block_index);
// const instruction_count = block.instructions.items.len;
// var instruction_i = instruction_count;
//
// while (instruction_i > 0) {
// instruction_i -= 1;
// print("Instruction #{}\n", .{instruction_i});
//
// register_allocator.used_in_instruction = RegisterBitset.initEmpty();
//
// const instruction_index = block.instructions.items[instruction_i];
// const instruction = mir.instructions.get(instruction_index);
//
// var register_define = false;
// var virtual_register_define = false;
// var early_clobber = false;
// var assign_live_throughs = false;
// var physical_register_use = false;
// var register_mask = false;
//
// for (instruction.operands.items) |operand_index| {
// const operand = mir.operands.get(operand_index);
// var register_buffer: [2]Register = undefined;
// const registers = getRegisters(operand, &register_buffer);
//
// for (registers) |register| switch (register.index) {
// .virtual => {
// switch (operand.flags.type) {
// .def => {
// register_define = true;
// virtual_register_define = true;
// // TODO early clobber, livethroughs
// if (operand.flags.early_clobber) {
// early_clobber = true;
// assign_live_throughs = true;
// }
//
// // TODO (tied and tied op undef) or (subreg and !undef)
// },
// .use => {},
// }
// },
// .physical => |physical_register| {
// if (!register_allocator.reserved.contains(physical_register)) {
// switch (operand.flags.type) {
// .def => {
// register_define = true;
// const displaced_any = try register_allocator.definePhysicalRegister(mir, instruction_selection, instruction_index, physical_register);
// if (operand.flags.early_clobber) {
// early_clobber = true;
// }
// if (!displaced_any) {
// operand.flags.dead_or_kill = true;
// }
// },
// .use => {},
// }
//
// if (operand.readsRegister()) {
// physical_register_use = true;
// }
// }
// },
// };
// }
//
// if (register_define) {
// if (virtual_register_define) {
// var rearranged_implicit_operands = true;
// if (assign_live_throughs) {
// unreachable;
// } else {
// while (rearranged_implicit_operands) {
// rearranged_implicit_operands = false;
//
// for (instruction.operands.items) |operand_index| {
// const operand = mir.operands.get(operand_index);
// switch (operand.u) {
// .register => |register| switch (operand.flags.type) {
// .def => switch (register.index) {
// .virtual => |virtual_register| {
// rearranged_implicit_operands = try register_allocator.defineVirtualRegister(mir, instruction_selection, instruction_index, operand_index, virtual_register, false);
// if (rearranged_implicit_operands) {
// break;
// }
// },
// .physical => {},
// },
// else => {},
// },
// .lea64mem => |lea64mem| {
// assert(lea64mem.gp64 == null);
// assert(lea64mem.scale_reg == null);
// },
// else => {},
// }
// }
// }
// }
// }
//
// var operand_i = instruction.operands.items.len;
// while (operand_i > 0) {
// operand_i -= 1;
// const operand_index = instruction.operands.items[operand_i];
// const operand = mir.operands.get(operand_index);
// var register_buffer: [2]Register = undefined;
// const registers = getRegisters(operand, &register_buffer);
// for (registers) |register| {
// switch (operand.flags.type) {
// .def => {
// if (operand.id == .lea64mem) unreachable;
// // TODO: missing checks
// switch (register.index) {
// .virtual => unreachable,
// .physical => |physical_register| switch (register_allocator.reserved.contains(physical_register)) {
// true => {},
// false => {
// register_allocator.freePhysicalRegister(physical_register);
// register_allocator.unmarkUsedRegisterInInstruction(physical_register);
// },
// },
// }
// },
// .use => {},
// }
// }
// }
// }
//
// if (register_mask) {
// unreachable;
// }
//
// if (physical_register_use) {
// unreachable;
// }
//
// var undef_use = false;
//
// while (true) {
// var rearrange_implicit_operands = false;
// operand_loop: for (instruction.operands.items, 0..) |operand_index, operand_i| {
// const operand = mir.operands.get(operand_index);
// var register_buffer: [2]Register = undefined;
// const registers = getRegisters(operand, &register_buffer);
//
// for (registers) |register| {
// switch (operand.flags.type) {
// .use => switch (register.index) {
// .virtual => |virtual_register_index| switch (operand.flags.undef) {
// true => undef_use = true,
// false => {
// _ = register_allocator.mayLiveIn(mir, instruction_selection, virtual_register_index);
// assert(!operand.flags.internal_read);
// assert(operand.readsRegister());
//
// if (try register_allocator.useVirtualRegister(mir, instruction_selection, instruction_index, virtual_register_index, @intCast(operand_i))) {
// break :operand_loop;
// }
// },
// },
// .physical => {},
// },
// .def => {},
// }
// }
// }
//
// if (!rearrange_implicit_operands) break;
// }
//
// if (undef_use) {
// unreachable;
// }
//
// if (early_clobber) {
// unreachable;
// }
//
// if (instruction.id == .copy and instruction.operands.items.len == 2) {
// const dst_register = mir.operands.get(instruction.operands.items[0]).u.register;
// const src_register = mir.operands.get(instruction.operands.items[1]).u.register;
//
// if (std.meta.eql(dst_register, src_register)) {
// try register_allocator.coalesced.append(mir.allocator, instruction_index);
// }
// }
// }
//
// // TODO:
// // try register_allocator.reloadAtBegin(instruction_selection.current_block);
//
// // Remove coalesced instructions
// for (register_allocator.coalesced.items) |instruction_index| {
// _ = instruction_index;
// unreachable;
// }
//
// // TODO: fix debug values
//
// }
//
// print("After register allocation before clearing virtual registers:\n{}\n", .{function});
//
// const clear_virtual_registers = true;
// if (clear_virtual_registers) {
// mir.clearVirtualRegisters();
// }
//
// unreachable;
// }
unreachable;
} }
fn clearVirtualRegisters(mir: *MIR) void { fn clearVirtualRegisters(mir: *MIR) void {
var vr_it = mir.virtual_registers.iterator(); var vr_it = mir.virtual_registers.iterator();
var vr_index = vr_it.getCurrentIndex(); var vr_index = vr_it.getCurrentIndex();
var verified_virtual_register_count: usize = 0;
var skipped: usize = 0;
while (vr_it.nextPointer()) |vr| { while (vr_it.nextPointer()) |vr| {
if (!vr.use_def_list_head.valid) { verified_virtual_register_count += 1;
if (vr.use_def_list_head.invalid) {
skipped += 1;
continue; continue;
} }
mir.verifyUseList(vr.use_def_list_head, vr_index); mir.verifyUseList(vr.use_def_list_head, vr_index);
vr_index = vr_it.getCurrentIndex(); vr_index = vr_it.getCurrentIndex();
} }
logln(.codegen, .register_allocation_operand_list_verification, "Verified {} virtual registers ({} skipped)", .{ verified_virtual_register_count, skipped });
} }
fn verifyUseList(mir: *MIR, start_operand_index: Operand.Index, register: Register.Virtual.Index) void { fn verifyUseList(mir: *MIR, start_operand_index: Operand.Index, register: Register.Virtual.Index) void {
@ -3741,15 +3653,17 @@ pub const MIR = struct {
.element = .operand, .element = .operand,
}).new(mir, start_operand_index); }).new(mir, start_operand_index);
while (iterator.next()) |operand| { while (iterator.nextPointer()) |operand| {
const instruction_index = operand.parent; const instruction_index = operand.parent;
assert(instruction_index.valid); assert(!instruction_index.invalid);
const instruction = mir.instructions.get(instruction_index); const instruction = mir.instructions.get(instruction_index);
logln(.codegen, .register_allocation_operand_list_verification, "Verifying instruction #{}, operand #{}\n", .{ instruction_index.uniqueInteger(), mir.operands.indexOf(operand).uniqueInteger() }); logln(.codegen, .register_allocation_operand_list_verification, "Verifying instruction #{}, operand #{}", .{ instruction_index.uniqueInteger(), mir.operands.indexOf(operand).uniqueInteger() });
_ = instruction; _ = instruction;
assert(operand.u == .register); assert(operand.u == .register);
assert(operand.u.register.index == .virtual and operand.u.register.index.virtual.eq(register)); assert(operand.u.register.index == .virtual and operand.u.register.index.virtual.eq(register));
} }
unreachable;
} }
pub fn encode(mir: *MIR) !emit.Result { pub fn encode(mir: *MIR) !emit.Result {
@ -3806,10 +3720,7 @@ pub const MIR = struct {
}, },
else => try writer.writeAll(@tagName(operand.u)), else => try writer.writeAll(@tagName(operand.u)),
} }
// switch (operand.u) {
// .memory =>
// else => |t| @panic(@tagName(t)),
// }
if (i < instruction.operands.items.len - 1) { if (i < instruction.operands.items.len - 1) {
try writer.writeByte(','); try writer.writeByte(',');
} }
@ -3873,7 +3784,7 @@ pub const MIR = struct {
if (instruction == .copy) { if (instruction == .copy) {
const i = instruction_allocation.ptr.*; const i = instruction_allocation.ptr.*;
_ = i; _ = i;
// print("Built copy: DST: {}. SRC: {}\n", .{ mir.operands.get(i.operands.items[0]).u.register.index, mir.operands.get(i.operands.items[1]).u.register.index }); // print("Built copy: DST: {}. SRC: {}", .{ mir.operands.get(i.operands.items[0]).u.register.index, mir.operands.get(i.operands.items[1]).u.register.index });
} }
return instruction_allocation.index; return instruction_allocation.index;