ir for main function

This commit is contained in:
David Gonzalez Martin 2023-09-30 12:51:58 -06:00
parent 611e611cab
commit bca2f024cd
5 changed files with 209 additions and 65 deletions

View File

@ -76,6 +76,20 @@ pub const Type = union(enum) {
pub const List = BlockList(@This()); pub const List = BlockList(@This());
pub const Index = List.Index; pub const Index = List.Index;
pub const Allocation = List.Allocation; pub const Allocation = List.Allocation;
pub fn getSize(type_info: Type) u64 {
return switch (type_info) {
.integer => |integer| integer.getSize(),
else => |t| @panic(@tagName(t)),
};
}
pub fn getAlignment(type_info: Type) u64 {
return switch (type_info) {
.integer => |integer| @min(16, integer.getSize()),
else => |t| @panic(@tagName(t)),
};
}
}; };
pub const Integer = struct { pub const Integer = struct {
@ -85,6 +99,10 @@ pub const Integer = struct {
unsigned = 0, unsigned = 0,
signed = 1, signed = 1,
}; };
pub fn getSize(integer: Integer) u64 {
return integer.bit_count / @bitSizeOf(u8) + @intFromBool(integer.bit_count % @bitSizeOf(u8) != 0);
}
}; };
/// A scope contains a bunch of declarations /// A scope contains a bunch of declarations
@ -201,6 +219,7 @@ pub const Syscall = struct {
pub const Call = struct { pub const Call = struct {
value: Value.Index, value: Value.Index,
arguments: ArgumentList.Index, arguments: ArgumentList.Index,
type: Type.Index,
pub const List = BlockList(@This()); pub const List = BlockList(@This());
pub const Index = List.Index; pub const Index = List.Index;
pub const Allocation = List.Allocation; pub const Allocation = List.Allocation;
@ -251,11 +270,11 @@ pub const Value = union(enum) {
}; };
} }
pub fn getType(value: *Value) !void { pub fn getType(value: *Value, module: *Module) Type.Index {
switch (value.*) { return switch (value.*) {
.call => |call_index| module.calls.get(call_index).type,
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} };
unreachable;
} }
}; };
@ -490,10 +509,7 @@ pub fn compileModule(compilation: *Compilation, descriptor: Module.Descriptor) !
var ir = try intermediate_representation.initialize(compilation, module, packages[0], main_declaration); var ir = try intermediate_representation.initialize(compilation, module, packages[0], main_declaration);
switch (@import("builtin").cpu.arch) { try emit.get(.x86_64).initialize(compilation.base_allocator, &ir);
.x86_64 => |arch| try emit.get(arch).initialize(compilation.base_allocator, &ir),
else => {},
}
} }
fn generateAST() !void {} fn generateAST() !void {}

View File

@ -46,13 +46,18 @@ pub const Result = struct {
break :blk @as([*]align(0x1000) u8, @ptrCast(@alignCast(try windows.VirtualAlloc(null, size, windows.MEM_COMMIT | windows.MEM_RESERVE, windows.PAGE_EXECUTE_READWRITE))))[0..size]; break :blk @as([*]align(0x1000) u8, @ptrCast(@alignCast(try windows.VirtualAlloc(null, size, windows.MEM_COMMIT | windows.MEM_RESERVE, windows.PAGE_EXECUTE_READWRITE))))[0..size];
}, },
.linux, .macos => |os_tag| blk: { .linux, .macos => |os_tag| blk: {
const jit = switch (os_tag) {
.macos => 0x800,
.linux => 0,
else => unreachable,
};
const execute_flag: switch (os_tag) { const execute_flag: switch (os_tag) {
.linux => u32, .linux => u32,
.macos => c_int, .macos => c_int,
else => unreachable, else => unreachable,
} = if (flags.executable) std.os.PROT.EXEC else 0; } = if (flags.executable) std.os.PROT.EXEC else 0;
const protection_flags: u32 = @intCast(std.os.PROT.READ | std.os.PROT.WRITE | execute_flag); const protection_flags: u32 = @intCast(std.os.PROT.READ | std.os.PROT.WRITE | execute_flag);
const mmap_flags = std.os.MAP.ANONYMOUS | std.os.MAP.PRIVATE; const mmap_flags = std.os.MAP.ANONYMOUS | std.os.MAP.PRIVATE | jit;
break :blk std.os.mmap(null, size, protection_flags, mmap_flags, -1, 0); break :blk std.os.mmap(null, size, protection_flags, mmap_flags, -1, 0);
}, },

