Implement phis
This commit is contained in:
parent
c868aa05ae
commit
bcb49f3adf
@ -65,6 +65,7 @@ pub extern fn NativityLLVMGetConstantArray(array_type: *LLVM.Type.Array, value_p
|
|||||||
pub extern fn NativityLLVMGetConstantStruct(struct_type: *LLVM.Type.Struct, constant_ptr: [*]const *LLVM.Value.Constant, constant_len: usize) *LLVM.Value.Constant;
|
pub extern fn NativityLLVMGetConstantStruct(struct_type: *LLVM.Type.Struct, constant_ptr: [*]const *LLVM.Value.Constant, constant_len: usize) *LLVM.Value.Constant;
|
||||||
pub extern fn NativityLLVMConstantToInt(constant: *LLVM.Value.Constant) ?*LLVM.Value.Constant.Int;
|
pub extern fn NativityLLVMConstantToInt(constant: *LLVM.Value.Constant) ?*LLVM.Value.Constant.Int;
|
||||||
pub extern fn NativityLLVMBuilderCreateICmp(builder: *LLVM.Builder, integer_comparison: LLVM.Value.Instruction.ICmp.Kind, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) *LLVM.Value;
|
pub extern fn NativityLLVMBuilderCreateICmp(builder: *LLVM.Builder, integer_comparison: LLVM.Value.Instruction.ICmp.Kind, left: *LLVM.Value, right: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) *LLVM.Value;
|
||||||
|
pub extern fn NativityLLVMBuilderCreateIsNotNull(builder: *LLVM.Builder, value: *LLVM.Value, name_ptr: [*]const u8, name_len: usize) *LLVM.Value;
|
||||||
pub extern fn NativityLLVMBuilderCreateLoad(builder: *LLVM.Builder, type: *LLVM.Type, value: *LLVM.Value, is_volatile: bool, name_ptr: [*]const u8, name_len: usize, alignment: u32) *LLVM.Value.Instruction.Load;
|
pub extern fn NativityLLVMBuilderCreateLoad(builder: *LLVM.Builder, type: *LLVM.Type, value: *LLVM.Value, is_volatile: bool, name_ptr: [*]const u8, name_len: usize, alignment: u32) *LLVM.Value.Instruction.Load;
|
||||||
pub extern fn NativityLLVMBuilderCreateRet(builder: *LLVM.Builder, value: ?*LLVM.Value) *LLVM.Value.Instruction.Ret;
|
pub extern fn NativityLLVMBuilderCreateRet(builder: *LLVM.Builder, value: ?*LLVM.Value) *LLVM.Value.Instruction.Ret;
|
||||||
pub extern fn NativityLLVMBuilderCreateCast(builder: *LLVM.Builder, cast_type: LLVM.Value.Instruction.Cast.Type, value: *LLVM.Value, type: *LLVM.Type, name_ptr: [*]const u8, name_len: usize) *LLVM.Value;
|
pub extern fn NativityLLVMBuilderCreateCast(builder: *LLVM.Builder, cast_type: LLVM.Value.Instruction.Cast.Type, value: *LLVM.Value, type: *LLVM.Type, name_ptr: [*]const u8, name_len: usize) *LLVM.Value;
|
||||||
|
@ -1176,9 +1176,9 @@ const BasicBlock = struct{
|
|||||||
.data = {},
|
.data = {},
|
||||||
},
|
},
|
||||||
|
|
||||||
const CommandList = std.DoublyLinkedList(void);
|
pub const Reference = **BasicBlock;
|
||||||
|
|
||||||
const Index = PinnedArray(BasicBlock).Index;
|
const CommandList = std.DoublyLinkedList(void);
|
||||||
|
|
||||||
pub fn get_llvm(basic_block: *BasicBlock) *LLVM.Value.BasicBlock{
|
pub fn get_llvm(basic_block: *BasicBlock) *LLVM.Value.BasicBlock{
|
||||||
return basic_block.value.llvm.?.toBasicBlock() orelse unreachable;
|
return basic_block.value.llvm.?.toBasicBlock() orelse unreachable;
|
||||||
@ -1255,11 +1255,13 @@ const Instruction = struct{
|
|||||||
|
|
||||||
const Id = enum{
|
const Id = enum{
|
||||||
branch,
|
branch,
|
||||||
|
call,
|
||||||
integer_binary_operation,
|
integer_binary_operation,
|
||||||
integer_compare,
|
integer_compare,
|
||||||
call,
|
jump,
|
||||||
load,
|
load,
|
||||||
local_symbol,
|
local_symbol,
|
||||||
|
phi,
|
||||||
ret,
|
ret,
|
||||||
ret_void,
|
ret_void,
|
||||||
store,
|
store,
|
||||||
@ -1270,8 +1272,10 @@ const Instruction = struct{
|
|||||||
.call = Call,
|
.call = Call,
|
||||||
.integer_binary_operation = IntegerBinaryOperation,
|
.integer_binary_operation = IntegerBinaryOperation,
|
||||||
.integer_compare = IntegerCompare,
|
.integer_compare = IntegerCompare,
|
||||||
|
.jump = Jump,
|
||||||
.local_symbol = LocalSymbol,
|
.local_symbol = LocalSymbol,
|
||||||
.load = Load,
|
.load = Load,
|
||||||
|
.phi = Phi,
|
||||||
.ret = Return,
|
.ret = Return,
|
||||||
.ret_void = void,
|
.ret_void = void,
|
||||||
.store = Store,
|
.store = Store,
|
||||||
@ -1315,6 +1319,7 @@ const IntegerCompare = struct {
|
|||||||
const Id = enum{
|
const Id = enum{
|
||||||
equal,
|
equal,
|
||||||
not_equal,
|
not_equal,
|
||||||
|
not_zero,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1325,6 +1330,11 @@ const Branch = struct {
|
|||||||
not_taken: *BasicBlock,
|
not_taken: *BasicBlock,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Jump = struct {
|
||||||
|
instruction: Instruction,
|
||||||
|
basic_block: *BasicBlock,
|
||||||
|
};
|
||||||
|
|
||||||
const Call = struct{
|
const Call = struct{
|
||||||
instruction: Instruction,
|
instruction: Instruction,
|
||||||
callable: *Value,
|
callable: *Value,
|
||||||
@ -1346,10 +1356,20 @@ const Store = struct {
|
|||||||
is_volatile: bool,
|
is_volatile: bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Phi = struct {
|
||||||
|
instruction: Instruction,
|
||||||
|
type: *Type,
|
||||||
|
nodes: PinnedArray(Node) = .{},
|
||||||
|
|
||||||
|
const Node = struct {
|
||||||
|
value: *Value,
|
||||||
|
basic_block: *BasicBlock,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const Return = struct{
|
const Return = struct{
|
||||||
instruction: Instruction,
|
instruction: Instruction,
|
||||||
value: *Value,
|
value: *Value,
|
||||||
const Index = PinnedArray(Call).Index;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const Import = struct {
|
const Import = struct {
|
||||||
@ -1383,11 +1403,13 @@ const Thread = struct{
|
|||||||
debug_info_file_map: PinnedHashMap(u32, LLVMFile) = .{},
|
debug_info_file_map: PinnedHashMap(u32, LLVMFile) = .{},
|
||||||
// pending_values_per_file: PinnedArray(PinnedArray(*Value)) = .{},
|
// pending_values_per_file: PinnedArray(PinnedArray(*Value)) = .{},
|
||||||
branches: PinnedArray(Branch) = .{},
|
branches: PinnedArray(Branch) = .{},
|
||||||
|
jumps: PinnedArray(Jump) = .{},
|
||||||
calls: PinnedArray(Call) = .{},
|
calls: PinnedArray(Call) = .{},
|
||||||
integer_binary_operations: PinnedArray(IntegerBinaryOperation) = .{},
|
integer_binary_operations: PinnedArray(IntegerBinaryOperation) = .{},
|
||||||
integer_compares: PinnedArray(IntegerCompare) = .{},
|
integer_compares: PinnedArray(IntegerCompare) = .{},
|
||||||
loads: PinnedArray(Load) = .{},
|
loads: PinnedArray(Load) = .{},
|
||||||
stores: PinnedArray(Store) = .{},
|
stores: PinnedArray(Store) = .{},
|
||||||
|
phis: PinnedArray(Phi) = .{},
|
||||||
returns: PinnedArray(Return) = .{},
|
returns: PinnedArray(Return) = .{},
|
||||||
lazy_expressions: PinnedArray(LazyExpression) = .{},
|
lazy_expressions: PinnedArray(LazyExpression) = .{},
|
||||||
imports: PinnedArray(Import) = .{},
|
imports: PinnedArray(Import) = .{},
|
||||||
@ -1631,8 +1653,6 @@ const File = struct{
|
|||||||
const Scope = struct {
|
const Scope = struct {
|
||||||
scope: compiler.Scope,
|
scope: compiler.Scope,
|
||||||
};
|
};
|
||||||
|
|
||||||
const Index = PinnedArray(File).Index;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var instance = Instance{};
|
var instance = Instance{};
|
||||||
@ -1645,14 +1665,14 @@ const CodegenBackend = union(enum){
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn add_file(file_absolute_path: []const u8, interested_threads: []const u32) File.Index {
|
fn add_file(file_absolute_path: []const u8, interested_threads: []const u32) u32 {
|
||||||
instance.file_mutex.lock();
|
instance.file_mutex.lock();
|
||||||
defer instance.file_mutex.unlock();
|
defer instance.file_mutex.unlock();
|
||||||
|
|
||||||
const hash = hash_bytes(file_absolute_path);
|
const hash = hash_bytes(file_absolute_path);
|
||||||
const new_file = instance.files.add_one();
|
const new_file = instance.files.add_one();
|
||||||
_ = instance.file_paths.append(hash);
|
_ = instance.file_paths.append(hash);
|
||||||
const new_file_index = instance.files.get_typed_index(new_file);
|
const new_file_index = instance.files.get_index(new_file);
|
||||||
new_file.* = .{
|
new_file.* = .{
|
||||||
.global_declaration = .{
|
.global_declaration = .{
|
||||||
.declaration = .{
|
.declaration = .{
|
||||||
@ -1762,7 +1782,7 @@ const Unit = struct {
|
|||||||
const new_file_index = add_file(main_source_file_absolute, &.{});
|
const new_file_index = add_file(main_source_file_absolute, &.{});
|
||||||
instance.threads[0].task_system.program_state = .analysis;
|
instance.threads[0].task_system.program_state = .analysis;
|
||||||
instance.threads[0].add_thread_work(Job{
|
instance.threads[0].add_thread_work(Job{
|
||||||
.offset = @intFromEnum(new_file_index),
|
.offset = new_file_index,
|
||||||
.count = 1,
|
.count = 1,
|
||||||
.id = .analyze_file,
|
.id = .analyze_file,
|
||||||
});
|
});
|
||||||
@ -1808,12 +1828,12 @@ fn control_thread(unit: *Unit) void {
|
|||||||
const file_absolute_path = thread.identifiers.get(analyze_file_path_hash).?;
|
const file_absolute_path = thread.identifiers.get(analyze_file_path_hash).?;
|
||||||
const interested_thread_index: u32 = @intCast(i);
|
const interested_thread_index: u32 = @intCast(i);
|
||||||
const file_index = add_file(file_absolute_path, &.{interested_thread_index});
|
const file_index = add_file(file_absolute_path, &.{interested_thread_index});
|
||||||
_ = instance.files.get(file_index).interested_files.append(&instance.files.pointer[interested_file_index]);
|
_ = instance.files.get_unchecked(file_index).interested_files.append(&instance.files.pointer[interested_file_index]);
|
||||||
const assigned_thread = &instance.threads[thread_index];
|
const assigned_thread = &instance.threads[thread_index];
|
||||||
|
|
||||||
assigned_thread.task_system.program_state = .analysis;
|
assigned_thread.task_system.program_state = .analysis;
|
||||||
assigned_thread.add_thread_work(Job{
|
assigned_thread.add_thread_work(Job{
|
||||||
.offset = @intFromEnum(file_index),
|
.offset = file_index,
|
||||||
.id = .analyze_file,
|
.id = .analyze_file,
|
||||||
.count = 1,
|
.count = 1,
|
||||||
});
|
});
|
||||||
@ -2270,13 +2290,18 @@ const CallingConvention = enum{
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Analyzer = struct{
|
const Analyzer = struct{
|
||||||
current_basic_block: *BasicBlock = undefined,
|
current_basic_block: *BasicBlock,
|
||||||
current_function: *Function = undefined,
|
current_function: *Function,
|
||||||
current_scope: *Scope = undefined,
|
current_scope: *Scope,
|
||||||
|
exit_blocks: PinnedArray(*BasicBlock) = .{},
|
||||||
|
return_block: ?*BasicBlock = null,
|
||||||
|
return_phi: ?*Phi = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const brace_open = 0x7b;
|
const brace_open = '{';
|
||||||
const brace_close = 0x7d;
|
const brace_close = '}';
|
||||||
|
|
||||||
|
const pointer_token = '*';
|
||||||
|
|
||||||
const cache_line_size = switch (builtin.os.tag) {
|
const cache_line_size = switch (builtin.os.tag) {
|
||||||
.macos => 128,
|
.macos => 128,
|
||||||
@ -2537,6 +2562,8 @@ fn worker_thread(thread_index: u32, cpu_count: *u32) void {
|
|||||||
basic_block_command_buffer.append(&nat_entry_basic_block.command_node);
|
basic_block_command_buffer.append(&nat_entry_basic_block.command_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var phis = PinnedArray(*Phi){};
|
||||||
|
var llvm_phi_nodes = PinnedArray(*LLVM.Value.Instruction.PhiNode){};
|
||||||
|
|
||||||
while (basic_block_command_buffer.len != 0) {
|
while (basic_block_command_buffer.len != 0) {
|
||||||
const basic_block_node = basic_block_command_buffer.first orelse unreachable;
|
const basic_block_node = basic_block_command_buffer.first orelse unreachable;
|
||||||
@ -2616,15 +2643,21 @@ fn worker_thread(thread_index: u32, cpu_count: *u32) void {
|
|||||||
const type_b = compare.right.get_type();
|
const type_b = compare.right.get_type();
|
||||||
assert(type_a == type_b);
|
assert(type_a == type_b);
|
||||||
const left = llvm_get_value(thread, compare.left);
|
const left = llvm_get_value(thread, compare.left);
|
||||||
|
if (compare.id == .not_zero) {
|
||||||
|
const is_not_null = builder.createIsNotNull(left, "", "".len);
|
||||||
|
break :block is_not_null;
|
||||||
|
} else {
|
||||||
const right = llvm_get_value(thread, compare.right);
|
const right = llvm_get_value(thread, compare.right);
|
||||||
const name = "";
|
const name = "";
|
||||||
const comparison: LLVM.Value.Instruction.ICmp.Kind = switch (compare.id) {
|
const comparison: LLVM.Value.Instruction.ICmp.Kind = switch (compare.id) {
|
||||||
.equal => .eq,
|
.equal => .eq,
|
||||||
.not_equal => .ne,
|
.not_equal => .ne,
|
||||||
|
.not_zero => unreachable,
|
||||||
};
|
};
|
||||||
|
|
||||||
const cmp = builder.createICmp(comparison, left, right, name, name.len);
|
const cmp = builder.createICmp(comparison, left, right, name, name.len);
|
||||||
break :block cmp;
|
break :block cmp;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
.branch => block: {
|
.branch => block: {
|
||||||
const branch = instruction.get_payload(.branch);
|
const branch = instruction.get_payload(.branch);
|
||||||
@ -2643,6 +2676,28 @@ fn worker_thread(thread_index: u32, cpu_count: *u32) void {
|
|||||||
const br = builder.createConditionalBranch(condition, taken, not_taken, branch_weights, unpredictable);
|
const br = builder.createConditionalBranch(condition, taken, not_taken, branch_weights, unpredictable);
|
||||||
break :block br.toValue();
|
break :block br.toValue();
|
||||||
},
|
},
|
||||||
|
.jump => block: {
|
||||||
|
const jump = instruction.get_payload(.jump);
|
||||||
|
const target_block = jump.basic_block;
|
||||||
|
const llvm_target_block = if (target_block.value.llvm) |llvm| llvm.toBasicBlock() orelse unreachable else bb: {
|
||||||
|
const block = thread.llvm.context.createBasicBlock("", "".len, function, null);
|
||||||
|
target_block.value.llvm = block.toValue();
|
||||||
|
basic_block_command_buffer.insertAfter(last_block, &target_block.command_node);
|
||||||
|
last_block = &target_block.command_node;
|
||||||
|
break :bb block;
|
||||||
|
};
|
||||||
|
const br = builder.createBranch(llvm_target_block);
|
||||||
|
break :block br.toValue();
|
||||||
|
},
|
||||||
|
.phi => block: {
|
||||||
|
const phi = instruction.get_payload(.phi);
|
||||||
|
const phi_type = llvm_get_type(thread, phi.type);
|
||||||
|
const reserved_value_count = phi.nodes.length;
|
||||||
|
const phi_node = builder.createPhi(phi_type, reserved_value_count, "", "".len);
|
||||||
|
_ = phis.append(phi);
|
||||||
|
_ = llvm_phi_nodes.append(phi_node);
|
||||||
|
break :block phi_node.toValue();
|
||||||
|
},
|
||||||
else => |t| @panic(@tagName(t)),
|
else => |t| @panic(@tagName(t)),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2652,6 +2707,13 @@ fn worker_thread(thread_index: u32, cpu_count: *u32) void {
|
|||||||
_ = basic_block_command_buffer.popFirst();
|
_ = basic_block_command_buffer.popFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (phis.const_slice(), llvm_phi_nodes.const_slice()) |phi, llvm_phi| {
|
||||||
|
for (phi.nodes.const_slice()) |phi_node| {
|
||||||
|
const llvm_value = llvm_get_value(thread, phi_node.value);
|
||||||
|
const llvm_basic_block = phi_node.basic_block.get_llvm();
|
||||||
|
llvm_phi.addIncoming(llvm_value, llvm_basic_block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (debug_info) {
|
if (debug_info) {
|
||||||
const file_index = nat_function.declaration.file;
|
const file_index = nat_function.declaration.file;
|
||||||
@ -2915,6 +2977,38 @@ fn llvm_get_function(thread: *Thread, nat_function: *Function.Declaration, overr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_basic_block(thread: *Thread) *BasicBlock {
|
||||||
|
const block = thread.basic_blocks.append(.{
|
||||||
|
.value = .{
|
||||||
|
.sema = .{
|
||||||
|
.thread = thread.get_index(),
|
||||||
|
.resolved = true,
|
||||||
|
.id = .basic_block,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_return(thread: *Thread, analyzer: *Analyzer, return_value: *Value) void {
|
||||||
|
const return_expression = thread.returns.append(.{
|
||||||
|
.instruction = .{
|
||||||
|
.value = .{
|
||||||
|
.sema = .{
|
||||||
|
.thread = thread.get_index(),
|
||||||
|
.resolved = return_value.sema.resolved,
|
||||||
|
.id = .instruction,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.id = .ret,
|
||||||
|
},
|
||||||
|
.value = return_value,
|
||||||
|
});
|
||||||
|
|
||||||
|
_ = analyzer.current_basic_block.instructions.append(&return_expression.instruction);
|
||||||
|
analyzer.current_basic_block.is_terminated = true;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser, file: *File) void {
|
pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser, file: *File) void {
|
||||||
const src = file.source_code;
|
const src = file.source_code;
|
||||||
const function = analyzer.current_function;
|
const function = analyzer.current_function;
|
||||||
@ -2950,25 +3044,77 @@ pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser
|
|||||||
parser.skip_space(src);
|
parser.skip_space(src);
|
||||||
|
|
||||||
if (function.declaration.return_type.sema.id != .unresolved) {
|
if (function.declaration.return_type.sema.id != .unresolved) {
|
||||||
const return_value = parser.parse_expression(analyzer, thread, file, function.declaration.return_type, .right);
|
const return_type = function.declaration.return_type;
|
||||||
|
const return_value = parser.parse_expression(analyzer, thread, file, return_type, .right);
|
||||||
parser.expect_character(src, ';');
|
parser.expect_character(src, ';');
|
||||||
|
|
||||||
const return_expression = thread.returns.append(.{
|
if (analyzer.return_block) |return_block| {
|
||||||
|
const return_phi = analyzer.return_phi.?;
|
||||||
|
_ = return_phi.nodes.append(.{
|
||||||
|
.value = return_value,
|
||||||
|
.basic_block = analyzer.current_basic_block,
|
||||||
|
});
|
||||||
|
assert(analyzer.current_basic_block != return_block);
|
||||||
|
|
||||||
|
const jump = thread.jumps.append(.{
|
||||||
.instruction = .{
|
.instruction = .{
|
||||||
|
.id = .jump,
|
||||||
.value = .{
|
.value = .{
|
||||||
.sema = .{
|
.sema = .{
|
||||||
.thread = thread.get_index(),
|
|
||||||
.resolved = return_value.sema.resolved,
|
|
||||||
.id = .instruction,
|
.id = .instruction,
|
||||||
|
.resolved = true,
|
||||||
|
.thread = thread.get_index(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.id = .ret,
|
|
||||||
},
|
},
|
||||||
|
.basic_block = return_block,
|
||||||
|
});
|
||||||
|
_ = analyzer.current_basic_block.instructions.append(&jump.instruction);
|
||||||
|
analyzer.current_basic_block.is_terminated = true;
|
||||||
|
|
||||||
|
_ = return_block.predecessors.append(analyzer.current_basic_block);
|
||||||
|
} else if (analyzer.exit_blocks.length > 0) {
|
||||||
|
const return_phi = thread.phis.append(.{
|
||||||
|
.instruction = .{
|
||||||
|
.id = .phi,
|
||||||
|
.value = .{
|
||||||
|
.sema = .{
|
||||||
|
.id = .instruction,
|
||||||
|
.thread = thread.get_index(),
|
||||||
|
.resolved = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.type = return_type,
|
||||||
|
});
|
||||||
|
analyzer.return_phi = return_phi;
|
||||||
|
const return_block = create_basic_block(thread);
|
||||||
|
analyzer.return_block = return_block;
|
||||||
|
_ = return_phi.nodes.append(.{
|
||||||
.value = return_value,
|
.value = return_value,
|
||||||
|
.basic_block = analyzer.current_basic_block,
|
||||||
});
|
});
|
||||||
|
|
||||||
_ = analyzer.current_basic_block.instructions.append(&return_expression.instruction);
|
const jump = thread.jumps.append(.{
|
||||||
|
.instruction = .{
|
||||||
|
.id = .jump,
|
||||||
|
.value = .{
|
||||||
|
.sema = .{
|
||||||
|
.id = .instruction,
|
||||||
|
.resolved = true,
|
||||||
|
.thread = thread.get_index(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.basic_block = return_block,
|
||||||
|
});
|
||||||
|
_ = analyzer.current_basic_block.instructions.append(&jump.instruction);
|
||||||
analyzer.current_basic_block.is_terminated = true;
|
analyzer.current_basic_block.is_terminated = true;
|
||||||
|
|
||||||
|
_ = return_block.predecessors.append(analyzer.current_basic_block);
|
||||||
|
} else {
|
||||||
|
build_return(thread, analyzer, return_value);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -3105,7 +3251,12 @@ pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser
|
|||||||
parser.skip_space(src);
|
parser.skip_space(src);
|
||||||
|
|
||||||
const condition_type = condition.get_type();
|
const condition_type = condition.get_type();
|
||||||
|
const compare = switch (condition_type.sema.id) {
|
||||||
|
.integer => int: {
|
||||||
|
const integer_ty = condition_type.get_payload(.integer);
|
||||||
|
if (integer_ty.bit_count == 1) {
|
||||||
|
break :int condition;
|
||||||
|
} else {
|
||||||
const zero = thread.constant_ints.append(.{
|
const zero = thread.constant_ints.append(.{
|
||||||
.value = .{
|
.value = .{
|
||||||
.sema = .{
|
.sema = .{
|
||||||
@ -3131,30 +3282,22 @@ pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser
|
|||||||
},
|
},
|
||||||
.left = condition,
|
.left = condition,
|
||||||
.right = &zero.value,
|
.right = &zero.value,
|
||||||
.id = .not_equal,
|
.id = .not_zero,
|
||||||
});
|
});
|
||||||
_ = analyzer.current_basic_block.instructions.append(&compare.instruction);
|
_ = analyzer.current_basic_block.instructions.append(&compare.instruction);
|
||||||
|
|
||||||
const taken_block = thread.basic_blocks.append(.{
|
break :int &compare.instruction.value;
|
||||||
.value = .{
|
}
|
||||||
.sema = .{
|
|
||||||
.thread = thread.get_index(),
|
|
||||||
.resolved = true,
|
|
||||||
.id = .basic_block,
|
|
||||||
},
|
},
|
||||||
},
|
else => |t| @panic(@tagName(t)),
|
||||||
});
|
};
|
||||||
const exit_block = thread.basic_blocks.append(.{
|
|
||||||
.value = .{
|
|
||||||
.sema = .{
|
|
||||||
.thread = thread.get_index(),
|
|
||||||
.resolved = true,
|
|
||||||
.id = .basic_block,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const original_block = analyzer.current_basic_block;
|
const original_block = analyzer.current_basic_block;
|
||||||
|
|
||||||
|
const taken_block = create_basic_block(thread);
|
||||||
|
const exit_block = create_basic_block(thread);
|
||||||
|
_ = analyzer.exit_blocks.append(exit_block);
|
||||||
|
|
||||||
const branch = thread.branches.append(.{
|
const branch = thread.branches.append(.{
|
||||||
.instruction = .{
|
.instruction = .{
|
||||||
.value = .{
|
.value = .{
|
||||||
@ -3166,19 +3309,18 @@ pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser
|
|||||||
},
|
},
|
||||||
.id = .branch,
|
.id = .branch,
|
||||||
},
|
},
|
||||||
.condition = &compare.instruction.value,
|
.condition = compare,
|
||||||
.taken = taken_block,
|
.taken = taken_block,
|
||||||
.not_taken = exit_block,
|
.not_taken = exit_block,
|
||||||
});
|
});
|
||||||
_ = analyzer.current_basic_block.instructions.append(&branch.instruction);
|
_ = analyzer.current_basic_block.instructions.append(&branch.instruction);
|
||||||
|
|
||||||
analyzer.current_basic_block.is_terminated = true;
|
analyzer.current_basic_block.is_terminated = true;
|
||||||
|
|
||||||
analyzer.current_basic_block = branch.taken;
|
analyzer.current_basic_block = branch.taken;
|
||||||
_ = branch.taken.predecessors.append(original_block);
|
_ = branch.taken.predecessors.append(original_block);
|
||||||
|
|
||||||
switch (src[parser.i]) {
|
switch (src[parser.i]) {
|
||||||
'{' =>{
|
brace_open => {
|
||||||
analyze_local_block(thread, analyzer, parser, file);
|
analyze_local_block(thread, analyzer, parser, file);
|
||||||
},
|
},
|
||||||
else => @panic((src.ptr + parser.i)[0..1]),
|
else => @panic((src.ptr + parser.i)[0..1]),
|
||||||
@ -3195,7 +3337,7 @@ pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser
|
|||||||
parser.skip_space(src);
|
parser.skip_space(src);
|
||||||
|
|
||||||
switch (src[parser.i]) {
|
switch (src[parser.i]) {
|
||||||
'{' =>{
|
brace_open => {
|
||||||
analyze_local_block(thread, analyzer, parser, file);
|
analyze_local_block(thread, analyzer, parser, file);
|
||||||
},
|
},
|
||||||
else => @panic((src.ptr + parser.i)[0..1]),
|
else => @panic((src.ptr + parser.i)[0..1]),
|
||||||
@ -3231,7 +3373,6 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
|
|||||||
file.functions.start = @intCast(thread.functions.length);
|
file.functions.start = @intCast(thread.functions.length);
|
||||||
|
|
||||||
var parser = Parser{};
|
var parser = Parser{};
|
||||||
var analyzer = Analyzer{};
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
parser.skip_space(src);
|
parser.skip_space(src);
|
||||||
@ -3261,19 +3402,7 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
|
|||||||
parser.skip_space(src);
|
parser.skip_space(src);
|
||||||
|
|
||||||
const function = thread.functions.add_one();
|
const function = thread.functions.add_one();
|
||||||
const entry_block = thread.basic_blocks.append(.{
|
const entry_block = create_basic_block(thread);
|
||||||
.value = .{
|
|
||||||
.sema = .{
|
|
||||||
.thread = thread.get_index(),
|
|
||||||
.resolved = true,
|
|
||||||
.id = .basic_block,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
analyzer.current_function = function;
|
|
||||||
analyzer.current_basic_block = entry_block;
|
|
||||||
|
|
||||||
function.* = .{
|
function.* = .{
|
||||||
.declaration = .{
|
.declaration = .{
|
||||||
.return_type = undefined,
|
.return_type = undefined,
|
||||||
@ -3304,6 +3433,12 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
|
|||||||
.entry_block = entry_block,
|
.entry_block = entry_block,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var analyzer = Analyzer{
|
||||||
|
.current_function = function,
|
||||||
|
.current_basic_block = entry_block,
|
||||||
|
.current_scope = &function.scope.scope,
|
||||||
|
};
|
||||||
|
|
||||||
const has_function_attributes = src[parser.i] == '[';
|
const has_function_attributes = src[parser.i] == '[';
|
||||||
parser.i += @intFromBool(has_function_attributes);
|
parser.i += @intFromBool(has_function_attributes);
|
||||||
|
|
||||||
@ -3455,8 +3590,23 @@ pub fn analyze_file(thread: *Thread, file_index: u32) void {
|
|||||||
analyzer.current_scope = &analyzer.current_function.scope.scope;
|
analyzer.current_scope = &analyzer.current_function.scope.scope;
|
||||||
|
|
||||||
switch (src[parser.i]) {
|
switch (src[parser.i]) {
|
||||||
'{' => {
|
brace_open => {
|
||||||
analyze_local_block(thread, &analyzer, &parser, file);
|
analyze_local_block(thread, &analyzer, &parser, file);
|
||||||
|
|
||||||
|
const current_basic_block = analyzer.current_basic_block;
|
||||||
|
if (analyzer.return_phi) |return_phi| {
|
||||||
|
analyzer.current_basic_block = analyzer.return_block.?;
|
||||||
|
_ = analyzer.current_basic_block.instructions.append(&return_phi.instruction);
|
||||||
|
build_return(thread, &analyzer, &return_phi.instruction.value);
|
||||||
|
analyzer.current_basic_block = current_basic_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
const return_type = function.declaration.return_type;
|
||||||
|
_ = return_type;
|
||||||
|
|
||||||
|
if (!current_basic_block.is_terminated and (current_basic_block.instructions.length > 0 or current_basic_block.predecessors.length > 0)) {
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
';' => {
|
';' => {
|
||||||
unreachable;
|
unreachable;
|
||||||
@ -3668,6 +3818,7 @@ pub const LLVM = struct {
|
|||||||
const createGEP = bindings.NativityLLVMBuilderCreateGEP;
|
const createGEP = bindings.NativityLLVMBuilderCreateGEP;
|
||||||
const createStructGEP = bindings.NativityLLVMBuilderCreateStructGEP;
|
const createStructGEP = bindings.NativityLLVMBuilderCreateStructGEP;
|
||||||
const createICmp = bindings.NativityLLVMBuilderCreateICmp;
|
const createICmp = bindings.NativityLLVMBuilderCreateICmp;
|
||||||
|
const createIsNotNull = bindings.NativityLLVMBuilderCreateIsNotNull;
|
||||||
const createLoad = bindings.NativityLLVMBuilderCreateLoad;
|
const createLoad = bindings.NativityLLVMBuilderCreateLoad;
|
||||||
const createMultiply = bindings.NativityLLVMBuilderCreateMultiply;
|
const createMultiply = bindings.NativityLLVMBuilderCreateMultiply;
|
||||||
const createRet = bindings.NativityLLVMBuilderCreateRet;
|
const createRet = bindings.NativityLLVMBuilderCreateRet;
|
||||||
|
@ -296,6 +296,10 @@ pub fn PinnedArrayAdvanced(comptime T: type, comptime MaybeIndex: ?type, comptim
|
|||||||
if (@intFromPtr(item) >= top) return false;
|
if (@intFromPtr(item) >= top) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear(array: *@This()) void {
|
||||||
|
array.length = 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,6 +445,13 @@ extern "C" Value* NativityLLVMBuilderCreateICmp(IRBuilder<>& builder, CmpInst::P
|
|||||||
return icmp;
|
return icmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" Value* NativityLLVMBuilderCreateIsNotNull(IRBuilder<>& builder, Value* value, const char* name_ptr, size_t name_len)
|
||||||
|
{
|
||||||
|
auto name = StringRef(name_ptr, name_len);
|
||||||
|
auto* not_null = builder.CreateIsNotNull(value, name);
|
||||||
|
return not_null;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" LoadInst* NativityLLVMBuilderCreateLoad(IRBuilder<>& builder, Type* type, Value* pointer, bool is_volatile, const char* name_ptr, size_t name_len, uint32_t alignment)
|
extern "C" LoadInst* NativityLLVMBuilderCreateLoad(IRBuilder<>& builder, Type* type, Value* pointer, bool is_volatile, const char* name_ptr, size_t name_len, uint32_t alignment)
|
||||||
{
|
{
|
||||||
auto align = Align{alignment};
|
auto align = Align{alignment};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user