ir for main function
This commit is contained in:
parent
611e611cab
commit
bca2f024cd
@ -76,6 +76,20 @@ pub const Type = union(enum) {
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
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 {
|
||||
@ -85,6 +99,10 @@ pub const Integer = struct {
|
||||
unsigned = 0,
|
||||
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
|
||||
@ -201,6 +219,7 @@ pub const Syscall = struct {
|
||||
pub const Call = struct {
|
||||
value: Value.Index,
|
||||
arguments: ArgumentList.Index,
|
||||
type: Type.Index,
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
pub const Allocation = List.Allocation;
|
||||
@ -251,11 +270,11 @@ pub const Value = union(enum) {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getType(value: *Value) !void {
|
||||
switch (value.*) {
|
||||
pub fn getType(value: *Value, module: *Module) Type.Index {
|
||||
return switch (value.*) {
|
||||
.call => |call_index| module.calls.get(call_index).type,
|
||||
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);
|
||||
|
||||
switch (@import("builtin").cpu.arch) {
|
||||
.x86_64 => |arch| try emit.get(arch).initialize(compilation.base_allocator, &ir),
|
||||
else => {},
|
||||
}
|
||||
try emit.get(.x86_64).initialize(compilation.base_allocator, &ir);
|
||||
}
|
||||
|
||||
fn generateAST() !void {}
|
||||
|
@ -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];
|
||||
},
|
||||
.linux, .macos => |os_tag| blk: {
|
||||
const jit = switch (os_tag) {
|
||||
.macos => 0x800,
|
||||
.linux => 0,
|
||||
else => unreachable,
|
||||
};
|
||||
const execute_flag: switch (os_tag) {
|
||||
.linux => u32,
|
||||
.macos => c_int,
|
||||
else => unreachable,
|
||||
} = 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 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);
|
||||
},
|
||||
|
@ -10,16 +10,20 @@ const Package = Compilation.Package;
|
||||
const data_structures = @import("../data_structures.zig");
|
||||
const ArrayList = data_structures.ArrayList;
|
||||
const BlockList = data_structures.BlockList;
|
||||
const AutoHashMap = data_structures.AutoHashMap;
|
||||
|
||||
pub const Result = struct {
|
||||
functions: BlockList(Function) = .{},
|
||||
blocks: BlockList(BasicBlock) = .{},
|
||||
calls: BlockList(Call) = .{},
|
||||
functions: BlockList(Function) = .{},
|
||||
instructions: BlockList(Instruction) = .{},
|
||||
jumps: BlockList(Jump) = .{},
|
||||
values: BlockList(Value) = .{},
|
||||
syscalls: BlockList(Syscall) = .{},
|
||||
loads: BlockList(Load) = .{},
|
||||
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 {
|
||||
@ -62,10 +66,12 @@ pub const BasicBlock = struct {
|
||||
};
|
||||
|
||||
pub const Instruction = union(enum) {
|
||||
call: Call.Index,
|
||||
jump: Jump.Index,
|
||||
load: Load.Index,
|
||||
phi: Phi.Index,
|
||||
ret: Ret,
|
||||
store: Store.Index,
|
||||
syscall: Syscall.Index,
|
||||
@"unreachable",
|
||||
|
||||
@ -106,9 +112,34 @@ const Load = struct {
|
||||
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) {
|
||||
integer: Integer,
|
||||
load: Load.Index,
|
||||
call: Call.Index,
|
||||
stack_reference: StackReference.Index,
|
||||
pub const List = BlockList(@This());
|
||||
pub const Index = List.Index;
|
||||
|
||||
@ -116,6 +147,8 @@ pub const Value = union(enum) {
|
||||
return switch (value) {
|
||||
.integer => false,
|
||||
.load => true,
|
||||
.call => true,
|
||||
.stack_reference => true,
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -138,11 +171,15 @@ pub const Builder = struct {
|
||||
current_basic_block: BasicBlock.Index = BasicBlock.Index.invalid,
|
||||
current_function_index: Function.Index = Function.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 {
|
||||
builder.current_function_index = (try builder.ir.functions.append(builder.allocator, .{})).index;
|
||||
// TODO: arguments
|
||||
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 is_noreturn = return_type.* == .noreturn;
|
||||
@ -301,28 +338,77 @@ pub const Builder = struct {
|
||||
});
|
||||
},
|
||||
.declaration => |sema_declaration_index| {
|
||||
_ = sema_declaration_index;
|
||||
unreachable;
|
||||
const sema_declaration = builder.module.declarations.get(sema_declaration_index);
|
||||
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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
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,
|
||||
});
|
||||
const instruction_index = try builder.append(.{
|
||||
.load = load_index,
|
||||
.load = load_allocation.index,
|
||||
});
|
||||
_ = instruction_index;
|
||||
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 {
|
||||
@ -335,14 +421,65 @@ pub const Builder = struct {
|
||||
.sign = false,
|
||||
},
|
||||
})).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)),
|
||||
};
|
||||
}
|
||||
|
||||
fn jump(builder: *Builder, jump_descriptor: Jump) !Jump.Index {
|
||||
const destination_block = builder.ir.blocks.get(jump_descriptor.destination);
|
||||
fn call(builder: *Builder, descriptor: Call) !Call.Index {
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -54,23 +54,6 @@ pub fn selectInstruction(instruction_selector: *InstructionSelector, function: *
|
||||
});
|
||||
// TODO
|
||||
} 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)),
|
||||
}
|
||||
@ -83,14 +66,14 @@ pub fn selectInstruction(instruction_selector: *InstructionSelector, function: *
|
||||
.phi => unreachable,
|
||||
.ret => unreachable,
|
||||
.jump => |jump_index| {
|
||||
_ = jump_index;
|
||||
// const jump = intermediate.jumps.get(jump_index);
|
||||
// const relocation = LocalRelative{
|
||||
// .instruction = .jmp_rel_8,
|
||||
// .source = @intCast(function.block_map.get(jump.source) orelse unreachable),
|
||||
// .destination = @intCast(function.block_map.get(jump.destination) orelse unreachable),
|
||||
// .offset_in_block = function.block_byte_count,
|
||||
// };
|
||||
const jump = intermediate.jumps.get(jump_index);
|
||||
const relocation = Displacement{
|
||||
.size = .one,
|
||||
.source = @intCast(function.block_map.get(jump.source) orelse unreachable),
|
||||
.destination = @intCast(function.block_map.get(jump.destination) orelse unreachable),
|
||||
.offset_in_block = function.block_byte_count,
|
||||
};
|
||||
_ = relocation;
|
||||
// const index = function.instructions.items.len;
|
||||
// try function.relocations.append(instruction_selector.allocator, @intCast(index));
|
||||
// try function.instructions.append(instruction_selector.allocator, .{
|
||||
@ -98,6 +81,8 @@ pub fn selectInstruction(instruction_selector: *InstructionSelector, function: *
|
||||
// });
|
||||
unreachable;
|
||||
},
|
||||
.call => unreachable,
|
||||
.store => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,6 +100,13 @@ const RegisterMemoryRegister = struct {
|
||||
direct: bool,
|
||||
};
|
||||
|
||||
const Displacement = struct {
|
||||
size: Size,
|
||||
source: u16,
|
||||
destination: u16,
|
||||
offset_in_block: u16,
|
||||
};
|
||||
|
||||
const RmResult = struct {
|
||||
rex: Rex,
|
||||
mod_rm: ModRm,
|
||||
@ -215,24 +207,7 @@ pub fn emitInstruction(result: *emit.Result, instruction: Instruction, intermedi
|
||||
result.appendCodeByte(opcode_byte);
|
||||
emitImmediate(result, intermediate, register_immediate.immediate, register_immediate.immediate_size);
|
||||
},
|
||||
// .jmp_rel_8 => unreachable, //result.appendOnlyOpcodeSkipInstructionBytes(instruction),
|
||||
// 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;
|
||||
// },
|
||||
.jmp_rel => unreachable,
|
||||
inline .syscall, .ud2 => |_, tag| {
|
||||
const opcode = tag.getOpcode(&.{});
|
||||
result.appendCode(opcode);
|
||||
@ -244,6 +219,7 @@ pub fn emitInstruction(result: *emit.Result, instruction: Instruction, intermedi
|
||||
pub const Instruction = union(Id) {
|
||||
xor_rm_r: RegisterMemoryRegister,
|
||||
mov_r_imm: RegisterImmediate,
|
||||
jmp_rel: Displacement,
|
||||
// jmp_rel_8: LocalRelative,
|
||||
// mov_reg_imm32: struct {
|
||||
// destination: GPRegister,
|
||||
@ -259,7 +235,7 @@ pub const Instruction = union(Id) {
|
||||
const Id = enum {
|
||||
xor_rm_r,
|
||||
mov_r_imm,
|
||||
// jmp_rel_8,
|
||||
jmp_rel,
|
||||
// mov_reg_imm32,
|
||||
// xor_reg32_reg32,
|
||||
syscall,
|
||||
@ -277,6 +253,11 @@ pub const Instruction = union(Id) {
|
||||
.one => &.{0x30},
|
||||
.two, .four, .eight => &.{0x31},
|
||||
},
|
||||
.jmp_rel => switch (operands[0].displacement.size) {
|
||||
.one => unreachable,
|
||||
.four => unreachable,
|
||||
else => unreachable,
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -396,10 +396,15 @@ const Analyzer = struct {
|
||||
.call_one => blk: {
|
||||
const this_value_node_index = node.left;
|
||||
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, .{
|
||||
.value = this_value_allocation.index,
|
||||
.arguments = ArgumentList.Index.invalid,
|
||||
.type = value_type,
|
||||
});
|
||||
break :blk .{
|
||||
.call = call_allocation.index,
|
||||
|
Loading…
x
Reference in New Issue
Block a user