Skip to content

Commit

Permalink
Merge pull request #13 from birth-software/fix-register-allocation
Browse files Browse the repository at this point in the history
Fix register allocation for argument passing
  • Loading branch information
david4r4 authored Nov 11, 2023
2 parents 9d6607b + e75f3f3 commit be143a8
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 66 deletions.
11 changes: 1 addition & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,5 @@ jobs:
uses: goto-bus-stop/setup-zig@v2
with:
version: master
- name: Zig environment variables
run: zig env
- name: Test
run: |
zig build test -Dall --summary all
zig build run -- test/first/main.nat
nat/first
zig build run -- test/stack/main.nat
nat/stack
zig build run -- test/hello_world/main.nat
nat/hello_world
run: ./ci.sh
1 change: 0 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
"test/hello_world/main.nat"
],
"cwd": "${workspaceFolder}",
"preLaunchTask": "zig build"
},
// {
// "type": "cppvsdbg",
Expand Down
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"zig.initialSetupDone": true
}
12 changes: 12 additions & 0 deletions ci.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash

set -xe
zig build test -Dall --summary all

for dir in test/*
do
zig build run -- $dir/main.nat
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
nat/${dir##*/}
fi
done
6 changes: 5 additions & 1 deletion src/backend/intermediate_representation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -490,10 +490,14 @@ pub const Builder = struct {
const ir_argument_instruction = builder.ir.instructions.get(ir_argument_instruction_index);
const ir_argument = builder.ir.arguments.get(ir_argument_instruction.argument);

const stack_reference = try builder.stackReference(.{
_ = try builder.stackReference(.{
.type = ir_argument.type,
.sema = sema_argument_index,
});
}

for (function_declaration.arguments.keys(), function_declaration.arguments.values()) |sema_argument_index, ir_argument_instruction_index| {
const stack_reference = builder.currentFunction().stack_map.get(sema_argument_index).?;

_ = try builder.store(.{
.source = ir_argument_instruction_index,
Expand Down
121 changes: 67 additions & 54 deletions src/backend/x86_64.zig
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,18 @@ pub const Logger = enum {
pub var bitset = std.EnumSet(Logger).initMany(&.{
.instruction_selection_ir_function,
.instruction_selection_mir_function,
// .instruction_selection_register_operand_list,
// .register_allocation_block,
// .register_allocation_problematic_hint,
// .register_allocation_assignment,
// .register_allocation_reload,
.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,
.encoding,
// .encoding,
});
};

Expand Down Expand Up @@ -2481,19 +2481,16 @@ pub const MIR = struct {
},
.call => |ir_call_index| {
const ir_call = mir.ir.calls.get(ir_call_index);
var argument_index = ir_call.arguments.len;
while (argument_index > 0) {
argument_index -= 1;
var argument_virtual_registers = try ArrayList(Register).initCapacity(mir.allocator, ir_call.arguments.len);
for (ir_call.arguments) |ir_argument_index| {
const register = try instruction_selection.getRegisterForValue(mir, ir_argument_index);
argument_virtual_registers.appendAssumeCapacity(register);
}

const ir_argument_index = ir_call.arguments[argument_index];
// print("index: {}", .{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_register_class = register_classes.get(source_value_type);
for (argument_virtual_registers.items, 0..) |argument_virtual_register, argument_index| {
const source_register_class = mir.virtual_registers.get(argument_virtual_register.index.virtual).register_class;
const argument_register = calling_convention.argument_registers.get(source_register_class)[argument_index];
// print("Argument register: {}", .{argument_register});

const destination_register = Register{
const argument_physical_register = Register{
.index = .{
.physical = argument_register,
},
Expand All @@ -2508,17 +2505,19 @@ pub const MIR = struct {
const source_operand = Operand{
.id = operand_id,
.u = .{
.register = source_register,
.register = argument_virtual_register,
},
.flags = .{},
};

const destination_operand = Operand{
.id = operand_id,
.u = .{
.register = destination_register,
.register = argument_physical_register,
},
.flags = .{
.type = .def,
},
.flags = .{},
};

const copy = try mir.buildInstruction(instruction_selection, .copy, &.{
Expand Down Expand Up @@ -2934,7 +2933,7 @@ pub const MIR = struct {

live_register.last_use = instruction_index;

register_allocator.markUsedRegisterInInstruction(live_register.physical);
register_allocator.setRegisterUsedInInstruction(live_register.physical, true);
return mir.setPhysicalRegister(instruction_selection, operand_index, live_register.physical);
}

Expand All @@ -2949,14 +2948,23 @@ pub const MIR = struct {
const register_class = mir.virtual_registers.get(live_register.virtual).register_class;

if (maybe_hint) |hint_register| {
if (hint_register.index == .physical
// TODO : and isAllocatable
and isRegisterInClass(hint_register.index.physical, register_class) and !register_allocator.isRegisterUsedInInstruction(hint_register.index.physical, look_at_physical_register_uses)) {
if (register_allocator.register_states.get(hint_register.index.physical) == .free) {
register_allocator.assignVirtualToPhysicalRegister(live_register, hint_register.index.physical);
return;
logln(.codegen, .register_allocation_problematic_hint, "Hint register 1: {s}", .{@tagName(hint_register.index.physical)});
if (hint_register.index == .physical) {
const hint_physical_register = hint_register.index.physical;
if (isRegisterInClass(hint_physical_register, register_class)) {
logln(.codegen, .register_allocation_problematic_hint, "Hint register 1 {s} is in register class {s}", .{ @tagName(hint_physical_register), @tagName(register_class) });
const is_used_in_instruction = register_allocator.isRegisterUsedInInstruction(hint_physical_register, look_at_physical_register_uses);
logln(.codegen, .register_allocation_problematic_hint, "Hint register 1 {s} is {s} in instruction", .{ @tagName(hint_physical_register), if (is_used_in_instruction) "used" else "unused" });
if (!is_used_in_instruction) {
logln(.codegen, .register_allocation_problematic_hint, "Register {s} used in instruction: false", .{@tagName(hint_physical_register)});
if (register_allocator.register_states.get(hint_physical_register) == .free) {
register_allocator.assignVirtualToPhysicalRegister(live_register, hint_physical_register);
return;
}
}
}
}
// TODO : and isAllocatable
}

logln(.codegen, .register_allocation_problematic_hint, "Tracing copies for VR{} in instruction #{}", .{ virtual_register.uniqueInteger(), instruction_index.uniqueInteger() });
Expand All @@ -2965,7 +2973,7 @@ pub const MIR = struct {
if (maybe_hint2) |hint| {
// TODO
const allocatable = true;
logln(.codegen, .register_allocation_problematic_hint, "Hint: {}. Register class: {s}", .{ hint, @tagName(register_class) });
logln(.codegen, .register_allocation_problematic_hint, "Hint register 2: {}. 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)) {
const physical_register = hint.physical;
Expand Down Expand Up @@ -2994,29 +3002,30 @@ pub const MIR = struct {
// }
// print("", .{});
for (register_class_members) |candidate_register| {
if (register_allocator.isRegisterUsedInInstruction(candidate_register, look_at_physical_register_uses)) continue;
const spill_cost = register_allocator.computeSpillCost(candidate_register);
if (!register_allocator.isRegisterUsedInInstruction(candidate_register, look_at_physical_register_uses)) {
const spill_cost = register_allocator.computeSpillCost(candidate_register);

if (spill_cost == 0) {
register_allocator.assignVirtualToPhysicalRegister(live_register, candidate_register);
return;
}
if (spill_cost == 0) {
register_allocator.assignVirtualToPhysicalRegister(live_register, candidate_register);
return;
}

if (maybe_hint) |hint| {
if (hint.index.physical == candidate_register) {
unreachable;
if (maybe_hint) |hint| {
if (hint.index.physical == candidate_register) {
unreachable;
}
}
}

if (maybe_hint2) |hint| {
if (hint.physical == candidate_register) {
unreachable;
if (maybe_hint2) |hint| {
if (hint.physical == candidate_register) {
unreachable;
}
}
}

if (spill_cost < best_cost) {
best_register = candidate_register;
best_cost = spill_cost;
if (spill_cost < best_cost) {
best_register = candidate_register;
best_cost = spill_cost;
}
}
}

Expand Down Expand Up @@ -3058,7 +3067,6 @@ pub const MIR = struct {
// }

const result = register_allocator.used_in_instruction.contains(physical_register);
logln(.codegen, .register_allocation_problematic_hint, "Register {s} used in instruction: {}", .{ @tagName(physical_register), result });
return result;
}

Expand Down Expand Up @@ -3193,7 +3201,7 @@ pub const MIR = struct {
fn usePhysicalRegister(register_allocator: *RegisterAllocator, mir: *MIR, instruction_selection: *InstructionSelection, instruction_index: Instruction.Index, physical_register: Register.Physical) !bool {
const displaced_any = try register_allocator.displacePhysicalRegister(mir, instruction_selection, instruction_index, physical_register);
register_allocator.register_states.set(physical_register, .preassigned);
register_allocator.markUsedRegisterInInstruction(physical_register);
register_allocator.setRegisterUsedInInstruction(physical_register, true);
return displaced_any;
}

Expand Down Expand Up @@ -3257,13 +3265,18 @@ pub const MIR = struct {
}
}

fn markUsedRegisterInInstruction(register_allocator: *RegisterAllocator, physical_register: Register.Physical) void {
register_allocator.used_in_instruction.setPresent(physical_register, true);
fn setRegisterUsedInInstruction(register_allocator: *RegisterAllocator, physical_register: Register.Physical, value: bool) void {
logln(.codegen, .register_allocation_problematic_hint, "Marked {s} {s} in instruction", .{ @tagName(physical_register), if (value) "used" else "unused" });
register_allocator.used_in_instruction.setPresent(physical_register, value);
}

fn unmarkUsedRegisterInInstruction(register_allocator: *RegisterAllocator, physical_register: Register.Physical) void {
register_allocator.used_in_instruction.setPresent(physical_register, false);
}
// fn markUsedRegisterInInstruction(register_allocator: *RegisterAllocator, physical_register: Register.Physical) void {
// register_allocator.used_in_instruction.setPresent(physical_register, true);
// }
//
// fn unmarkUsedRegisterInInstruction(register_allocator: *RegisterAllocator, physical_register: Register.Physical) void {
// register_allocator.used_in_instruction.setPresent(physical_register, false);
// }

fn definePhysicalRegister(register_allocator: *RegisterAllocator, mir: *MIR, instruction_selection: *InstructionSelection, instruction_index: Instruction.Index, physical_register: Register.Physical) !bool {
const displaced_any = try register_allocator.displacePhysicalRegister(mir, instruction_selection, instruction_index, physical_register);
Expand Down Expand Up @@ -3313,7 +3326,7 @@ pub const MIR = struct {

// bundle?

register_allocator.markUsedRegisterInInstruction(physical_register);
register_allocator.setRegisterUsedInInstruction(physical_register, true);
return mir.setPhysicalRegister(instruction_selection, operand_index, physical_register);
}

Expand Down Expand Up @@ -3587,7 +3600,7 @@ pub const MIR = struct {
.def => switch (register.index) {
.physical => |physical_register| {
register_allocator.freePhysicalRegister(physical_register);
register_allocator.unmarkUsedRegisterInInstruction(physical_register);
register_allocator.setRegisterUsedInInstruction(physical_register, false);
},
.virtual => {},
},
Expand Down

0 comments on commit be143a8

Please sign in to comment.