Merge pull request #202 from birth-software/phis

Implement phis
This commit is contained in:
David 2024-05-28 15:54:13 -06:00 committed by GitHub
commit 3d1cea128a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 266 additions and 103 deletions

View File

@ -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;

View File

@ -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);
const right = llvm_get_value(thread, compare.right); if (compare.id == .not_zero) {
const name = ""; const is_not_null = builder.createIsNotNull(left, "", "".len);
const comparison: LLVM.Value.Instruction.ICmp.Kind = switch (compare.id) { break :block is_not_null;
.equal => .eq, } else {
.not_equal => .ne, const right = llvm_get_value(thread, compare.right);
}; const name = "";
const comparison: LLVM.Value.Instruction.ICmp.Kind = switch (compare.id) {
.equal => .eq,
.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| {
.instruction = .{ const return_phi = analyzer.return_phi.?;
.value = .{ _ = return_phi.nodes.append(.{
.sema = .{ .value = return_value,
.thread = thread.get_index(), .basic_block = analyzer.current_basic_block,
.resolved = return_value.sema.resolved, });
.id = .instruction, assert(analyzer.current_basic_block != return_block);
},
},
.id = .ret,
},
.value = return_value,
});
_ = analyzer.current_basic_block.instructions.append(&return_expression.instruction); const jump = thread.jumps.append(.{
analyzer.current_basic_block.is_terminated = true; .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;
_ = 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,
.basic_block = analyzer.current_basic_block,
});
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;
_ = return_block.predecessors.append(analyzer.current_basic_block);
} else {
build_return(thread, analyzer, return_value);
}
} else { } else {
exit(1); exit(1);
} }
@ -3105,56 +3251,53 @@ 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(.{
.value = .{
.sema = .{
.thread = thread.get_index(),
.resolved = true,
.id = .constant_int,
},
},
.n = 0,
.type = condition_type,
});
const zero = thread.constant_ints.append(.{ const compare = thread.integer_compares.append(.{
.value = .{ .instruction = .{
.sema = .{ .value = .{
.thread = thread.get_index(), .sema = .{
.resolved = true, .thread = thread.get_index(),
.id = .constant_int, .resolved = true,
}, .id = .instruction,
}, },
.n = 0, },
.type = condition_type, .id = .integer_compare,
}); },
.left = condition,
.right = &zero.value,
.id = .not_zero,
});
_ = analyzer.current_basic_block.instructions.append(&compare.instruction);
const compare = thread.integer_compares.append(.{ break :int &compare.instruction.value;
.instruction = .{ }
.value = .{
.sema = .{
.thread = thread.get_index(),
.resolved = true,
.id = .instruction,
},
},
.id = .integer_compare,
}, },
.left = condition, else => |t| @panic(@tagName(t)),
.right = &zero.value, };
.id = .not_equal,
});
_ = analyzer.current_basic_block.instructions.append(&compare.instruction);
const taken_block = thread.basic_blocks.append(.{
.value = .{
.sema = .{
.thread = thread.get_index(),
.resolved = true,
.id = .basic_block,
},
},
});
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;

View File

@ -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;
}
}; };
} }

View File

@ -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};