View File

@ -10,16 +10,20 @@ const Package = Compilation.Package;
const data_structures = @import("../data_structures.zig"); const data_structures = @import("../data_structures.zig");
const ArrayList = data_structures.ArrayList; const ArrayList = data_structures.ArrayList;
const BlockList = data_structures.BlockList; const BlockList = data_structures.BlockList;
const AutoHashMap = data_structures.AutoHashMap;
pub const Result = struct { pub const Result = struct {
functions: BlockList(Function) = .{},
blocks: BlockList(BasicBlock) = .{}, blocks: BlockList(BasicBlock) = .{},
calls: BlockList(Call) = .{},
functions: BlockList(Function) = .{},
instructions: BlockList(Instruction) = .{}, instructions: BlockList(Instruction) = .{},
jumps: BlockList(Jump) = .{}, jumps: BlockList(Jump) = .{},
values: BlockList(Value) = .{},
syscalls: BlockList(Syscall) = .{},
loads: BlockList(Load) = .{}, loads: BlockList(Load) = .{},
phis: BlockList(Phi) = .{}, phis: BlockList(Phi) = .{},
stores: BlockList(Store) = .{},
syscalls: BlockList(Syscall) = .{},
values: BlockList(Value) = .{},
stack_references: BlockList(StackReference) = .{},
}; };
pub fn initialize(compilation: *Compilation, module: *Module, package: *Package, main_file: Compilation.Type.Index) !Result { pub fn initialize(compilation: *Compilation, module: *Module, package: *Package, main_file: Compilation.Type.Index) !Result {
@ -62,10 +66,12 @@ pub const BasicBlock = struct {
}; };
pub const Instruction = union(enum) { pub const Instruction = union(enum) {
call: Call.Index,
jump: Jump.Index, jump: Jump.Index,
load: Load.Index, load: Load.Index,
phi: Phi.Index, phi: Phi.Index,
ret: Ret, ret: Ret,
store: Store.Index,
syscall: Syscall.Index, syscall: Syscall.Index,
@"unreachable", @"unreachable",
@ -106,9 +112,34 @@ const Load = struct {
pub const Index = List.Index; pub const Index = List.Index;
}; };
const Store = struct {
source: Value.Index,
destination: StackReference.Index,
pub const List = BlockList(@This());
pub const Index = List.Index;
};
const StackReference = struct {
size: u64,
alignment: u64,
offset: u64,
pub const List = BlockList(@This());
pub const Index = List.Index;
};
const Call = struct {
function: Function.Index,
pub const List = BlockList(@This());
pub const Index = List.Index;
pub const Allocation = List.Allocation;
};
pub const Value = union(enum) { pub const Value = union(enum) {
integer: Integer, integer: Integer,
load: Load.Index, load: Load.Index,
call: Call.Index,
stack_reference: StackReference.Index,
pub const List = BlockList(@This()); pub const List = BlockList(@This());
pub const Index = List.Index; pub const Index = List.Index;
@ -116,6 +147,8 @@ pub const Value = union(enum) {
return switch (value) { return switch (value) {
.integer => false, .integer => false,
.load => true, .load => true,
.call => true,
.stack_reference => true,
}; };
} }
}; };
@ -138,11 +171,15 @@ pub const Builder = struct {
current_basic_block: BasicBlock.Index = BasicBlock.Index.invalid, current_basic_block: BasicBlock.Index = BasicBlock.Index.invalid,
current_function_index: Function.Index = Function.Index.invalid, current_function_index: Function.Index = Function.Index.invalid,
return_phi_node: Instruction.Index = Instruction.Index.invalid, return_phi_node: Instruction.Index = Instruction.Index.invalid,
current_stack_offset: usize = 0,
stack_map: AutoHashMap(Compilation.Declaration.Index, StackReference.Index) = .{},
fn function(builder: *Builder, sema_function: Compilation.Function) !void { fn function(builder: *Builder, sema_function: Compilation.Function) !void {
builder.current_function_index = (try builder.ir.functions.append(builder.allocator, .{})).index; builder.current_function_index = (try builder.ir.functions.append(builder.allocator, .{})).index;
// TODO: arguments // TODO: arguments
builder.current_basic_block = try builder.newBlock(); builder.current_basic_block = try builder.newBlock();
builder.current_stack_offset = 0;
builder.stack_map = .{};
const return_type = builder.module.types.get(builder.module.function_prototypes.get(sema_function.prototype).return_type); const return_type = builder.module.types.get(builder.module.function_prototypes.get(sema_function.prototype).return_type);
const is_noreturn = return_type.* == .noreturn; const is_noreturn = return_type.* == .noreturn;
@ -301,28 +338,77 @@ pub const Builder = struct {
}); });
}, },
.declaration => |sema_declaration_index| { .declaration => |sema_declaration_index| {
_ = sema_declaration_index; const sema_declaration = builder.module.declarations.get(sema_declaration_index);
unreachable; assert(sema_declaration.scope_type == .local);
const sema_init_value = builder.module.values.get(sema_declaration.init_value);
const declaration_type = builder.module.types.get(sema_init_value.getType(builder.module));
const size = declaration_type.getSize();
const alignment = declaration_type.getAlignment();
const stack_offset = switch (size > 0) {
true => builder.allocateStack(size, alignment),
false => 0,
};
var value_index = try builder.emitValue(sema_declaration.init_value);
const value = builder.ir.values.get(value_index);
print("Value: {}\n", .{value.*});
value_index = switch (value.isInMemory()) {
false => try builder.load(value_index),
true => value_index,
};
if (stack_offset > 0) {
_ = try builder.store(.{
.source = value_index,
.destination = try builder.stackReference(stack_offset, declaration_type.*, sema_declaration_index),
});
}
}, },
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
} }
} }
fn stackReference(builder: *Builder, stack_offset: u64, t: Compilation.Type, value: Compilation.Declaration.Index) !StackReference.Index {
const stack_reference_allocation = try builder.ir.stack_references.append(builder.allocator, .{
.offset = stack_offset,
.size = t.getSize(),
.alignment = t.getAlignment(),
});
const index = stack_reference_allocation.index;
try builder.stack_map.put(builder.allocator, value, index);
return index;
}
fn store(builder: *Builder, descriptor: Store) !void {
const store_allocation = try builder.ir.stores.append(builder.allocator, descriptor);
_ = try builder.append(.{
.store = store_allocation.index,
});
}
fn allocateStack(builder: *Builder, size: u64, alignment: u64) u64 {
builder.current_stack_offset = std.mem.alignForward(u64, builder.current_stack_offset, alignment);
builder.current_stack_offset += size;
return builder.current_stack_offset;
}
fn load(builder: *Builder, value_index: Value.Index) !Value.Index { fn load(builder: *Builder, value_index: Value.Index) !Value.Index {
print("Doing load!\n", .{}); print("Doing load!\n", .{});
const load_index = try builder.ir.loads.append(builder.allocator, .{ const load_allocation = try builder.ir.loads.append(builder.allocator, .{
.value = value_index, .value = value_index,
}); });
const instruction_index = try builder.append(.{ const instruction_index = try builder.append(.{
.load = load_index, .load = load_allocation.index,
}); });
_ = instruction_index; _ = instruction_index;
const result = try builder.ir.values.append(builder.allocator, .{ const result = try builder.ir.values.append(builder.allocator, .{
.load = load_index, .load = load_allocation.index,
}); });
return result; return result.index;
} }
fn emitValue(builder: *Builder, sema_value_index: Compilation.Value.Index) !Value.Index { fn emitValue(builder: *Builder, sema_value_index: Compilation.Value.Index) !Value.Index {
@ -335,14 +421,65 @@ pub const Builder = struct {
.sign = false, .sign = false,
}, },
})).index, })).index,
.call => |sema_call_index| {
const sema_call = builder.module.calls.get(sema_call_index);
const argument_list_index = sema_call.arguments;
if (argument_list_index.valid) {
unreachable;
}
const call_index = try builder.call(.{
.function = switch (builder.module.values.get(sema_call.value).*) {
.function => |function_index| .{
.index = function_index.index,
.block = function_index.block,
},
else => |t| @panic(@tagName(t)),
},
});
_ = try builder.append(.{
.call = call_index,
});
const value_allocation = try builder.ir.values.append(builder.allocator, .{
.call = call_index,
});
return value_allocation.index;
},
.declaration_reference => |sema_declaration_index| {
const sema_declaration = builder.module.declarations.get(sema_declaration_index);
const sema_init_value = builder.module.values.get(sema_declaration.init_value);
const init_type = sema_init_value.getType(builder.module);
_ = init_type;
switch (sema_declaration.scope_type) {
.local => {
const stack_reference = builder.stack_map.get(sema_declaration_index).?;
const value = try builder.ir.values.append(builder.allocator, .{
.stack_reference = stack_reference,
});
return value.index;
},
.global => unreachable,
}
// switch (sema_declaration.*) {
// else => |t| @panic(@tagName(t)),
// }
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}; };
} }
fn jump(builder: *Builder, jump_descriptor: Jump) !Jump.Index { fn call(builder: *Builder, descriptor: Call) !Call.Index {
const destination_block = builder.ir.blocks.get(jump_descriptor.destination); const call_allocation = try builder.ir.calls.append(builder.allocator, descriptor);
return call_allocation.index;
}
fn jump(builder: *Builder, descriptor: Jump) !Jump.Index {
const destination_block = builder.ir.blocks.get(descriptor.destination);
assert(!destination_block.sealed); assert(!destination_block.sealed);
const jump_allocation = try builder.ir.jumps.append(builder.allocator, jump_descriptor); const jump_allocation = try builder.ir.jumps.append(builder.allocator, descriptor);
return jump_allocation.index; return jump_allocation.index;
} }

