commit
20fe6c8f97
33
ci.sh
33
ci.sh
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
echo "Testing Nativity with Zig"
|
echo "Testing Nativity with Zig"
|
||||||
echo "Compiling Nativity with Zig"
|
echo "Compiling Nativity with Zig"
|
||||||
zig build -Doptimize=ReleaseSafe
|
zig build
|
||||||
failed_test_count=0
|
failed_test_count=0
|
||||||
passed_test_count=0
|
passed_test_count=0
|
||||||
test_directory_name=test
|
test_directory_name=test
|
||||||
@ -10,12 +10,17 @@ test_directory=$test_directory_name/*
|
|||||||
total_test_count=$(ls 2>/dev/null -Ubad1 -- test/* | wc -l)
|
total_test_count=$(ls 2>/dev/null -Ubad1 -- test/* | wc -l)
|
||||||
ran_test_count=0
|
ran_test_count=0
|
||||||
test_i=1
|
test_i=1
|
||||||
|
passed_compilation_count=0
|
||||||
|
failed_compilation_count=0
|
||||||
|
failed_compilations=()
|
||||||
|
failed_tests=()
|
||||||
|
|
||||||
for dir in $test_directory
|
for dir in $test_directory
|
||||||
do
|
do
|
||||||
MY_TESTNAME=${dir##*/}
|
MY_TESTNAME=${dir##*/}
|
||||||
zig build run -Doptimize=ReleaseSafe -- $dir/main.nat
|
zig build run -- $dir/main.nat
|
||||||
if [[ "$?" == "0" ]]; then
|
if [[ "$?" == "0" ]]; then
|
||||||
|
passed_compilation_count=$(($passed_compilation_count + 1))
|
||||||
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||||
nat/$MY_TESTNAME
|
nat/$MY_TESTNAME
|
||||||
if [[ "$?" == "0" ]]; then
|
if [[ "$?" == "0" ]]; then
|
||||||
@ -24,19 +29,39 @@ do
|
|||||||
else
|
else
|
||||||
failed_test_count=$(($failed_test_count + 1))
|
failed_test_count=$(($failed_test_count + 1))
|
||||||
result="FAILED"
|
result="FAILED"
|
||||||
|
failed_tests+=("$test_i. $MY_TESTNAME")
|
||||||
fi
|
fi
|
||||||
echo "[$test_i/$total_test_count] [$result] $MY_TESTNAME"
|
echo "[$test_i/$total_test_count] [$result] $MY_TESTNAME"
|
||||||
ran_test_count=$(($ran_test_count + 1))
|
ran_test_count=$(($ran_test_count + 1))
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
"$MY_TESTNAME failed to compile"
|
failed_compilation_count=$(($failed_compilation_count + 1))
|
||||||
|
echo "$MY_TESTNAME failed to compile"
|
||||||
|
failed_compilations+=("$test_i. $MY_TESTNAME")
|
||||||
fi
|
fi
|
||||||
test_i=$(($test_i + 1))
|
test_i=$(($test_i + 1))
|
||||||
done
|
done
|
||||||
|
|
||||||
|
echo "Ran $total_test_count compilations ($passed_compilation_count succeeded, $failed_compilation_count failed)."
|
||||||
echo "Ran $ran_test_count tests ($passed_test_count passed, $failed_test_count failed)."
|
echo "Ran $ran_test_count tests ($passed_test_count passed, $failed_test_count failed)."
|
||||||
|
|
||||||
if [[ $failed_test_count == "0" ]]; then
|
if [[ "$failed_compilation_count" != "0" ]]; then
|
||||||
|
echo "Failed compilations:"
|
||||||
|
for failed_compilation in "${failed_compilations[@]}"
|
||||||
|
do
|
||||||
|
echo "$failed_compilation"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$failed_test_count" != "0" ]]; then
|
||||||
|
echo "Failed tests:"
|
||||||
|
for failed_test in "${failed_tests[@]}"
|
||||||
|
do
|
||||||
|
echo "$failed_test"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$failed_test_count" == "0" && "$failed_compilation_count" == "0" ]]; then
|
||||||
true
|
true
|
||||||
else
|
else
|
||||||
false
|
false
|
||||||
|
@ -546,7 +546,7 @@ pub const BinaryOperation = struct {
|
|||||||
pub const Index = List.Index;
|
pub const Index = List.Index;
|
||||||
pub const Allocation = List.Allocation;
|
pub const Allocation = List.Allocation;
|
||||||
|
|
||||||
const Id = enum {
|
pub const Id = enum {
|
||||||
add,
|
add,
|
||||||
sub,
|
sub,
|
||||||
logical_and,
|
logical_and,
|
||||||
@ -554,6 +554,8 @@ pub const BinaryOperation = struct {
|
|||||||
logical_or,
|
logical_or,
|
||||||
multiply,
|
multiply,
|
||||||
divide,
|
divide,
|
||||||
|
shift_left,
|
||||||
|
shift_right,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -602,12 +604,13 @@ pub const Value = union(enum) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn isComptime(value: Value) bool {
|
pub fn isComptime(value: *Value, module: *Module) bool {
|
||||||
return switch (value) {
|
return switch (value.*) {
|
||||||
.bool, .void, .undefined, .function, .type, .enum_field => true,
|
.bool, .void, .undefined, .function, .type, .enum_field => true,
|
||||||
.integer => |integer| integer.type.eq(Type.comptime_int),
|
.integer => |integer| integer.type.eq(Type.comptime_int),
|
||||||
.call => false,
|
.call => false,
|
||||||
.binary_operation => false,
|
.binary_operation => false,
|
||||||
|
.declaration_reference => |declaration_reference| module.declarations.get(declaration_reference.value).mutability == .@"const" and isComptime(module.values.get(module.declarations.get(declaration_reference.value).init_value), module),
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -240,6 +240,8 @@ pub const BinaryOperation = struct {
|
|||||||
logical_or,
|
logical_or,
|
||||||
signed_multiply,
|
signed_multiply,
|
||||||
signed_divide,
|
signed_divide,
|
||||||
|
shift_left,
|
||||||
|
shift_right,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const List = BlockList(@This());
|
pub const List = BlockList(@This());
|
||||||
@ -749,7 +751,6 @@ pub const Builder = struct {
|
|||||||
},
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
},
|
},
|
||||||
//.multiply,
|
|
||||||
.divide => switch (sema_type) {
|
.divide => switch (sema_type) {
|
||||||
.integer => |integer| switch (integer.signedness) {
|
.integer => |integer| switch (integer.signedness) {
|
||||||
.signed => .signed_divide,
|
.signed => .signed_divide,
|
||||||
@ -757,7 +758,8 @@ pub const Builder = struct {
|
|||||||
},
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
},
|
},
|
||||||
//.divide,
|
.shift_left => .shift_left,
|
||||||
|
.shift_right => .shift_right,
|
||||||
},
|
},
|
||||||
.type = binary_operation_type,
|
.type = binary_operation_type,
|
||||||
});
|
});
|
||||||
@ -917,6 +919,19 @@ pub const Builder = struct {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.call => |sema_call_index| _ = try builder.processCall(sema_call_index),
|
.call => |sema_call_index| _ = try builder.processCall(sema_call_index),
|
||||||
|
.assign => |sema_assignment_index| {
|
||||||
|
const sema_assignment = builder.ir.module.assignments.get(sema_assignment_index);
|
||||||
|
const sema_left = builder.ir.module.values.get(sema_assignment.store);
|
||||||
|
assert(sema_left.* == .declaration_reference);
|
||||||
|
const sema_declaration_index = sema_left.declaration_reference.value;
|
||||||
|
const stack = builder.currentFunction().stack_map.get(sema_declaration_index).?;
|
||||||
|
const value_index = try builder.emitDeclarationInitValue(sema_assignment.load);
|
||||||
|
const store_instruction = try builder.store(.{
|
||||||
|
.source = value_index,
|
||||||
|
.destination = stack,
|
||||||
|
});
|
||||||
|
_ = store_instruction;
|
||||||
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ const std = @import("std");
|
|||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const equal = std.mem.eql;
|
const equal = std.mem.eql;
|
||||||
const print = std.debug.print;
|
|
||||||
|
|
||||||
const Compilation = @import("../Compilation.zig");
|
const Compilation = @import("../Compilation.zig");
|
||||||
|
|
||||||
@ -487,7 +486,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 : {}", .{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 +502,83 @@ 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: {}", .{segment_load_command});
|
//print("SLC: {}", .{segment_load_command});
|
||||||
print("segment name: {s}", .{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("{}", .{section});
|
_ = section;
|
||||||
print("Section name: {s}. Segment name: {s}", .{ section.name, section.segment_name });
|
//print("{}", .{section});
|
||||||
|
//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: {}", .{command});
|
_ = 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: {}", .{command});
|
_ = 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: {}", .{command});
|
_ = 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: {}", .{command});
|
_ = 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: {}", .{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}", .{name});
|
_ = 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: {}", .{command});
|
_ = 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: {}", .{command});
|
_ = 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: {}", .{command});
|
_ = 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: {}", .{command});
|
_ = 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: {}", .{command});
|
_ = command;
|
||||||
print("Dylib: {s}", .{@as([*:0]const u8, @ptrFromInt(@intFromPtr(load_command_ptr) + @sizeOf(LoadCommand.Dylib)))});
|
//print("command: {}", .{command});
|
||||||
|
//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: {}", .{command});
|
_ = 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: {}", .{command});
|
_ = 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: {}", .{command});
|
_ = command;
|
||||||
|
//print("command: {}", .{command});
|
||||||
},
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
}
|
}
|
||||||
@ -666,7 +679,8 @@ pub fn interpretFile(allocator: Allocator, descriptor: Compilation.Module.Descri
|
|||||||
writer.index = writer.segment_offset + @sizeOf(LoadCommand.Segment64);
|
writer.index = writer.segment_offset + @sizeOf(LoadCommand.Segment64);
|
||||||
|
|
||||||
for (file[16384 + 56 ..][0..48]) |b| {
|
for (file[16384 + 56 ..][0..48]) |b| {
|
||||||
print("0x{x}, ", .{b});
|
_ = b;
|
||||||
|
//print("0x{x}, ", .{b});
|
||||||
}
|
}
|
||||||
|
|
||||||
const chained_fixup_bytes = &.{ 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
|
const chained_fixup_bytes = &.{ 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const print = std.debug.print;
|
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
const data_structures = @import("../data_structures.zig");
|
const data_structures = @import("../data_structures.zig");
|
||||||
@ -22,21 +21,23 @@ 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: {}", .{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: {}", .{dos_header.file_address_of_new_exe_header});
|
//print("File address: {}", .{dos_header.file_address_of_new_exe_header});
|
||||||
print("File: {s}", .{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| {
|
||||||
|
_ = index;
|
||||||
if (byte == 'T') {
|
if (byte == 'T') {
|
||||||
print("Index: {}", .{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("{}", .{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: {}", .{file_header});
|
_ = 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,
|
||||||
|
@ -87,8 +87,8 @@ const Register = struct {
|
|||||||
const Class = enum {
|
const Class = enum {
|
||||||
not_a_register,
|
not_a_register,
|
||||||
any,
|
any,
|
||||||
// gp8,
|
gp8,
|
||||||
// gp16,
|
gp16,
|
||||||
gp32,
|
gp32,
|
||||||
gp64,
|
gp64,
|
||||||
gp64_nosp,
|
gp64_nosp,
|
||||||
@ -804,31 +804,81 @@ const zero_register_class_descriptor = Register.Class.Descriptor{
|
|||||||
const register_class_descriptors = std.EnumArray(Register.Class, Register.Class.Descriptor).init(.{
|
const register_class_descriptors = std.EnumArray(Register.Class, Register.Class.Descriptor).init(.{
|
||||||
.not_a_register = zero_register_class_descriptor,
|
.not_a_register = zero_register_class_descriptor,
|
||||||
.any = zero_register_class_descriptor,
|
.any = zero_register_class_descriptor,
|
||||||
|
.gp8 = .{
|
||||||
|
.size = @sizeOf(u8),
|
||||||
|
.spill_size = @sizeOf(u8),
|
||||||
|
.spill_alignment = @sizeOf(u8),
|
||||||
|
},
|
||||||
|
.gp16 = .{
|
||||||
|
.size = @sizeOf(u16),
|
||||||
|
.spill_size = @sizeOf(u16),
|
||||||
|
.spill_alignment = @sizeOf(u16),
|
||||||
|
},
|
||||||
.gp32 = .{
|
.gp32 = .{
|
||||||
.size = 32,
|
.size = @sizeOf(u32),
|
||||||
.spill_size = 32,
|
.spill_size = @sizeOf(u32),
|
||||||
.spill_alignment = 32,
|
.spill_alignment = @sizeOf(u32),
|
||||||
},
|
},
|
||||||
.gp64 = .{
|
.gp64 = .{
|
||||||
.size = 64,
|
.size = @sizeOf(u64),
|
||||||
.spill_size = 64,
|
.spill_size = @sizeOf(u64),
|
||||||
.spill_alignment = 64,
|
.spill_alignment = @sizeOf(u64),
|
||||||
},
|
},
|
||||||
.gp64_nosp = .{
|
.gp64_nosp = .{
|
||||||
.size = 64,
|
.size = @sizeOf(u64),
|
||||||
.spill_size = 64,
|
.spill_size = @sizeOf(u64),
|
||||||
.spill_alignment = 64,
|
.spill_alignment = @sizeOf(u64),
|
||||||
},
|
},
|
||||||
.ccr = .{
|
.ccr = .{
|
||||||
.size = 32,
|
.size = @sizeOf(u32),
|
||||||
.spill_size = 32,
|
.spill_size = @sizeOf(u32),
|
||||||
.spill_alignment = 32,
|
.spill_alignment = @sizeOf(u32),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const registers_by_class = RegisterGroupMap.init(.{
|
const registers_by_class = RegisterGroupMap.init(.{
|
||||||
.not_a_register = &.{},
|
.not_a_register = &.{},
|
||||||
.any = &.{},
|
.any = &.{},
|
||||||
|
.gp8 = &.{
|
||||||
|
.al,
|
||||||
|
.cl,
|
||||||
|
.dl,
|
||||||
|
.ah,
|
||||||
|
.ch,
|
||||||
|
.dh,
|
||||||
|
.bl,
|
||||||
|
.bh,
|
||||||
|
.sil,
|
||||||
|
.dil,
|
||||||
|
.bpl,
|
||||||
|
.spl,
|
||||||
|
.r8b,
|
||||||
|
.r9b,
|
||||||
|
.r10b,
|
||||||
|
.r11b,
|
||||||
|
.r14b,
|
||||||
|
.r15b,
|
||||||
|
.r12b,
|
||||||
|
.r13b,
|
||||||
|
},
|
||||||
|
.gp16 = &.{
|
||||||
|
.ax,
|
||||||
|
.cx,
|
||||||
|
.dx,
|
||||||
|
.si,
|
||||||
|
.di,
|
||||||
|
.bx,
|
||||||
|
.bp,
|
||||||
|
.sp,
|
||||||
|
.r8w,
|
||||||
|
.r9w,
|
||||||
|
.r10w,
|
||||||
|
.r11w,
|
||||||
|
.r14w,
|
||||||
|
.r15w,
|
||||||
|
.r12w,
|
||||||
|
.r13w,
|
||||||
|
},
|
||||||
.gp32 = &.{
|
.gp32 = &.{
|
||||||
.eax,
|
.eax,
|
||||||
.ecx,
|
.ecx,
|
||||||
@ -881,6 +931,8 @@ const system_v = CallingConvention{
|
|||||||
.argument_registers = RegisterGroupMap.init(.{
|
.argument_registers = RegisterGroupMap.init(.{
|
||||||
.not_a_register = &.{},
|
.not_a_register = &.{},
|
||||||
.any = &.{},
|
.any = &.{},
|
||||||
|
.gp8 = &.{},
|
||||||
|
.gp16 = &.{},
|
||||||
.gp32 = &system_v_gp32_argument_registers,
|
.gp32 = &system_v_gp32_argument_registers,
|
||||||
.gp64 = &system_v_gp64_argument_registers,
|
.gp64 = &system_v_gp64_argument_registers,
|
||||||
.gp64_nosp = &.{},
|
.gp64_nosp = &.{},
|
||||||
@ -917,8 +969,8 @@ const ValueType = struct {
|
|||||||
any = 0,
|
any = 0,
|
||||||
// other = 1,
|
// other = 1,
|
||||||
// i1 = 2,
|
// i1 = 2,
|
||||||
// i8 = 3,
|
i8 = 3,
|
||||||
// i16 = 4,
|
i16 = 4,
|
||||||
i32 = 5,
|
i32 = 5,
|
||||||
i64 = 6,
|
i64 = 6,
|
||||||
// i128 = 7,
|
// i128 = 7,
|
||||||
@ -934,6 +986,20 @@ const value_types = std.EnumArray(ValueType.Id, ValueType).init(.{
|
|||||||
.data_type = .integer,
|
.data_type = .integer,
|
||||||
.scalarness = .scalar,
|
.scalarness = .scalar,
|
||||||
},
|
},
|
||||||
|
.i8 = .{
|
||||||
|
.size = @sizeOf(u8),
|
||||||
|
.element_count = 1,
|
||||||
|
.element_type = @intFromEnum(ValueType.Id.i8),
|
||||||
|
.data_type = .integer,
|
||||||
|
.scalarness = .scalar,
|
||||||
|
},
|
||||||
|
.i16 = .{
|
||||||
|
.size = @sizeOf(u16),
|
||||||
|
.element_count = 1,
|
||||||
|
.element_type = @intFromEnum(ValueType.Id.i16),
|
||||||
|
.data_type = .integer,
|
||||||
|
.scalarness = .scalar,
|
||||||
|
},
|
||||||
.i32 = .{
|
.i32 = .{
|
||||||
.size = @sizeOf(u32),
|
.size = @sizeOf(u32),
|
||||||
.element_count = 1,
|
.element_count = 1,
|
||||||
@ -959,6 +1025,8 @@ const value_types = std.EnumArray(ValueType.Id, ValueType).init(.{
|
|||||||
|
|
||||||
const register_classes = std.EnumArray(ValueType.Id, Register.Class).init(.{
|
const register_classes = std.EnumArray(ValueType.Id, Register.Class).init(.{
|
||||||
.any = .any,
|
.any = .any,
|
||||||
|
.i8 = .gp8,
|
||||||
|
.i16 = .gp16,
|
||||||
.i32 = .gp32,
|
.i32 = .gp32,
|
||||||
.i64 = .gp64,
|
.i64 = .gp64,
|
||||||
.ccr = .ccr,
|
.ccr = .ccr,
|
||||||
@ -1076,7 +1144,7 @@ const InstructionSelection = struct {
|
|||||||
fn loadRegisterFromStackSlot(instruction_selection: *InstructionSelection, mir: *MIR, insert_before_instruction_index: usize, destination_register: Register.Physical, frame_index: u32, register_class: Register.Class, virtual_register: Register.Virtual.Index) !void {
|
fn loadRegisterFromStackSlot(instruction_selection: *InstructionSelection, mir: *MIR, insert_before_instruction_index: usize, destination_register: Register.Physical, frame_index: u32, register_class: Register.Class, virtual_register: Register.Virtual.Index) !void {
|
||||||
_ = virtual_register;
|
_ = virtual_register;
|
||||||
const stack_object = instruction_selection.stack_objects.items[frame_index];
|
const stack_object = instruction_selection.stack_objects.items[frame_index];
|
||||||
switch (@divExact(stack_object.size, 8)) {
|
switch (stack_object.size) {
|
||||||
@sizeOf(u64) => {
|
@sizeOf(u64) => {
|
||||||
switch (register_class) {
|
switch (register_class) {
|
||||||
.gp64 => {
|
.gp64 => {
|
||||||
@ -1203,8 +1271,6 @@ const InstructionSelection = struct {
|
|||||||
// const destination_register = try instruction_selection.getRegisterForValue(mir, ir_instruction_index);
|
// const destination_register = try instruction_selection.getRegisterForValue(mir, ir_instruction_index);
|
||||||
const integer = mir.ir.instructions.get(ir_instruction_index).u.load_integer;
|
const integer = mir.ir.instructions.get(ir_instruction_index).u.load_integer;
|
||||||
const value_type = resolveType(integer.type);
|
const value_type = resolveType(integer.type);
|
||||||
// const destination_register_class = register_classes.get(value_type);
|
|
||||||
// const instruction_id: Instruction.Id =
|
|
||||||
switch (integer.value.unsigned == 0) {
|
switch (integer.value.unsigned == 0) {
|
||||||
true => {
|
true => {
|
||||||
const instruction_id: Instruction.Id = switch (value_type) {
|
const instruction_id: Instruction.Id = switch (value_type) {
|
||||||
@ -1534,6 +1600,10 @@ const Instruction = struct {
|
|||||||
or32mr,
|
or32mr,
|
||||||
or32rr,
|
or32rr,
|
||||||
ret,
|
ret,
|
||||||
|
shl32mi,
|
||||||
|
shl32ri,
|
||||||
|
shr32mi,
|
||||||
|
shr32ri,
|
||||||
sub32mr,
|
sub32mr,
|
||||||
sub32rr,
|
sub32rr,
|
||||||
sub32rm,
|
sub32rm,
|
||||||
@ -2289,6 +2359,78 @@ const instruction_descriptors = std.EnumArray(Instruction.Id, Instruction.Descri
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
.shl32ri = .{
|
||||||
|
.opcode = 0xc1,
|
||||||
|
.operands = &.{
|
||||||
|
.{
|
||||||
|
.id = .gp32,
|
||||||
|
.kind = .dst,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.id = .gp32,
|
||||||
|
.kind = .src,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.id = .imm8,
|
||||||
|
.kind = .src,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.implicit_definitions = &.{.eflags},
|
||||||
|
},
|
||||||
|
.shr32ri = .{
|
||||||
|
.opcode = 0xc1,
|
||||||
|
.operands = &.{
|
||||||
|
.{
|
||||||
|
.id = .gp32,
|
||||||
|
.kind = .dst,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.id = .gp32,
|
||||||
|
.kind = .src,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.id = .imm8,
|
||||||
|
.kind = .src,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.implicit_definitions = &.{.eflags},
|
||||||
|
},
|
||||||
|
.shl32mi = .{
|
||||||
|
.opcode = 0xc1,
|
||||||
|
.operands = &.{
|
||||||
|
.{
|
||||||
|
.id = .i32mem,
|
||||||
|
.kind = .dst,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.id = .i32mem,
|
||||||
|
.kind = .src,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.id = .imm8,
|
||||||
|
.kind = .src,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.implicit_definitions = &.{.eflags},
|
||||||
|
},
|
||||||
|
.shr32mi = .{
|
||||||
|
.opcode = 0xc1,
|
||||||
|
.operands = &.{
|
||||||
|
.{
|
||||||
|
.id = .i32mem,
|
||||||
|
.kind = .dst,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.id = .i32mem,
|
||||||
|
.kind = .src,
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.id = .imm8,
|
||||||
|
.kind = .src,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.implicit_definitions = &.{.eflags},
|
||||||
|
},
|
||||||
.sub32mr = .{
|
.sub32mr = .{
|
||||||
// .format = .mrm_dest_reg, // right?
|
// .format = .mrm_dest_reg, // right?
|
||||||
.opcode = 0x29,
|
.opcode = 0x29,
|
||||||
@ -2542,6 +2684,7 @@ pub const MIR = struct {
|
|||||||
const value_type = resolveType(ir_type);
|
const value_type = resolveType(ir_type);
|
||||||
const type_info = value_types.get(value_type);
|
const type_info = value_types.get(value_type);
|
||||||
const total_size = type_info.size * stack.count;
|
const total_size = type_info.size * stack.count;
|
||||||
|
assert(total_size <= 8);
|
||||||
const frame_index = try mir.createStackObject(instruction_selection, total_size, @intCast(stack.alignment), ir_instruction_index, false);
|
const frame_index = try mir.createStackObject(instruction_selection, total_size, @intCast(stack.alignment), ir_instruction_index, false);
|
||||||
try instruction_selection.stack_map.putNoClobber(allocator, ir_instruction_index, frame_index);
|
try instruction_selection.stack_map.putNoClobber(allocator, ir_instruction_index, frame_index);
|
||||||
}
|
}
|
||||||
@ -3112,13 +3255,21 @@ pub const MIR = struct {
|
|||||||
const ir_binary_operation = mir.ir.binary_operations.get(ir_binary_operation_index);
|
const ir_binary_operation = mir.ir.binary_operations.get(ir_binary_operation_index);
|
||||||
const value_type = resolveType(ir_binary_operation.type);
|
const value_type = resolveType(ir_binary_operation.type);
|
||||||
|
|
||||||
const is_left_load = switch (mir.ir.instructions.get(ir_binary_operation.left).u) {
|
const BinaryOperandKind = enum {
|
||||||
.load => true,
|
load,
|
||||||
else => false,
|
immediate,
|
||||||
|
rest,
|
||||||
};
|
};
|
||||||
const is_right_load = switch (mir.ir.instructions.get(ir_binary_operation.right).u) {
|
|
||||||
.load => true,
|
const left_kind: BinaryOperandKind = switch (mir.ir.instructions.get(ir_binary_operation.left).u) {
|
||||||
else => false,
|
.load => .load,
|
||||||
|
.load_integer => .immediate,
|
||||||
|
else => .rest,
|
||||||
|
};
|
||||||
|
const right_kind: BinaryOperandKind = switch (mir.ir.instructions.get(ir_binary_operation.right).u) {
|
||||||
|
.load => .load,
|
||||||
|
.load_integer => .immediate,
|
||||||
|
else => .rest,
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (ir_binary_operation.id) {
|
switch (ir_binary_operation.id) {
|
||||||
@ -3163,7 +3314,7 @@ pub const MIR = struct {
|
|||||||
});
|
});
|
||||||
try instruction_selection.instruction_cache.append(mir.allocator, copy_low);
|
try instruction_selection.instruction_cache.append(mir.allocator, copy_low);
|
||||||
|
|
||||||
if (is_right_load) {
|
if (right_kind == .load) {
|
||||||
try instruction_selection.folded_loads.putNoClobber(mir.allocator, ir_binary_operation.right, {});
|
try instruction_selection.folded_loads.putNoClobber(mir.allocator, ir_binary_operation.right, {});
|
||||||
|
|
||||||
const instruction_id: Instruction.Id = switch (value_type) {
|
const instruction_id: Instruction.Id = switch (value_type) {
|
||||||
@ -3254,157 +3405,11 @@ pub const MIR = struct {
|
|||||||
// const use = mir.ir.instructions.get(use_index);
|
// const use = mir.ir.instructions.get(use_index);
|
||||||
// std.debug.print("Use: {s}\n", .{@tagName(use.u)});
|
// std.debug.print("Use: {s}\n", .{@tagName(use.u)});
|
||||||
// }
|
// }
|
||||||
|
switch (left_kind) {
|
||||||
if (!is_left_load and is_right_load) {
|
.load => switch (right_kind) {
|
||||||
unreachable;
|
.load => {
|
||||||
} else if (is_left_load and !is_right_load) {
|
|
||||||
try instruction_selection.folded_loads.putNoClobber(mir.allocator, ir_binary_operation.left, {});
|
|
||||||
const instruction_id: Instruction.Id = switch (ir_binary_operation.id) {
|
|
||||||
.add => switch (value_type) {
|
|
||||||
.i32 => .add32mr,
|
|
||||||
else => unreachable,
|
|
||||||
},
|
|
||||||
.sub => switch (value_type) {
|
|
||||||
.i32 => .sub32mr,
|
|
||||||
else => unreachable,
|
|
||||||
},
|
|
||||||
.logical_and => switch (value_type) {
|
|
||||||
.i32 => .and32mr,
|
|
||||||
else => unreachable,
|
|
||||||
},
|
|
||||||
.logical_xor => switch (value_type) {
|
|
||||||
.i32 => .xor32mr,
|
|
||||||
else => unreachable,
|
|
||||||
},
|
|
||||||
.logical_or => switch (value_type) {
|
|
||||||
.i32 => .or32mr,
|
|
||||||
else => unreachable,
|
|
||||||
},
|
|
||||||
.signed_multiply => switch (value_type) {
|
|
||||||
.i32 => .imul32mr,
|
|
||||||
else => unreachable,
|
|
||||||
},
|
|
||||||
.signed_divide => unreachable,
|
|
||||||
};
|
|
||||||
|
|
||||||
const instruction_descriptor = instruction_descriptors.get(instruction_id);
|
|
||||||
// const left_register = try instruction_selection.getRegisterForValue(mir, ir_binary_operation.left);
|
|
||||||
const destination_operand_id = instruction_descriptor.operands[0].id;
|
|
||||||
const left_operand_id = instruction_descriptor.operands[1].id;
|
|
||||||
const right_operand_id = instruction_descriptor.operands[2].id;
|
|
||||||
// const ir_load = mir.ir.loads.get(mir.ir.instructions.get(ir_binary_operation.right).u.load);
|
|
||||||
// const right_operand_addressing_mode = instruction_selection.getAddressingModeFromIr(mir, ir_load.instruction);
|
|
||||||
const ir_load = mir.ir.loads.get(mir.ir.instructions.get(ir_binary_operation.left).u.load);
|
|
||||||
|
|
||||||
const right_register = try instruction_selection.getRegisterForValue(mir, ir_binary_operation.right);
|
|
||||||
const right_operand = Operand{
|
|
||||||
.id = right_operand_id,
|
|
||||||
.u = .{
|
|
||||||
.register = right_register,
|
|
||||||
},
|
|
||||||
.flags = .{},
|
|
||||||
};
|
|
||||||
|
|
||||||
const left_operand_addressing_mode = instruction_selection.getAddressingModeFromIr(mir, ir_load.instruction);
|
|
||||||
const destination_operand = Operand{
|
|
||||||
.id = destination_operand_id,
|
|
||||||
.u = .{
|
|
||||||
.memory = .{ .addressing_mode = left_operand_addressing_mode },
|
|
||||||
},
|
|
||||||
.flags = .{},
|
|
||||||
};
|
|
||||||
|
|
||||||
const left_operand = Operand{
|
|
||||||
.id = left_operand_id,
|
|
||||||
.u = .{
|
|
||||||
.memory = .{ .addressing_mode = left_operand_addressing_mode },
|
|
||||||
},
|
|
||||||
.flags = .{},
|
|
||||||
};
|
|
||||||
|
|
||||||
const binary_op_instruction = try mir.buildInstruction(instruction_selection, instruction_id, &.{
|
|
||||||
destination_operand,
|
|
||||||
left_operand,
|
|
||||||
right_operand,
|
|
||||||
});
|
|
||||||
|
|
||||||
try instruction_selection.instruction_cache.append(mir.allocator, binary_op_instruction);
|
|
||||||
} else if (!is_left_load and !is_right_load) {
|
|
||||||
const destination_register = try instruction_selection.getRegisterForValue(mir, ir_instruction_index);
|
|
||||||
const instruction_id: Instruction.Id = switch (ir_binary_operation.id) {
|
|
||||||
.add => switch (value_type) {
|
|
||||||
.i32 => .add32rr,
|
|
||||||
else => unreachable,
|
|
||||||
},
|
|
||||||
.sub => switch (value_type) {
|
|
||||||
.i32 => .sub32rr,
|
|
||||||
else => unreachable,
|
|
||||||
},
|
|
||||||
.logical_and => switch (value_type) {
|
|
||||||
.i32 => .and32rr,
|
|
||||||
else => unreachable,
|
|
||||||
},
|
|
||||||
.logical_xor => switch (value_type) {
|
|
||||||
.i32 => .xor32rr,
|
|
||||||
else => unreachable,
|
|
||||||
},
|
|
||||||
.logical_or => switch (value_type) {
|
|
||||||
.i32 => .or32rr,
|
|
||||||
else => unreachable,
|
|
||||||
},
|
|
||||||
.signed_multiply => switch (value_type) {
|
|
||||||
.i32 => .imul32rr,
|
|
||||||
else => unreachable,
|
|
||||||
},
|
|
||||||
.signed_divide => unreachable,
|
|
||||||
};
|
|
||||||
|
|
||||||
const instruction_descriptor = instruction_descriptors.get(instruction_id);
|
|
||||||
const left_register = try instruction_selection.getRegisterForValue(mir, ir_binary_operation.left);
|
|
||||||
const right_register = try instruction_selection.getRegisterForValue(mir, ir_binary_operation.right);
|
|
||||||
const destination_operand_id = instruction_descriptor.operands[0].id;
|
|
||||||
const left_operand_id = instruction_descriptor.operands[1].id;
|
|
||||||
|
|
||||||
const right_operand_id = instruction_descriptor.operands[2].id;
|
|
||||||
|
|
||||||
const destination_operand = Operand{
|
|
||||||
.id = destination_operand_id,
|
|
||||||
.u = .{
|
|
||||||
.register = destination_register,
|
|
||||||
},
|
|
||||||
.flags = .{
|
|
||||||
.type = .def,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const left_operand = Operand{
|
|
||||||
.id = left_operand_id,
|
|
||||||
.u = .{
|
|
||||||
.register = left_register,
|
|
||||||
},
|
|
||||||
.flags = .{},
|
|
||||||
};
|
|
||||||
|
|
||||||
const right_operand = Operand{
|
|
||||||
.id = right_operand_id,
|
|
||||||
.u = .{
|
|
||||||
.register = right_register,
|
|
||||||
},
|
|
||||||
.flags = .{},
|
|
||||||
};
|
|
||||||
|
|
||||||
const binary_op_instruction = try mir.buildInstruction(instruction_selection, instruction_id, &.{
|
|
||||||
destination_operand,
|
|
||||||
left_operand,
|
|
||||||
right_operand,
|
|
||||||
});
|
|
||||||
|
|
||||||
try instruction_selection.instruction_cache.append(mir.allocator, binary_op_instruction);
|
|
||||||
|
|
||||||
try instruction_selection.updateValueMap(mir.allocator, ir_instruction_index, destination_register, false);
|
|
||||||
} else {
|
|
||||||
const destination_register = try instruction_selection.getRegisterForValue(mir, ir_instruction_index);
|
|
||||||
// If both operands come from memory (both operands are loads), load the left one into a register and operate from the stack with the right one, when possible
|
// If both operands come from memory (both operands are loads), load the left one into a register and operate from the stack with the right one, when possible
|
||||||
|
const destination_register = try instruction_selection.getRegisterForValue(mir, ir_instruction_index);
|
||||||
const instruction_id: Instruction.Id = switch (ir_binary_operation.id) {
|
const instruction_id: Instruction.Id = switch (ir_binary_operation.id) {
|
||||||
.add => switch (value_type) {
|
.add => switch (value_type) {
|
||||||
.i32 => .add32rm,
|
.i32 => .add32rm,
|
||||||
@ -3431,6 +3436,8 @@ pub const MIR = struct {
|
|||||||
else => unreachable,
|
else => unreachable,
|
||||||
},
|
},
|
||||||
.signed_divide => unreachable,
|
.signed_divide => unreachable,
|
||||||
|
.shift_left => unreachable,
|
||||||
|
.shift_right => unreachable,
|
||||||
};
|
};
|
||||||
|
|
||||||
try instruction_selection.folded_loads.putNoClobber(mir.allocator, ir_binary_operation.right, {});
|
try instruction_selection.folded_loads.putNoClobber(mir.allocator, ir_binary_operation.right, {});
|
||||||
@ -3478,7 +3485,306 @@ pub const MIR = struct {
|
|||||||
try instruction_selection.instruction_cache.append(mir.allocator, binary_op_instruction);
|
try instruction_selection.instruction_cache.append(mir.allocator, binary_op_instruction);
|
||||||
|
|
||||||
try instruction_selection.updateValueMap(mir.allocator, ir_instruction_index, destination_register, false);
|
try instruction_selection.updateValueMap(mir.allocator, ir_instruction_index, destination_register, false);
|
||||||
|
},
|
||||||
|
.immediate => {
|
||||||
|
const destination_register = try instruction_selection.getRegisterForValue(mir, ir_instruction_index);
|
||||||
|
const instruction_id: Instruction.Id = switch (ir_binary_operation.id) {
|
||||||
|
.shift_left => .shl32ri,
|
||||||
|
.shift_right => .shr32ri,
|
||||||
|
else => |t| @panic(@tagName(t)),
|
||||||
|
};
|
||||||
|
const instruction_descriptor = instruction_descriptors.get(instruction_id);
|
||||||
|
// const left_register = try instruction_selection.getRegisterForValue(mir, ir_binary_operation.left);
|
||||||
|
const left_register = try instruction_selection.getRegisterForValue(mir, ir_binary_operation.left);
|
||||||
|
const destination_operand_id = instruction_descriptor.operands[0].id;
|
||||||
|
const left_operand_id = instruction_descriptor.operands[1].id;
|
||||||
|
|
||||||
|
const destination_operand = Operand{
|
||||||
|
.id = destination_operand_id,
|
||||||
|
.u = .{
|
||||||
|
.register = destination_register,
|
||||||
|
},
|
||||||
|
.flags = .{
|
||||||
|
.type = .def,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const left_operand = Operand{
|
||||||
|
.id = left_operand_id,
|
||||||
|
.u = .{
|
||||||
|
.register = left_register,
|
||||||
|
},
|
||||||
|
.flags = .{},
|
||||||
|
};
|
||||||
|
|
||||||
|
const right_immediate = mir.ir.instructions.get(ir_binary_operation.right).u.load_integer;
|
||||||
|
const right_value_type: ValueType.Id = switch (right_immediate.type) {
|
||||||
|
.i8 => .i8,
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
_ = right_value_type;
|
||||||
|
const right_operand = Operand{
|
||||||
|
.id = .imm8,
|
||||||
|
.u = .{
|
||||||
|
.immediate = right_immediate.value.unsigned,
|
||||||
|
},
|
||||||
|
.flags = .{},
|
||||||
|
};
|
||||||
|
|
||||||
|
const binary_op_instruction = try mir.buildInstruction(instruction_selection, instruction_id, &.{
|
||||||
|
destination_operand,
|
||||||
|
left_operand,
|
||||||
|
right_operand,
|
||||||
|
});
|
||||||
|
|
||||||
|
try instruction_selection.instruction_cache.append(mir.allocator, binary_op_instruction);
|
||||||
|
|
||||||
|
try instruction_selection.updateValueMap(mir.allocator, ir_instruction_index, destination_register, false);
|
||||||
|
},
|
||||||
|
.rest => {
|
||||||
|
const destination_register = try instruction_selection.getRegisterForValue(mir, ir_instruction_index);
|
||||||
|
const instruction_id: Instruction.Id = switch (ir_binary_operation.id) {
|
||||||
|
.add => switch (value_type) {
|
||||||
|
.i32 => .add32rr,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.sub => switch (value_type) {
|
||||||
|
.i32 => .sub32rr,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.logical_and => switch (value_type) {
|
||||||
|
.i32 => .and32rr,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.logical_xor => switch (value_type) {
|
||||||
|
.i32 => .xor32rr,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.logical_or => switch (value_type) {
|
||||||
|
.i32 => .or32rr,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.signed_multiply => switch (value_type) {
|
||||||
|
.i32 => .imul32rr,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.signed_divide => unreachable,
|
||||||
|
.shift_left => unreachable,
|
||||||
|
.shift_right => unreachable,
|
||||||
|
};
|
||||||
|
|
||||||
|
const instruction_descriptor = instruction_descriptors.get(instruction_id);
|
||||||
|
const left_register = try instruction_selection.getRegisterForValue(mir, ir_binary_operation.left);
|
||||||
|
const right_register = try instruction_selection.getRegisterForValue(mir, ir_binary_operation.right);
|
||||||
|
const destination_operand_id = instruction_descriptor.operands[0].id;
|
||||||
|
const left_operand_id = instruction_descriptor.operands[1].id;
|
||||||
|
|
||||||
|
const right_operand_id = instruction_descriptor.operands[2].id;
|
||||||
|
|
||||||
|
const destination_operand = Operand{
|
||||||
|
.id = destination_operand_id,
|
||||||
|
.u = .{
|
||||||
|
.register = destination_register,
|
||||||
|
},
|
||||||
|
.flags = .{
|
||||||
|
.type = .def,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const left_operand = Operand{
|
||||||
|
.id = left_operand_id,
|
||||||
|
.u = .{
|
||||||
|
.register = left_register,
|
||||||
|
},
|
||||||
|
.flags = .{},
|
||||||
|
};
|
||||||
|
|
||||||
|
const right_operand = Operand{
|
||||||
|
.id = right_operand_id,
|
||||||
|
.u = .{
|
||||||
|
.register = right_register,
|
||||||
|
},
|
||||||
|
.flags = .{},
|
||||||
|
};
|
||||||
|
|
||||||
|
const binary_op_instruction = try mir.buildInstruction(instruction_selection, instruction_id, &.{
|
||||||
|
destination_operand,
|
||||||
|
left_operand,
|
||||||
|
right_operand,
|
||||||
|
});
|
||||||
|
|
||||||
|
try instruction_selection.instruction_cache.append(mir.allocator, binary_op_instruction);
|
||||||
|
|
||||||
|
try instruction_selection.updateValueMap(mir.allocator, ir_instruction_index, destination_register, false);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.rest => switch (right_kind) {
|
||||||
|
.load => unreachable,
|
||||||
|
.immediate => unreachable,
|
||||||
|
.rest => {
|
||||||
|
const destination_register = try instruction_selection.getRegisterForValue(mir, ir_instruction_index);
|
||||||
|
const instruction_id: Instruction.Id = switch (ir_binary_operation.id) {
|
||||||
|
.add => switch (value_type) {
|
||||||
|
.i32 => .add32rr,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.sub => switch (value_type) {
|
||||||
|
.i32 => .sub32rr,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.logical_and => switch (value_type) {
|
||||||
|
.i32 => .and32rr,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.logical_xor => switch (value_type) {
|
||||||
|
.i32 => .xor32rr,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.logical_or => switch (value_type) {
|
||||||
|
.i32 => .or32rr,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.signed_multiply => switch (value_type) {
|
||||||
|
.i32 => .imul32rr,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.signed_divide => unreachable,
|
||||||
|
.shift_left => unreachable,
|
||||||
|
.shift_right => unreachable,
|
||||||
|
};
|
||||||
|
|
||||||
|
const instruction_descriptor = instruction_descriptors.get(instruction_id);
|
||||||
|
const left_register = try instruction_selection.getRegisterForValue(mir, ir_binary_operation.left);
|
||||||
|
const right_register = try instruction_selection.getRegisterForValue(mir, ir_binary_operation.right);
|
||||||
|
const destination_operand_id = instruction_descriptor.operands[0].id;
|
||||||
|
const left_operand_id = instruction_descriptor.operands[1].id;
|
||||||
|
|
||||||
|
const right_operand_id = instruction_descriptor.operands[2].id;
|
||||||
|
|
||||||
|
const destination_operand = Operand{
|
||||||
|
.id = destination_operand_id,
|
||||||
|
.u = .{
|
||||||
|
.register = destination_register,
|
||||||
|
},
|
||||||
|
.flags = .{
|
||||||
|
.type = .def,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const left_operand = Operand{
|
||||||
|
.id = left_operand_id,
|
||||||
|
.u = .{
|
||||||
|
.register = left_register,
|
||||||
|
},
|
||||||
|
.flags = .{},
|
||||||
|
};
|
||||||
|
|
||||||
|
const right_operand = Operand{
|
||||||
|
.id = right_operand_id,
|
||||||
|
.u = .{
|
||||||
|
.register = right_register,
|
||||||
|
},
|
||||||
|
.flags = .{},
|
||||||
|
};
|
||||||
|
|
||||||
|
const binary_op_instruction = try mir.buildInstruction(instruction_selection, instruction_id, &.{
|
||||||
|
destination_operand,
|
||||||
|
left_operand,
|
||||||
|
right_operand,
|
||||||
|
});
|
||||||
|
|
||||||
|
try instruction_selection.instruction_cache.append(mir.allocator, binary_op_instruction);
|
||||||
|
|
||||||
|
try instruction_selection.updateValueMap(mir.allocator, ir_instruction_index, destination_register, false);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.immediate => switch (right_kind) {
|
||||||
|
.load => unreachable,
|
||||||
|
.immediate => switch (ir_binary_operation.id) {
|
||||||
|
else => |t| @panic(@tagName(t)),
|
||||||
|
},
|
||||||
|
.rest => unreachable,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
// if (!is_left_load and is_right_load) {
|
||||||
|
// unreachable;
|
||||||
|
// } else if (is_left_load and !is_right_load) {
|
||||||
|
// try instruction_selection.folded_loads.putNoClobber(mir.allocator, ir_binary_operation.left, {});
|
||||||
|
// const instruction_id: Instruction.Id = switch (ir_binary_operation.id) {
|
||||||
|
// .add => switch (value_type) {
|
||||||
|
// .i32 => .add32mr,
|
||||||
|
// else => unreachable,
|
||||||
|
// },
|
||||||
|
// .sub => switch (value_type) {
|
||||||
|
// .i32 => .sub32mr,
|
||||||
|
// else => unreachable,
|
||||||
|
// },
|
||||||
|
// .logical_and => switch (value_type) {
|
||||||
|
// .i32 => .and32mr,
|
||||||
|
// else => unreachable,
|
||||||
|
// },
|
||||||
|
// .logical_xor => switch (value_type) {
|
||||||
|
// .i32 => .xor32mr,
|
||||||
|
// else => unreachable,
|
||||||
|
// },
|
||||||
|
// .logical_or => switch (value_type) {
|
||||||
|
// .i32 => .or32mr,
|
||||||
|
// else => unreachable,
|
||||||
|
// },
|
||||||
|
// .signed_multiply => switch (value_type) {
|
||||||
|
// .i32 => .imul32mr,
|
||||||
|
// else => unreachable,
|
||||||
|
// },
|
||||||
|
// .signed_divide => unreachable,
|
||||||
|
// .shift_left => unreachable,
|
||||||
|
// .shift_right => unreachable,
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// const instruction_descriptor = instruction_descriptors.get(instruction_id);
|
||||||
|
// // const left_register = try instruction_selection.getRegisterForValue(mir, ir_binary_operation.left);
|
||||||
|
// const destination_operand_id = instruction_descriptor.operands[0].id;
|
||||||
|
// const left_operand_id = instruction_descriptor.operands[1].id;
|
||||||
|
// const right_operand_id = instruction_descriptor.operands[2].id;
|
||||||
|
// // const ir_load = mir.ir.loads.get(mir.ir.instructions.get(ir_binary_operation.right).u.load);
|
||||||
|
// // const right_operand_addressing_mode = instruction_selection.getAddressingModeFromIr(mir, ir_load.instruction);
|
||||||
|
// const ir_load = mir.ir.loads.get(mir.ir.instructions.get(ir_binary_operation.left).u.load);
|
||||||
|
//
|
||||||
|
// const right_register = try instruction_selection.getRegisterForValue(mir, ir_binary_operation.right);
|
||||||
|
// const right_operand = Operand{
|
||||||
|
// .id = right_operand_id,
|
||||||
|
// .u = .{
|
||||||
|
// .register = right_register,
|
||||||
|
// },
|
||||||
|
// .flags = .{},
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// const left_operand_addressing_mode = instruction_selection.getAddressingModeFromIr(mir, ir_load.instruction);
|
||||||
|
// const destination_operand = Operand{
|
||||||
|
// .id = destination_operand_id,
|
||||||
|
// .u = .{
|
||||||
|
// .memory = .{ .addressing_mode = left_operand_addressing_mode },
|
||||||
|
// },
|
||||||
|
// .flags = .{},
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// const left_operand = Operand{
|
||||||
|
// .id = left_operand_id,
|
||||||
|
// .u = .{
|
||||||
|
// .memory = .{ .addressing_mode = left_operand_addressing_mode },
|
||||||
|
// },
|
||||||
|
// .flags = .{},
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// const binary_op_instruction = try mir.buildInstruction(instruction_selection, instruction_id, &.{
|
||||||
|
// destination_operand,
|
||||||
|
// left_operand,
|
||||||
|
// right_operand,
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// try instruction_selection.instruction_cache.append(mir.allocator, binary_op_instruction);
|
||||||
|
// } else if (!is_left_load and !is_right_load) {
|
||||||
|
// } else {
|
||||||
|
// }
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -3798,6 +4104,7 @@ pub const MIR = struct {
|
|||||||
const virtual_register = live_register.virtual;
|
const virtual_register = live_register.virtual;
|
||||||
const register_class = mir.virtual_registers.get(live_register.virtual).register_class;
|
const register_class = mir.virtual_registers.get(live_register.virtual).register_class;
|
||||||
|
|
||||||
|
logln(.codegen, .register_allocation_problematic_hint, "Hint 1: {?}", .{maybe_hint});
|
||||||
if (maybe_hint) |hint_register| {
|
if (maybe_hint) |hint_register| {
|
||||||
logln(.codegen, .register_allocation_problematic_hint, "Hint register 1: {s}", .{@tagName(hint_register.index.physical)});
|
logln(.codegen, .register_allocation_problematic_hint, "Hint register 1: {s}", .{@tagName(hint_register.index.physical)});
|
||||||
if (hint_register.index == .physical) {
|
if (hint_register.index == .physical) {
|
||||||
@ -3821,6 +4128,7 @@ pub const MIR = struct {
|
|||||||
logln(.codegen, .register_allocation_problematic_hint, "Tracing copies for VR{} in instruction #{}", .{ virtual_register.uniqueInteger(), instruction_index.uniqueInteger() });
|
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);
|
||||||
|
logln(.codegen, .register_allocation_problematic_hint, "Hint 2: {?}", .{maybe_hint2});
|
||||||
if (maybe_hint2) |hint| {
|
if (maybe_hint2) |hint| {
|
||||||
// TODO
|
// TODO
|
||||||
const allocatable = true;
|
const allocatable = true;
|
||||||
@ -3855,6 +4163,7 @@ pub const MIR = struct {
|
|||||||
for (register_class_members) |candidate_register| {
|
for (register_class_members) |candidate_register| {
|
||||||
if (!register_allocator.isRegisterUsedInInstruction(candidate_register, look_at_physical_register_uses)) {
|
if (!register_allocator.isRegisterUsedInInstruction(candidate_register, look_at_physical_register_uses)) {
|
||||||
const spill_cost = register_allocator.computeSpillCost(candidate_register);
|
const spill_cost = register_allocator.computeSpillCost(candidate_register);
|
||||||
|
logln(.codegen, .register_allocation_problematic_hint, "Candidate: {s}. Spill cost: {}", .{ @tagName(candidate_register), spill_cost });
|
||||||
|
|
||||||
if (spill_cost == 0) {
|
if (spill_cost == 0) {
|
||||||
register_allocator.assignVirtualToPhysicalRegister(live_register, candidate_register);
|
register_allocator.assignVirtualToPhysicalRegister(live_register, candidate_register);
|
||||||
@ -3891,7 +4200,10 @@ pub const MIR = struct {
|
|||||||
.free => 0,
|
.free => 0,
|
||||||
.preassigned => SpillCost.impossible,
|
.preassigned => SpillCost.impossible,
|
||||||
.virtual => |virtual_register_index| blk: {
|
.virtual => |virtual_register_index| blk: {
|
||||||
const sure_spill = register_allocator.stack_slots.get(virtual_register_index) != null or register_allocator.live_virtual_registers.get(virtual_register_index).?.live_out;
|
const stack_slot = register_allocator.stack_slots.get(virtual_register_index) != null;
|
||||||
|
const live_out = register_allocator.live_virtual_registers.get(virtual_register_index).?.live_out;
|
||||||
|
log(.codegen, .register_allocation_problematic_hint, "Register {s} has stack slot: {}. Live out: {}", .{ @tagName(physical_register), stack_slot, live_out });
|
||||||
|
const sure_spill = stack_slot or live_out;
|
||||||
break :blk if (sure_spill) SpillCost.clean else SpillCost.dirty;
|
break :blk if (sure_spill) SpillCost.clean else SpillCost.dirty;
|
||||||
},
|
},
|
||||||
.livein => unreachable,
|
.livein => unreachable,
|
||||||
@ -4056,10 +4368,12 @@ pub const MIR = struct {
|
|||||||
return switch (state.*) {
|
return switch (state.*) {
|
||||||
.free => false,
|
.free => false,
|
||||||
.preassigned => blk: {
|
.preassigned => blk: {
|
||||||
|
logln(.codegen, .register_allocation_problematic_hint, "Freeing preassigned {s} at displacePhysicalRegister", .{@tagName(physical_register)});
|
||||||
state.* = .free;
|
state.* = .free;
|
||||||
break :blk true;
|
break :blk true;
|
||||||
},
|
},
|
||||||
.virtual => |virtual_register| blk: {
|
.virtual => |virtual_register| blk: {
|
||||||
|
logln(.codegen, .register_allocation_problematic_hint, "Freeing assigned {s} at displacePhysicalRegister", .{@tagName(physical_register)});
|
||||||
const live_reg = register_allocator.live_virtual_registers.getPtr(virtual_register).?;
|
const live_reg = register_allocator.live_virtual_registers.getPtr(virtual_register).?;
|
||||||
const before = mir.getNextInstructionIndex(instruction_index);
|
const before = mir.getNextInstructionIndex(instruction_index);
|
||||||
try register_allocator.reload(mir, instruction_selection, before, virtual_register, physical_register);
|
try register_allocator.reload(mir, instruction_selection, before, virtual_register, physical_register);
|
||||||
@ -4099,7 +4413,10 @@ pub const MIR = struct {
|
|||||||
const state = register_allocator.register_states.getPtr(physical_register);
|
const state = register_allocator.register_states.getPtr(physical_register);
|
||||||
switch (state.*) {
|
switch (state.*) {
|
||||||
.free => unreachable,
|
.free => unreachable,
|
||||||
.preassigned => state.* = .free,
|
.preassigned => {
|
||||||
|
logln(.codegen, .register_allocation_problematic_hint, "Freeing preassigned {s} at freePhysicalRegister", .{@tagName(physical_register)});
|
||||||
|
state.* = .free;
|
||||||
|
},
|
||||||
.virtual => |virtual_register_index| {
|
.virtual => |virtual_register_index| {
|
||||||
const live_register = register_allocator.live_virtual_registers.getPtr(virtual_register_index).?;
|
const live_register = register_allocator.live_virtual_registers.getPtr(virtual_register_index).?;
|
||||||
assert(live_register.physical == physical_register);
|
assert(live_register.physical == physical_register);
|
||||||
@ -4255,37 +4572,35 @@ pub const MIR = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn reloadAtBegin(register_allocator: *RegisterAllocator, mir: *MIR, instruction_selection: *InstructionSelection, basic_block: BasicBlock.Index) !void {
|
fn reloadAtBegin(register_allocator: *RegisterAllocator, mir: *MIR, instruction_selection: *InstructionSelection, basic_block: BasicBlock.Index) !void {
|
||||||
_ = instruction_selection;
|
|
||||||
_ = mir;
|
|
||||||
_ = register_allocator;
|
|
||||||
_ = basic_block;
|
_ = basic_block;
|
||||||
// if (register_allocator.live_virtual_registers.entries.len > 0) {
|
if (register_allocator.live_virtual_registers.entries.len > 0) {
|
||||||
// // 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: {}", .{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;
|
||||||
// if (physical_register == .no_register) {
|
if (physical_register == .no_register) {
|
||||||
// continue;
|
continue;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// if (register_allocator.register_states.get(physical_register) == .livein) {
|
if (register_allocator.register_states.get(physical_register) == .livein) {
|
||||||
// unreachable;
|
unreachable;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// // assert?
|
// assert?
|
||||||
//
|
|
||||||
// const virtual_register = live_register.virtual;
|
const virtual_register = live_register.virtual;
|
||||||
// if (false) {
|
if (false) {
|
||||||
// unreachable;
|
unreachable;
|
||||||
// } else {
|
} else {
|
||||||
// try register_allocator.reload(mir, instruction_selection, 0, virtual_register, physical_register);
|
try register_allocator.reload(mir, instruction_selection, 0, virtual_register, physical_register);
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// unreachable;
|
|
||||||
// }
|
register_allocator.live_virtual_registers.clearRetainingCapacity();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -4523,6 +4838,8 @@ pub const MIR = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try register_allocator.reloadAtBegin(mir, instruction_selection, block_index);
|
||||||
|
|
||||||
for (register_allocator.coalesced.items) |coalesced| {
|
for (register_allocator.coalesced.items) |coalesced| {
|
||||||
for (block.instructions.items, 0..) |instruction_index, i| {
|
for (block.instructions.items, 0..) |instruction_index, i| {
|
||||||
if (coalesced.eq(instruction_index)) {
|
if (coalesced.eq(instruction_index)) {
|
||||||
@ -4616,6 +4933,7 @@ pub const MIR = struct {
|
|||||||
for (stack_objects) |stack_object| {
|
for (stack_objects) |stack_object| {
|
||||||
result += @intCast(stack_object.size);
|
result += @intCast(stack_object.size);
|
||||||
result = std.mem.alignForward(u32, result, stack_object.alignment);
|
result = std.mem.alignForward(u32, result, stack_object.alignment);
|
||||||
|
// logln(.codegen, .register_allocation_problematic_hint, "Stack size: {} after Stack object: {}", .{ result, stack_object });
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -5170,6 +5488,68 @@ pub const MIR = struct {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
.shl32ri,
|
||||||
|
.shr32ri,
|
||||||
|
.shl32mi,
|
||||||
|
.shr32mi,
|
||||||
|
=> {
|
||||||
|
const instruction_descriptor = instruction_descriptors.get(instruction.id);
|
||||||
|
const opcode: u8 = @intCast(instruction_descriptor.opcode);
|
||||||
|
try image.section_manager.appendCodeByte(opcode);
|
||||||
|
|
||||||
|
const destination_operand_index = instruction.operands.items[0];
|
||||||
|
const destination_operand = mir.operands.get(destination_operand_index);
|
||||||
|
|
||||||
|
const left_operand_index = instruction.operands.items[1];
|
||||||
|
const left_operand = mir.operands.get(left_operand_index);
|
||||||
|
|
||||||
|
switch (destination_operand.u) {
|
||||||
|
.memory => switch (destination_operand.u.memory.addressing_mode.base) {
|
||||||
|
.register_base => unreachable,
|
||||||
|
.frame_index => |frame_index| {
|
||||||
|
assert(left_operand.u.memory.addressing_mode.base.frame_index == frame_index);
|
||||||
|
const modrm = ModRm{
|
||||||
|
.rm = @intFromEnum(Encoding.GP64.bp),
|
||||||
|
.reg = switch (instruction.id) {
|
||||||
|
.shl32mi => 4,
|
||||||
|
.shr32mi => 5,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.mod = @as(u2, @intFromBool(false)) << 1 | @intFromBool(true),
|
||||||
|
};
|
||||||
|
try image.section_manager.appendCodeByte(@bitCast(modrm));
|
||||||
|
|
||||||
|
const stack_offset = computeStackOffset(function.instruction_selection.stack_objects.items[0 .. frame_index + 1]);
|
||||||
|
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];
|
||||||
|
try image.section_manager.appendCode(stack_bytes);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.register => {
|
||||||
|
const register = getGP32Encoding(destination_operand.*);
|
||||||
|
// std.debug.print("Register: {}\n", .{register});
|
||||||
|
const modrm = ModRm{
|
||||||
|
.rm = @intCast(@intFromEnum(register)),
|
||||||
|
.reg = switch (instruction.id) {
|
||||||
|
.shl32ri => 4,
|
||||||
|
.shr32ri => 5,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.mod = @as(u2, @intFromBool(true)) << 1 | @intFromBool(true),
|
||||||
|
};
|
||||||
|
try image.section_manager.appendCodeByte(@bitCast(modrm));
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
|
||||||
|
const source_operand_index = instruction.operands.items[2];
|
||||||
|
const source_operand = mir.operands.get(source_operand_index);
|
||||||
|
assert(source_operand.id == .imm8);
|
||||||
|
const source_immediate: u8 = @intCast(source_operand.u.immediate);
|
||||||
|
|
||||||
|
try image.section_manager.appendCodeByte(source_immediate);
|
||||||
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +202,7 @@ const Analyzer = struct {
|
|||||||
const declaration_index = try analyzer.symbolDeclaration(scope_index, statement_node_index, .local);
|
const declaration_index = try analyzer.symbolDeclaration(scope_index, statement_node_index, .local);
|
||||||
const declaration = analyzer.module.declarations.get(declaration_index);
|
const declaration = analyzer.module.declarations.get(declaration_index);
|
||||||
const init_value = analyzer.module.values.get(declaration.init_value);
|
const init_value = analyzer.module.values.get(declaration.init_value);
|
||||||
switch (init_value.isComptime() and declaration.mutability == .@"const") {
|
switch (init_value.isComptime(analyzer.module) and declaration.mutability == .@"const") {
|
||||||
// Dont add comptime declaration statements
|
// Dont add comptime declaration statements
|
||||||
true => continue,
|
true => continue,
|
||||||
false => {
|
false => {
|
||||||
@ -461,7 +461,7 @@ const Analyzer = struct {
|
|||||||
fn processAssignment(analyzer: *Analyzer, scope_index: Scope.Index, node_index: Node.Index) !Value {
|
fn processAssignment(analyzer: *Analyzer, scope_index: Scope.Index, node_index: Node.Index) !Value {
|
||||||
const node = analyzer.getScopeNode(scope_index, node_index);
|
const node = analyzer.getScopeNode(scope_index, node_index);
|
||||||
assert(node.id == .assign);
|
assert(node.id == .assign);
|
||||||
const assignment = switch (node.left.invalid) {
|
switch (node.left.invalid) {
|
||||||
// In an assignment, the node being invalid means a discarding underscore, like this: ```_ = result```
|
// In an assignment, the node being invalid means a discarding underscore, like this: ```_ = result```
|
||||||
true => {
|
true => {
|
||||||
var result = Value{
|
var result = Value{
|
||||||
@ -477,23 +477,25 @@ const Analyzer = struct {
|
|||||||
false => {
|
false => {
|
||||||
// const id = analyzer.tokenIdentifier(.token);
|
// const id = analyzer.tokenIdentifier(.token);
|
||||||
// logln("id: {s}\n", .{id});
|
// logln("id: {s}\n", .{id});
|
||||||
// const left = try analyzer.expression(scope_index, ExpectType.none, statement_node.left);
|
const left = try analyzer.unresolvedAllocate(scope_index, ExpectType.none, node.left);
|
||||||
|
const right = try analyzer.unresolvedAllocate(scope_index, ExpectType{
|
||||||
|
.type_index = left.ptr.getType(analyzer.module),
|
||||||
|
}, node.right);
|
||||||
|
|
||||||
// if (analyzer.module.values.get(left).isComptime() and analyzer.module.values.get(right).isComptime()) {
|
if (left.ptr.isComptime(analyzer.module) and right.ptr.isComptime(analyzer.module)) {
|
||||||
// unreachable;
|
|
||||||
// } else {
|
|
||||||
// const assignment_index = try analyzer.module.assignments.append(analyzer.allocator, .{
|
|
||||||
// .store = result.left,
|
|
||||||
// .load = result.right,
|
|
||||||
// });
|
|
||||||
// return assignment_index;
|
|
||||||
// }
|
|
||||||
unreachable;
|
unreachable;
|
||||||
},
|
} else {
|
||||||
|
const assignment = try analyzer.module.assignments.append(analyzer.allocator, .{
|
||||||
|
.store = left.index,
|
||||||
|
.load = right.index,
|
||||||
|
});
|
||||||
|
|
||||||
|
return Value{
|
||||||
|
.assign = assignment.index,
|
||||||
};
|
};
|
||||||
_ = assignment;
|
}
|
||||||
|
},
|
||||||
unreachable;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn processReturn(analyzer: *Analyzer, scope_index: Scope.Index, expect_type: ExpectType, node_index: Node.Index) !Value {
|
fn processReturn(analyzer: *Analyzer, scope_index: Scope.Index, expect_type: ExpectType, node_index: Node.Index) !Value {
|
||||||
@ -524,20 +526,7 @@ const Analyzer = struct {
|
|||||||
|
|
||||||
fn processBinaryOperation(analyzer: *Analyzer, scope_index: Scope.Index, expect_type: ExpectType, node_index: Node.Index) !Value {
|
fn processBinaryOperation(analyzer: *Analyzer, scope_index: Scope.Index, expect_type: ExpectType, node_index: Node.Index) !Value {
|
||||||
const node = analyzer.getScopeNode(scope_index, node_index);
|
const node = analyzer.getScopeNode(scope_index, node_index);
|
||||||
|
const binary_operation_id: Compilation.BinaryOperation.Id = switch (node.id) {
|
||||||
const left_allocation = try analyzer.unresolvedAllocate(scope_index, expect_type, node.left);
|
|
||||||
const right_allocation = try analyzer.unresolvedAllocate(scope_index, expect_type, node.right);
|
|
||||||
const left_type = left_allocation.ptr.getType(analyzer.module);
|
|
||||||
const right_type = right_allocation.ptr.getType(analyzer.module);
|
|
||||||
if (!left_type.eq(right_type)) {
|
|
||||||
unreachable;
|
|
||||||
}
|
|
||||||
|
|
||||||
const binary_operation = try analyzer.module.binary_operations.append(analyzer.allocator, .{
|
|
||||||
.left = left_allocation.index,
|
|
||||||
.right = right_allocation.index,
|
|
||||||
.type = left_type,
|
|
||||||
.id = switch (node.id) {
|
|
||||||
.add => .add,
|
.add => .add,
|
||||||
.sub => .sub,
|
.sub => .sub,
|
||||||
.logical_and => .logical_and,
|
.logical_and => .logical_and,
|
||||||
@ -545,8 +534,38 @@ const Analyzer = struct {
|
|||||||
.logical_or => .logical_or,
|
.logical_or => .logical_or,
|
||||||
.multiply => .multiply,
|
.multiply => .multiply,
|
||||||
.divide => .divide,
|
.divide => .divide,
|
||||||
|
.shift_left => .shift_left,
|
||||||
|
.shift_right => .shift_right,
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
|
};
|
||||||
|
|
||||||
|
const right_expect_type: ExpectType = switch (binary_operation_id) {
|
||||||
|
.add,
|
||||||
|
.sub,
|
||||||
|
.logical_and,
|
||||||
|
.logical_xor,
|
||||||
|
.logical_or,
|
||||||
|
.multiply,
|
||||||
|
.divide,
|
||||||
|
=> expect_type,
|
||||||
|
.shift_left,
|
||||||
|
.shift_right,
|
||||||
|
=> ExpectType{
|
||||||
|
.type_index = Type.u8,
|
||||||
},
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const left_allocation = try analyzer.unresolvedAllocate(scope_index, expect_type, node.left);
|
||||||
|
const right_allocation = try analyzer.unresolvedAllocate(scope_index, right_expect_type, node.right);
|
||||||
|
const left_type = left_allocation.ptr.getType(analyzer.module);
|
||||||
|
const right_type = right_allocation.ptr.getType(analyzer.module);
|
||||||
|
_ = right_type;
|
||||||
|
|
||||||
|
const binary_operation = try analyzer.module.binary_operations.append(analyzer.allocator, .{
|
||||||
|
.left = left_allocation.index,
|
||||||
|
.right = right_allocation.index,
|
||||||
|
.type = left_type,
|
||||||
|
.id = binary_operation_id,
|
||||||
});
|
});
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
@ -606,11 +625,11 @@ const Analyzer = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logln(.sema, .identifier, "Declaration resolved as: {}\n", .{init_value});
|
logln(.sema, .identifier, "Declaration resolved as: {}\n", .{init_value});
|
||||||
logln(.sema, .identifier, "Declaration mutability: {s}. Is comptime: {}\n", .{ @tagName(declaration.mutability), init_value.isComptime() });
|
logln(.sema, .identifier, "Declaration mutability: {s}. Is comptime: {}\n", .{ @tagName(declaration.mutability), init_value.isComptime(analyzer.module) });
|
||||||
|
|
||||||
const typecheck_result = try analyzer.typeCheck(expect_type, declaration.type);
|
const typecheck_result = try analyzer.typeCheck(expect_type, declaration.type);
|
||||||
|
|
||||||
if (init_value.isComptime() and declaration.mutability == .@"const") {
|
if (init_value.isComptime(analyzer.module) and declaration.mutability == .@"const") {
|
||||||
assert(!declaration.init_value.invalid);
|
assert(!declaration.init_value.invalid);
|
||||||
assert(typecheck_result == .success);
|
assert(typecheck_result == .success);
|
||||||
return declaration.init_value;
|
return declaration.init_value;
|
||||||
@ -1017,6 +1036,8 @@ const Analyzer = struct {
|
|||||||
.logical_or,
|
.logical_or,
|
||||||
.multiply,
|
.multiply,
|
||||||
.divide,
|
.divide,
|
||||||
|
.shift_left,
|
||||||
|
.shift_right,
|
||||||
=> try analyzer.processBinaryOperation(scope_index, expect_type, node_index),
|
=> try analyzer.processBinaryOperation(scope_index, expect_type, node_index),
|
||||||
.expression_group => return try analyzer.resolveNode(value, scope_index, expect_type, node.left), //unreachable,
|
.expression_group => return try analyzer.resolveNode(value, scope_index, expect_type, node.left), //unreachable,
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
|
@ -160,6 +160,8 @@ pub const Node = packed struct(u128) {
|
|||||||
logical_or = 66,
|
logical_or = 66,
|
||||||
multiply = 67,
|
multiply = 67,
|
||||||
divide = 68,
|
divide = 68,
|
||||||
|
shift_left = 69,
|
||||||
|
shift_right = 70,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -721,6 +723,8 @@ const Analyzer = struct {
|
|||||||
logical_or,
|
logical_or,
|
||||||
multiply,
|
multiply,
|
||||||
divide,
|
divide,
|
||||||
|
shift_left,
|
||||||
|
shift_right,
|
||||||
};
|
};
|
||||||
|
|
||||||
const operator_precedence = std.EnumArray(PrecedenceOperator, i32).init(.{
|
const operator_precedence = std.EnumArray(PrecedenceOperator, i32).init(.{
|
||||||
@ -733,6 +737,8 @@ const Analyzer = struct {
|
|||||||
.logical_or = 40,
|
.logical_or = 40,
|
||||||
.multiply = 70,
|
.multiply = 70,
|
||||||
.divide = 70,
|
.divide = 70,
|
||||||
|
.shift_left = 50,
|
||||||
|
.shift_right = 50,
|
||||||
});
|
});
|
||||||
|
|
||||||
const operator_associativity = std.EnumArray(PrecedenceOperator, Associativity).init(.{
|
const operator_associativity = std.EnumArray(PrecedenceOperator, Associativity).init(.{
|
||||||
@ -745,6 +751,8 @@ const Analyzer = struct {
|
|||||||
.logical_or = .left,
|
.logical_or = .left,
|
||||||
.multiply = .left,
|
.multiply = .left,
|
||||||
.divide = .left,
|
.divide = .left,
|
||||||
|
.shift_left = .left,
|
||||||
|
.shift_right = .left,
|
||||||
});
|
});
|
||||||
|
|
||||||
const operator_node_id = std.EnumArray(PrecedenceOperator, Node.Id).init(.{
|
const operator_node_id = std.EnumArray(PrecedenceOperator, Node.Id).init(.{
|
||||||
@ -757,6 +765,8 @@ const Analyzer = struct {
|
|||||||
.logical_or = .logical_or,
|
.logical_or = .logical_or,
|
||||||
.multiply = .multiply,
|
.multiply = .multiply,
|
||||||
.divide = .divide,
|
.divide = .divide,
|
||||||
|
.shift_left = .shift_left,
|
||||||
|
.shift_right = .shift_right,
|
||||||
});
|
});
|
||||||
|
|
||||||
fn expressionPrecedence(analyzer: *Analyzer, minimum_precedence: i32) !Node.Index {
|
fn expressionPrecedence(analyzer: *Analyzer, minimum_precedence: i32) !Node.Index {
|
||||||
@ -825,6 +835,14 @@ const Analyzer = struct {
|
|||||||
.equal => unreachable,
|
.equal => unreachable,
|
||||||
else => .divide,
|
else => .divide,
|
||||||
},
|
},
|
||||||
|
.less => switch (next_token_id) {
|
||||||
|
.less => .shift_left,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
.greater => switch (next_token_id) {
|
||||||
|
.greater => .shift_right,
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
@ -845,7 +863,7 @@ const Analyzer = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const operator_token = analyzer.token_i;
|
const operator_token = analyzer.token_i;
|
||||||
const extra_token = switch (operator) {
|
const extra_tokens: u32 = switch (operator) {
|
||||||
.add,
|
.add,
|
||||||
.sub,
|
.sub,
|
||||||
.logical_and,
|
.logical_and,
|
||||||
@ -853,13 +871,15 @@ const Analyzer = struct {
|
|||||||
.logical_or,
|
.logical_or,
|
||||||
.multiply,
|
.multiply,
|
||||||
.divide,
|
.divide,
|
||||||
=> false,
|
=> 0,
|
||||||
.compare_equal,
|
.compare_equal,
|
||||||
.compare_not_equal,
|
.compare_not_equal,
|
||||||
=> true,
|
.shift_right,
|
||||||
|
.shift_left,
|
||||||
|
=> 1,
|
||||||
// else => |t| @panic(@tagName(t)),
|
// else => |t| @panic(@tagName(t)),
|
||||||
};
|
};
|
||||||
analyzer.token_i += @as(u32, 1) + @intFromBool(extra_token);
|
analyzer.token_i += @as(u32, 1) + extra_tokens;
|
||||||
|
|
||||||
// TODO: fix this
|
// TODO: fix this
|
||||||
const right = try analyzer.expressionPrecedence(precedence + 1);
|
const right = try analyzer.expressionPrecedence(precedence + 1);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
const main = fn () s32 {
|
const main = fn () s32 {
|
||||||
const a: s32 = 5;
|
const a: s32 = 5;
|
||||||
const b: s32 = 4;
|
const b: s32 = 4;
|
||||||
return 5 * 4 - a * b;
|
return a * b - a * b;
|
||||||
}
|
}
|
||||||
|
7
test/shifts/main.nat
Normal file
7
test/shifts/main.nat
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
const main = fn() s32 {
|
||||||
|
const x: u32 = 1;
|
||||||
|
x = x << 5;
|
||||||
|
x = x >> 5;
|
||||||
|
const b: u32 = 1;
|
||||||
|
return x - b;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user