View File

@ -54,23 +54,6 @@ pub fn selectInstruction(instruction_selector: *InstructionSelector, function: *
}); });
// TODO // TODO
} else unreachable; } else unreachable;
// if (integer.value == 0) {
// try function.instructions.append(instruction_selector.allocator, .{
// .xor_reg32_reg32 = .{
// .destination = syscall_register,
// .source = syscall_register,
// },
// });
// } else if (integer.value < std.math.maxInt(u32)) {
// try function.instructions.append(instruction_selector.allocator, .{
// .mov_reg_imm32 = .{
// .destination = syscall_register,
// .source = @intCast(integer.value),
// },
// });
// } else {
// unreachable;
// }
}, },
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
@ -83,14 +66,14 @@ pub fn selectInstruction(instruction_selector: *InstructionSelector, function: *
.phi => unreachable, .phi => unreachable,
.ret => unreachable, .ret => unreachable,
.jump => |jump_index| { .jump => |jump_index| {
_ = jump_index; const jump = intermediate.jumps.get(jump_index);
// const jump = intermediate.jumps.get(jump_index); const relocation = Displacement{
// const relocation = LocalRelative{ .size = .one,
// .instruction = .jmp_rel_8, .source = @intCast(function.block_map.get(jump.source) orelse unreachable),
// .source = @intCast(function.block_map.get(jump.source) orelse unreachable), .destination = @intCast(function.block_map.get(jump.destination) orelse unreachable),
// .destination = @intCast(function.block_map.get(jump.destination) orelse unreachable), .offset_in_block = function.block_byte_count,
// .offset_in_block = function.block_byte_count, };
// }; _ = relocation;
// const index = function.instructions.items.len; // const index = function.instructions.items.len;
// try function.relocations.append(instruction_selector.allocator, @intCast(index)); // try function.relocations.append(instruction_selector.allocator, @intCast(index));
// try function.instructions.append(instruction_selector.allocator, .{ // try function.instructions.append(instruction_selector.allocator, .{
@ -98,6 +81,8 @@ pub fn selectInstruction(instruction_selector: *InstructionSelector, function: *
// }); // });
unreachable; unreachable;
}, },
.call => unreachable,
.store => unreachable,
} }
} }
@ -115,6 +100,13 @@ const RegisterMemoryRegister = struct {
direct: bool, direct: bool,
}; };
const Displacement = struct {
size: Size,
source: u16,
destination: u16,
offset_in_block: u16,
};
const RmResult = struct { const RmResult = struct {
rex: Rex, rex: Rex,
mod_rm: ModRm, mod_rm: ModRm,
@ -215,24 +207,7 @@ pub fn emitInstruction(result: *emit.Result, instruction: Instruction, intermedi
result.appendCodeByte(opcode_byte); result.appendCodeByte(opcode_byte);
emitImmediate(result, intermediate, register_immediate.immediate, register_immediate.immediate_size); emitImmediate(result, intermediate, register_immediate.immediate, register_immediate.immediate_size);
}, },
// .jmp_rel_8 => unreachable, //result.appendOnlyOpcodeSkipInstructionBytes(instruction), .jmp_rel => unreachable,
// inline .mov_reg_imm32 => |content, tag| {
// _ = tag;
// _ = content;
// // const descriptor = instruction_descriptors.get(tag);
// // result.writeOpcode(descriptor.opcode);
// // result.appendCodeByte(descriptor.getOpcode()[0] | @intFromEnum(content.destination));
// // result.appendCode(std.mem.asBytes(&content.source));
// unreachable;
// },
// inline .xor_reg32_reg32 => |content, tag| {
// _ = tag;
// _ = content;
// // const descriptor = instruction_descriptors.get(tag);
// // result.appendCodeByte(descriptor.getOpcode()[0]);
// // result.appendCodeByte(0xc0 | @as(u8, @intFromEnum(content.source)) << 4 | @intFromEnum(content.destination));
// unreachable;
// },
inline .syscall, .ud2 => |_, tag| { inline .syscall, .ud2 => |_, tag| {
const opcode = tag.getOpcode(&.{}); const opcode = tag.getOpcode(&.{});
result.appendCode(opcode); result.appendCode(opcode);
@ -244,6 +219,7 @@ pub fn emitInstruction(result: *emit.Result, instruction: Instruction, intermedi
pub const Instruction = union(Id) { pub const Instruction = union(Id) {
xor_rm_r: RegisterMemoryRegister, xor_rm_r: RegisterMemoryRegister,
mov_r_imm: RegisterImmediate, mov_r_imm: RegisterImmediate,
jmp_rel: Displacement,
// jmp_rel_8: LocalRelative, // jmp_rel_8: LocalRelative,
// mov_reg_imm32: struct { // mov_reg_imm32: struct {
// destination: GPRegister, // destination: GPRegister,
@ -259,7 +235,7 @@ pub const Instruction = union(Id) {
const Id = enum { const Id = enum {
xor_rm_r, xor_rm_r,
mov_r_imm, mov_r_imm,
// jmp_rel_8, jmp_rel,
// mov_reg_imm32, // mov_reg_imm32,
// xor_reg32_reg32, // xor_reg32_reg32,
syscall, syscall,
@ -277,6 +253,11 @@ pub const Instruction = union(Id) {
.one => &.{0x30}, .one => &.{0x30},
.two, .four, .eight => &.{0x31}, .two, .four, .eight => &.{0x31},
}, },
.jmp_rel => switch (operands[0].displacement.size) {
.one => unreachable,
.four => unreachable,
else => unreachable,
},
}; };
} }
}; };

View File

@ -396,10 +396,15 @@ const Analyzer = struct {
.call_one => blk: { .call_one => blk: {
const this_value_node_index = node.left; const this_value_node_index = node.left;
const this_value_allocation = try analyzer.unresolvedAllocate(scope_index, ExpectType.none, this_value_node_index); const this_value_allocation = try analyzer.unresolvedAllocate(scope_index, ExpectType.none, this_value_node_index);
const value_type = switch (this_value_allocation.ptr.*) {
.function => |function_index| analyzer.module.function_prototypes.get(analyzer.module.functions.get(function_index).prototype).return_type,
else => |t| @panic(@tagName(t)),
};
const call_allocation = try analyzer.module.calls.append(analyzer.allocator, .{ const call_allocation = try analyzer.module.calls.append(analyzer.allocator, .{
.value = this_value_allocation.index, .value = this_value_allocation.index,
.arguments = ArgumentList.Index.invalid, .arguments = ArgumentList.Index.invalid,
.type = value_type,
}); });
break :blk .{ break :blk .{
.call = call_allocation.index, .call = call_allocation.index,